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 org.androidtransfuse.adapter.ASTMethod;
019import org.androidtransfuse.adapter.ASTType;
020import org.androidtransfuse.adapter.PackageClass;
021import org.androidtransfuse.adapter.element.ASTElementFactory;
022import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor;
023import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository;
024import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory;
025import org.androidtransfuse.annotations.Application;
026import org.androidtransfuse.experiment.ComponentDescriptor;
027import org.androidtransfuse.experiment.ScopesGeneration;
028import org.androidtransfuse.experiment.generators.ApplicationManifestEntryGenerator;
029import org.androidtransfuse.experiment.generators.ApplicationScopeSeedGenerator;
030import org.androidtransfuse.experiment.generators.ObservesExpressionGenerator;
031import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator;
032import org.androidtransfuse.gen.variableBuilder.ProviderInjectionNodeBuilderFactory;
033import org.androidtransfuse.model.InjectionSignature;
034import org.androidtransfuse.scope.ApplicationScope;
035import org.androidtransfuse.util.AndroidLiterals;
036
037import javax.inject.Inject;
038import javax.lang.model.type.TypeMirror;
039
040import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror;
041
042/**
043 * @author John Ericksen
044 */
045public class ApplicationAnalysis implements Analysis<ComponentDescriptor> {
046
047    private final InjectionNodeBuilderRepositoryFactory variableBuilderRepositoryFactory;
048    private final ASTElementFactory astElementFactory;
049    private final ASTTypeBuilderVisitor astTypeBuilderVisitor;
050    private final AnalysisContextFactory analysisContextFactory;
051    private final ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder;
052    private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory;
053    private final OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory;
054    private final ApplicationManifestEntryGenerator applicationManifestEntryGenerator;
055    private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory;
056    private final ComponentAnalysis componentAnalysis;
057    private final ApplicationScopeSeedGenerator applicationScopeSeedGenerator;
058
059    @Inject
060    public ApplicationAnalysis(InjectionNodeBuilderRepositoryFactory variableBuilderRepositoryFactory,
061                               ASTElementFactory astElementFactory,
062                               ASTTypeBuilderVisitor astTypeBuilderVisitor,
063                               AnalysisContextFactory analysisContextFactory,
064                               ProviderInjectionNodeBuilderFactory providerInjectionNodeBuilder,
065                               ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionGeneratorFactory,
066                               OnCreateInjectionGenerator.InjectionGeneratorFactory injectionGeneratorFactory,
067                               ApplicationManifestEntryGenerator applicationManifestEntryGenerator,
068                               ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory,
069                               ComponentAnalysis componentAnalysis,
070                               ApplicationScopeSeedGenerator applicationScopeSeedGenerator) {
071        this.variableBuilderRepositoryFactory = variableBuilderRepositoryFactory;
072        this.astElementFactory = astElementFactory;
073        this.astTypeBuilderVisitor = astTypeBuilderVisitor;
074        this.analysisContextFactory = analysisContextFactory;
075        this.providerInjectionNodeBuilder = providerInjectionNodeBuilder;
076        this.observesExpressionGeneratorFactory = observesExpressionGeneratorFactory;
077        this.injectionGeneratorFactory = injectionGeneratorFactory;
078        this.applicationManifestEntryGenerator = applicationManifestEntryGenerator;
079        this.scopesGenerationFactory = scopesGenerationFactory;
080        this.componentAnalysis = componentAnalysis;
081        this.applicationScopeSeedGenerator = applicationScopeSeedGenerator;
082    }
083
084    public ComponentDescriptor analyze(ASTType astType) {
085        Application applicationAnnotation = astType.getAnnotation(Application.class);
086
087
088        PackageClass applicationClassName;
089        ComponentDescriptor applicationDescriptor = null;
090
091        if (astType.extendsFrom(AndroidLiterals.APPLICATION)) {
092            //vanilla Android Application
093            PackageClass activityPackageClass = astType.getPackageClass();
094            applicationClassName = componentAnalysis.buildComponentPackageClass(astType, activityPackageClass.getClassName(), "Application");
095            applicationDescriptor = new ComponentDescriptor(astType, null, applicationClassName);
096        } else {
097
098            applicationClassName = componentAnalysis.buildComponentPackageClass(astType, applicationAnnotation.name(), "Application");
099
100            TypeMirror type = getTypeMirror(applicationAnnotation, "type");
101
102            ASTType applicationType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.APPLICATION : type.accept(astTypeBuilderVisitor, null);
103
104            //analyze delegate
105            AnalysisContext analysisContext = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(applicationType));
106
107            applicationDescriptor = new ComponentDescriptor(astType, applicationType, applicationClassName, analysisContext);
108
109            componentAnalysis.setupGenerators(applicationDescriptor, applicationType, Application.class);
110
111            applicationDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onCreate")));
112            applicationDescriptor.getGenerators().add(injectionGeneratorFactory.build(getASTMethod("onCreate"), astType));
113            applicationDescriptor.getGenerators().add(observesExpressionGeneratorFactory.build(
114                    getASTMethod("onCreate"),
115                    getASTMethod("onCreate"),
116                    getASTMethod("onTerminate")
117            ));
118            applicationDescriptor.getGenerators().add(applicationScopeSeedGenerator);
119        }
120
121        //add manifest elements
122        applicationDescriptor.getGenerators().add(applicationManifestEntryGenerator);
123
124        return applicationDescriptor;
125    }
126
127    private ASTMethod getASTMethod(String methodName, ASTType... args) {
128        return astElementFactory.findMethod(AndroidLiterals.APPLICATION, methodName, args);
129    }
130
131    private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType applicationType) {
132        InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(applicationType, Application.class);
133
134
135        ASTType applicationScopeType = astElementFactory.getType(ApplicationScope.ApplicationScopeQualifier.class);
136        ASTType applicationProvider = astElementFactory.getType(ApplicationScope.ApplicationProvider.class);
137        injectionNodeBuilderRepository.putType(AndroidLiterals.APPLICATION, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider));
138        injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, providerInjectionNodeBuilder.builderProviderBuilder(applicationProvider));
139        injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.APPLICATION), applicationScopeType);
140        injectionNodeBuilderRepository.putScoped(new InjectionSignature(AndroidLiterals.CONTEXT), applicationScopeType);
141
142        /*while(!applicationType.equals(AndroidLiterals.APPLICATION) && applicationType.inheritsFrom(AndroidLiterals.APPLICATION)){
143            injectionNodeBuilderRepository.putType(applicationType, injectionBindingBuilder.buildThis(applicationType));
144            applicationType = applicationType.getSuperClass();
145        }*/
146
147
148        injectionNodeBuilderRepository.addRepository(variableBuilderRepositoryFactory.buildApplicationInjections());
149        injectionNodeBuilderRepository.addRepository(variableBuilderRepositoryFactory.buildModuleConfiguration());
150
151        return injectionNodeBuilderRepository;
152
153    }
154}