Package com.asakusafw.vocabulary.flow.util

Source Code of com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure

/**
* 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.vocabulary.flow.util;

import static com.asakusafw.vocabulary.flow.util.PseudElementDescription.*;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import com.asakusafw.vocabulary.flow.Operator;
import com.asakusafw.vocabulary.flow.Source;
import com.asakusafw.vocabulary.flow.graph.FlowBoundary;
import com.asakusafw.vocabulary.flow.graph.FlowElementOutput;
import com.asakusafw.vocabulary.flow.graph.FlowElementResolver;
import com.asakusafw.vocabulary.flow.graph.OperatorDescription;


/**
* 標準的な演算子オブジェクトを生成するファクトリ。
*/
public class CoreOperatorFactory {

    /**
     * 空演算子の共通インスタンス名。
     */
    public static final String EMPTY_NAME = "empty";

    /**
     * 停止演算子の共通インスタンス名。
     */
    public static final String STOP_NAME = "stop";

    /**
     * 合流演算子の共通インスタンス名。
     */
    public static final String CONFLUENT_NAME = "confluent";

    /**
     * チェックポイント演算子の共通インスタンス名。
     */
    public static final String CHECKPOINT_NAME = "checkpoint";

    /**
     * 射影演算子の共通インスタンス名。
     */
    public static final String PROJECT_NAME = "project";

    /**
     * 拡張演算子の共通インスタンス名。
     */
    public static final String EXTEND_NAME = "extend";

    /**
     * 再構築演算子の共通インスタンス名。
     */
    public static final String RESTRUCTURE_NAME = "restructure";

