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.sun.codemodel.JBlock; 019import com.sun.codemodel.JExpr; 020import org.androidtransfuse.adapter.ASTMethod; 021import org.androidtransfuse.adapter.ASTType; 022import org.androidtransfuse.adapter.PackageClass; 023import org.androidtransfuse.adapter.element.ASTElementFactory; 024import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor; 025import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository; 026import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory; 027import org.androidtransfuse.annotations.Service; 028import org.androidtransfuse.experiment.*; 029import org.androidtransfuse.experiment.generators.ObservesExpressionGenerator; 030import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator; 031import org.androidtransfuse.experiment.generators.ServiceManifestEntryGenerator; 032import org.androidtransfuse.gen.GeneratorFactory; 033import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator; 034import org.androidtransfuse.gen.variableBuilder.InjectionBindingBuilder; 035import org.androidtransfuse.gen.variableBuilder.ProviderInjectionNodeBuilderFactory; 036import org.androidtransfuse.intentFactory.ServiceIntentFactoryStrategy; 037import org.androidtransfuse.model.InjectionSignature; 038import org.androidtransfuse.model.MethodDescriptor; 039import org.androidtransfuse.scope.ApplicationScope; 040import org.androidtransfuse.util.AndroidLiterals; 041 042import javax.inject.Inject; 043import javax.lang.model.type.TypeMirror; 044 045import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror; 046 047/** 048 * Service related Analysis 049 * 050 * @author John Ericksen 051 */ 052public class ServiceAnalysis implements Analysis<ComponentDescriptor> { 053 054 private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory; 055 private final AnalysisContextFactory analysisContextFactory; 056 private final ASTElementFactory astElementFactory; 057 private final ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder; 058 private final InjectionBindingBuilder injectionBindingBuilder; 059 private final ASTTypeBuilderVisitor astTypeBuilderVisitor; 060 private final GeneratorFactory generatorFactory; 061 private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory; 062 private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionDecoratorFactory; 063 private final ServiceManifestEntryGenerator serviceManifestEntryGenerator; 064 private final OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory; 065 private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory; 066 private final ComponentAnalysis componentAnalysis; 067 068 @Inject 069 public ServiceAnalysis(InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory, 070 AnalysisContextFactory analysisContextFactory, 071 ASTElementFactory astElementFactory, 072 ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder, 073 InjectionBindingBuilder injectionBindingBuilder, 074 ASTTypeBuilderVisitor astTypeBuilderVisitor, 075 GeneratorFactory generatorFactory, 076 ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory, 077 ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionDecoratorFactory, 078 ServiceManifestEntryGenerator serviceManifestEntryGenerator, 079 OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory, 080 ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory, 081 ComponentAnalysis componentAnalysis) { 082 this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory; 083 this.analysisContextFactory = analysisContextFactory; 084 this.astElementFactory = astElementFactory; 085 this.providerInjectionNodeBuilder = providerInjectionNodeBuilder; 086 this.injectionBindingBuilder = injectionBindingBuilder; 087 this.astTypeBuilderVisitor = astTypeBuilderVisitor; 088 this.generatorFactory = generatorFactory; 089 this.listenerRegistrationGeneratorFactory = listenerRegistrationGeneratorFactory; 090 this.observesExpressionDecoratorFactory = observesExpressionDecoratorFactory; 091 this.serviceManifestEntryGenerator = serviceManifestEntryGenerator; 092 this.onCreateInjectionGeneratorFactory = onCreateInjectionGeneratorFactory; 093 this.scopesGenerationFactory = scopesGenerationFactory; 094 this.componentAnalysis = componentAnalysis; 095 } 096 097 public ComponentDescriptor analyze(ASTType input) { 098 099 Service serviceAnnotation = input.getAnnotation(Service.class); 100 PackageClass serviceClassName; 101 ComponentDescriptor serviceDescriptor = null; 102 103 if (input.extendsFrom(AndroidLiterals.SERVICE)) { 104 //vanilla Android Service 105 PackageClass packageClass = input.getPackageClass(); 106 serviceClassName = componentAnalysis.buildComponentPackageClass(input, packageClass.getClassName(), "Service"); 107 108 serviceDescriptor = new ComponentDescriptor(input, null, packageClass); 109 } else { 110 //generated Android Service 111 serviceClassName = componentAnalysis.buildComponentPackageClass(input, serviceAnnotation.name(), "Service"); 112 113 TypeMirror type = getTypeMirror(serviceAnnotation, "type"); 114 115 ASTType serviceType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.SERVICE : type.accept(astTypeBuilderVisitor, null); 116 117 AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(serviceType)); 118 119 serviceDescriptor = new ComponentDescriptor(input, serviceType, serviceClassName, context); 120 121 componentAnalysis.setupGenerators(serviceDescriptor, serviceType, Service.class); 122 123 serviceDescriptor.getGenerators().add(onCreateInjectionGeneratorFactory.build(getASTMethod("onCreate"), input)); 124 serviceDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onCreate"))); 125 serviceDescriptor.getGenerators().add(new OnBindGenerator()); 126 serviceDescriptor.getGenerators().add(listenerRegistrationGeneratorFactory.build(getASTMethod("onCreate"))); 127 serviceDescriptor.getGenerators().add(observesExpressionDecoratorFactory.build( 128 getASTMethod("onCreate"), 129 getASTMethod("onCreate"), 130 getASTMethod("onDestroy") 131 )); 132 serviceDescriptor.getGenerators().add(generatorFactory.buildStrategyGenerator(ServiceIntentFactoryStrategy.class)); 133 } 134 135 serviceDescriptor.getGenerators().add(serviceManifestEntryGenerator); 136 137 return serviceDescriptor; 138 } 139 140 private ASTMethod getASTMethod(String methodName, ASTType... args) { 141 return getASTMethod(AndroidLiterals.SERVICE, methodName, args); 142 } 143 144 private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) { 145 return astElementFactory.findMethod(type, methodName, args); 146 } 147 148 private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType serviceType) { 149 150 InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(serviceType, Service.class); 151 152 153 ASTType applicationScopeType = astElementFactory.getType(ApplicationScope.ApplicationScopeQualifier.class); 154 ASTType applicationProvider = astElementFactory.getType(ApplicationScope.ApplicationProvider.class); 155 injectionNodeBuilderRepository.putType(AndroidLiterals.APPLICATION, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider)); 156 injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.buildThis(AndroidLiterals.CONTEXT)); 157 injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.APPLICATION), applicationScopeType); 158 159 injectionNodeBuilderRepository.putType(AndroidLiterals.SERVICE, injectionBindingBuilder.buildThis(AndroidLiterals.SERVICE)); 160 161 while(!serviceType.equals(AndroidLiterals.SERVICE) && serviceType.inheritsFrom(AndroidLiterals.SERVICE)){ 162 injectionNodeBuilderRepository.putType(serviceType, injectionBindingBuilder.buildThis(serviceType)); 163 serviceType = serviceType.getSuperClass(); 164 } 165 166 injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildApplicationInjections()); 167 injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildModuleConfiguration()); 168 169 return injectionNodeBuilderRepository; 170 171 } 172 173 private final class OnBindGenerator implements Generation { 174 @Override 175 public void schedule(ComponentBuilder builder, ComponentDescriptor descriptor) { 176 builder.add(getASTMethod("onBind", AndroidLiterals.INTENT), GenerationPhase.INIT, new ComponentMethodGenerator() { 177 @Override 178 public void generate(MethodDescriptor methodDescriptor, JBlock block) { 179 block._return(JExpr._null()); 180 } 181 }); 182 } 183 } 184}