com.drgarbage.visualgraphic.model.ControlFlowGraphDiagramFactory.java Source code

Java tutorial

Introduction

Here is the source code for com.drgarbage.visualgraphic.model.ControlFlowGraphDiagramFactory.java

Source

/**
 * Copyright (c) 2008-2012, Dr. Garbage Community
 *
 * 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.drgarbage.visualgraphic.model;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.draw2d.Graphics;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.launching.JavaRuntime;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

import com.drgarbage.algorithms.HierarchicalLayout;
import com.drgarbage.asm.visitor.AllCodeVisitor;
import com.drgarbage.bytecode.ByteCodeConstants;
import com.drgarbage.bytecode.LineNumberTableEntry;
import com.drgarbage.bytecode.instructions.AbstractInstruction;
import com.drgarbage.controlflowgraph.ControlFlowGraphException;
import com.drgarbage.controlflowgraph.ControlFlowGraphGenerator;
import com.drgarbage.controlflowgraph.intf.IBasicBlock;
import com.drgarbage.controlflowgraph.intf.IDirectedGraphExt;
import com.drgarbage.controlflowgraph.intf.IEdgeExt;
import com.drgarbage.controlflowgraph.intf.IEdgeListExt;
import com.drgarbage.controlflowgraph.intf.INodeExt;
import com.drgarbage.controlflowgraph.intf.INodeListExt;
import com.drgarbage.controlflowgraph.intf.INodeType;
import com.drgarbage.controlflowgraphfactory.ControlFlowFactoryMessages;
import com.drgarbage.controlflowgraphfactory.ControlFlowFactoryPlugin;
import com.drgarbage.controlflowgraphfactory.actions.LayoutAlgorithmsUtils;
import com.drgarbage.controlflowgraphfactory.export.AbstractExport;
import com.drgarbage.controlflowgraphfactory.export.AbstractExport2;
import com.drgarbage.controlflowgraphfactory.export.ExportException;
import com.drgarbage.controlflowgraphfactory.export.GraphDOTExport;
import com.drgarbage.controlflowgraphfactory.export.GraphMlExport;
import com.drgarbage.controlflowgraphfactory.export.GraphXMLExport;
import com.drgarbage.controlflowgraphfactory.preferences.ControlFlowFactoryPreferenceConstants;
import com.drgarbage.core.CoreMessages;
import com.drgarbage.core.img.CoreImg;
import com.drgarbage.graph.GraphConstants;
import com.drgarbage.graph.IGraphSpecification;
import com.drgarbage.io.FileExtensions;
import com.drgarbage.javalang.JavaLangUtils;
import com.drgarbage.utils.Messages;

/**
 * Control flow Graph diagram factory.
 * 
 * @author Sergej Alekseev
 * @version $Revision$ $Id: ControlFlowGraphDiagramFactory.java 1390
 *          2009-10-25 15:41:10Z Peter Palaga $
 */
public class ControlFlowGraphDiagramFactory {

    public enum Result {
        OK, YES_TO_ALL, NO_TO_ALL, CANCELED, ERROR, YES, NO
    };

