/** * 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; import java.text.MessageFormat; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import com.asakusafw.compiler.common.Precondition; import com.asakusafw.utils.collections.Lists; import com.asakusafw.vocabulary.external.ExporterDescription; import com.asakusafw.vocabulary.external.ImporterDescription; import com.asakusafw.vocabulary.flow.FlowDescription; import com.asakusafw.vocabulary.flow.In; import com.asakusafw.vocabulary.flow.Out; import com.asakusafw.vocabulary.flow.graph.FlowGraph; import com.asakusafw.vocabulary.flow.graph.FlowIn; import com.asakusafw.vocabulary.flow.graph.FlowOut; import com.asakusafw.vocabulary.flow.graph.InputDescription; import com.asakusafw.vocabulary.flow.graph.OutputDescription; /** * Creates {@link FlowGraph} from {@link FlowDescription}. */ public class FlowDescriptionDriver { private final List<Object> ports = new ArrayList<>(); private final Map<String, FlowIn<?>> inputs = new LinkedHashMap<>(); private final Map<String, FlowOut<?>> outputs = new LinkedHashMap<>(); /** * Returns a new flow input. * @param <T> the data type * @param name the input name * @param importer the importer description for the target input * @return the created input * @throws IllegalStateException if the input name is conflicted * @throws IllegalArgumentException if the input name is invalid, or the parameters are {@code null} */ public <T> In<T> createIn(String name, ImporterDescription importer) { Precondition.checkMustNotBeNull(name, "name"); //$NON-NLS-1$ Precondition.checkMustNotBeNull(importer, "importer"); //$NON-NLS-1$ if (isValidName(name) == false) { throw new IllegalArgumentException(MessageFormat.format( Messages.getString("FlowDescriptionDriver.errorInvalidInputName"), //$NON-NLS-1$ name)); } if (inputs.containsKey(name)) { throw new IllegalStateException(MessageFormat.format( Messages.getString("FlowDescriptionDriver.errorConflictInputName"), //$NON-NLS-1$ name)); } FlowIn<T> in = new FlowIn<>(new InputDescription(name, importer)); inputs.put(name, in); ports.add(in); return in; } /** * Returns a new flow output. * @param <T> the data type * @param name the output name * @param exporter the exporter description for the target output * @return the created output * @throws IllegalStateException if the output name is conflicted * @throws IllegalArgumentException if the output name is invalid, or the parameters are {@code null} */ public <T> Out<T> createOut(String name, ExporterDescription exporter) { Precondition.checkMustNotBeNull(name, "name"); //$NON-NLS-1$ Precondition.checkMustNotBeNull(exporter, "exporter"); //$NON-NLS-1$ if (isValidName(name) == false) { throw new IllegalArgumentException(MessageFormat.format( Messages.getString("FlowDescriptionDriver.errorInvalidOutputName"), //$NON-NLS-1$ name)); } if (outputs.containsKey(name)) { throw new IllegalStateException(MessageFormat.format( Messages.getString("FlowDescriptionDriver.errorConflictOutputName"), //$NON-NLS-1$ name)); } FlowOut<T> out = new FlowOut<>(new OutputDescription(name, exporter)); outputs.put(name, out); ports.add(out); return out; } private static final Pattern VALID_NAME = Pattern.compile("[A-Za-z_][0-9A-Za-z_]*"); //$NON-NLS-1$ /** * Returns whether the target name is valid for flow input/output name or not. * @param name the input/output name * @return {@code true} if the target name is valid, otherwise {@code false} */ public boolean isValidName(String name) { if (name == null) { return false; } return VALID_NAME.matcher(name).matches(); } /** * Returns the previously added flow inputs/outputs by their order. * The returned list will only contain {@link FlowIn} (for inputs) and {@link FlowOut} (for outputs). * @return the added flow inputs/output */ public List<Object> getPorts() { return ports; } /** * Analyzes the target flow description, and returns the corresponded flow graph. * @param description the target flow description * @return the analyzed flow graph * @throws IllegalArgumentException if the parameter is {@code null} */ public FlowGraph createFlowGraph(FlowDescription description) { Precondition.checkMustNotBeNull(description, "description"); //$NON-NLS-1$ description.start(); FlowGraph result = new FlowGraph( description.getClass(), Lists.from(inputs.values()), Lists.from(outputs.values())); inputs.clear(); outputs.clear(); return result; } }