Package com.asakusafw.compiler.flow.jobflow

Source Code of com.asakusafw.compiler.flow.jobflow.JobflowModel$Target

/**
* 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.jobflow;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.hadoop.mapreduce.OutputFormat;

import com.asakusafw.compiler.common.Precondition;
import com.asakusafw.compiler.flow.Compilable;
import com.asakusafw.compiler.flow.ExternalIoDescriptionProcessor;
import com.asakusafw.compiler.flow.ExternalIoDescriptionProcessor.SourceInfo;
import com.asakusafw.compiler.flow.Location;
import com.asakusafw.compiler.flow.plan.FlowBlock;
import com.asakusafw.compiler.flow.plan.StageGraph;
import com.asakusafw.compiler.flow.stage.StageModel;
import com.asakusafw.runtime.stage.input.TemporaryInputFormat;
import com.asakusafw.runtime.stage.output.TemporaryOutputFormat;
import com.asakusafw.utils.collections.Maps;
import com.asakusafw.utils.collections.Sets;
import com.asakusafw.utils.graph.Graph;
import com.asakusafw.utils.graph.Graphs;
import com.asakusafw.utils.java.model.syntax.Name;
import com.asakusafw.vocabulary.flow.graph.FlowElementOutput;
import com.asakusafw.vocabulary.flow.graph.InputDescription;
import com.asakusafw.vocabulary.flow.graph.OutputDescription;

/**
* ジョブフロー全体のモデル。
*/
public class JobflowModel extends Compilable.Trait<CompiledJobflow> {

    private final StageGraph stageGraph;

    private final String batchId;

    private final String flowId;

    private final List<Import> imports;

    private final List<Export> exports;

    private final List<Stage> stages;

    /**
     * インスタンスを生成する。
     * @param stageGraph このモデルの元となったステージグラフ
     * @param batchId このモデルに関連するバッチID
     * @param flowId このモデルに関連するフローID
     * @param imports ジョブフローへの入力の一覧
     * @param exports ジョブフローからの出力の一覧
     * @param stages ステージ情報の一覧
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public JobflowModel(
            StageGraph stageGraph,
            String batchId,
            String flowId, List<Import> imports,
            List<Export> exports,
            List<Stage> stages) {
        Precondition.checkMustNotBeNull(stageGraph, "stageGraph"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(batchId, "batchId"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(flowId, "flowId"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(imports, "imports"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(exports, "exports"); //$NON-NLS-1$
        Precondition.checkMustNotBeNull(stages, "stages"); //$NON-NLS-1$
        this.stageGraph = stageGraph;
        this.batchId = batchId;
        this.flowId = flowId;
        this.imports = imports;
        this.exports = exports;
        this.stages = stages;
    }

    /**
     * このモデルの元となったステージグラフを返す。
     * @return このモデルの元となったステージグラフ
     */
    public StageGraph getStageGraph() {
        return stageGraph;
    }

    /**
     * このモデルに関連するバッチIDを返す。
     * @return このモデルに関連するバッチID
     */
    public String getBatchId() {
        return batchId;
    }

    /**
     * このモデルに関連するフローIDを返す。
     * @return このモデルに関連するフローID
     */
    public String getFlowId() {
        return flowId;
    }

    /**
     * ジョブフローへの入力の一覧を返す。
     * @return ジョブフローへの入力の一覧
     */
    public List<Import> getImports() {
        return imports;
    }

    /**
     * ジョブフローからの出力の一覧を返す。
     * @return ジョブフローからの出力の一覧
     */
    public List<Export> getExports() {
        return exports;
    }

    /**
     * ステージ情報の一覧を返す。
     * @return ステージ情報の一覧
     */
    public List<Stage> getStages() {
        return stages;
    }