    /**
     * Build bytecode graph diagram.
     * 
     * @param instruction
     *            list
     * @throws IOException
     * @throws ControlFlowGraphException
     */
    public static ControlFlowGraphDiagram buildByteCodeControlFlowDiagram(List<AbstractInstruction> instructions)
            throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        IDirectedGraphExt graph = ControlFlowGraphGenerator.generateControlFlowGraph(instructions, null,
                createStartNode, createExitNode, createBackEdge);
        return createControlFlowDiagram(graph);
    }

    /**
     * Build bytecode graph diagram.
     * 
     * @param classPath
     *            , the class path
     * @param packageName
     *            , the name of the package
     * @param className
     *            , the name of the class
     * @param methodName
     *            , the name of the method
     * @param methodSig
     *            , the method signature
     * @throws ControlFlowGraphException
     *             , IOException, InvalidByteCodeException
     */
    public static ControlFlowGraphDiagram buildByteCodeControlFlowDiagram(String[] classPath, String packageName,
            String className, String methodName, String methodSig) throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        IDirectedGraphExt graph = ControlFlowGraphGenerator.generateControlFlowGraph(classPath, packageName,
                className, methodName, methodSig, createStartNode, createExitNode, createBackEdge);
        Map<String, Object> attr = graph.getUserObject();
        attr.put(ByteCodeConstants.NAME, className + "." + methodName + methodSig);
        return createControlFlowDiagram(graph);
    }

    /**
     * Build basic block graph diagram.
     * 
     * @param instruction
     *            list
     * @throws IOException
     * @throws ControlFlowGraphException
     */
    public static ControlFlowGraphDiagram buildBasicblockGraphDiagram(List<AbstractInstruction> instructions)
            throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        /* generate control flow graph */
        IDirectedGraphExt basicBlockGraph = ControlFlowGraphGenerator.generateBasicBlockGraph(instructions, null,
                createStartNode, createExitNode, createBackEdge);
        return createBasicBlockDiagram(basicBlockGraph);
    }

    /**
     * Build basicblock graph diagram.
     * 
     * @param classPath
     *            , the class path
     * @param packageName
     *            , the name of the package
     * @param className
     *            , the name of the class
     * @param methodName
     *            , the name of the method
     * @param methodSig
     *            , the method signature
     * @throws ControlFlowGraphException
     *             , IOException, InvalidByteCodeException
     */
    public static ControlFlowGraphDiagram buildBasicblockGraphDiagram(String[] classPath, String packageName,
            String className, String methodName, String methodSig) throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();

        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        /* generate control flow graph */
        IDirectedGraphExt basicBlockGraph = ControlFlowGraphGenerator.generateBasicBlockGraph(classPath,
                packageName, className, methodName, methodSig, createStartNode, createExitNode, createBackEdge);
        Map<String, Object> attr = basicBlockGraph.getUserObject();
        attr.put(ByteCodeConstants.NAME, className + "." + methodName + methodSig);
        return createBasicBlockDiagram(basicBlockGraph);
    }

    /**
     * Build sourcecode graph diagram.
     * 
     * @param instruction
     *            list
     */
    public static ControlFlowGraphDiagram buildSourceControlFlowDiagram(List<AbstractInstruction> instructions,
            LineNumberTableEntry[] lineNumberTable) throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        /* generate control flow graph */
        IDirectedGraphExt graph = ControlFlowGraphGenerator.generateSourceCodeGraph(instructions, lineNumberTable,
                createStartNode, createExitNode, createBackEdge);
        return createSourceCodeGraphDiagram(graph);
    }

    /**
     * Build sourcecode graph diagram.
     * 
     * @param classPath
     *            , the class path
     * @param packageName
     *            , the name of the package
     * @param className
     *            , the name of the class
     * @param methodName
     *            , the name of the method
     * @param methodSig
     *            , the method signature
     * @throws ControlFlowGraphException
     *             , IOException, InvalidByteCodeException
     */
    public static ControlFlowGraphDiagram buildSourceControlFlowDiagram(String[] classPath, String packageName,
            String className, String methodName, String methodSig) throws ControlFlowGraphException, IOException {
        /* get preferences */
        IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
        boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
        boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
        boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

        /* generate control flow graph */
        IDirectedGraphExt graph = ControlFlowGraphGenerator.generateSourceCodeGraph(classPath, packageName,
                className, methodName, methodSig, createStartNode, createExitNode, createBackEdge);
        Map<String, Object> attr = graph.getUserObject();
        attr.put(ByteCodeConstants.NAME, className + "." + methodName + methodSig);
        return createSourceCodeGraphDiagram(graph);
    }

    /* private methods */

    /**
     * Creates graph diagram.
     * 
     * @param graph
     * @return diagram
     */
    private static ControlFlowGraphDiagram createControlFlowDiagram(IDirectedGraphExt graph) {
        int nodeWeigth = 78;
        int nodeHeight = 36;
        INodeExt node = null;

        /* build Diagram */
        ControlFlowGraphDiagram diagram = new ControlFlowGraphDiagram();

        VertexBase r = null;
        for (int i = 0; i < graph.getNodeList().size(); i++) {
            /* get Node */
            node = graph.getNodeList().getNodeExt(i);

            /* create visual Node */
            switch (node.getVertexType()) {
            case INodeType.NODE_TYPE_SIMPLE:
                r = new RectangularVertex();
                break;
            case INodeType.NODE_TYPE_IF:
                r = new DecisionVertex();
                break;
            case INodeType.NODE_TYPE_RETURN:
                r = new ReturnVertex();
                break;
            case INodeType.NODE_TYPE_GOTO_JUMP:
                r = new GotoJumpVertex();
                break;
            case INodeType.NODE_TYPE_SWITCH:
                r = new SwitchVertex();
                break;
            case INodeType.NODE_TYPE_INVOKE:
                r = new InvokeVertex();
                break;
            case INodeType.NODE_TYPE_GET:
                r = new GetVertex();
                break;
            case INodeType.NODE_TYPE_START:
                r = new StartVertex();
                break;
            case INodeType.NODE_TYPE_EXIT:
                r = new ExitVertex();
                break;
            default:
                r = new RectangularVertex();
            }

            r.setSize(new Dimension(node.getWidth(), node.getHeight()));
            r.setLocation(new Point(node.getX(), node.getY()));
            if (node.getVertexType() == INodeType.NODE_TYPE_START
                    || node.getVertexType() == INodeType.NODE_TYPE_EXIT) {
                /* do nothing */
            } else {
                r.setLabel(" " + node.getByteCodeOffset() + "  " + node.getByteCodeString() + " ");
            }

            r.setSize(new Dimension(nodeWeigth, nodeHeight));

            node.setData(r);

            diagram.addChild(r);
        }

        /* create connections */
        createConnections(graph.getEdgeList());

        /* create additions */
        createAdditions(graph, diagram);

        /* layout graph */
        IDirectedGraphExt graph2 = LayoutAlgorithmsUtils.generateGraph(diagram);
        new HierarchicalLayout().visit(graph2);

        INodeListExt listNode = graph2.getNodeList();
        VertexBase vb = null;
        for (int i = 0; i < listNode.size(); i++) {
            node = listNode.getNodeExt(i);
            vb = (VertexBase) node.getData();
            vb.setLocation(new Point(node.getX(), node.getY()));
        }

        return diagram;
    }

    /**
     * Build basic block graph diagram.
     * 
     * @param graph
     * @return diagram
     */
    private static ControlFlowGraphDiagram createBasicBlockDiagram(IDirectedGraphExt basicBlockGraph) {

        boolean createBasicBlockLongDescr = ControlFlowFactoryPlugin.getDefault().getPreferenceStore()
                .getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BASIC_BLOCK_LONG_DESCR);

        /* build Diagram */
        ControlFlowGraphDiagram diagram = new ControlFlowGraphDiagram();

        VertexBase r = null;
        INodeExt node = null;
        for (int i = 0; i < basicBlockGraph.getNodeList().size(); i++) {
            node = basicBlockGraph.getNodeList().getNodeExt(i);

            if (node.getVertexType() == INodeType.NODE_TYPE_START) {
                r = new StartVertex();
                r.setSize(new Dimension(node.getWidth(), node.getHeight()));

            } else if (node.getVertexType() == INodeType.NODE_TYPE_EXIT) {
                r = new ExitVertex();
                r.setSize(new Dimension(node.getWidth(), node.getHeight()));
            } else {
                if (createBasicBlockLongDescr) {
                    StringBuffer buf = new StringBuffer();
                    buf.append(getBasicBlockContext(node));

                    String s = buf.toString();
                    //               BasicBlockVertex bbv = new BasicBlockVertex();
                    RectangularVertex bbv = new RectangularVertex();
                    bbv.setLabel(s);
                    bbv.setToolTip("Basic Block: " + node.getData().toString());

                    StringLine sl = new StringLine(s);
                    //TODO: define capital letter hight = 15 and width = 7
                    bbv.setSize(new Dimension(7 * sl.getMaxLineLenght(), (15 * sl.getNumberOfLines()) + 10));

                    r = bbv;
                    r.setLongDescrUsed(true);
                } else {
                    r = new RectangularVertex();
                    r.setLabel(node.getData().toString());
                    r.setToolTip(getBasicBlockContext(node));
                    r.setSize(new Dimension(node.getWidth(), node.getHeight()));
                }
            }

            r.setLocation(new Point(node.getX(), node.getY()));

            node.setData(r);
            diagram.addChild(r);
        }

        /* create connections */
        createConnections(basicBlockGraph.getEdgeList());

        /* create additions */
        createAdditions(basicBlockGraph, diagram);

        /* layout graph */
        IDirectedGraphExt graph2 = LayoutAlgorithmsUtils.generateGraph(diagram);
        new HierarchicalLayout().visit(graph2);

        INodeListExt listNode = graph2.getNodeList();
        VertexBase vb = null;
        for (int i = 0; i < listNode.size(); i++) {
            node = listNode.getNodeExt(i);
            vb = (VertexBase) node.getData();
            vb.setLocation(new Point(node.getX(), node.getY()));
        }

        return diagram;
    }

    /**
     * Creates source code graph diagram.
     * 
     * @param graph
     * @return diagram
     */
    private static ControlFlowGraphDiagram createSourceCodeGraphDiagram(IDirectedGraphExt graph) {

        boolean createSourcecodeBlockLongDescr = ControlFlowFactoryPlugin.getDefault().getPreferenceStore()
                .getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_SOURSECODE_BLOCK_LONG_DESCR);

        int nodeWeigth = 78;
        int nodeHeight = 36;
        INodeExt node = null;

        /* build Diagram */
        ControlFlowGraphDiagram diagram = new ControlFlowGraphDiagram();

        VertexBase r = null;
        for (int i = 0; i < graph.getNodeList().size(); i++) {
            node = graph.getNodeList().getNodeExt(i);

            StringBuffer buf = new StringBuffer();
            if (createSourcecodeBlockLongDescr) {
                buf.append(node.getToolTipText());
            } else {
                buf.append(String.valueOf(node.getByteCodeOffset()));
            }

            String lb = buf.toString();

            /* create visual Node */
            switch (node.getVertexType()) {
            case INodeType.NODE_TYPE_SIMPLE:
                //            r = new BasicBlockVertex();
                r = new RectangularVertex();

                if (createSourcecodeBlockLongDescr) {
                    //TODO: define capital letter height = 15 and width = 8
                    StringLine sl = new StringLine(lb);
                    nodeWeigth = 7 * sl.getMaxLineLenght() + 20;
                    nodeHeight = 15 * sl.getNumberOfLines() + 10;
                }

                break;
            case INodeType.NODE_TYPE_IF:
                r = new DecisionVertex();
                if (createSourcecodeBlockLongDescr) {
                    //TODO: define capital letter height = 15 and width = 8
                    StringLine sl = new StringLine(lb);
                    nodeWeigth = (7 * sl.getMaxLineLenght()) * 2;
                    nodeHeight = (15 * sl.getNumberOfLines()) * 2;
                }
                break;
            case INodeType.NODE_TYPE_RETURN:
                r = new ReturnVertex();
                if (createSourcecodeBlockLongDescr) {
                    //TODO: define capital letter height = 15 and width = 8
                    StringLine sl = new StringLine(lb);
                    nodeWeigth = 7 * sl.getMaxLineLenght() + 20;
                    nodeHeight = 15 * sl.getNumberOfLines() + 10;
                }

                break;
            case INodeType.NODE_TYPE_GOTO_JUMP:
                r = new GotoJumpVertex();
                break;
            case INodeType.NODE_TYPE_SWITCH:
                r = new SwitchVertex();
                if (createSourcecodeBlockLongDescr) {
                    StringLine sl = new StringLine(lb);
                    //TODO: define capital letter height = 15 and width = 8
                    nodeWeigth = (7 * sl.getMaxLineLenght()) * 2;
                    nodeHeight = (15 * sl.getNumberOfLines()) + 10;
                }
                break;
            case INodeType.NODE_TYPE_INVOKE:
                r = new InvokeVertex();
                break;
            case INodeType.NODE_TYPE_GET:
                r = new GetVertex();
                break;
            case INodeType.NODE_TYPE_START:
                r = new StartVertex();
                break;
            case INodeType.NODE_TYPE_EXIT:
                r = new ExitVertex();
                break;
            case INodeType.NODE_TYPE_COMMENT:
                r = new CommentElement();
                break;
            default:
                r = new RectangularVertex();
            }

            if (node.getVertexType() == INodeType.NODE_TYPE_START
                    || node.getVertexType() == INodeType.NODE_TYPE_EXIT) {
                /* do nothing */
            } else {
                /*
                 * r.setLabel(" " + node.getByteCodeOffset() + "  " +
                 * node.getByteCodeString() + " ");
                 */
                r.setLabel(lb);
                if (createSourcecodeBlockLongDescr) {
                    r.setLongDescrUsed(true);
                    r.setToolTip("Source line: " + node.getByteCodeOffset());
                } else {
                    r.setToolTip(node.getToolTipText());
                }
                r.setSize(new Dimension(nodeWeigth, nodeHeight));
            }

            node.setData(r);
            diagram.addChild(r);
        }

        /* create connections */
        createConnections(graph.getEdgeList());

        /* create additions */
        createAdditions(graph, diagram);

        /* layout graph */
        IDirectedGraphExt graph2 = LayoutAlgorithmsUtils.generateGraph(diagram);
        new HierarchicalLayout().visit(graph2);

        INodeListExt listNode = graph2.getNodeList();
        VertexBase vb = null;
        for (int i = 0; i < listNode.size(); i++) {
            node = listNode.getNodeExt(i);
            vb = (VertexBase) node.getData();
            vb.setLocation(new Point(node.getX(), node.getY()));
        }

        return diagram;
    }

    public static ControlFlowGraphDiagram createControlFlowGraphDiagram(IDirectedGraphExt graph) {
        int nodeWeigth = 78;
        int nodeHeight = 36;
        INodeExt node = null;

        /* build Diagram */
        ControlFlowGraphDiagram diagram = new ControlFlowGraphDiagram();

        VertexBase r = null;
        for (int i = 0; i < graph.getNodeList().size(); i++) {
            node = graph.getNodeList().getNodeExt(i);

            // * create visual Node */
            switch (node.getVertexType()) {
            case INodeType.NODE_TYPE_SIMPLE:
                r = new RectangularVertex();
                break;
            case INodeType.NODE_TYPE_IF:
                r = new DecisionVertex();
                break;
            case INodeType.NODE_TYPE_RETURN:
                r = new ReturnVertex();
                break;
            case INodeType.NODE_TYPE_GOTO_JUMP:
                r = new GotoJumpVertex();
                break;
            case INodeType.NODE_TYPE_SWITCH:
                r = new SwitchVertex();
                break;
            case INodeType.NODE_TYPE_INVOKE:
                r = new InvokeVertex();
                break;
            case INodeType.NODE_TYPE_GET:
                r = new GetVertex();
                break;
            case INodeType.NODE_TYPE_START:
                r = new StartVertex();
                break;
            case INodeType.NODE_TYPE_EXIT:
                r = new ExitVertex();
                break;
            case INodeType.NODE_TYPE_COMMENT:
                r = new CommentElement();
                break;
            default:
                r = new RectangularVertex();
            }

            if (node.getVertexType() == INodeType.NODE_TYPE_START
                    || node.getVertexType() == INodeType.NODE_TYPE_EXIT) {
                /* do nothing */
            } else {

                /*
                 * r.setLabel(" " + node.getByteCodeOffset() + "  " +
                 * node.getByteCodeString() + " ");
                 */
                r.setLabel(String.valueOf(node.getByteCodeString()));
                r.setToolTip(node.getToolTipText());

                // r.setLabel(node.getByteCodeString());

            }

            r.setSize(new Dimension(nodeWeigth, nodeHeight));

            // String t = node.getByteCodeString();
            // if(t != null){
            // StringLine strLine = new StringLine(node.getByteCodeString());
            // r.setSize(new Dimension(6 * strLine.getMaxLineLenght(), 18 *
            // strLine.getNumberOfLines()));
            // }
            // else{
            // r.setSize(new Dimension(nodeWeigth, nodeHeight));
            // }

            node.setData(r);

            diagram.addChild(r);
        }

        /* create connections */
        createConnections(graph.getEdgeList());

        /* create additions */
        createAdditions(graph, diagram);

        /* layout graph */
        IDirectedGraphExt graph2 = LayoutAlgorithmsUtils.generateGraph(diagram);
        new HierarchicalLayout().visit(graph2);

        INodeListExt listNode = graph2.getNodeList();
        VertexBase vb = null;
        for (int i = 0; i < listNode.size(); i++) {
            node = listNode.getNodeExt(i);
            vb = (VertexBase) node.getData();
            vb.setLocation(new Point(node.getX(), node.getY()));
        }

        return diagram;
    }

    /**
     * Creates diagram connections for the given edge list.
     * 
     * @param edges
     */
    private static void createConnections(IEdgeListExt edges) {
        Connection c = null;
        for (int i = 0; i < edges.size(); i++) {
            IEdgeExt edge = edges.getEdgeExt(i);

            c = new Connection((VertexBase) edge.getSource().getData(), (VertexBase) edge.getTarget().getData());

            if (edge.getData() != null) {
                c.setLabel((String) edge.getData());
            }

            if (edge.getSource().getVertexType() == INodeType.NODE_TYPE_EXIT
                    || edge.getSource().getVertexType() == INodeType.NODE_TYPE_START
                    || edge.getTarget().getVertexType() == INodeType.NODE_TYPE_EXIT) {
                c.setLineStyle(Graphics.LINE_DASH);
            } else {
                c.setLineStyle(Graphics.LINE_SOLID);
            }
        }
    }

    private static void createAdditions(IDirectedGraphExt graph, ControlFlowGraphDiagram diagram) {

        Map<String, Object> attr = graph.getUserObject();
        Object name = attr.get(ByteCodeConstants.NAME);
        if (name != null) {
            diagram.setPropertyValue(ByteCodeConstants.NAME, (String) name);
        }

        /* create additions */
        boolean copyLineNumberTable = ControlFlowFactoryPlugin.getDefault().getPreferenceStore()
                .getBoolean(ControlFlowFactoryPreferenceConstants.COPY_LINE_NUMBER_TABLE);

        if (copyLineNumberTable) {
            Object o = attr.get(ByteCodeConstants.LINE_NUMBER_TABLE);
            if (o != null && o instanceof String) {
                String txt = (String) o;
                VertexBase r = new CommentElement();
                r.setLabel(txt);

                StringLine strLine = new StringLine(txt);
                r.setSize(new Dimension(8 * strLine.getMaxLineLenght() + 10, 12 * strLine.getNumberOfLines() + 20));
                diagram.addChild(r);
            }
        }
    }

    private static String getBasicBlockContext(INodeExt node) {
        if (node instanceof IBasicBlock) {
            StringBuffer buf = new StringBuffer();
            buf.append(" ");
            buf.append(node.getData().toString());
            buf.append(" := {");
            IBasicBlock bb = null;
            INodeListExt basicblockVertices = null;
            bb = (IBasicBlock) node;
            basicblockVertices = bb.getBasicBlockVertices();
            for (int j = 0; j < basicblockVertices.size(); j++) {
                INodeExt b = basicblockVertices.getNodeExt(j);
                buf.append("\n  ");
                buf.append(b.getByteCodeOffset());
                buf.append("  ");
                buf.append(b.getByteCodeString());
                if (b.getLongDescr() != null) {
                    buf.append("\n");
                    buf.append(b.getLongDescr());
                }
            }
            buf.append("\n }");
            return buf.toString();
        } else {
            return node.getData().toString();
        }
    }

    /**
     * Return the input stream for the given class. The result may be null, if
     * the class has not been compiled.
     * 
     * @param type
     * @return input stream
     * @throws CoreException
     * @throws IOException
     */
    private static InputStream getInputStream(IType type) throws CoreException, IOException {

        if (type.isBinary()) {
            IClassFile classFile = type.getClassFile();
            byte[] bytes = classFile.getBytes();
            return new ByteArrayInputStream(bytes);
        } else {
            String[] classpath = JavaRuntime.computeDefaultRuntimeClassPath(type.getJavaProject());
            String packageName = type.getPackageFragment().getElementName();

            // if(type.isAnonymous()){
            // Messages.info("Generate graph",
            // "Cannot generate graph for anonymous source class '"+
            // type.getTypeQualifiedName()
            // +"', because the name is unknown. The comiler generates the name automatically by inserting a $ with a constant for example $1, $2 ...");
            // return null;
            // }

            String name = type.getTypeQualifiedName();

            return JavaLangUtils.findResource(classpath, packageName, name);
        }
    }

    /**
     * Generates graphs for the given type.
     * 
     * @param shell
     * @param folder
     * @param type
     * @param graphType
     * @param createMonitor
     * @return Result: OK, YES_TO_ALL, NO_TO_ALL, ERROR, CANCELED
     * @throws CoreException
     * @throws InvocationTargetException
     * @throws InterruptedException
     * @throws IOException
     */
    public static Result builAndSavedControlFlowDiagrams(final Shell shell, final IFolder folder, final IType type,
            final IGraphSpecification spec, boolean createMonitor)
            throws CoreException, InvocationTargetException, InterruptedException, IOException {
        final InputStream in = getInputStream(type);

        if (in == null) {
            String msg = MessageFormat.format(ControlFlowFactoryMessages.ClassFileInputNotCreated,
                    new Object[] { type.getElementName() });
            ControlFlowFactoryPlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, msg));
            return Result.ERROR;
        }

        Result res = null;

        if (createMonitor) {
            ProgressMonitorDialog monitor = new ProgressMonitorDialog(shell);
            monitor.run(false, true, new WorkspaceModifyOperation() {

                /*
                 * (non-Javadoc)
                 * 
                 * @see
                 * org.eclipse.ui.actions.WorkspaceModifyOperation#execute(org
                 * .eclipse.core.runtime.IProgressMonitor)
                 */
                @Override
                protected void execute(IProgressMonitor monitor)
                        throws CoreException, InvocationTargetException, InterruptedException {

                    final int ticks = type.getMethods().length;
                    monitor.beginTask(ControlFlowFactoryMessages.ProgressDialogCreateGraphs, ticks);
                    try {
                        generateControlFlowGraphs(monitor, folder, getElementName(type), in, spec);
                    } catch (IOException e) {
                        ControlFlowFactoryPlugin.getDefault().getLog().log(
                                new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, e.getMessage(), e));
                        if (!spec.isSupressMessages()) {
                            Messages.error(e.getMessage() + CoreMessages.ExceptionAdditionalMessage);
                        }
                        return;
                    } catch (ControlFlowGraphException e) {
                        ControlFlowFactoryPlugin.getDefault().getLog().log(
                                new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, e.getMessage(), e));
                        if (!spec.isSupressMessages()) {
                            Messages.error(e.getMessage() + CoreMessages.ExceptionAdditionalMessage);
                        }
                        return;
                    } finally {
                        monitor.done();
                    }
                }
            });
        } else {
            try {
                res = generateControlFlowGraphs(null, folder, getElementName(type), in, spec);
            } catch (ControlFlowGraphException e) {
                ControlFlowFactoryPlugin.getDefault().getLog()
                        .log(new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, e.getMessage(), e));
                if (!spec.isSupressMessages()) {
                    Messages.error(e.getMessage() + CoreMessages.ExceptionAdditionalMessage);
                }

                return Result.ERROR;
            }
        }

        return res;
    }

    /**
     * Return element name for the given type.
     * 
     * @param type
     * @return name
     * @throws JavaModelException
     */
    private static String getElementName(IType type) throws JavaModelException {
        String name = type.getFullyQualifiedName();
        int index = name.lastIndexOf('.');
        name = name.substring(++index);
        return name;
    }

    /**
     * Starts process.
     * 
     * @param monitor
     * @param folder
     * @param elementName
     * @param in
     * @param graphType
     * @param exportDecorations 
     * @param exportGeometry 
     * @param exportComments 
     * @return result: OK, YES_TO_ALL, NO_TO_ALL, ERROR
     * @throws IOException
     * @throws ControlFlowGraphException
     */
    private static Result generateControlFlowGraphs(IProgressMonitor monitor, final IFolder folder,
            final String elementName, final InputStream in, IGraphSpecification spec)
            throws IOException, ControlFlowGraphException {

        boolean yes_To_All = false;
        if (spec.isOverwriteAll()) {
            yes_To_All = true;
        }

        AllCodeVisitor codeVisitor = ControlFlowGraphGenerator.getClassFileVisitor(in);
        for (Map<String, Object> attr : codeVisitor.getInstructionLists()) {

            if (monitor != null && monitor.isCanceled()) {
                return Result.CANCELED;
            }

            String name = (String) attr.get(ByteCodeConstants.NAME);
            String signature = (String) attr.get(ByteCodeConstants.DESCRIPTOR);

            if (monitor != null)
                monitor.subTask(name);

            List<AbstractInstruction> instructions = (List<AbstractInstruction>) attr.get(ByteCodeConstants.CODE);

            /* get preferences */
            IPreferenceStore store = ControlFlowFactoryPlugin.getDefault().getPreferenceStore();
            boolean createStartNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_START_NODE);
            boolean createExitNode = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_EXIT_NODE);
            boolean createBackEdge = store.getBoolean(ControlFlowFactoryPreferenceConstants.GENERATE_BACK_EDGE);

            IDirectedGraphExt cfg = null;
            ControlFlowGraphDiagram diagram = null;
            LineNumberTableEntry[] lineNumberTable = null;
            Object o;
            switch (spec.getGraphType()) {
            case GraphConstants.GRAPH_TYPE_BYTECODE_GRAPH:

                o = attr.get(ByteCodeConstants.LINE_NUMBER_TABLE);

                if (o != null) {
                    lineNumberTable = (LineNumberTableEntry[]) o;
                }

                cfg = ControlFlowGraphGenerator.generateControlFlowGraph(instructions, lineNumberTable,
                        createStartNode, createExitNode, createBackEdge);

                if (cfg == null) {
                    // Messages.error(ControlFlowFactoryMessages.DiagramIsNullMessage);
                    // return Result.ERROR;
                    throw new ControlFlowGraphException(ControlFlowFactoryMessages.DiagramIsNullMessage);
                }

                diagram = createControlFlowDiagram(cfg);
                break;
            case GraphConstants.GRAPH_TYPE_BASICBLOCK_GRAPH:
                o = attr.get(ByteCodeConstants.LINE_NUMBER_TABLE);

                if (o != null) {
                    lineNumberTable = (LineNumberTableEntry[]) o;
                }

                cfg = ControlFlowGraphGenerator.generateBasicBlockGraph(instructions, lineNumberTable,
                        createStartNode, createExitNode, createBackEdge);

                if (cfg == null) {
                    // Messages.error(ControlFlowFactoryMessages.DiagramIsNullMessage);
                    // return Result.ERROR;
                    throw new ControlFlowGraphException(ControlFlowFactoryMessages.DiagramIsNullMessage);
                }

                diagram = createBasicBlockDiagram(cfg);
                break;
            case GraphConstants.GRAPH_TYPE_SOURCE_GRAPH:

                o = attr.get(ByteCodeConstants.LINE_NUMBER_TABLE);

                if (o == null) {
                    // Messages.error(ControlFlowFactoryMessages.ERROR_LineNumberTable_is_Missing
                    // + name + signature);
                    // return Result.ERROR;
                    throw new ControlFlowGraphException(
                            ControlFlowFactoryMessages.ERROR_LineNumberTable_is_Missing + name + signature);
                }

                lineNumberTable = (LineNumberTableEntry[]) o;
                cfg = ControlFlowGraphGenerator.generateSourceCodeGraph(instructions, lineNumberTable,
                        createStartNode, createExitNode, createBackEdge);

                if (cfg == null) {
                    // Messages.error(ControlFlowFactoryMessages.DiagramIsNullMessage);
                    // return Result.ERROR;
                    throw new ControlFlowGraphException(ControlFlowFactoryMessages.DiagramIsNullMessage);
                }

                diagram = createSourceCodeGraphDiagram(cfg);
                break;
            default:
                throw new IllegalStateException("Unexpected graph type '" + spec.getGraphType() + "'");
            }

            if (diagram == null) {
                // Messages.error(ControlFlowFactoryMessages.DiagramIsNullMessage);
                // return Result.ERROR;
                throw new ControlFlowGraphException(ControlFlowFactoryMessages.DiagramIsNullMessage);
            }

            if (name.equals(ByteCodeConstants.INIT)) {
                name = "init"; //$NON-NLS-1$
            }

            if (name.equals(ByteCodeConstants.CLINIT)) {
                name = "clinit"; //$NON-NLS-1$
            }

            /* set name property */
            diagram.setPropertyValue(ByteCodeConstants.NAME, elementName + "." + name + signature);

            String fileName = elementName + "." + name + signature.replace('/', '.') + "."
                    + GraphConstants.graphTypeSuffixes[spec.getGraphType()];
            IPath pathToFile = folder.getFullPath().append(fileName).addFileExtension(FileExtensions.GRAPH);

            try {
                Result r;

                switch (spec.getExportFormat()) {
                case GraphConstants.EXPORT_FORMAT_DRGARBAGE_GRAPH:
                    final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToFile);
                    r = saveDiagram(file, diagram, monitor, yes_To_All);
                    break;
                default:

                    AbstractExport2 exporter = null;

                    switch (spec.getExportFormat()) {
                    case GraphConstants.EXPORT_FORMAT_DOT:
                        exporter = new GraphDOTExport();
                        pathToFile = pathToFile.addFileExtension(FileExtensions.DOT);
                        break;
                    case GraphConstants.EXPORT_FORMAT_GRAPHXML:
                        exporter = new GraphXMLExport();
                        pathToFile = pathToFile.addFileExtension(FileExtensions.XML);
                        break;
                    case GraphConstants.EXPORT_FORMAT_GRAPHML:
                        exporter = new GraphMlExport();
                        pathToFile = pathToFile.addFileExtension(FileExtensions.GRAPHML);
                        break;
                    default:
                        throw new IllegalStateException("Unexpected export format.");
                    }

                    exporter.setGraphSpecification(spec);
                    StringWriter sb = new StringWriter();
                    try {
                        exporter.write(diagram, sb);
                    } catch (ExportException e) {
                        /*
                         * This will never happen as StringWriter.append(*)
                         * does not throw IOException
                         */
                        throw new RuntimeException(e);
                    }

                    final IFile file2 = ResourcesPlugin.getWorkspace().getRoot().getFile(pathToFile);
                    r = saveContentToFile(file2, sb.toString(), monitor, yes_To_All);
                }

                if (r == Result.NO) {
                    continue;
                } else if (r == Result.NO_TO_ALL) {
                    return Result.NO_TO_ALL;
                } else if (r == Result.YES_TO_ALL) {
                    yes_To_All = true;
                } else if (r == Result.CANCELED) {
                    return Result.CANCELED;
                }

            } catch (CoreException e) {
                ControlFlowFactoryPlugin.getDefault().getLog()
                        .log(new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, e.getMessage(), e));
                // Messages.error(e.getMessage() +
                // CoreMessages.ExceptionAdditionalMessage);
                return Result.ERROR;
            }

        }

        if (yes_To_All) {
            return Result.YES_TO_ALL;
        }

        return Result.OK;
    }

    private static Result saveDiagram(IFile file, ControlFlowGraphDiagram diagram, IProgressMonitor monitor,
            boolean yes_To_All) throws IOException, CoreException {

        /* save graph */
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        ObjectOutputStream oos = new ObjectOutputStream(out);
        oos.writeObject(diagram);
        oos.close();

        /* delete if exists */
        if (file.exists()) {
            if (!yes_To_All) {
                String msg = MessageFormat.format(ControlFlowFactoryMessages.EXPORT_FILE_OVERWRITE_MESSAGE_2,
                        new Object[] { file.getName() });

                int res = openConfirm(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                        ControlFlowFactoryMessages.EXPORT_FILE_OVERWRITE_TITLE, msg);
                if (res == 0) { /* YES */
                    file.delete(false, monitor);
                } else if (res == 1) { /* YES_TO_ALL */
                    yes_To_All = true;
                    file.delete(false, monitor);
                } else if (res == 2) { /* NO */
                    if (monitor != null)
                        monitor.worked(1);
                    return Result.NO;
                } else if (res == 3) { /* NO_TO_ALL */
                    return Result.NO_TO_ALL;
                }
            } else {
                file.delete(false, monitor);
            }

        }

        try {
            file.create(new ByteArrayInputStream(out.toByteArray()), /* contents */
                    true, /* keep saving, even if IFile is out of sync with the Workspace */
                    monitor); /* progress monitor */

        } catch (CoreException ce) {
            ControlFlowFactoryPlugin.getDefault().getLog()
                    .log(new Status(IStatus.ERROR, ControlFlowFactoryPlugin.PLUGIN_ID, ce.getMessage(), ce));

            String msg = MessageFormat.format(ControlFlowFactoryMessages.EXPORT_FILE_COULD_NOT_WRITE,
                    new Object[] { file.getName() });

            int res = openStop(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                    "File could not be written", msg);

            if (res == 1) { /* YES */
                return Result.CANCELED;
            }
        }

        if (monitor != null)
            monitor.worked(1);

        if (yes_To_All) {
            return Result.YES_TO_ALL;
        }

        return Result.OK;
    }

    private static Result saveContentToFile(IFile file, String content, IProgressMonitor monitor,
            boolean yes_To_All) throws IOException, CoreException {

        /* delete if exists */
        if (file.exists()) {
            if (!yes_To_All) {
                String msg = MessageFormat.format(ControlFlowFactoryMessages.EXPORT_FILE_OVERWRITE_MESSAGE_2,
                        new Object[] { file.getName() });

                int res = openConfirm(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(),
                        ControlFlowFactoryMessages.EXPORT_FILE_OVERWRITE_TITLE, msg);
                if (res == 0) { /* YES */
                    file.delete(false, monitor);
                } else if (res == 1) { /* YES_TO_ALL */
                    yes_To_All = true;
                    file.delete(false, monitor);
                } else if (res == 2) { /* NO */
                    if (monitor != null)
                        monitor.worked(1);
                    return Result.NO;
                } else if (res == 3) { /* NO_TO_ALL */
                    return Result.NO_TO_ALL;
                }
            } else {
                file.delete(false, monitor);
            }

        }

        file.create(new ByteArrayInputStream(content.getBytes()), /* contents */
                true, /* keep saving, even if IFile is out of sync with the Workspace */
                monitor); /* progress monitor */

        if (monitor != null)
            monitor.worked(1);

        if (yes_To_All) {
            return Result.YES_TO_ALL;
        }

        return Result.OK;

    }

    public static int openConfirm(Shell parent, String title, String message) {
        MessageDialog dialog = new MessageDialog(parent, title, CoreImg.aboutDrGarbageIcon_16x16.createImage(),
                message, MessageDialog.QUESTION,
                new String[] { IDialogConstants.YES_LABEL, IDialogConstants.YES_TO_ALL_LABEL,
                        IDialogConstants.NO_LABEL, IDialogConstants.NO_TO_ALL_LABEL },
                3); /*
                    * OK is the
                    * default
                    */
        return dialog.open();
    }

    public static int openStop(Shell parent, String title, String message) {
        MessageDialog dialog = new MessageDialog(parent, title, CoreImg.aboutDrGarbageIcon_16x16.createImage(),
                message, MessageDialog.QUESTION,
                new String[] { IDialogConstants.NO_LABEL, IDialogConstants.YES_LABEL }, 1); /*
                                                                                            * YES is the
                                                                                            * default
                                                                                            */
        return dialog.open();
    }

    public static VertexBase clone(VertexBase vb) {
        VertexBase vb2 = null;

        if (vb instanceof CommentElement) {
            vb2 = new CommentElement();
        } else if (vb instanceof DecisionVertex) {
            vb2 = new DecisionVertex();
        } else if (vb instanceof GetVertex) {
            vb2 = new GetVertex();
        } else if (vb instanceof GotoJumpVertex) {
            vb2 = new GotoJumpVertex();
        } else if (vb instanceof InvokeVertex) {
            vb2 = new InvokeVertex();
        } else if (vb instanceof RectangularVertex) {
            vb2 = new RectangularVertex();
        } else if (vb instanceof ReturnVertex) {
            vb2 = new ReturnVertex();
        } else if (vb instanceof StartVertex) {
            vb2 = new StartVertex();
        } else if (vb instanceof ExitVertex) {
            vb2 = new ExitVertex();
        } else if (vb instanceof SwitchVertex) {
            vb2 = new SwitchVertex();
        }

        if (vb2 == null) {
            return null;
        }

        vb2.setLabel(vb.getLabel());
        vb2.setSize(vb.getSize());

        Point p = new Point();
        p.x = vb.getLocation().x + 10;
        p.y = vb.getLocation().y + 10;
        vb2.setLocation(p);

        return vb2;
    }

}