/**
* 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.visualizer;
import java.util.HashSet;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.asakusafw.compiler.common.Naming;
import com.asakusafw.compiler.common.Precondition;
import com.asakusafw.compiler.flow.plan.FlowBlock;
import com.asakusafw.compiler.flow.plan.FlowGraphUtil;
import com.asakusafw.compiler.flow.plan.StageBlock;
import com.asakusafw.compiler.flow.plan.StageGraph;
import com.asakusafw.utils.collections.Sets;
import com.asakusafw.vocabulary.flow.graph.FlowElement;
import com.asakusafw.vocabulary.flow.graph.FlowElementKind;
import com.asakusafw.vocabulary.flow.graph.FlowGraph;
import com.asakusafw.vocabulary.flow.graph.FlowPartDescription;
/**
* Analyzes flow elements and convert them to visual models.
* @since 0.1.0
* @version 0.4.0
*/
public final class VisualAnalyzer {
static final Logger LOG = LoggerFactory.getLogger(VisualAnalyzer.class);
private final Set<FlowElement> sawElements = new HashSet<>();
private VisualAnalyzer() {
return;
}
/**
* Converts a flow graph into a corresponded visual model.
* @param graph the target graph
* @return the corresponded visual model
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public static VisualGraph convertFlowGraph(FlowGraph graph) {
Precondition.checkMustNotBeNull(graph, "graph"); //$NON-NLS-1$
LOG.debug("analyzing flow graph for visualizing: {}", graph); //$NON-NLS-1$
VisualAnalyzer analyzer = new VisualAnalyzer();
Set<VisualNode> nodes = new HashSet<>();
for (FlowElement element : FlowGraphUtil.collectElements(graph)) {
VisualNode node = analyzer.convertElement(element);
if (node != null) {
nodes.add(node);
}
}
return new VisualGraph(null, nodes);
}
/**
* Converts a stage graph into a corresponded visual model.
* @param graph the target graph
* @return the corresponded visual model
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public static VisualGraph convertStageGraph(StageGraph graph) {
Precondition.checkMustNotBeNull(graph, "graph"); //$NON-NLS-1$
LOG.debug("analyzing stage graph for visualizing: {}", graph); //$NON-NLS-1$
VisualAnalyzer analyzer = new VisualAnalyzer();
Set<VisualNode> nodes = new HashSet<>();
nodes.add(analyzer.convertBlock("(source)", graph.getInput())); //$NON-NLS-1$
for (StageBlock stage : graph.getStages()) {
nodes.add(analyzer.convertStage(stage));
}
nodes.add(analyzer.convertBlock("(sink)", graph.getOutput())); //$NON-NLS-1$
return new VisualGraph(null, nodes);
}
/**
* Converts a stage block into a corresponded visual model.
* @param stage the target block
* @return the corresponded visual model
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public static VisualGraph convertStageBlock(StageBlock stage) {
Precondition.checkMustNotBeNull(stage, "stage"); //$NON-NLS-1$
LOG.debug("analyzing stage block for visualizing: {}", stage); //$NON-NLS-1$
VisualAnalyzer analyzer = new VisualAnalyzer();
Set<VisualNode> nodes = new HashSet<>();
for (FlowBlock head : stage.getMapBlocks()) {
for (FlowBlock.Input input : head.getBlockInputs()) {
for (FlowBlock.Connection conn : input.getConnections()) {
FlowElement element = conn.getUpstream().getElementPort().getOwner();
VisualNode node = analyzer.convertElement(element);
if (node != null) {
nodes.add(node);
}
}
}
}
nodes.add(analyzer.convertStage(stage));
Set<FlowBlock> tails = stage.hasReduceBlocks() ? stage.getReduceBlocks() : stage.getMapBlocks();
for (FlowBlock tail : tails) {
for (FlowBlock.Output output : tail.getBlockOutputs()) {
for (FlowBlock.Connection conn : output.getConnections()) {
FlowElement element = conn.getDownstream().getElementPort().getOwner();
VisualNode node = analyzer.convertElement(element);
if (node != null) {
nodes.add(node);
}
}
}
}
return new VisualGraph(null, nodes);
}
/**
* Converts a flow block into a corresponded visual model.
* @param block the target block
* @return the corresponded visual model
* @throws IllegalArgumentException if the parameter is {@code null}
* @since 0.4.0
*/
public static VisualGraph convertFlowBlock(FlowBlock block) {
Precondition.checkMustNotBeNull(block, "block"); //$NON-NLS-1$
LOG.debug("analyzing flow block for visualizing: {}", block); //$NON-NLS-1$
VisualAnalyzer analyzer = new VisualAnalyzer();
Set<VisualNode> nodes = new HashSet<>();
nodes.add(analyzer.convertBlock("block", block)); //$NON-NLS-1$
return new VisualGraph(null, nodes);
}
private VisualGraph convertStage(StageBlock stage) {
assert stage != null;
Set<VisualBlock> nodes = new HashSet<>();
for (FlowBlock block : stage.getMapBlocks()) {
// "cluster"'s bug of dot
nodes.add(convertBlock(null, block));
}
for (FlowBlock block : stage.getReduceBlocks()) {
nodes.add(convertBlock(null, block));
}
return new VisualGraph(
Naming.getStageName(stage.getStageNumber()),
nodes);
}
private VisualBlock convertBlock(String label, FlowBlock block) {
assert block != null;
Set<VisualNode> nodes = new HashSet<>();
for (FlowElement element : block.getElements()) {
VisualNode node = convertElement(element);
if (node != null) {
nodes.add(node);
}
}
return new VisualBlock(
label,
Sets.from(block.getBlockInputs()),
Sets.from(block.getBlockOutputs()),
nodes);
}
private VisualNode convertElement(FlowElement element) {
assert element != null;
if (sawElements.contains(element)) {
LOG.debug("Ignored already presented element: {}", element); //$NON-NLS-1$
return null;
}
sawElements.add(element);
if (element.getDescription().getKind() == FlowElementKind.FLOW_COMPONENT) {
FlowPartDescription desc = (FlowPartDescription) element.getDescription();
Set<VisualNode> nodes = new HashSet<>();
for (FlowElement inner : FlowGraphUtil.collectElements(desc.getFlowGraph())) {
VisualNode node = convertElement(inner);
if (node != null) {
nodes.add(node);
}
}
return new VisualFlowPart(element, nodes);
}
return new VisualElement(element);
}
}