/** * 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.gen; import com.sun.codemodel.*; import org.androidtransfuse.TransfuseAnalysisException; import org.androidtransfuse.adapter.PackageClass; import org.androidtransfuse.analysis.astAnalyzer.IntentFactoryExtraAspect; import org.androidtransfuse.analysis.repository.BundlePropertyBuilderRepository; import org.androidtransfuse.analysis.repository.ParcelerPropertyBuilder; import org.androidtransfuse.analysis.repository.PropertyBuilder; import org.androidtransfuse.experiment.ComponentBuilder; import org.androidtransfuse.experiment.ComponentDescriptor; import org.androidtransfuse.experiment.ComponentPartGenerator; import org.androidtransfuse.experiment.Generation; import org.androidtransfuse.intentFactory.AbstractIntentFactoryStrategy; import org.androidtransfuse.intentFactory.ActivityIntentFactoryStrategy; import org.androidtransfuse.model.InjectionNode; import org.androidtransfuse.model.TypedExpression; import org.androidtransfuse.util.AndroidLiterals; import org.androidtransfuse.util.StringUtil; import javax.inject.Inject; import java.util.*; /** * @author John Ericksen */ public class IntentFactoryStrategyGenerator implements Generation { public static final PackageClass ATPARCEL_NAME = new PackageClass("org.parceler", "Parcel"); public static final PackageClass PARCELS_NAME = new PackageClass("org.parceler", "Parcels"); public static final String WRAP_METHOD = "wrap"; public static final String UNWRAP_METHOD = "unwrap"; private static final String STRATEGY_EXT = "Strategy"; private final Class<? extends AbstractIntentFactoryStrategy> factoryStrategyClass; private final ClassGenerationUtil generationUtil; private final UniqueVariableNamer namer; private final BundlePropertyBuilderRepository repository; private final ParcelerPropertyBuilder parcelerPropertyBuilder; @Inject public IntentFactoryStrategyGenerator(/*@Assisted*/ Class factoryStrategyClass, ClassGenerationUtil generationUtil, UniqueVariableNamer namer, BundlePropertyBuilderRepository repository, ParcelerPropertyBuilder parcelerPropertyBuilder) { this.factoryStrategyClass = factoryStrategyClass; this.generationUtil = generationUtil; this.namer = namer; this.repository = repository; this.parcelerPropertyBuilder = parcelerPropertyBuilder; } @Override public String getName() { return "IntentFactoryStrategy Generator"; } @Override public void schedule(final ComponentBuilder builder, ComponentDescriptor descriptor) { builder.add(new ComponentPartGenerator() { @Override public void generate(org.androidtransfuse.experiment.ComponentDescriptor descriptor) { try { JDefinedClass strategyClass = generationUtil.defineClass(descriptor.getPackageClass().append(STRATEGY_EXT)); strategyClass._extends(factoryStrategyClass); JInvocation getExtrasMethod = JExpr.invoke(ActivityIntentFactoryStrategy.GET_EXTRAS_METHOD); List<IntentFactoryExtraAspect> extras = getExtras(builder.getExpressionMap()); //constructor, with required extras JMethod constructor = strategyClass.constructor(JMod.PUBLIC); JBlock constructorBody = constructor.body(); JDocComment javadocComments = constructor.javadoc(); javadocComments.append("Strategy Class for generating Intent for " + descriptor.getPackageClass().getClassName()); constructorBody.add(JExpr.invoke("super") .arg(generationUtil.ref(descriptor.getPackageClass()).dotclass()) .arg(JExpr._new(generationUtil.ref(AndroidLiterals.BUNDLE))) ); //addFlags method JMethod addFlags = strategyClass.method(JMod.PUBLIC, strategyClass, "addFlags"); JVar flagParam = addFlags.param(int.class, namer.generateName(int.class)); JBlock addFlagsBody = addFlags.body(); addFlagsBody.invoke("internalAddFlags").arg(flagParam); addFlagsBody._return(JExpr._this()); //addCategories method JMethod addCategory = strategyClass.method(JMod.PUBLIC, strategyClass, "addCategory"); JVar categoryParam = addCategory.param(String.class, namer.generateName(String.class)); JBlock addCategoryBody = addCategory.body(); addCategoryBody.invoke("internalAddCategory").arg(categoryParam); addCategoryBody._return(JExpr._this()); for (IntentFactoryExtraAspect extraAspect : extras) { if (extraAspect.isRequired()) { JVar extraParam = constructor.param(generationUtil.ref(extraAspect.getType()), extraAspect.getName()); constructorBody.add(buildBundleMethod(extraAspect, getExtrasMethod, extraParam)); javadocComments.addParam(extraParam); } else { //setter for non-required extra JMethod setterMethod = strategyClass.method(JMod.PUBLIC, strategyClass, "set" + StringUtil.upperFirst(extraAspect.getName())); JVar extraParam = setterMethod.param(generationUtil.ref(extraAspect.getType()), extraAspect.getName()); JBlock setterBody = setterMethod.body(); setterBody.add(buildBundleMethod(extraAspect, getExtrasMethod, extraParam)); setterMethod.javadoc().append("Optional Extra parameter"); setterMethod.javadoc().addParam(extraParam); setterBody._return(JExpr._this()); } } } catch (JClassAlreadyExistsException e) { throw new TransfuseAnalysisException("Class already defined while trying to define IntentFactoryStrategy", e); } } }); } private JStatement buildBundleMethod(IntentFactoryExtraAspect extraAspect, JInvocation extras, JVar extraParam) { PropertyBuilder builder; if(extraAspect.isForceParceler()){ builder = parcelerPropertyBuilder; } else { builder = repository.get(extraAspect.getType()); } if(builder == null){ throw new TransfuseAnalysisException("Unable to find appropriate type to build intent factory strategy: " + extraAspect.getType().getName()); } return builder.buildWriter(extras, extraAspect.getName(), extraParam); } private List<IntentFactoryExtraAspect> getExtras(Map<InjectionNode, TypedExpression> expressionMap) { Set<IntentFactoryExtraAspect> uniqueExtras = new HashSet<IntentFactoryExtraAspect>(); List<IntentFactoryExtraAspect> extras = new ArrayList<IntentFactoryExtraAspect>(); for (InjectionNode injectionNode : expressionMap.keySet()) { IntentFactoryExtraAspect intentFactoryExtra = injectionNode.getAspect(IntentFactoryExtraAspect.class); if (intentFactoryExtra != null && !uniqueExtras.contains(intentFactoryExtra)) { uniqueExtras.add(intentFactoryExtra); extras.add(intentFactoryExtra); } } Collections.sort(extras); return extras; } }