/**
* 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.sun.codemodel.JBlock;
import com.sun.codemodel.JExpr;
import org.androidtransfuse.adapter.ASTMethod;
import org.androidtransfuse.adapter.ASTType;
import org.androidtransfuse.adapter.PackageClass;
import org.androidtransfuse.adapter.element.ASTElementFactory;
import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor;
import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepository;
import org.androidtransfuse.analysis.repository.InjectionNodeBuilderRepositoryFactory;
import org.androidtransfuse.annotations.Service;
import org.androidtransfuse.experiment.*;
import org.androidtransfuse.experiment.generators.IntentFactoryGenerator;
import org.androidtransfuse.experiment.generators.ObservesExpressionGenerator;
import org.androidtransfuse.experiment.generators.OnCreateInjectionGenerator;
import org.androidtransfuse.experiment.generators.ServiceManifestEntryGenerator;
import org.androidtransfuse.gen.GeneratorFactory;
import org.androidtransfuse.gen.componentBuilder.ListenerRegistrationGenerator;
import org.androidtransfuse.gen.variableBuilder.InjectionBindingBuilder;
import org.androidtransfuse.intentFactory.ServiceIntentFactoryStrategy;
import org.androidtransfuse.model.MethodDescriptor;
import org.androidtransfuse.util.AndroidLiterals;
import javax.inject.Inject;
import javax.lang.model.type.TypeMirror;
import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror;
/**
* Service related Analysis
*
* @author John Ericksen
*/
public class ServiceAnalysis implements Analysis<ComponentDescriptor> {
private final InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory;
private final AnalysisContextFactory analysisContextFactory;
private final ASTElementFactory astElementFactory;
private final InjectionBindingBuilder injectionBindingBuilder;
private final ASTTypeBuilderVisitor astTypeBuilderVisitor;
private final GeneratorFactory generatorFactory;
private final ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory;
private final ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionDecoratorFactory;
private final ServiceManifestEntryGenerator serviceManifestEntryGenerator;
private final OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory;
private final ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory;
private final ComponentAnalysis componentAnalysis;
private final IntentFactoryGenerator intentFactoryGenerator;
@Inject
public ServiceAnalysis(InjectionNodeBuilderRepositoryFactory injectionNodeBuilderRepositoryFactory,
AnalysisContextFactory analysisContextFactory,
ASTElementFactory astElementFactory,
InjectionBindingBuilder injectionBindingBuilder,
ASTTypeBuilderVisitor astTypeBuilderVisitor,
GeneratorFactory generatorFactory,
ListenerRegistrationGenerator.ListerRegistrationGeneratorFactory listenerRegistrationGeneratorFactory,
ObservesExpressionGenerator.ObservesExpressionGeneratorFactory observesExpressionDecoratorFactory,
ServiceManifestEntryGenerator serviceManifestEntryGenerator,
OnCreateInjectionGenerator.InjectionGeneratorFactory onCreateInjectionGeneratorFactory,
ScopesGeneration.ScopesGenerationFactory scopesGenerationFactory,
ComponentAnalysis componentAnalysis,
IntentFactoryGenerator intentFactoryGenerator) {
this.injectionNodeBuilderRepositoryFactory = injectionNodeBuilderRepositoryFactory;
this.analysisContextFactory = analysisContextFactory;
this.astElementFactory = astElementFactory;
this.injectionBindingBuilder = injectionBindingBuilder;
this.astTypeBuilderVisitor = astTypeBuilderVisitor;
this.generatorFactory = generatorFactory;
this.listenerRegistrationGeneratorFactory = listenerRegistrationGeneratorFactory;
this.observesExpressionDecoratorFactory = observesExpressionDecoratorFactory;
this.serviceManifestEntryGenerator = serviceManifestEntryGenerator;
this.onCreateInjectionGeneratorFactory = onCreateInjectionGeneratorFactory;
this.scopesGenerationFactory = scopesGenerationFactory;
this.componentAnalysis = componentAnalysis;
this.intentFactoryGenerator = intentFactoryGenerator;
}
public ComponentDescriptor analyze(ASTType input) {
Service serviceAnnotation = input.getAnnotation(Service.class);
PackageClass serviceClassName;
ComponentDescriptor serviceDescriptor = null;
if (input.inherits(AndroidLiterals.SERVICE)) {
//vanilla Android Service
PackageClass packageClass = input.getPackageClass();
serviceClassName = componentAnalysis.buildComponentPackageClass(input, packageClass.getClassName(), "Service");
serviceDescriptor = new ComponentDescriptor(input, null, packageClass);
} else {
//generated Android Service
serviceClassName = componentAnalysis.buildComponentPackageClass(input, serviceAnnotation.name(), "Service");
TypeMirror type = getTypeMirror(serviceAnnotation, "type");
ASTType serviceType = type == null || type.toString().equals("java.lang.Object") ? AndroidLiterals.SERVICE : type.accept(astTypeBuilderVisitor, null);
AnalysisContext context = analysisContextFactory.buildAnalysisContext(buildVariableBuilderMap(serviceType));
serviceDescriptor = new ComponentDescriptor(input, serviceType, serviceClassName, context);
componentAnalysis.setupGenerators(serviceDescriptor, serviceType, Service.class);
serviceDescriptor.getGenerators().add(onCreateInjectionGeneratorFactory.build(getASTMethod("onCreate"), input));
serviceDescriptor.getGenerators().add(scopesGenerationFactory.build(getASTMethod("onCreate")));
serviceDescriptor.getGenerators().add(new OnBindGenerator());
serviceDescriptor.getGenerators().add(listenerRegistrationGeneratorFactory.build(getASTMethod("onCreate")));
serviceDescriptor.getGenerators().add(observesExpressionDecoratorFactory.build(
getASTMethod("onCreate"),
getASTMethod("onDestroy"),
getASTMethod("onCreate"),
getASTMethod("onDestroy")
));
serviceDescriptor.getGenerators().add(generatorFactory.buildStrategyGenerator(ServiceIntentFactoryStrategy.class));
}
serviceDescriptor.getGenerators().add(serviceManifestEntryGenerator);
serviceDescriptor.getGenerators().add(intentFactoryGenerator);
return serviceDescriptor;
}
private ASTMethod getASTMethod(String methodName, ASTType... args) {
return getASTMethod(AndroidLiterals.SERVICE, methodName, args);
}
private ASTMethod getASTMethod(ASTType type, String methodName, ASTType... args) {
return astElementFactory.findMethod(type, methodName, args);
}
private InjectionNodeBuilderRepository buildVariableBuilderMap(ASTType serviceType) {
InjectionNodeBuilderRepository injectionNodeBuilderRepository = componentAnalysis.setupInjectionNodeBuilderRepository(serviceType, Service.class);
injectionNodeBuilderRepository.putType(AndroidLiterals.CONTEXT, injectionBindingBuilder.buildThis(AndroidLiterals.CONTEXT));
injectionNodeBuilderRepository.putType(AndroidLiterals.SERVICE, injectionBindingBuilder.buildThis(AndroidLiterals.SERVICE));
while(!serviceType.equals(AndroidLiterals.SERVICE) && serviceType.inherits(AndroidLiterals.SERVICE)){
injectionNodeBuilderRepository.putType(serviceType, injectionBindingBuilder.buildThis(serviceType));
serviceType = serviceType.getSuperClass();
}
injectionNodeBuilderRepository.addRepository(injectionNodeBuilderRepositoryFactory.buildModuleConfiguration());
return injectionNodeBuilderRepository;
}
private final class OnBindGenerator implements Generation {
@Override
public void schedule(ComponentBuilder builder, ComponentDescriptor descriptor) {
builder.add(getASTMethod("onBind", AndroidLiterals.INTENT), GenerationPhase.INIT, new ComponentMethodGenerator() {
@Override
public void generate(MethodDescriptor methodDescriptor, JBlock block) {
block._return(JExpr._null());
}
});
}
@Override
public String getName() {
return "Service OnBind Generator";
}
}
}