    /**
     * このジョブフローに含まれるステージの関係を依存元から依存先へのグラフにして返す。
     * @return 構築したグラフ
     * @throws IllegalArgumentException 引数に{@code null}が指定された場合
     */
    public Graph<Stage> getDependencyGraph() {
        Map<Delivery, Stage> deliveries = Maps.create();
        for (Stage stage : stages) {
            for (Delivery delivery : stage.getDeliveries()) {
                deliveries.put(delivery, stage);
            }
        }
        Graph<Stage> graph = Graphs.newInstance();
        for (Stage stage : stages) {
            graph.addNode(stage);
            for (Process process : stage.getProcesses()) {
                for (Source source : process.getResolvedSources()) {
                    Stage dependence = deliveries.get(source);
                    if (dependence == null) {
                        // 先頭ステージ
                        continue;
                    }
                    graph.addEdge(stage, dependence);
                }
            }
        }
        return graph;
    }

    /**
     * ステージの定義。
     */
    public static class Stage extends Compilable.Trait<CompiledStage> {

        private final StageModel model;

        private final List<Process> processes;

        private final List<Delivery> deliveries;

        private final Reduce reduceOrNull;

        private final Set<SideData> sideData;

        /**
         * インスタンスを生成する。
         * @param model このステージの構造
         * @param processes このステージのプロセス情報一覧
         * @param deliveries このステージの成果物一覧
         * @param reduceOrNull このステージのレデューサー定義、利用しない場合は{@code null}
         * @param sideData このステージで利用するサイドデータの一覧
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Stage(
                StageModel model,
                List<Process> processes,
                List<Delivery> deliveries,
                Reduce reduceOrNull,
                Set<SideData> sideData) {
            Precondition.checkMustNotBeNull(model, "model"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(processes, "processes"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(deliveries, "deliveries"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(sideData, "sideData"); //$NON-NLS-1$
            this.model = model;
            this.processes = processes;
            this.deliveries = deliveries;
            this.reduceOrNull = reduceOrNull;
            this.sideData = sideData;
        }

        /**
         * このステージのステージ番号を返す。
         * @return このステージのステージ番号
         */
        public int getNumber() {
            return model.getStageBlock().getStageNumber();
        }

        /**
         * このステージの構造を返す。
         * @return このステージの構造
         */
        public StageModel getModel() {
            return model;
        }

        /**
         * このステージのプロセス情報を返す。
         * @return プロセス情報
         */
        public List<Process> getProcesses() {
            return processes;
        }

        /**
         * このステージの成果物情報を返す。
         * @return 成果物情報
         */
        public List<Delivery> getDeliveries() {
            return deliveries;
        }

        /**
         * レデューサーの定義を返す。
         * @return レデューサーの定義、レデュースフェーズが存在しない場合は{@code null}
         */
        public Reduce getReduceOrNull() {
            return reduceOrNull;
        }

