Package dk.brics.jwig.analysis

Source Code of dk.brics.jwig.analysis.DotVisualizer

package dk.brics.jwig.analysis;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import soot.SootClass;
import soot.SootMethod;
import dk.brics.jwig.URLPattern;
import dk.brics.jwig.WebApp;
import dk.brics.jwig.WebContext;
import dk.brics.jwig.WebSite;
import dk.brics.jwig.analysis.graph.FilterState;
import dk.brics.jwig.analysis.graph.FilterTransition;
import dk.brics.jwig.analysis.graph.HandlerState;
import dk.brics.jwig.analysis.graph.HandlerTransition;
import dk.brics.jwig.analysis.graph.LambdaTransition;
import dk.brics.jwig.analysis.graph.PredecessorResolver;
import dk.brics.jwig.analysis.graph.State;
import dk.brics.jwig.analysis.graph.StateMachine;
import dk.brics.jwig.analysis.graph.Transition;
import dk.brics.jwig.analysis.graph.WebMethodState;
import dk.brics.jwig.analysis.graph.WebMethodTransition;

/**
* Visualizes a #StateMachine in Graphviz dot format
*/
public class DotVisualizer {

    private final StateMachine stateMachine;
    private final Set<State> statesWithManyIngoingEdges;

    // TODO make legend
    public DotVisualizer(StateMachine stateMachine) {
        this.stateMachine = stateMachine;
        statesWithManyIngoingEdges = findStatesWithManyIngoingEdges(stateMachine);
    }

    private Set<State> findStatesWithManyIngoingEdges(StateMachine stateMachine) {
        Map<State, Integer> inCount = new HashMap<State, Integer>();
        final Set<State> allStates = stateMachine.getAllStates();
        for (State state : allStates) {
            for (Transition transition : state.getTransitions()) {
                final State target = transition.getTarget();
                if (target != null) {
                    if (!inCount.containsKey(target))
                        inCount.put(target, 0);
                    Integer count = inCount.get(target);
                    inCount.put(target, count + 1);
                }
            }
        }
        Integer threshold = 25;
        Set<State> states = new HashSet<State>();
        for (Entry<State, Integer> entry : inCount.entrySet()) {
            if (entry.getValue() >= threshold) {
                states.add(entry.getKey());
            }
        }
        return states;
    }

    /**
     * Visualizes
     */
    public String visualize(boolean full) {
        // remove WebContext, WebSite and WebApp from the diagram:
        final Set<State> states = stateMachine.getStateFlattener()
                .getAllStates();
        if (!full) {
            JwigResolver resolver = JwigResolver.get();
            Set<SootClass> jwigClasses = new HashSet<SootClass>();

            jwigClasses.add(resolver.getSootClass(WebContext.class));
            jwigClasses.add(resolver.getSootClass(WebSite.class));
            jwigClasses.add(resolver.getSootClass(WebApp.class));

            for (State state : states) {
                for (Transition transition : state.getTransitions()) {
                    final State target = transition.getTarget();
                    if (target != null) {
                        if (jwigClasses.contains(target.getMethod()
                                .getDeclaringClass())) {
                            state.removeSuccessor(transition);
                        }
                    }
                }
            }
        }
        return visualize(states);
    }

    public String visualize(Collection<State> states) {
        StringBuilder buffer = new StringBuilder();
        buffer.append("digraph StateMachine {\n");
        buffer.append("rankdir=LR;\n");

        Map<State, String> names = new HashMap<State, String>();
        int i = 0;
        for (State s : states) {
            String name = "N" + i++;
            names.put(s, name);
        }
        buffer.append(visualizeStates(names));
        buffer.append(visualizeTransitions(names));
        buffer.append(visualizeManyTransitions(names));
        buffer.append("}\n");
        return buffer.toString();
    }

    public String visualize(Set<SootClass> classes) {
        Collection<State> states = new LinkedList<State>();
        for (State state : stateMachine.getAllStates()) {
            if (classes.contains(state.getMethod().getDeclaringClass())) {
                states.add(state);
            }
        }
        return visualize(states);
    }

    private String visualizeManyTransitions(Map<State, String> names) {
        StringBuilder sb = new StringBuilder();
        for (State state : statesWithManyIngoingEdges) {
            final String id = names.get(state);
            if (id != null)
                sb.append(id + "_many[label=\"many\",shape=none]\n");
        }
        for (State state : statesWithManyIngoingEdges) {
            final String id = names.get(state);
            if (id != null)
                sb.append(id + "_many->" + id + "[color=grey];\n");
        }
        return sb.toString();
    }

