/** * Copyright 2011-2017 Asakusa Framework Team. * * 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 com.asakusafw.compiler.flow.stage; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.asakusafw.compiler.common.NameGenerator; import com.asakusafw.compiler.common.Precondition; import com.asakusafw.compiler.flow.FlowCompilingEnvironment; import com.asakusafw.compiler.flow.stage.StageModel.Fragment; import com.asakusafw.compiler.flow.stage.StageModel.ResourceFragment; import com.asakusafw.runtime.core.Result; import com.asakusafw.utils.java.model.syntax.ConstructorDeclaration; import com.asakusafw.utils.java.model.syntax.Expression; import com.asakusafw.utils.java.model.syntax.FieldDeclaration; import com.asakusafw.utils.java.model.syntax.FormalParameterDeclaration; import com.asakusafw.utils.java.model.syntax.ModelFactory; import com.asakusafw.utils.java.model.syntax.SimpleName; import com.asakusafw.utils.java.model.syntax.Statement; import com.asakusafw.utils.java.model.util.AttributeBuilder; import com.asakusafw.utils.java.model.util.ExpressionBuilder; import com.asakusafw.utils.java.model.util.ImportBuilder; import com.asakusafw.utils.java.model.util.JavadocBuilder; import com.asakusafw.utils.java.model.util.Models; import com.asakusafw.vocabulary.flow.graph.FlowElementOutput; import com.asakusafw.vocabulary.flow.graph.FlowElementPortDescription; import com.asakusafw.vocabulary.flow.graph.FlowResourceDescription; /** * Common operators for {@code *FragmentEmitter}. */ public class FragmentConnection { private final Map<FlowResourceDescription, SimpleName> resources = new HashMap<>(); private final Map<FlowElementOutput, SimpleName> successors = new HashMap<>(); private final ModelFactory factory; private final Fragment fragment; private final ImportBuilder importer; /** * Creates a new instance. * @param environment the current environment * @param fragment the target fragment * @param names the unique name generator * @param importer the import declaration builder * @throws IllegalArgumentException if the parameters are {@code null} */ public FragmentConnection( FlowCompilingEnvironment environment, Fragment fragment, NameGenerator names, ImportBuilder importer) { assert environment != null; assert fragment != null; assert names != null; assert importer != null; this.factory = environment.getModelFactory(); this.fragment = fragment; this.importer = importer; for (ResourceFragment resource : fragment.getResources()) { SimpleName name = names.create("resource"); //$NON-NLS-1$ resources.put(resource.getDescription(), name); } for (FlowElementOutput output : fragment.getOutputPorts()) { SimpleName name = names.create(output.getDescription().getName()); successors.put(output, name); } } /** * Returns the field declarations. * @return the field declarations */ public List<FieldDeclaration> createFields() { List<FieldDeclaration> results = new ArrayList<>(); for (ResourceFragment resource : fragment.getResources()) { results.add(createResourceField(resource)); } for (FlowElementOutput output : fragment.getOutputPorts()) { results.add(createOutputField(output)); } return results; } /** * Returns a constructor declaration. * @param className the simple name of the target fragment class * @return the constructor declaration * @throws IllegalArgumentException if the parameter is {@code null} */ public ConstructorDeclaration createConstructor(SimpleName className) { Precondition.checkMustNotBeNull(className, "className"); //$NON-NLS-1$ JavadocBuilder javadoc = new JavadocBuilder(factory) .text("Creates a new instance."); //$NON-NLS-1$ List<FormalParameterDeclaration> parameters = new ArrayList<>(); List<Statement> statements = new ArrayList<>(); for (ResourceFragment resource : fragment.getResources()) { SimpleName param = getResource(resource.getDescription()); javadoc.param(param) .text(resource.getDescription().toString()); parameters.add(factory.newFormalParameterDeclaration( importer.toType(resource.getCompiled().getQualifiedName()), param)); statements.add(new ExpressionBuilder(factory, factory.newThis()) .field(param) .assignFrom(param) .toStatement()); } for (FlowElementOutput output : fragment.getOutputPorts()) { SimpleName chain = successors.get(output); assert chain != null; javadoc.param(chain) .inline("output for {0}.", d -> d.code("{0}#{1}", //$NON-NLS-1$ output.getOwner().getDescription().getName(), output.getDescription().getName())); parameters.add(factory.newFormalParameterDeclaration( importer.resolve(factory.newParameterizedType( Models.toType(factory, Result.class), Models.toType(factory, output.getDescription().getDataType()))), chain)); statements.add(new ExpressionBuilder(factory, factory.newThis()) .field(chain) .assignFrom(chain) .toStatement()); } return factory.newConstructorDeclaration( javadoc.toJavadoc(), new AttributeBuilder(factory) .Public() .toAttributes(), className, parameters, statements); } private FieldDeclaration createResourceField(ResourceFragment resource) { assert resource != null; return factory.newFieldDeclaration( null, new AttributeBuilder(factory) .Private() .Final() .toAttributes(), importer.toType(resource.getCompiled().getQualifiedName()), getResource(resource.getDescription()), null); } private FieldDeclaration createOutputField(FlowElementOutput output) { assert output != null; return factory.newFieldDeclaration( null, new AttributeBuilder(factory) .Private() .Final() .toAttributes(), importer.resolve(factory.newParameterizedType( Models.toType(factory, Result.class), Models.toType(factory, output.getDescription().getDataType()))), successors.get(output), null); } private SimpleName getResource(FlowResourceDescription description) { Precondition.checkMustNotBeNull(description, "description"); //$NON-NLS-1$ SimpleName name = resources.get(description); Precondition.checkMustNotBeNull(name, "name"); //$NON-NLS-1$ return name; } /** * Returns expressions which provides external resources. * @return a mapping of external resource description to its expression */ public Map<FlowResourceDescription, Expression> getResources() { Map<FlowResourceDescription, Expression> results = new HashMap<>(); for (ResourceFragment key : fragment.getResources()) { SimpleName name = resources.get(key.getDescription()); assert name != null; results.put( key.getDescription(), new ExpressionBuilder(factory, factory.newThis()) .field(name) .toExpression()); } return results; } /** * Returns expressions which provides {@link Result} outputs. * @return a mapping of output port to its expression */ public Map<FlowElementPortDescription, Expression> getOutputs() { Map<FlowElementPortDescription, Expression> results = new HashMap<>(); for (FlowElementOutput key : fragment.getOutputPorts()) { SimpleName name = successors.get(key); assert name != null; results.put( key.getDescription(), new ExpressionBuilder(factory, factory.newThis()) .field(name) .toExpression()); } return results; } }