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}