Package com.asakusafw.compiler.flow

Source Code of com.asakusafw.compiler.flow.FlowGraphGenerator

/**
* Copyright 2011-2014 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.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.asakusafw.compiler.flow.plan.FlowPath;
import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.collections.Maps;
import com.asakusafw.utils.collections.Sets;
import com.asakusafw.vocabulary.flow.FlowDescription;
import com.asakusafw.vocabulary.flow.graph.FlowBoundary;
import com.asakusafw.vocabulary.flow.graph.FlowElement;
import com.asakusafw.vocabulary.flow.graph.FlowElementAttribute;
import com.asakusafw.vocabulary.flow.graph.FlowElementDescription;
import com.asakusafw.vocabulary.flow.graph.FlowElementInput;
import com.asakusafw.vocabulary.flow.graph.FlowElementOutput;
import com.asakusafw.vocabulary.flow.graph.FlowElementPortDescription;
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.FlowPartDescription;
import com.asakusafw.vocabulary.flow.graph.FlowResourceDescription;
import com.asakusafw.vocabulary.flow.graph.InputDescription;
import com.asakusafw.vocabulary.flow.graph.OperatorDescription;
import com.asakusafw.vocabulary.flow.graph.OutputDescription;
import com.asakusafw.vocabulary.flow.graph.PortConnection;
import com.asakusafw.vocabulary.flow.graph.PortDirection;
import com.asakusafw.vocabulary.flow.util.PseudElementDescription;
import com.asakusafw.vocabulary.operator.Identity;


/**
* テストで利用するフローグラフ生成器。
*/
public class FlowGraphGenerator {

    private static final Class<String> TYPE = String.class;

    private final List<FlowIn<?>> flowInputs = Lists.create();

    private final List<FlowOut<?>> flowOutputs = Lists.create();

    private final Map<String, FlowElement> elements = Maps.create();

    /**
     * 入力要素を追加する。
     * @param name 追加する要素の名前
     * @return 追加した要素
     */
    public FlowElement defineInput(String name) {
        InputDescription desc = new InputDescription(name, TYPE);
        FlowIn<?> node = new FlowIn<Object>(desc);
        flowInputs.add(node);
        return register(name, node.getFlowElement());
    }

    /**
     * 出力要素を追加する。
     * @param name 追加する要素の名前
     * @return 追加した要素
     */
    public FlowElement defineOutput(String name) {
        OutputDescription desc = new OutputDescription(name, TYPE);
        FlowOut<?> node = new FlowOut<Object>(desc);
        flowOutputs.add(node);
        return register(name, node.getFlowElement());
    }

    /**
     * 演算子を追加する。
     * @param name 追加する要素の名前
     * @param inputList スペース区切りの入力ポート名の一覧
     * @param outputList スペース区切りの出力ポート名の一覧
     * @param attributes 属性の一覧
     * @return 追加した要素
     */
    public FlowElement defineOperator(
            String name,
            String inputList,
            String outputList,
            FlowElementAttribute... attributes) {
        Class<String> type = TYPE;
        return defineOperator(type, name, inputList, outputList, attributes);
    }

    /**
     * Defines a new operator and registers into this generator.
     * @param type target operator type
     * @param name target name
     * @param inputList target input names
     * @param outputList target output names
     * @param attributes operator attributes
     * @return the defined element
     */
    public FlowElement defineOperator(
            Class<?> type, String name,
            String inputList, String outputList,
            FlowElementAttribute... attributes) {
        List<FlowElementPortDescription> inputs = parsePorts(PortDirection.INPUT, inputList);
        List<FlowElementPortDescription> outputs = parsePorts(PortDirection.OUTPUT, outputList);
        FlowElementDescription desc = new OperatorDescription(
                new OperatorDescription.Declaration(
                        Identity.class,
                        type,
                        type,
                        name,
                        Collections.<Class<?>>emptyList()),
                inputs,
                outputs,
                Collections.<FlowResourceDescription>emptyList(),
                Collections.<OperatorDescription.Parameter>emptyList(),
                Arrays.asList(attributes));
        return register(name, desc);
    }

