Skip to content

Commit

Permalink
first complete version of injection plan traversal and graphviz output.
Browse files Browse the repository at this point in the history
  • Loading branch information
motus committed Jun 17, 2013
1 parent e83bb91 commit f944680
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 34 deletions.
1 change: 1 addition & 0 deletions tang/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
type-hierarchy.*
injection-plan.*
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.microsoft.tang.examples;

import java.io.FileWriter;
import java.io.IOException;
import javax.inject.Inject;

Expand All @@ -31,14 +32,13 @@
import com.microsoft.tang.exceptions.InjectionException;

import com.microsoft.tang.formats.CommandLine;
import com.microsoft.tang.formats.ConfigurationFile;
import com.microsoft.tang.implementation.InjectionPlan;

import com.microsoft.tang.util.walk.GraphVisitorGraphviz;
import java.io.FileWriter;
import com.microsoft.tang.util.walk.graphviz.GraphvizConfigVisitor;
import com.microsoft.tang.util.walk.graphviz.GraphvizInjectionPlanVisitor;

/**
* Prints sample configuration in Graphviz DOT format to stdout.
* Build a Graphviz representation of TANG configuration and injection plan.
*/
public final class PrintTypeHierarchy {

Expand Down Expand Up @@ -86,12 +86,16 @@ public static void main(final String[] aArgs)
final PrintTypeHierarchy myself = injector.getInstance(PrintTypeHierarchy.class);

try (final FileWriter out = new FileWriter("type-hierarchy.dot")) {
out.write(GraphVisitorGraphviz.getGraphvizStr(config, true, true));
out.write(GraphvizConfigVisitor.getGraphvizStr(config, true, true));
}

final InjectionPlan<PrintTypeHierarchy> plan =
injector.getInjectionPlan(PrintTypeHierarchy.class);

System.out.println(plan.toPrettyString());
try (final FileWriter out = new FileWriter("injection-plan.dot")) {
out.write(GraphvizInjectionPlanVisitor.getGraphvizStr(plan));
}

System.out.println(myself);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* Dispatches between ClassNode, PackageNode, and NamedParameterNode types.
* It is used e.g. in Walk.preorder()
*/
public abstract class AbstractTypedNodeVisitor implements NodeVisitor<Node> {
public abstract class AbstractConfigNodeVisitor implements NodeVisitor<Node> {

/**
* Manually dispatch between different types of Nodes and call a proper visit() method.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright 2013 Microsoft.
*
* 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.microsoft.tang.util.walk;

import com.microsoft.tang.implementation.InjectionPlan;
import com.microsoft.tang.implementation.Constructor;
import com.microsoft.tang.implementation.RequiredSingleton;
import com.microsoft.tang.implementation.Subplan;
import com.microsoft.tang.implementation.java.JavaInstance;

/**
* Generic interface to traverse nodes of the injection plan.
* Dispatches between Constructor, Subplan, RequiredSingleton, and JavaInstance types.
* It is used e.g. in Walk.preorder()
*/
public abstract class AbstractInjectionPlanNodeVisitor implements NodeVisitor<InjectionPlan<?>> {

/**
* Manually dispatch between different types of injection plan objects and call proper
* visit() method. Currently dispatches between Constructor, Subplan, RequiredSingleton,
* and JavaInstance types.
* @param aNode TANG injection plan node.
* @return true to proceed with the next node, false to cancel.
* @throws ClassCastException if argument is not one of Constructor, Subplan,
* RequiredSingleton, or JavaInstance.
*/
@Override
public boolean visit(final InjectionPlan<?> aNode) {
if (aNode instanceof Constructor<?>) {
return visit((Constructor) aNode);
} else if (aNode instanceof Subplan<?>) {
return visit((Subplan) aNode);
} else if (aNode instanceof RequiredSingleton<?,?>) {
return visit((RequiredSingleton) aNode);
} else if (aNode instanceof JavaInstance<?>) {
return visit((JavaInstance) aNode);
}
throw new ClassCastException(
"Node " + aNode.getClass() + " cannot be casted to one of the known subclasses."
+ " Override this method to handle the case.");
}

/**
* Process current injection plan node of Constructor type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
public abstract boolean visit(Constructor<?> aNode);

/**
* Process current injection plan node of JavaInstance type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
public abstract boolean visit(JavaInstance<?> aNode);

/**
* Process current injection plan node of RequiredSingleton type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
public abstract boolean visit(RequiredSingleton<?,?> aNode);

/**
* Process current injection plan node of Subplan type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
public abstract boolean visit(Subplan<?> aNode);
}
24 changes: 4 additions & 20 deletions tang/src/main/java/com/microsoft/tang/util/walk/Walk.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@
*/
package com.microsoft.tang.util.walk;

import com.microsoft.tang.Configuration;
import com.microsoft.tang.types.Node;
import com.microsoft.tang.types.Traversable;

/**
* Graph traversal.
* Generic graph traversal.
*/
public final class Walk {

Expand All @@ -32,30 +30,16 @@ private Walk() throws IllegalAccessException {
throw new IllegalAccessException("Do not instantiate this class.");
}

/**
* Traverse the entire configuration tree in preorder.
* @param aNodeVisitor node visitor. Can be null.
* @param aEdgeVisitor edge visitor. Can be null.
* @param aConfig configuration to process.
* @return true if all nodes has been walked, false if visitor stopped early.
*/
public static boolean preorder(
final NodeVisitor<Node> aNodeVisitor, final EdgeVisitor<Node> aEdgeVisitor, final Configuration aConfig)
{
assert (aNodeVisitor != null || aEdgeVisitor != null);
final Node root = aConfig.getClassHierarchy().getNamespace();
return preorder(aNodeVisitor, aEdgeVisitor, root);
}

/**
* Traverse the configuration (sub)tree in preorder, starting from the given node.
* FIXME: handle loopy graphs correctly!
* @param aNodeVisitor node visitor. Can be null.
* @param aEdgeVisitor edge visitor. Can be null.
* @param aNode current node of the configuration tree.
* @return true if all nodes has been walked, false if visitor stopped early.
*/
private static <T extends Traversable<T>> boolean preorder(
final NodeVisitor<T> aNodeVisitor, final EdgeVisitor<T> aEdgeVisitor, final T aNode)
public static <T extends Traversable<T>> boolean preorder(
final NodeVisitor<T> aNodeVisitor, final EdgeVisitor<T> aEdgeVisitor, final T aNode)
{
if (aNodeVisitor != null && aNodeVisitor.visit(aNode)) {
for (final T child : aNode.getChildren()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.microsoft.tang.util.walk;
package com.microsoft.tang.util.walk.graphviz;

import com.microsoft.tang.Configuration;

import com.microsoft.tang.types.Node;
import com.microsoft.tang.types.ClassNode;
import com.microsoft.tang.types.PackageNode;
import com.microsoft.tang.types.NamedParameterNode;

import com.microsoft.tang.util.walk.Walk;
import com.microsoft.tang.util.walk.EdgeVisitor;
import com.microsoft.tang.util.walk.AbstractConfigNodeVisitor;

/**
* Build a Graphviz representation of the configuration graph.
*/
public final class GraphVisitorGraphviz
extends AbstractTypedNodeVisitor implements EdgeVisitor<Node>
public final class GraphvizConfigVisitor
extends AbstractConfigNodeVisitor implements EdgeVisitor<Node>
{

/** Legend for the configuration graph in Graphviz format */
Expand Down Expand Up @@ -74,7 +79,7 @@ public final class GraphVisitorGraphviz
* @param aShowImpl If true, plot IS-A edges for know implementations.
* @param aShowLegend If true, add legend to the plot.
*/
public GraphVisitorGraphviz(final Configuration aConfig,
public GraphvizConfigVisitor(final Configuration aConfig,
final boolean aShowImpl, final boolean aShowLegend) {
super();
this.mConfig = aConfig;
Expand Down Expand Up @@ -201,8 +206,10 @@ public boolean visit(final Node aNodeFrom, final Node aNodeTo) {
public static String getGraphvizStr(final Configuration aConfig,
final boolean aShowImpl, final boolean aShowLegend)
{
final GraphVisitorGraphviz visitor = new GraphVisitorGraphviz(aConfig, aShowImpl, aShowLegend);
Walk.preorder(visitor, visitor, aConfig);
final GraphvizConfigVisitor visitor =
new GraphvizConfigVisitor(aConfig, aShowImpl, aShowLegend);
final Node root = aConfig.getClassHierarchy().getNamespace();
Walk.preorder(visitor, visitor, root);
return visitor.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2013 Microsoft.
*
* 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.microsoft.tang.util.walk.graphviz;

import com.microsoft.tang.implementation.InjectionPlan;
import com.microsoft.tang.implementation.Constructor;
import com.microsoft.tang.implementation.RequiredSingleton;
import com.microsoft.tang.implementation.Subplan;
import com.microsoft.tang.implementation.java.JavaInstance;

import com.microsoft.tang.util.walk.Walk;
import com.microsoft.tang.util.walk.EdgeVisitor;
import com.microsoft.tang.util.walk.AbstractInjectionPlanNodeVisitor;

/**
* Build a Graphviz representation of the injection plan graph.
*/
public final class GraphvizInjectionPlanVisitor
extends AbstractInjectionPlanNodeVisitor implements EdgeVisitor<InjectionPlan<?>>
{
/** Accumulate string representation of the graph here. */
private final transient StringBuilder mGraphStr =
new StringBuilder("digraph InjectionPlanMain {\n");

/**
* Process current injection plan node of Constructor type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
@Override
public boolean visit(final Constructor<?> aNode) {
mGraphStr.append(" ")
.append(aNode.getNode().getName())
.append(" [label=\"")
.append(aNode)
.append("\", shape=box")
.append("];\n");
return true;
}

/**
* Process current injection plan node of JavaInstance type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
@Override
public boolean visit(final JavaInstance<?> aNode) {
mGraphStr.append(" ")
.append(aNode.getNode().getName())
.append(" [label=\"")
.append(aNode)
.append("\", shape=box")
.append("];\n");
return true;
}

/**
* Process current injection plan node of RequiredSingleton type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
@Override
public boolean visit(final RequiredSingleton<?,?> aNode) {
mGraphStr.append(" ")
.append(aNode.getNode().getName())
.append(" [label=\"")
.append(aNode)
.append("\", shape=box, style=filled")
.append("];\n");
return true;
}

/**
* Process current injection plan node of Subplan type.
* @param aNode Current injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
@Override
public boolean visit(final Subplan<?> aNode) {
mGraphStr.append(" ")
.append(aNode.getNode().getName())
.append(" [label=\"")
.append(aNode)
.append("\", shape=oval")
.append("];\n");
return true;
}

/**
* Process current edge of the injection plan.
* @param aNodeFrom Current injection plan node.
* @param aNodeTo Destination injection plan node.
* @return true to proceed with the next node, false to cancel.
*/
@Override
public boolean visit(final InjectionPlan<?> aNodeFrom, final InjectionPlan<?> aNodeTo) {
mGraphStr.append(" ")
.append(aNodeFrom.getNode().getName())
.append(" -> ")
.append(aNodeTo.getNode().getName())
.append(" [style=solid];\n");
return true;
}

/**
* @return TANG injection plan represented as a Graphviz DOT string.
*/
@Override
public String toString() {
return mGraphStr.toString() + "}\n";
}

/**
* Produce a Graphviz DOT string for a given TANG injection plan.
* @param aConfig TANG configuration object.
* @param aShowImpl If true, plot IS-A edges for know implementations.
* @param aShowLegend If true, add legend to the plot.
* @return Injection plan represented as a string in Graphviz DOT format.
*/
public static String getGraphvizStr(final InjectionPlan<?> plan)
{
final GraphvizInjectionPlanVisitor visitor = new GraphvizInjectionPlanVisitor();
Walk.preorder(visitor, visitor, plan);
return visitor.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2013 Microsoft.
*
* 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.
*/

/**
* produce Graphviz representation of TANG configuration graph and injection plan.
*/
package com.microsoft.tang.util.walk.graphviz;
Loading

0 comments on commit f944680

Please sign in to comment.