        /**
         * このステージで利用するサイドデータの一覧を返す。
         * @return サイドデータ
         */
        public Set<SideData> getSideData() {
            return sideData;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "Stage({0})",
                    String.valueOf(getNumber()));
        }
    }

    /**
     * レデューサーの定義。
     */
    public static class Reduce {

        private final Name reducerTypeName;

        private final Name combinerTypeNameOrNull;

        private final Name keyTypeName;

        private final Name valueTypeName;

        private final Name groupingComparatorTypeName;

        private final Name sortComparatorTypeName;

        private final Name partitionerTypeName;

        /**
         * インスタンスを生成する。
         * @param reducerTypeName レデューサークラスの完全限定名
         * @param combinerTypeNameOrNull コンバイナークラスの完全限定名、利用しない場合は{@code null}
         * @param keyTypeName キークラスの完全限定名
         * @param valueTypeName 値クラスの完全限定名
         * @param groupingComparatorTypeName グループ比較器クラスの完全限定名
         * @param sortComparatorTypeName 順序比較器クラスの完全限定名
         * @param partitionerTypeName パーティショナークラスの完全限定名
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Reduce(
                Name reducerTypeName,
                Name combinerTypeNameOrNull,
                Name keyTypeName,
                Name valueTypeName,
                Name groupingComparatorTypeName,
                Name sortComparatorTypeName,
                Name partitionerTypeName) {
            Precondition.checkMustNotBeNull(reducerTypeName, "reducerTypeName"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(keyTypeName, "keyTypeName"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(valueTypeName, "valueTypeName"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(groupingComparatorTypeName, "groupingComparatorTypeName"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(sortComparatorTypeName, "sortComparatorTypeName"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(partitionerTypeName, "partitionerTypeName"); //$NON-NLS-1$
            this.reducerTypeName = reducerTypeName;
            this.combinerTypeNameOrNull = combinerTypeNameOrNull;
            this.keyTypeName = keyTypeName;
            this.valueTypeName = valueTypeName;
            this.groupingComparatorTypeName = groupingComparatorTypeName;
            this.sortComparatorTypeName = sortComparatorTypeName;
            this.partitionerTypeName = partitionerTypeName;
        }

        /**
         * このオブジェクトに関連するコンバイナークラスの完全限定名を返す。
         * @return コンバイナークラスの完全限定名、利用しない場合は{@code null}
         */
        public Name getCombinerTypeNameOrNull() {
            return combinerTypeNameOrNull;
        }

        /**
         * このオブジェクトに関連するレデューサークラスの完全限定名を返す。
         * @return レデューサークラスの完全限定名
         */
        public Name getReducerTypeName() {
            return reducerTypeName;
        }

        /**
         * シャッフル時に利用するキークラスの完全限定名を返す。
         * @return キークラスの完全限定名
         */
        public Name getKeyTypeName() {
            return keyTypeName;
        }

        /**
         * シャッフル時に利用する値クラスの完全限定名を返す。
         * @return 値クラスの完全限定名
         */
        public Name getValueTypeName() {
            return valueTypeName;
        }

        /**
         * シャッフル時に利用するグループ化比較器クラスの完全限定名を返す。
         * @return グループ化比較器クラスの完全限定名
         */
        public Name getGroupingComparatorTypeName() {
            return groupingComparatorTypeName;
        }

        /**
         * シャッフル時に利用する順序比較器クラスの完全限定名を返す。
         * @return 順序比較器クラスの完全限定名
         */
        public Name getSortComparatorTypeName() {
            return sortComparatorTypeName;
        }

        /**
         * シャッフル時に利用するパーティショナークラスの完全限定名を返す。
         * @return パーティショナークラスの完全限定名
         */
        public Name getPartitionerTypeName() {
            return partitionerTypeName;
        }
    }

    /**
     * 何らかの出力を提供するインターフェース。
     */
    public abstract static class Source {

        private final Set<FlowBlock.Output> outputs;

        /**
         * インスタンスを生成する。
         * @param outputs このソースに関連する出力ポートの一覧
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        protected Source(Set<FlowBlock.Output> outputs) {
            Precondition.checkMustNotBeNull(outputs, "outputs"); //$NON-NLS-1$
            this.outputs = outputs;
        }

        /**
         * Returns input information.
         * @return input information
         */
        public abstract SourceInfo getInputInfo();

        /**
         * このソースに関連する出力ポートを返す。
         * @return 関連する出力ポート
         */
        public Set<FlowBlock.Output> getOutputs() {
            return outputs;
        }
    }

    /**
     * {@link JobflowModel.Source}からの出力を受け取るインターフェース。
     */
    public abstract static class Target {

        private final List<FlowBlock.Input> inputs;

        private Set<Source> sources;

        /**
         * インスタンスを生成する。
         * @param inputs 関連する入力ポート群
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Target(List<FlowBlock.Input> inputs) {
            Precondition.checkMustNotBeNull(inputs, "inputs"); //$NON-NLS-1$
            if (inputs.isEmpty()) {
                throw new IllegalArgumentException("inputs must not be empty"); //$NON-NLS-1$
            }
            this.inputs = inputs;
        }

        /**
         * このオブジェクトが受け取るべき出力の一覧を設定する。
         * @param opposites 受け取るべき出力の一覧
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public void resolveSources(Collection<? extends Source> opposites) {
            Precondition.checkMustNotBeNull(opposites, "opposites"); //$NON-NLS-1$
            this.sources = Sets.from(opposites);
        }

        /**
         * このオブジェクトに設定された出力の一覧を返す。
         * @return 設定された出力の一覧
         * @throws IllegalStateException 設定されていない場合
         * @see #resolveSources(Collection)
         */
        public Set<Source> getResolvedSources() {
            if (sources == null) {
                throw new IllegalStateException();
            }
            return sources;
        }

        /**
         * このオブジェクトに設定された出力からのパス一覧を返す。
         * @return 設定された出力からのパス一覧
         * @throws IllegalStateException 設定されていない場合
         * @see #resolveSources(Collection)
         */
        public Set<Location> getResolvedLocations() {
            Set<Location> results = Sets.create();
            for (Source source : getResolvedSources()) {
                results.addAll(source.getInputInfo().getLocations());
            }
            return results;
        }

        /**
         * このターゲットに関連する入力ポートを返す。
         * @return 関連する入力ポート
         */
        public List<FlowBlock.Input> getInputs() {
            return inputs;
        }

        /**
         * このターゲットのデータ型を返す。
         * @return このターゲットのデータ型
         */
        public java.lang.reflect.Type getDataType() {
            if (inputs.isEmpty()) {
                return void.class;
            }
            return inputs.get(0).getElementPort().getDescription().getDataType();
        }
    }

    /**
     * 外部入出力に対するプロセッサーを提供するインターフェース。
     */
    public interface Processible {

        /**
         * このオブジェクトの記述を処理するプロセッサーを返す。
         * @return 記述を処理するプロセッサー
         */
        ExternalIoDescriptionProcessor getProcessor();
    }

    /**
     * ステージで処理されるプロセスの情報。
     */
    public static class Process extends Target {

        private final Name mapperTypeName;

        /**
         * インスタンスを生成する。
         * @param inputs 関連する入力ポート
         * @param mapperTypeName 処理を行うマッパークラスの限定名
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Process(List<FlowBlock.Input> inputs, Name mapperTypeName) {
            super(inputs);
            Precondition.checkMustNotBeNull(mapperTypeName, "mapperTypeName"); //$NON-NLS-1$
            this.mapperTypeName = mapperTypeName;
        }

        /**
         * 処理を行うマッパークラスの限定名を返す。
         * @return 処理を行うマッパークラスの限定名
         */
        public Name getMapperTypeName() {
            return mapperTypeName;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "Process(inputs={0}, mapper={1})",
                    getInputs(),
                    getMapperTypeName());
        }
    }

    /**
     * ステージで出力される成果物。
     */
    public static class Delivery extends Source {

        private final Set<Location> locations;

        /**
         * インスタンスを生成する。
         * @param outputs 関連する出力ポートの一覧
         * @param locations 出力先のパス一覧
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Delivery(Set<FlowBlock.Output> outputs, Set<Location> locations) {
            super(outputs);
            Precondition.checkMustNotBeNull(locations, "locations"); //$NON-NLS-1$
            this.locations = locations;
        }

        /**
         * この成果物の型を返す。
         * @return この成果物の型
         */
        public java.lang.reflect.Type getDataType() {
            FlowBlock.Output first = getOutputs().iterator().next();
            FlowElementOutput port = first.getElementPort();
            return port.getDescription().getDataType();
        }

        @Override
        public SourceInfo getInputInfo() {
            return new SourceInfo(locations, TemporaryInputFormat.class);
        }

        /**
         * この成果物の形式を表す{@link OutputFormat}クラスを返す。
         * @return この成果物の形式を表す{@link OutputFormat}クラス
         */
        @SuppressWarnings("rawtypes")
        public Class<? extends OutputFormat> getOutputFormatType() {
            return TemporaryOutputFormat.class;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "Delivery(output={0}, locations={1})",
                    getOutputs(),
                    getInputInfo().getLocations());
        }
    }

    /**
     * フロー全体への入力。
     */
    public static class Import extends Source implements Processible {

        private final InputDescription description;

        private final ExternalIoDescriptionProcessor processor;

        /**
         * インスタンスを生成する。
         * @param description 入力記述
         * @param processor 上記記述を処理するプロセッサー
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Import(
                InputDescription description,
                ExternalIoDescriptionProcessor processor) {
            super(Collections.<FlowBlock.Output>emptySet());
            Precondition.checkMustNotBeNull(description, "description"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(processor, "processor"); //$NON-NLS-1$
            this.description = description;
            this.processor = processor;
        }

        /**
         * インスタンスを生成する。
         * @param output 関連する出力ポート
         * @param description 入力記述
         * @param processor 上記記述を処理するプロセッサー
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Import(
                FlowBlock.Output output,
                InputDescription description,
                ExternalIoDescriptionProcessor processor) {
            super(Collections.singleton(output));
            Precondition.checkMustNotBeNull(description, "description"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(processor, "processor"); //$NON-NLS-1$
            this.description = description;
            this.processor = processor;
        }

        /**
         * このオブジェクトが構成する識別子を返す。
         * @return このオブジェクトが構成する識別子
         */
        public String getId() {
            return description.getName();
        }

        @Override
        public SourceInfo getInputInfo() {
            return processor.getInputInfo(description);
        }

        /**
         * この入力を後続で利用する形式を表す{@link OutputFormat}クラスを返す。
         * @return この入力を後続で利用する形式を表す{@link OutputFormat}クラス
         */
        @SuppressWarnings("rawtypes")
        public Class<? extends OutputFormat> getOutputFormatType() {
            return TemporaryOutputFormat.class;
        }

        /**
         * このオブジェクトの内容を表す入力記述を返す。
         * @return 記述
         */
        public InputDescription getDescription() {
            return description;
        }

        @Override
        public ExternalIoDescriptionProcessor getProcessor() {
            return processor;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "Import(output={0}, locations={1}, description={2})",
                    getOutputs(),
                    getInputInfo().getLocations(),
                    getDescription());
        }
    }

    /**
     * フロー全体からの出力。
     */
    public static class Export extends Target implements Processible {

        private final OutputDescription description;

        private final ExternalIoDescriptionProcessor processor;

        /**
         * インスタンスを生成する。
         * @param inputs 関連する入力ポート
         * @param description 入力記述
         * @param processor 上記記述を処理するプロセッサー
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public Export(
                List<FlowBlock.Input> inputs,
                OutputDescription description,
                ExternalIoDescriptionProcessor processor) {
            super(inputs);
            Precondition.checkMustNotBeNull(description, "description"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(processor, "processor"); //$NON-NLS-1$
            this.description = description;
            this.processor = processor;
        }

        /**
         * このオブジェクトが構成する識別子を返す。
         * @return このオブジェクトが構成する識別子
         */
        public String getId() {
            return description.getName();
        }

        /**
         * このオブジェクトの内容を表す出力記述を返す。
         * @return 記述
         */
        public OutputDescription getDescription() {
            return description;
        }

        @Override
        public ExternalIoDescriptionProcessor getProcessor() {
            return processor;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "Export(inputs={0}, description={1})",
                    getInputs(),
                    getDescription());
        }
    }

    /**
     * ステージで利用するサイドデータの一覧。
     */
    public static class SideData {

        private final Set<Location> clusterPaths;

        private final String localName;

        /**
         * インスタンスを生成する。
         * @param clusterPaths サイドデータのクラスター上のパス
         * @param localName ローカル上での名前
         * @throws IllegalArgumentException 引数に{@code null}が指定された場合
         */
        public SideData(Set<Location> clusterPaths, String localName) {
            Precondition.checkMustNotBeNull(clusterPaths, "clusterPath"); //$NON-NLS-1$
            Precondition.checkMustNotBeNull(localName, "localName"); //$NON-NLS-1$
            this.clusterPaths = clusterPaths;
            this.localName = localName;
        }

        /**
         * サイドデータのクラスター上のパスを返す。
         * @return サイドデータのクラスター上のパス
         */
        public Set<Location> getClusterPaths() {
            return clusterPaths;
        }

        /**
         * ローカル上での名前を返す。
         * @return ローカル上での名前
         */
        public String getLocalName() {
            return localName;
        }

        @Override
        public String toString() {
            return MessageFormat.format(
                    "SideData(path={0}, name={1})",
                    getClusterPaths(),
                    getLocalName());
        }
    }
}
TOP

Related Classes of com.asakusafw.compiler.flow.jobflow.JobflowModel$Target

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.