    /**
     * フロー部品を追加する。
     * @param name 追加する要素の名前
     * @param graph フロー部品グラフ
     * @return 追加した要素
     */
    public FlowElement defineFlowPart(
            String name,
            FlowGraph graph) {
        FlowElementDescription desc = new FlowPartDescription(graph);
        return register(name, desc);
    }

    /**
     * 空要素を追加する。
     * @param name 追加する要素の名前
     * @return 追加した要素
     */
    public FlowElement defineEmpty(String name) {
        return register(name, new PseudElementDescription(
                name,
                TYPE,
                false,
                true,
                FlowBoundary.STAGE));
    }

    /**
     * 停止要素を追加する。
     * @param name 追加する要素の名前
     * @return 追加した要素
     */
    public FlowElement defineStop(String name) {
        return register(name, new PseudElementDescription(
                name,
                TYPE,
                true,
                false,
                FlowBoundary.STAGE));
    }

    /**
     * 疑似要素を追加する。
     * @param name 追加する要素の名前
     * @param attributes 属性の一覧
     * @return 追加した要素
     */
    public FlowElement definePseud(
            String name,
            FlowElementAttribute... attributes) {
        return register(name, new PseudElementDescription(
                name,
                TYPE,
                true,
                true,
                attributes));
    }

    /**
     * 指定のポート間を接続する。
     * ポートは "element-name.port-name"の形式で指定する。
     * ただし、対象の要素がポートを一つしか有さない場合、"element-name"の形式でも指定できる
     * @param upstream 上流
     * @param downstream 下流
     * @return 自身のオブジェクト
     */
    public FlowGraphGenerator connect(String upstream, String downstream) {
        FlowElementOutput output = findOutput(upstream);
        FlowElementInput input = findInput(downstream);
        PortConnection.connect(output, input);
        return this;
    }

    /**
     * 指定の名前を有する要素を返す。
     * @param name 対象の名前
     * @return 発見した要素
     */
    public FlowElement get(String name) {
        FlowElement found = elements.get(name);
        if (found == null) {
            throw new AssertionError(name + elements.keySet());
        }
        return found;
    }

    /**
     * 指定の名前を有する要素を返す。
     * @param name 対象の名前
     * @return 発見した要素
     */
    public FlowElementDescription desc(String name) {
        FlowElement found = elements.get(name);
        if (found == null) {
            throw new AssertionError(name + elements.keySet());
        }
        return found.getDescription();
    }

    /**
     * 指定の名前を有する入力を返す。
     * @param input 入力名
     * @return 発見したポート
     */
    public FlowElementInput input(String input) {
        return findInput(input);
    }

    /**
     * 指定の名前を有する入力を返す。
     * @param inputs 入力名
     * @return 発見したポート
     */
    public Set<FlowElementInput> inputs(String... inputs) {
        Set<FlowElementInput> results = Sets.create();
        for (String input : inputs) {
            results.add(input(input));
        }
        return results;
    }

    /**
     * 指定の名前を有する出力を返す。
     * @param output 出力名
     * @return 発見したポート
     */
    public FlowElementOutput output(String output) {
        return findOutput(output);
    }

    /**
     * 指定の名前を有する出力を返す。
     * @param outputs 出力名
     * @return 発見したポート
     */
    public Set<FlowElementOutput> outputs(String... outputs) {
        Set<FlowElementOutput> results = Sets.create();
        for (String output : outputs) {
            results.add(output(output));
        }
        return results;
    }

    /**
     * 指定の名前を持つ要素の一覧を返す。
     * @param names 名前の一覧
     * @return 要素の一覧
     */
    public Set<FlowElement> getAsSet(String... names) {
        Set<FlowElement> results = Sets.create();
        for (String name : names) {
            results.add(get(name));
        }
        return results;
    }

    /**
     * ここまでに作成した要素の一覧を返す。
     * @return ここまでに作成した要素の一覧
     */
    public Set<FlowElement> all() {
        return new HashSet<FlowElement>(elements.values());
    }