    private String visualizeStates(Map<State, String> names) {
        Map<SootClass, String> webapps = new HashMap<SootClass, String>();
        SootClass current = null;
        StringBuilder sb = new StringBuilder();
        State[] states = names.keySet().toArray(
                new State[names.keySet().size()]);
        Arrays.sort(states, new Comparator<State>() {
            @Override
            public int compare(State o1, State o2) {
                int hash1 = StateMachine.getHash(o1);
                int hash2 = StateMachine.getHash(o2);
                return hash1 - hash2;
            }
        });
        for (State s : states) {
            if (s != null) {
                SootClass cl = s.getMethod().getDeclaringClass();
                if (cl != current) {
                    if (current != null) {
                        sb.append("}\n");
                    }
                    final String className = cl.getName();
                    final String label = className + getURLPattern(cl);
                    String name = className.replace(".", "").replace("$", "");
                    sb.append("subgraph cluster" + name + " {\n");
                    sb.append("label=\"" + label + "\";\n");
                    current = cl;
                    webapps.put(cl, name);
                }

                String style = "solid";
                String color = "black";
                if (s instanceof WebMethodState) {
                    //
                } else if (s instanceof FilterState) {
                    style = "dotted";
                } else if (s instanceof HandlerState) {
                    style = "dashed";
                } else {
                    color = "grey";
                }

                if (s.isInSession()) {
                    style = style + ",bold";
                }
                final String name = s.getMethod().getName();
                final String priority = s.getPriority()
                        + (s.isDefaultPriority() ? "" : "!");
                String urlPattern = getURLPattern(s.getMethod());
                final String label = name + "(" + priority + ")" + urlPattern;
                sb.append(names.get(s) + " [label=\"" + label
                        + "\", shape=box,style=\"" + style + "\",color="
                        + color + "];\n");
            }
        }
        sb.append("}\n");
        return sb.toString();
    }

    private String getURLPattern(SootClass cl) {
        URLPattern up = JwigResolver.get().getJavaClass(cl)
                .getAnnotation(URLPattern.class);
        if (up == null)
            return "";
        return "[" + up.value() + "]";
    }

    private String getURLPattern(SootMethod method) {
        if (!method.isPublic() || method.isStatic())
            return "";
        Method m = JwigResolver.get().getJavaMethod(method);
        URLPattern up = m.getAnnotation(URLPattern.class);
        if (up == null)
            return "";
        return "[" + up.value() + "]";
    }

    private String visualizeTransitions(Map<State, String> names) {
        StringBuilder sb = new StringBuilder();
        for (Entry<State, String> entry : names.entrySet()) {
            if (entry != null && (entry.getKey() != null)) {
                for (Transition suc : entry.getKey().getTransitions()) {
                    State target = suc.getTarget();
                    if (!statesWithManyIngoingEdges.contains(target)) {
                        String trans = "";
                        String style = "solid";
                        String color = "black";
                        if (suc instanceof LambdaTransition) {
                            color = "grey";
                        } else if (suc instanceof WebMethodTransition) {
                            //
                        } else if (suc instanceof FilterTransition) {
                            style = "dotted";
                        } else if (suc instanceof HandlerTransition) {
                            style = "dashed";
                        } else {
                            color = "grey";
                        }

                        if (suc.isInSession()) {
                            style = style + ", " + "bold";
                        }

                        String name;
                        if (target != null) {
                            name = names.get(target);
                            if (name == null) {
                                name = "IGNORED";
                                trans = "";
                                style = "dotted";
                            }
                        } else {
                            name = "ANY";
                        }
                        sb.append(entry.getValue() + " -> " + name
                                + " [label=\"" + trans + "\",style=\"" + style
                                + "\",color=" + color + "];\n");
                    }
                }
            }
        }
        return sb.toString();
    }

    public String visualizeSuccessors(State state) {
        Set<State> successors = new HashSet<State>();
        for (Transition transition : state.getTransitions())
            successors.add(transition.getTarget());
        successors.add(state);
        return visualize(successors);
    }

    public String visualizePredecessors(State state) {
        Set<State> successors = new HashSet<State>();
        for (Transition transition : new PredecessorResolver(stateMachine)
                .getPredecessors(state))
            successors.add(transition.getTarget());
        successors.add(state);
        return visualize(successors);
    }
}
TOP

Related Classes of dk.brics.jwig.analysis.DotVisualizer

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.