/**
* Copyright 2011-2015 John Ericksen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.androidtransfuse.analysis;
import com.google.common.base.Function;
import com.google.common.collect.FluentIterable;
import org.androidtransfuse.ComponentBuilder;
import org.androidtransfuse.ConfigurationRepository;
import org.androidtransfuse.EventMapping;
import org.androidtransfuse.InjectionMapping;
import org.androidtransfuse.adapter.ASTType;
import org.androidtransfuse.adapter.classes.ASTClassFactory;
import org.androidtransfuse.util.matcher.Matcher;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.lang.annotation.Annotation;
import java.util.*;
/**
* @author John Ericksen
*/
@Singleton
public class ConfigurationRepositoryImpl implements ConfigurationRepository{
private final ASTClassFactory astClassFactory;
private final Map<Matcher<AnnotatedType>, Configuration> configurations = new HashMap<Matcher<AnnotatedType>, Configuration>();
private static class Configuration{
private final List<EventMapping> events = new ArrayList<EventMapping>();
private final List<InjectionMapping> mappings = new ArrayList<InjectionMapping>();
private final List<SuperCallMapping> superCalls = new ArrayList<SuperCallMapping>();
private final Set<Class<?>> callThroughEvents = new HashSet<Class<?>>();
private final Map<ASTType, ListenableMethod> listeners = new HashMap<ASTType, ListenableMethod>();
private Registration registraion = null;
}
@Inject
public ConfigurationRepositoryImpl(ASTClassFactory astClassFactory) {
this.astClassFactory = astClassFactory;
}
private List<Configuration> findConfigurations(ASTType type, Class<? extends Annotation> annotation){
AnnotatedType signature = new AnnotatedType(type, astClassFactory.getType(annotation));
List<Configuration> matched = new ArrayList<Configuration>();
for (Map.Entry<Matcher<AnnotatedType>,Configuration> configurationEntry : configurations.entrySet()) {
if(configurationEntry.getKey().matches(signature)){
matched.add(configurationEntry.getValue());
}
}
return matched;
}
private Configuration getConfiguration(ASTType type, Class<? extends Annotation> annotation){
AnnotatedTypeMatcher annotatedTypeMatcher = new AnnotatedTypeMatcher(type, astClassFactory.getType(annotation));
if(!configurations.containsKey(annotatedTypeMatcher)){
configurations.put(annotatedTypeMatcher, new Configuration());
}
return configurations.get(annotatedTypeMatcher);
}
@Override
public void addRegistration(Class<? extends Annotation> componentAnnotation, ASTType componentType, String methodName, List<ASTType> parameters) {
getConfiguration(componentType, componentAnnotation).registraion = new Registration(methodName, parameters);
}
@Override
public void addSuperCall(Class<? extends Annotation> componentAnnotation, ASTType componentType, String methodName, List<ASTType> parameters, boolean executeLast) {
getConfiguration(componentType, componentAnnotation).superCalls.add(new SuperCallMapping(methodName, parameters, executeLast));
}
@Override
public ComponentBuilder component(Class<? extends Annotation> annotation) {
return new ComponentBuilder(this, annotation);
}
@Override
public void addEvent(Class<? extends Annotation> componentType, ASTType type, EventMapping eventMapping) {
getConfiguration(type, componentType).events.add(eventMapping);
}
public void addMapping(Class<? extends Annotation> componentType, ASTType type, InjectionMapping injectionMapping) {
getConfiguration(type, componentType).mappings.add(injectionMapping);
}
@Override
public void addCallThroughEvent(Class<? extends Annotation> componentType, ASTType type, Class<?> callThroughEventClass) {
getConfiguration(type, componentType).callThroughEvents.add(callThroughEventClass);
}
@Override
public void addListener(Class<? extends Annotation> componentType, ASTType type, ASTType listenerType, ASTType listenable, String listenerMethod) {
getConfiguration(type, componentType).listeners.put(listenerType, new ListenableMethod(listenable, listenerMethod));
}
public List<EventMapping> getEvents(ASTType type, Class<? extends Annotation> annotation){
return FluentIterable.from(findConfigurations(type, annotation))
.transformAndConcat(new Function<Configuration, Iterable<EventMapping>>() {
public Iterable<EventMapping> apply(Configuration configuration) {
return configuration.events;
}
}).toList();
}
public List<InjectionMapping> getMappings(ASTType type, Class<? extends Annotation> annotation) {
return FluentIterable.from(findConfigurations(type, annotation))
.transformAndConcat(new Function<Configuration, Iterable<InjectionMapping>>() {
public Iterable<InjectionMapping> apply(Configuration configuration) {
return configuration.mappings;
}
}).toList();
}
public Map<ASTType, ListenableMethod> getListeners(ASTType type, Class<? extends Annotation> annotation) {
Map<ASTType, ListenableMethod> matchedListeners = new HashMap<ASTType, ListenableMethod>();
for (Configuration configuration : findConfigurations(type, annotation)) {
matchedListeners.putAll(configuration.listeners);
}
return matchedListeners;
}
public Set<Class<?>> getCallThroughClasses(ASTType type, Class<? extends Annotation> annotation) {
return FluentIterable.from(findConfigurations(type, annotation))
.transformAndConcat(new Function<Configuration, Iterable<Class<?>>>() {
public Iterable<Class<?>> apply(Configuration configuration) {
return configuration.callThroughEvents;
}
}).toSet();
}
public List<SuperCallMapping> getSuperCalls(ASTType type, Class<? extends Annotation> annotation){
return FluentIterable.from(findConfigurations(type, annotation))
.transformAndConcat(new Function<Configuration, Iterable<SuperCallMapping>>() {
public Iterable<SuperCallMapping> apply(Configuration configuration) {
return configuration.superCalls;
}
}).toList();
}
public Registration getRegistration(ASTType type, Class<? extends Annotation> annotation){
for(Configuration configuration : findConfigurations(type, annotation)){
if(configuration.registraion != null){
return configuration.registraion;
}
}
return null;
}
}