    /**
     * ここまでに構築した内容を元にしたグラフを返す。
     * @return 構築した内容を元にしたグラフ
     */
    public FlowGraph toGraph() {
        return new FlowGraph(Testing.class, flowInputs, flowOutputs);
    }

    /**
     * ここまでに構築した内容を元にしたパスを返す。
     * <p>
     * 返されるパスはグラフの入力から出力までを表現する。
     * </p>
     * @param direction パスの向き、逆方向を指定すると入出力が反転する
     * @return 構築したパス
     */
    public FlowPath toPath(FlowPath.Direction direction) {
        Set<FlowElement> inputs = Sets.create();
        Set<FlowElement> passings = Sets.create();
        Set<FlowElement> outputs = Sets.create();

        for (FlowIn<?> node : flowInputs) {
            inputs.add(node.getFlowElement());
        }
        for (FlowOut<?> node : flowOutputs) {
            outputs.add(node.getFlowElement());
        }
        passings.removeAll(inputs);
        passings.removeAll(outputs);
        return new FlowPath(
                direction,
                direction == FlowPath.Direction.FORWARD ? inputs : outputs,
                passings,
                direction == FlowPath.Direction.FORWARD ? outputs : inputs);
    }

    private static final Pattern PORT = Pattern.compile("(.+?)(\\.(.+?))?");

    private FlowElementInput findInput(String spec) {
        Matcher matcher = PORT.matcher(spec);
        if (matcher.matches() == false) {
            throw new AssertionError(spec);
        }
        String elementName = matcher.group(1);
        FlowElement element = elements.get(elementName);
        if (element == null) {
            throw new AssertionError(elementName + elements.keySet());
        }

        String portName = matcher.group(3);
        if (portName == null) {
            if (element.getInputPorts().size() != 1) {
                throw new AssertionError(element.getInputPorts());
            }
            return element.getInputPorts().get(0);
        }

        FlowElementInput port = null;
        for (FlowElementInput finding : element.getInputPorts()) {
            if (portName.equals(finding.getDescription().getName())) {
                port = finding;
                break;
            }
        }
        if (port == null) {
            throw new AssertionError(elementName + "." + portName + elements.keySet());

        }
        return port;
    }

    private FlowElementOutput findOutput(String spec) {
        Matcher matcher = PORT.matcher(spec);
        if (matcher.matches() == false) {
            throw new AssertionError(spec);
        }
        String elementName = matcher.group(1);
        FlowElement element = elements.get(elementName);
        if (element == null) {
            throw new AssertionError(elementName + elements.keySet());
        }

        String portName = matcher.group(3);
        if (portName == null) {
            if (element.getOutputPorts().size() != 1) {
                throw new AssertionError(element.getOutputPorts());
            }
            return element.getOutputPorts().get(0);
        }

        FlowElementOutput port = null;
        for (FlowElementOutput finding : element.getOutputPorts()) {
            if (portName.equals(finding.getDescription().getName())) {
                port = finding;
                break;
            }
        }
        if (port == null) {
            throw new AssertionError(elementName + "." + portName + elements.keySet());

        }
        return port;
    }

    private FlowElement register(String name, FlowElementDescription desc) {
        FlowElement element = new FlowElement(desc);
        return register(name, element);
    }

    private FlowElement register(String name, FlowElement element) {
        if (elements.containsKey(name)) {
            throw new AssertionError(name + elements.keySet());
        }
        elements.put(name, element);
        return element;
    }

    private List<FlowElementPortDescription> parsePorts(
            PortDirection direction,
            String nameList) {
        String[] names = nameList.trim().split("\\s+");
        List<FlowElementPortDescription> results = Lists.create();
        for (String name : names) {
            results.add(new FlowElementPortDescription(name, TYPE, direction));
        }
        return results;
    }

    private static class Testing extends FlowDescription {
        @Override
        protected void describe() {
            return;
        }
    }
}
TOP

Related Classes of com.asakusafw.compiler.flow.FlowGraphGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.