    /**
     * 出力先に何もデータを流さない疑似演算子。入力のダミーとして振る舞う。
     * @param <T> 取り扱うデータの種類
     * @param type 取り扱うデータの種類
     * @return 空(から)演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Empty<T> empty(Class<T> type) {
        return empty((Type) type);
    }

    /**
     * 出力先に何もデータを流さない疑似演算子。入力のダミーとして振る舞う。
     * @param <T> 取り扱うデータの種類
     * @param type 取り扱うデータの種類
     * @return 空(から)演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Empty<T> empty(Type type) {
        if (type == null) {
            throw new IllegalArgumentException("type must not be null"); //$NON-NLS-1$
        }
        return new Empty<T>(type);
    }

    /**
     * 入力に対して何も行わない疑似演算子。出力のダミーとして振る舞う。
     * @param in 入力
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public void stop(Source<?> in) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null"); //$NON-NLS-1$
        }
        PseudElementDescription desc = new PseudElementDescription(
                STOP_NAME,
                getPortType(in),
                true,
                false,
                FlowBoundary.STAGE);
        FlowElementResolver resolver = new FlowElementResolver(desc);
        resolver.resolveInput(INPUT_PORT_NAME, in);
    }

    /**
     * 複数の入力をまとめ、それらの流れるすべてのデータを単一の出力に流す。
     * @param <T> 取り扱うデータの種類
     * @param a 入力1
     * @param b 入力2
     * @return 合流演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Confluent<T> confluent(Source<T> a, Source<T> b) {
        if (a == null) {
            throw new IllegalArgumentException("a must not be null"); //$NON-NLS-1$
        }
        if (b == null) {
            throw new IllegalArgumentException("b must not be null"); //$NON-NLS-1$
        }
        Type type = getPortType(a);
        List<Source<T>> input = new ArrayList<Source<T>>();
        input.add(a);
        input.add(b);
        return new Confluent<T>(type, input);
    }

    /**
     * 複数の入力をまとめ、それらの流れるすべてのデータを単一の出力に流す。
     * @param <T> 取り扱うデータの種類
     * @param a 入力1
     * @param b 入力2
     * @param c 入力3
     * @return 合流演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Confluent<T> confluent(Source<T> a, Source<T> b, Source<T> c) {
        if (a == null) {
            throw new IllegalArgumentException("a must not be null"); //$NON-NLS-1$
        }
        if (b == null) {
            throw new IllegalArgumentException("b must not be null"); //$NON-NLS-1$
        }
        if (c == null) {
            throw new IllegalArgumentException("b must not be null"); //$NON-NLS-1$
        }
        Type type = getPortType(a);
        List<Source<T>> input = new ArrayList<Source<T>>();
        input.add(a);
        input.add(b);
        input.add(c);
        return new Confluent<T>(type, input);
    }

    /**
     * 複数の入力をまとめ、それらの流れるすべてのデータを単一の出力に流す。
     * @param <T> 取り扱うデータの種類
     * @param a 入力1
     * @param b 入力2
     * @param c 入力3
     * @param d 入力4
     * @return 合流演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Confluent<T> confluent(
            Source<T> a,
            Source<T> b,
            Source<T> c,
            Source<T> d) {
        if (a == null) {
            throw new IllegalArgumentException("a must not be null"); //$NON-NLS-1$
        }
        if (b == null) {
            throw new IllegalArgumentException("b must not be null"); //$NON-NLS-1$
        }
        if (c == null) {
            throw new IllegalArgumentException("b must not be null"); //$NON-NLS-1$
        }
        if (d == null) {
            throw new IllegalArgumentException("d must not be null"); //$NON-NLS-1$
        }

        Type type = getPortType(a);
        List<Source<T>> input = new ArrayList<Source<T>>();
        input.add(a);
        input.add(b);
        input.add(c);
        input.add(d);
        return new Confluent<T>(type, input);
    }

    /**
     * 複数の入力をまとめ、それらの流れるすべてのデータを単一の出力に流す。
     * @param <T> 取り扱うデータの種類
     * @param inputs 入力の一覧
     * @return 合流演算子
     * @throws IllegalArgumentException 引数に{@code null}が含まれる場合
     */
    public <T> Confluent<T> confluent(Iterable<? extends Source<T>> inputs) {
        if (inputs == null) {
            throw new IllegalArgumentException("inputs must not be null"); //$NON-NLS-1$
        }
        List<Source<T>> input = new ArrayList<Source<T>>();
        for (Source<T> in : inputs) {
            if (in == null) {
                throw new IllegalArgumentException("inputs must not contain null"); //$NON-NLS-1$
            }
            input.add(in);
        }
        if (input.isEmpty()) {
            throw new IllegalArgumentException("inputs must not be empty"); //$NON-NLS-1$
        }
        Type type = getPortType(input.get(0));
        return new Confluent<T>(type, input);
    }

