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.experiment.generators; 017 018import com.sun.codemodel.*; 019import org.androidtransfuse.TransfuseAnalysisException; 020import org.androidtransfuse.adapter.ASTMethod; 021import org.androidtransfuse.adapter.ASTType; 022import org.androidtransfuse.adapter.element.ASTElementFactory; 023import org.androidtransfuse.adapter.element.ASTTypeBuilderVisitor; 024import org.androidtransfuse.analysis.AnalysisContext; 025import org.androidtransfuse.analysis.InjectionPointFactory; 026import org.androidtransfuse.annotations.LayoutHandler; 027import org.androidtransfuse.experiment.*; 028import org.androidtransfuse.gen.*; 029import org.androidtransfuse.layout.LayoutHandlerDelegate; 030import org.androidtransfuse.model.InjectionNode; 031import org.androidtransfuse.model.MethodDescriptor; 032import org.androidtransfuse.model.TypedExpression; 033import org.androidtransfuse.scope.Scopes; 034import org.androidtransfuse.util.AndroidLiterals; 035 036import javax.inject.Inject; 037import javax.inject.Provider; 038import javax.lang.model.type.TypeMirror; 039import java.util.Map; 040 041import static org.androidtransfuse.util.TypeMirrorUtil.getTypeMirror; 042 043/** 044 * @author John Ericksen 045 */ 046public class LayoutHandlerGenerator implements Generation { 047 048 private final Provider<ASTTypeBuilderVisitor> astTypeBuilderVisitorProvider; 049 private final InjectionPointFactory injectionPointFactory; 050 private final InjectionFragmentGenerator injectionFragmentGenerator; 051 private final InstantiationStrategyFactory instantiationStrategyFactory; 052 private final UniqueVariableNamer namer; 053 private final ClassGenerationUtil generationUtil; 054 private final ASTElementFactory astElementFactory; 055 056 @Inject 057 public LayoutHandlerGenerator(Provider<ASTTypeBuilderVisitor> astTypeBuilderVisitorProvider, 058 InjectionPointFactory injectionPointFactory, 059 InjectionFragmentGenerator injectionFragmentGenerator, 060 InstantiationStrategyFactory instantiationStrategyFactory, 061 UniqueVariableNamer namer, 062 ClassGenerationUtil generationUtil, 063 ASTElementFactory astElementFactory) { 064 this.astTypeBuilderVisitorProvider = astTypeBuilderVisitorProvider; 065 this.injectionPointFactory = injectionPointFactory; 066 this.injectionFragmentGenerator = injectionFragmentGenerator; 067 this.instantiationStrategyFactory = instantiationStrategyFactory; 068 this.namer = namer; 069 this.generationUtil = generationUtil; 070 this.astElementFactory = astElementFactory; 071 } 072 073 @Override 074 public void schedule(final ComponentBuilder builder, final ComponentDescriptor descriptor) { 075 076 ASTType target = descriptor.getTarget(); 077 078 if(target.isAnnotated(LayoutHandler.class)) { 079 LayoutHandler layoutHandlerAnnotation = target.getAnnotation(LayoutHandler.class); 080 081 final InjectionNode layoutHandlerInjectionNode = buildLayoutHandlerInjectionNode(layoutHandlerAnnotation, builder.getAnalysisContext()); 082 083 ASTMethod onCreateMethod = astElementFactory.findMethod(AndroidLiterals.ACTIVITY, "onCreate", AndroidLiterals.BUNDLE); 084 builder.add(onCreateMethod, GenerationPhase.LAYOUT, new ComponentMethodGenerator() { 085 @Override 086 public void generate(MethodDescriptor methodDescriptor, JBlock block) { 087 try { 088 JDefinedClass definedClass = builder.getDefinedClass(); 089 090 // Scopes instance 091 JClass scopesRef = generationUtil.ref(Scopes.class); 092 JInvocation scopesBuildInvocation = generationUtil.ref(ScopesGenerator.TRANSFUSE_SCOPES_UTIL).staticInvoke(ScopesGenerator.GET_INSTANCE); 093 JVar scopesVar = block.decl(scopesRef, namer.generateName(Scopes.class), scopesBuildInvocation); 094 095 Map<InjectionNode, TypedExpression> expressionMap = injectionFragmentGenerator.buildFragment(block, 096 instantiationStrategyFactory.buildMethodStrategy(block, scopesVar), 097 definedClass, 098 layoutHandlerInjectionNode, 099 scopesVar); 100 101 //LayoutHandlerDelegate.invokeLayout() 102 JExpression layoutHandlerDelegate = expressionMap.get(layoutHandlerInjectionNode).getExpression(); 103 104 block.add(layoutHandlerDelegate.invoke(LayoutHandlerDelegate.INVOKE_LAYOUT_METHOD)); 105 106 } catch (JClassAlreadyExistsException e) { 107 throw new TransfuseAnalysisException("Class Already Exists ", e); 108 } 109 } 110 }); 111 } 112 113 114 } 115 116 private InjectionNode buildLayoutHandlerInjectionNode(final LayoutHandler layoutHandlerAnnotation, AnalysisContext context) { 117 if (layoutHandlerAnnotation != null) { 118 TypeMirror layoutHandlerType = getTypeMirror(layoutHandlerAnnotation, "value"); 119 120 if (layoutHandlerType != null) { 121 ASTType layoutHandlerASTType = layoutHandlerType.accept(astTypeBuilderVisitorProvider.get(), null); 122 return injectionPointFactory.buildInjectionNode(layoutHandlerASTType, context); 123 } 124 } 125 return null; 126 } 127}