001/** 002 * Copyright 2013 John Ericksen 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.androidtransfuse.analysis; 017 018import com.google.common.base.Joiner; 019import com.google.common.collect.ImmutableMap; 020import org.androidtransfuse.EventMapping; 021import org.androidtransfuse.TransfuseAnalysisException; 022import org.androidtransfuse.adapter.ASTMethod; 023import org.androidtransfuse.adapter.ASTType; 024import org.androidtransfuse.adapter.MethodSignature; 025import org.androidtransfuse.adapter.PackageClass; 026import org.androidtransfuse.adapter.classes.ASTClassFactory; 027import org.androidtransfuse.adapter.element.ASTElementFactory; 028import org.androidtransfuse.analysis.astAnalyzer.RegistrationAnalyzer; 029import org.androidtransfuse.analysis.astAnalyzer.registration.RegistrationGenerators; 030import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository; 031import org.androidtransfuse.analysis.repository.RegistrationGeneratorFactory; 032import org.androidtransfuse.experiment.ComponentDescriptor; 033import org.androidtransfuse.experiment.generators.MethodCallbackGenerator; 034import org.androidtransfuse.experiment.generators.SuperGenerator; 035import org.androidtransfuse.gen.componentBuilder.ComponentBuilderFactory; 036import org.apache.commons.lang.StringUtils; 037 038import javax.inject.Inject; 039import javax.inject.Provider; 040import java.lang.annotation.Annotation; 041import java.util.List; 042import java.util.Map; 043 044/** 045 * @author John Ericksen 046 */ 047public class ComponentAnalysis { 048 049 private final ConfigurationRepositoryImpl repository; 050 private final ASTElementFactory astElementFactory; 051 private final ASTClassFactory astClassFactory; 052 private final ComponentBuilderFactory componentBuilderFactory; 053 private final SuperGenerator.SuperGeneratorFactory superGeneratorFactory; 054 private final Provider<InjectionNodeBuilderRepository> injectionNodeBuilderRepositoryProvider; 055 private final RegistrationGenerators registrationGenerators; 056 private final ManualSuperGenerator.Factory manualSuperGeneratorFactory; 057 058 @Inject 059 public ComponentAnalysis(ConfigurationRepositoryImpl repository, 060 ASTElementFactory astElementFactory, 061 ASTClassFactory astClassFactory, 062 ComponentBuilderFactory componentBuilderFactory, 063 SuperGenerator.SuperGeneratorFactory superGeneratorFactory, 064 Provider<InjectionNodeBuilderRepository> injectionNodeBuilderRepositoryProvider, 065 RegistrationGenerators registrationGenerators, 066 ManualSuperGenerator.Factory manualSuperGeneratorFactory){ 067 this.repository = repository; 068 this.astElementFactory = astElementFactory; 069 this.astClassFactory = astClassFactory; 070 this.componentBuilderFactory = componentBuilderFactory; 071 this.superGeneratorFactory = superGeneratorFactory; 072 this.injectionNodeBuilderRepositoryProvider = injectionNodeBuilderRepositoryProvider; 073 this.registrationGenerators = registrationGenerators; 074 this.manualSuperGeneratorFactory = manualSuperGeneratorFactory; 075 } 076 077 078 public void setupGenerators(ComponentDescriptor descriptor, ASTType componentType, Class<? extends Annotation> componentAnnotation) { 079 Registration registration = repository.getRegistration(componentType, componentAnnotation); 080 ASTMethod registrationMethod = getASTMethod(componentType, registration.getMethodName(), registration.getParameters()); 081 descriptor.getGenerateFirst().add(new MethodSignature(registrationMethod)); 082 addSuperCalls(descriptor, componentType, componentAnnotation); 083 addEvents(descriptor, componentType, componentAnnotation, registrationMethod); 084 085 descriptor.getGenerators().add(manualSuperGeneratorFactory.build(registrationMethod)); 086 } 087 088 private void addSuperCalls(ComponentDescriptor descriptor, ASTType componentType, Class<? extends Annotation> componentAnnotation) { 089 for (SuperCallMapping superCallMapping : repository.getSuperCalls(componentType, componentAnnotation)) { 090 descriptor.getGenerators().add(superGeneratorFactory.build(getASTMethod(componentType, superCallMapping.getMethodName(), superCallMapping.getParameters()))); 091 } 092 } 093 094 public void addEvents(ComponentDescriptor descriptor, ASTType componentType, Class<? extends Annotation> componentAnnotation, ASTMethod registrationMethod) { 095 for (EventMapping eventMapping : repository.getEvents(componentType, componentAnnotation)) { 096 descriptor.getGenerators().add(buildEventMethod(componentType, eventMapping, registrationMethod)); 097 } 098 } 099 100 private MethodCallbackGenerator buildEventMethod(ASTType componentType, EventMapping eventMapping, ASTMethod registrationMethod){ 101 ASTMethod method = getASTMethod(componentType, eventMapping.getMethodName(), eventMapping.getMethodArguments()); 102 103 if(method == null){ 104 throw new TransfuseAnalysisException("Unable to find method with signature: " + 105 componentType + "." + 106 eventMapping.getMethodName() + "(" + Joiner.on(", ").join(eventMapping.getMethodArguments()) + ")"); 107 } 108 109 ASTType eventAnnotation = astClassFactory.getType(eventMapping.getAnnotation()); 110 111 return componentBuilderFactory.buildMethodCallbackGenerator(eventAnnotation, method, registrationMethod); 112 } 113 114 private ASTMethod getASTMethod(ASTType type, String methodName, List<ASTType> args) { 115 return astElementFactory.findMethod(type, methodName, args.toArray(new ASTType[args.size()])); 116 } 117 118 public InjectionNodeBuilderRepository setupInjectionNodeBuilderRepository(ASTType componentType, Class<? extends Annotation> componentAnnotation) { 119 InjectionNodeBuilderRepository injectionNodeBuilderRepository = injectionNodeBuilderRepositoryProvider.get(); 120 121 ImmutableMap.Builder<ASTType, RegistrationGeneratorFactory> builder = ImmutableMap.builder(); 122 123 for (Map.Entry<ASTType, ListenableMethod> listenerEntry : repository.getListeners(componentType, componentAnnotation).entrySet()) { 124 builder.put(listenerEntry.getKey(), registrationGenerators.buildViewRegistrationGenerator(listenerEntry.getValue())); 125 } 126 127 for (Class<?> listenerClass : repository.getCallThroughClasses(componentType, componentAnnotation)) { 128 ASTType listenerType = astElementFactory.getType(listenerClass); 129 builder.put(listenerType, registrationGenerators.buildCallThroughMethodGenerator(listenerType)); 130 } 131 132 injectionNodeBuilderRepository.getAnalysisRepository().add(new RegistrationAnalyzer(builder.build())); 133 134 return injectionNodeBuilderRepository; 135 } 136 137 public PackageClass buildComponentPackageClass(ASTType astType, String className, String componentName) { 138 PackageClass inputPackageClass = astType.getPackageClass(); 139 140 if (StringUtils.isBlank(className)) { 141 return inputPackageClass.append(componentName); 142 } else { 143 return inputPackageClass.replaceName(className); 144 } 145 } 146}