    /**
     * 入力されたデータをそのまま出力するが、その際にデータを永続化し、
     * 以降に失敗した場合に永続化したデータを利用して再試行できるようにする。
     * @param <T> 取り扱うデータの種類
     * @param in 永続化対象の入力
     * @return チェックポイント演算子
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public <T> Checkpoint<T> checkpoint(Source<T> in) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null"); //$NON-NLS-1$
        }
        Type type = getPortType(in);
        return new Checkpoint<T>(type, in);
    }

    /**
     * 入力されたデータを指定のデータ型に射影する。
     * <p>
     * 入力するデータ型は変換後のデータ型の全てのプロパティを有していなければならない。
     * この演算子の処理結果は、入力されたデータのうち変換後のデータ型に含まれる
     * 全てのプロパティをコピーしたデータになる。
     * </p>
     * <p>
     * 入力されたデータの型と出力先のデータの型に、同じ名前で異なる型のプロパティが存在する場合、
     * この演算子を含むフローのコンパイルは失敗する。
     * </p>
     * @param <T> 変換後のデータの種類
     * @param in 射影対象の入力
     * @param targetType 射影する型
     * @return 射影演算子
     * @throws IllegalArgumentException if some parameters were {@code null}
     * @since 0.2.0
     */
    public <T> Project<T> project(Source<?> in, Class<T> targetType) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null"); //$NON-NLS-1$
        }
        if (targetType == null) {
            throw new IllegalArgumentException("targetType must not be null"); //$NON-NLS-1$
        }
        return new Project<T>(in, targetType);
    }

    /**
     * 入力されたデータを指定のデータ型に拡張する。
     * <p>
     * 変換後のデータ型は入力するデータ型の全てのプロパティを有していなければならない。
     * この演算子の処理結果は、入力されたデータ型に含まれる全てのプロパティをコピーしたデータになる。
     * また、入力されたデータに含まれないプロパティは、それぞれの初期値となる。
     * </p>
     * <p>
     * 入力されたデータの型と出力先のデータの型に、同じ名前で異なる型のプロパティが存在する場合、
     * この演算子を含むフローのコンパイルは失敗する。
     * </p>
     * @param <T> 変換後のデータの種類
     * @param in 拡張対象の入力
     * @param targetType 射影する型
     * @return 拡張演算子
     * @throws IllegalArgumentException if some parameters were {@code null}
     * @since 0.2.0
     */
    public <T> Extend<T> extend(Source<?> in, Class<T> targetType) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null"); //$NON-NLS-1$
        }
        if (targetType == null) {
            throw new IllegalArgumentException("targetType must not be null"); //$NON-NLS-1$
        }
        return new Extend<T>(in, targetType);
    }

    /**
     * 入力されたデータを指定のデータ型に再構築する。
     * <p>
     * この演算子の処理結果は、入力されたデータ型に含まれるプロパティのうち、
     * 対象のデータ型にも含まれるプロパティのみをすべてコピーしたデータになる。
     * また、入力されたデータに含まれないプロパティは、それぞれの初期値となる。
     * </p>
     * <p>
     * 入力されたデータの型と出力先のデータの型に、同じ名前で異なる型のプロパティが存在する場合、
     * この演算子を含むフローのコンパイルは失敗する。
     * </p>
     * @param <T> 変換後のデータの種類
     * @param in 再構築対象の入力
     * @param targetType 射影する型
     * @return 再構築演算子
     * @throws IllegalArgumentException if some parameters were {@code null}
     * @since 0.2.1
     */
    public <T> Restructure<T> restructure(Source<?> in, Class<T> targetType) {
        if (in == null) {
            throw new IllegalArgumentException("in must not be null"); //$NON-NLS-1$
        }
        if (targetType == null) {
            throw new IllegalArgumentException("targetType must not be null"); //$NON-NLS-1$
        }
        return new Restructure<T>(in, targetType);
    }

    private <T> Type getPortType(Source<T> source) {
        assert source != null;
        FlowElementOutput port = source.toOutputPort();
        Type type = port.getDescription().getDataType();
        return type;
    }

    /**
     * 出力先に何もデータを流さない疑似演算子。入力のダミーとして振る舞う。
     * @param <T> 取り扱うデータの種類
     */
    public static final class Empty<T> implements Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Empty(Type type) {
            assert type != null;
            this.out = this;
            PseudElementDescription desc = new PseudElementDescription(
                    EMPTY_NAME,
                    type,
                    false,
                    true,
                    FlowBoundary.STAGE);
            this.resolver = new FlowElementResolver(desc);
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }

    /**
     * 複数の入力をまとめて、単一の出力とする演算子。
     * @param <T> 取り扱うデータの種類
     */
    public static final class Confluent<T> implements Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Confluent(Type type, List<Source<T>> input) {
            assert type != null;
            assert input != null;
            this.out = this;
            PseudElementDescription desc = new PseudElementDescription(
                    CONFLUENT_NAME,
                    type,
                    true,
                    true);
            resolver = new FlowElementResolver(desc);
            for (Source<T> in : input) {
                resolver.resolveInput(INPUT_PORT_NAME, in);
            }
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }

    /**
     * 入力されたデータをそのまま出力するが、その際にデータを永続化し、
     * 以降に失敗した場合に永続化したデータを利用して再試行できるようにする。
     * @param <T> 取り扱うデータの種類
     */
    public static final class Checkpoint<T> implements Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Checkpoint(Type type, Source<T> in) {
            assert type != null;
            assert in != null;
            this.out = this;
            PseudElementDescription desc = new PseudElementDescription(
                    CHECKPOINT_NAME,
                    type,
                    true,
                    true,
                    FlowBoundary.STAGE);
            this.resolver = new FlowElementResolver(desc);
            resolver.resolveInput(INPUT_PORT_NAME, in);
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }

    /**
     * 入力されたデータを指定のデータ型に射影する。
     * @param <T> 変換後の型
     * @since 0.2.0
     */
    public static final class Project<T> implements Operator, Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Project(Source<?> in, Class<T> targetClass) {
            assert in != null;
            assert targetClass != null;
            OperatorDescription.Builder builder =
                new OperatorDescription.Builder(com.asakusafw.vocabulary.operator.Project.class);
            builder.declare(CoreOperatorFactory.class, CoreOperatorFactory.class, "project");
            builder.declareParameter(Source.class);
            builder.declareParameter(Class.class);
            builder.addInput(INPUT_PORT_NAME, in);
            builder.addOutput(OUTPUT_PORT_NAME, targetClass);
            this.resolver = builder.toResolver();
            this.resolver.resolveInput(INPUT_PORT_NAME, in);
            this.resolver.setName(PROJECT_NAME);
            this.out = this.resolver.resolveOutput(OUTPUT_PORT_NAME);
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }

    /**
     * 入力されたデータを指定のデータ型に拡張する。
     * @param <T> 変換後の型
     * @since 0.2.0
     */
    public static final class Extend<T> implements Operator, Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Extend(Source<?> in, Class<T> targetClass) {
            assert in != null;
            assert targetClass != null;
            OperatorDescription.Builder builder =
                new OperatorDescription.Builder(com.asakusafw.vocabulary.operator.Extend.class);
            builder.declare(CoreOperatorFactory.class, CoreOperatorFactory.class, "extend");
            builder.declareParameter(Source.class);
            builder.declareParameter(Class.class);
            builder.addInput(INPUT_PORT_NAME, in);
            builder.addOutput(OUTPUT_PORT_NAME, targetClass);
            this.resolver = builder.toResolver();
            this.resolver.resolveInput(INPUT_PORT_NAME, in);
            this.resolver.setName(EXTEND_NAME);
            this.out = this.resolver.resolveOutput(OUTPUT_PORT_NAME);
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }

    /**
     * 入力されたデータを指定のデータ型に再構築する。
     * @param <T> 変換後の型
     * @since 0.2.1
     */
    public static final class Restructure<T> implements Operator, Source<T> {

        /**
         * この演算子の唯一の出力。
         */
        public final Source<T> out;

        private final FlowElementResolver resolver;

        Restructure(Source<?> in, Class<T> targetClass) {
            assert in != null;
            assert targetClass != null;
            OperatorDescription.Builder builder =
                new OperatorDescription.Builder(com.asakusafw.vocabulary.operator.Restructure.class);
            builder.declare(CoreOperatorFactory.class, CoreOperatorFactory.class, "restructure");
            builder.declareParameter(Source.class);
            builder.declareParameter(Class.class);
            builder.addInput(INPUT_PORT_NAME, in);
            builder.addOutput(OUTPUT_PORT_NAME, targetClass);
            this.resolver = builder.toResolver();
            this.resolver.resolveInput(INPUT_PORT_NAME, in);
            this.resolver.setName(RESTRUCTURE_NAME);
            this.out = this.resolver.resolveOutput(OUTPUT_PORT_NAME);
        }

        @Override
        public FlowElementOutput toOutputPort() {
            return resolver.getOutput(OUTPUT_PORT_NAME);
        }
    }
}
TOP

Related Classes of com.asakusafw.vocabulary.flow.util.CoreOperatorFactory$Restructure

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.