org.fireflow.webdesigner.transformer.AbstractFpdlDiagramSerializer.java Source code

Java tutorial

Introduction

Here is the source code for org.fireflow.webdesigner.transformer.AbstractFpdlDiagramSerializer.java

Source

/**
 * Copyright 2007-2010 ?
 * All rights reserved. 
 * 
 * This library is free software; you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License v3 as published by the Free Software
 * Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along
 * with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
 *
 */
package org.fireflow.webdesigner.transformer;

import java.awt.Dimension;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fireflow.model.ModelElement;
import org.fireflow.model.binding.ServiceBinding;
import org.fireflow.model.io.SerializerException;
import org.fireflow.model.servicedef.ServiceDef;
import org.fireflow.pdl.fpdl.diagram.ActivityShape;
import org.fireflow.pdl.fpdl.diagram.CommentShape;
import org.fireflow.pdl.fpdl.diagram.Diagram;
import org.fireflow.pdl.fpdl.diagram.DiagramElement;
import org.fireflow.pdl.fpdl.diagram.EndNodeShape;
import org.fireflow.pdl.fpdl.diagram.GroupShape;
import org.fireflow.pdl.fpdl.diagram.LaneShape;
import org.fireflow.pdl.fpdl.diagram.NodeShape;
import org.fireflow.pdl.fpdl.diagram.PoolShape;
import org.fireflow.pdl.fpdl.diagram.ProcessNodeShape;
import org.fireflow.pdl.fpdl.diagram.RouterShape;
import org.fireflow.pdl.fpdl.diagram.StartNodeShape;
import org.fireflow.pdl.fpdl.diagram.figure.Figure;
import org.fireflow.pdl.fpdl.diagram.figure.part.Bounds;
import org.fireflow.pdl.fpdl.diagram.figure.part.BoundsImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.Point;
import org.fireflow.pdl.fpdl.io.FPDLNames;
import org.fireflow.pdl.fpdl.process.Activity;
import org.fireflow.pdl.fpdl.process.EndNode;
import org.fireflow.pdl.fpdl.process.Router;
import org.fireflow.pdl.fpdl.process.StartNode;
import org.fireflow.pdl.fpdl.process.Synchronizer;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.fireflow.pdl.fpdl.process.features.Feature;
import org.fireflow.pdl.fpdl.process.features.endnode.NormalEndFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowCompensationFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowFaultFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowTerminationFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.AndJoinAndSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.CustomizedRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.DefaultRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.OrJoinOrSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.XOrJoinXOrSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.CatchCompensationFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.CatchFaultFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.TimerStartFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.WebserviceStartFeature;
import org.w3c.dom.Document;

/**
 *
 * @author ? nychen2000@163.com
 * Fire Workflow www.firesoa.com  www.fireflow.org
 *
 */
public abstract class AbstractFpdlDiagramSerializer implements FpdlDiagramSerializer {
    private Log log = LogFactory.getLog(AbstractFpdlDiagramSerializer.class);

    protected static DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    protected static final int IconTextGap = 5;
    protected static final int IMG_RADIUS = 16;
    protected static final int SVC_LOGO_RADIUS = 8;
    protected static final int DEFAULT_FONT_SIZE = 12;
    protected static final int GROUP_TITLE_HEIGHT = 20;
    protected static final int POOL_LANE_TITLE_HEIGHT = 32;
    protected static final String TYPE = "element_" + FPDLNames.TYPE;
    protected static final String ON_CLICK_HANDLER = "on_element_click";

    protected static final String DEFAULT_DOT_DASHARRAY = "1 2";
    protected static final String DEFAULT_DASH_DASHARRAY = "5 4";
    protected static final String DEFAULT_DOTDASH_DASHARRAY = "2 4 5 4";

    protected static final String DEFAULT_GROUP_DASHARRAY = "3 2";
    protected static final String DEFAULT_ASSOC_DASHARRAY = DEFAULT_DASH_DASHARRAY;
    protected static final String DEFAULT_MESSAGEFLOW_DASHARRAY = DEFAULT_DASH_DASHARRAY;

    protected static final float PT_2_PX_RATE = 1.8f;

    protected static final Map<String, String> SERVICE_LOGO_CACHE = new HashMap<String, String>();

    protected WorkflowProcess workflowProcess = null;
    protected String subProcessName = null;

    protected Document document = null;
    protected Diagram diagram = null;
    protected int leftTopX = 0;//x
    protected int leftTopY = 0;//y
    protected int rightDownX = 0;//?x
    protected int rightDownY = 0;//?y

    protected String resourcePathPrefix = null;

    protected void _refreshDiagramSize(Bounds bounds) {
        if (bounds.getX() < this.leftTopX) {
            this.leftTopX = bounds.getX();
        }

        if (bounds.getY() < this.leftTopY) {
            this.leftTopY = bounds.getY();
        }

        int x = bounds.getX() + bounds.getWidth();
        int y = bounds.getY() + bounds.getHeight();

        if (x > this.rightDownX) {
            this.rightDownX = x;
        }
        if (y > this.rightDownY) {
            this.rightDownY = y;
        }

    }

    protected void _refreshDiagramSize(List<Point> pointList) {
        if (pointList == null || pointList.size() == 0) {
            for (Point p : pointList) {
                if (p.getX() < this.leftTopX) {
                    this.leftTopX = p.getX();
                }

                if (p.getX() > this.rightDownX) {
                    this.rightDownX = p.getX();
                }

                if (p.getY() < this.leftTopY) {
                    this.leftTopY = p.getY();
                }

                if (p.getY() > this.rightDownY) {
                    this.rightDownY = p.getY();
                }
            }
        }
    }

    protected Point _calculateAnchor(NodeShape nodeShape, Bounds nodeBounds, Point refPoint) {

        Point boundsCenter = new Point();
        boundsCenter.setX(nodeBounds.getX() + nodeBounds.getWidth() / 2);
        boundsCenter.setY(nodeBounds.getY() + nodeBounds.getHeight() / 2);

        if (nodeShape instanceof StartNodeShape || nodeShape instanceof EndNodeShape) {
            Point anchor = _calculateStartNodeEndNodeAnchor(nodeBounds, boundsCenter, refPoint);
            return anchor;
        }
        if (nodeShape instanceof ActivityShape || nodeShape instanceof CommentShape
                || nodeShape instanceof PoolShape || nodeShape instanceof LaneShape) {
            Point anchor = _calculateChopboxAnchor(nodeBounds, boundsCenter, refPoint);
            return anchor;
        } else if (nodeShape instanceof RouterShape) {
            Point anchor = _calculateRouterAnchor(nodeBounds, boundsCenter, refPoint);
            return anchor;
        }

        //bounds
        return boundsCenter;
    }

    protected Point _calculateRouterAnchor(Bounds r, Point center, Point reference) {

        float centerX = center.getX();
        float centerY = center.getY();

        if (r.getWidth() <= 0 || r.getHeight() <= 0
                || (reference.getX() == (int) centerX && reference.getY() == (int) centerY))
            return new Point((int) centerX, (int) centerY); // This avoids
        // divide-by-zero

        //
        Point ref = new Point();
        ref.setX(reference.getX() - center.getX());
        ref.setY(reference.getY() - center.getY());
        if (Math.abs(ref.getX()) <= 1)//?1?
            return new Point(reference.getX(), (ref.getY() > 0) ? r.getY() + r.getHeight() : r.getY());
        if (Math.abs(ref.getY()) <= 1)//?1?
            return new Point((ref.getX() > 0) ? r.getX() + r.getWidth() : r.getX(), reference.getY());

        float dx = reference.getX() - centerX;
        float dy = reference.getY() - centerY;

        if (dy == 0) {
            if (dx > 0) {//right
                Point result = new Point();
                result.setX(r.getX() + r.getWidth());
                result.setY(r.getY() + r.getHeight() / 2);
                return result;
            } else {//left
                Point result = new Point();
                result.setX(r.getX());
                result.setY(r.getY() + r.getHeight() / 2);
                return result;
            }
        }
        if (dx == 0) {
            if (dy > 0) {//bottom
                Point result = new Point();
                result.setX(r.getX() + r.getWidth() / 2);
                result.setY(r.getY() + r.getHeight());
                return result;
            } else {
                Point result = new Point();
                result.setX(r.getX() + r.getWidth() / 2);
                result.setY(r.getY());
                return result;
            }
        }

        float scale = Math.abs(dx / dy);
        float ddy = 0.5f * r.getWidth() / (scale + 1);
        float ddx = Math.abs(scale * ddy);

        if (dx >= 0 && dy >= 0) {
            Point result = new Point();
            result.setX((int) (centerX + ddx));
            result.setY((int) (centerY + ddy));
            return result;
        } else if (dx <= 0 && dy <= 0) {
            Point result = new Point();
            result.setX((int) (centerX - ddx));
            result.setY((int) (centerY - ddy));

            return result;
        } else if (dx >= 0 && dy <= 0) {
            Point result = new Point();
            result.setX((int) (centerX + ddx));
            result.setY((int) (centerY - ddy));
            return result;
        } else {
            Point result = new Point();
            result.setX((int) (centerX - ddx));
            result.setY((int) (centerY + ddy));

            return result;
        }
    }

    protected Point _getLabelAbsolutePosition(Point fromAnchor, Point toAnchor, List<Point> linePoints,
            Point relativePos) {
        Point result = new Point();
        Point centerP = null;
        if (linePoints != null && linePoints.size() > 0) {
            if ((linePoints.size() % 2) == 1) {
                int index = (linePoints.size() - 1) / 2;
                centerP = linePoints.get(index);
            } else {
                int index = (linePoints.size()) / 2;
                Point p1 = linePoints.get(index - 1);
                Point p2 = linePoints.get(index);
                centerP = new Point();
                centerP.setX((p1.getX() + p2.getX()) / 2);
                centerP.setY((p1.getY() + p2.getY()) / 2);

            }

        } else {
            centerP = new Point();
            centerP.setX((fromAnchor.getX() + toAnchor.getX()) / 2);
            centerP.setY((fromAnchor.getY() + toAnchor.getY()) / 2);
        }

        result.setX(centerP.getX() + relativePos.getX());
        result.setY(centerP.getY() + relativePos.getY());
        return result;
    }

    protected Point _calculateChopboxAnchor(Bounds r, Point center, Point reference) {
        r.setX(r.getX() - 1);
        r.setY(r.getY() - 1);
        r.setWidth(r.getWidth() + 1);
        r.setHeight(r.getHeight() + 1);

        float centerX = center.getX();
        float centerY = center.getY();

        if (r.getWidth() <= 0 || r.getHeight() <= 0
                || (reference.getX() == (int) centerX && reference.getY() == (int) centerY))
            return new Point((int) centerX, (int) centerY); // This avoids

        //
        Point ref = new Point();
        ref.setX(reference.getX() - center.getX());
        ref.setY(reference.getY() - center.getY());
        if (Math.abs(ref.getX()) <= 1)//?1?
            return new Point(reference.getX(), (ref.getY() > 0) ? r.getY() + r.getHeight() : r.getY());
        if (Math.abs(ref.getY()) <= 1)//?1?
            return new Point((ref.getX() > 0) ? r.getX() + r.getWidth() : r.getX(), reference.getY());

        // divide-by-zero
        float dx = reference.getX() - centerX;
        float dy = reference.getY() - centerY;

        // r.width, r.height, dx, and dy are guaranteed to be non-zero.
        float scale = 0.5f / Math.max(Math.abs(dx) / r.getWidth(), Math.abs(dy) / r.getHeight());

        dx *= scale;
        dy *= scale;
        centerX += dx;
        centerY += dy;

        return new Point(Math.round(centerX), Math.round(centerY));
    }

    protected Point _calculateStartNodeEndNodeAnchor(Bounds r, Point center, Point reference) {
        Point ref = new Point();
        ref.setX(reference.getX() - center.getX());
        ref.setY(reference.getY() - center.getY());

        //Point ref = r.getCenter().negate().translate(reference);

        if (Math.abs(ref.getX()) <= 1)//?1?
            return new Point(reference.getX(), (ref.getY() > 0) ? r.getY() + r.getHeight() : r.getY());
        if (Math.abs(ref.getY()) <= 1)//?1?
            return new Point((ref.getX() > 0) ? r.getX() + r.getWidth() : r.getX(), reference.getY());

        float dx = (ref.getX() > 0) ? 0.5f : -0.5f;
        float dy = (ref.getY() > 0) ? 0.5f : -0.5f;

        // ref.x, ref.y, r.width, r.height != 0 => safe to proceed

        float k = (float) (ref.getY() * r.getWidth()) / (ref.getX() * r.getHeight());
        k = k * k;

        int ddx = (int) (r.getWidth() * dx / Math.sqrt(1 + k));
        int ddy = (int) (r.getHeight() * dy / Math.sqrt(1 + 1 / k));

        Point result = new Point();
        result.setX(center.getX() + ddx);
        result.setY(center.getY() + ddy);
        return result;
    }

    protected Bounds _getAbsoluteBounds(DiagramElement diagramElm) {
        //TODO Activity?
        //TODO ???
        Bounds result = null;
        Bounds original = null;
        if (diagramElm instanceof LaneShape) {
            LaneShape argLane = (LaneShape) diagramElm;
            original = new BoundsImpl();
            original.setX(0);
            original.setY(0);
            original.setWidth(0);
            original.setHeight(0);

            PoolShape poolShape = (PoolShape) diagramElm.getParent();
            List<DiagramElement> allLanes = poolShape.getChildren();

            for (DiagramElement tmpElm : allLanes) {
                LaneShape lane = (LaneShape) tmpElm;
                Bounds tmpBounds = lane.getFigure().getBounds();
                if (argLane.equals(lane)) {
                    original.setWidth(tmpBounds.getWidth() - tmpBounds.getThick() * 2);
                    original.setHeight(tmpBounds.getHeight() - tmpBounds.getThick() * 2);
                    break;
                } else {
                    if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                        original.setX(original.getX() + tmpBounds.getWidth());
                    } else {
                        original.setY(original.getY() + tmpBounds.getHeight());
                    }
                }
            }
            result = original;
        } else if (diagramElm instanceof StartNodeShape || diagramElm instanceof EndNodeShape
                || diagramElm instanceof RouterShape) {
            original = diagramElm.getFigure() == null ? null : diagramElm.getFigure().getBounds();

            if (original == null) {
                log.warn("NodeShape[id=" + diagramElm.getId()
                        + "]bounds?bounds?????");
                return null;
            }
            result = original.copy();
        } else {
            original = diagramElm.getFigure() == null ? null : diagramElm.getFigure().getBounds();

            if (original == null) {
                log.warn("NodeShape[id=" + diagramElm.getId()
                        + "]bounds?bounds?????");
                return null;
            }
            result = original.copy();

            result.setX(result.getX() + result.getThick());
            result.setY(result.getY() + result.getThick());
            result.setWidth(result.getWidth() - result.getThick() * 2);
            result.setHeight(result.getHeight() - result.getThick() * 2);
        }

        DiagramElement parent = diagramElm.getParent();
        if (parent == null) {
            return result;
        } else {

            Bounds parentBounds = _getAbsoluteBounds(parent);
            if (parentBounds != null) {

                if (parent instanceof GroupShape) {
                    result.setX(parentBounds.getX() + result.getX());
                    result.setY(
                            parentBounds.getY() + result.getY() + (GROUP_TITLE_HEIGHT - parentBounds.getThick()));

                } else if ((parent instanceof LaneShape) || (parent instanceof PoolShape)) {
                    if (Diagram.VERTICAL.equals(diagram.getDirection())) {
                        result.setX(parentBounds.getX() + result.getX());
                        result.setY(parentBounds.getY() + result.getY()
                                + (POOL_LANE_TITLE_HEIGHT - parentBounds.getThick()));
                    } else {
                        result.setX(parentBounds.getX() + result.getX()
                                + (POOL_LANE_TITLE_HEIGHT - parentBounds.getThick()));
                        result.setY(parentBounds.getY() + result.getY());
                    }
                } else if (parent instanceof ActivityShape) {//
                    ActivityShape actShape = (ActivityShape) parent;

                    Bounds actBounds = actShape.getFigure().getBounds();
                    result.setX((parentBounds.getX() - parentBounds.getThick()) + result.getX());

                    result.setY(parentBounds.getY() + (actBounds.getHeight() - parentBounds.getThick() - IMG_RADIUS)
                            + result.getY());
                } else {
                    result.setX(parentBounds.getX() + result.getX());
                    result.setY(parentBounds.getY() + result.getY());
                }
            }

        }

        return result;
    }

    protected String _getSynchronizerNodeImgUri(ProcessNodeShape nodeShape) {
        ModelElement modelElm = nodeShape.getWorkflowElementRef();
        Synchronizer node = (Synchronizer) modelElm;
        Feature f = node.getFeature();

        String uri = null;
        //
        if (node instanceof StartNode) {
            if (f == null) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/empty_start_event.png";
            } else if (f instanceof TimerStartFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/timer_start_event.png";
            } else if (f instanceof WebserviceStartFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/message_start_event.png";
            }

            else if ((f instanceof CatchFaultFeature)) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/error_start_event.png";
            } else if (f instanceof CatchCompensationFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/compensation_start_event.png";
            }

            else {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/empty_start_event.png";
            }
        } else if (node instanceof EndNode) {
            if (f == null) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
            } else if (f instanceof NormalEndFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
            } else if (f instanceof ThrowFaultFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_error_event.png";
            } else if (f instanceof ThrowCompensationFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_compensation_event.png";

            } else if (f instanceof ThrowTerminationFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_terminate_event.png";
            } else {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
            }
        } else if (node instanceof Router) {
            if (f == null) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";

            } else if (f instanceof AndJoinAndSplitRouterFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/parallel_gateway.png";
            } else if (f instanceof OrJoinOrSplitRouterFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/inclusive_gateway.png";
            } else if (f instanceof XOrJoinXOrSplitRouterFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/exclusive_gateway_2.jpg";
            } else if (f instanceof CustomizedRouterFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/complex_gateway.png";
            } else if (f instanceof DefaultRouterFeature) {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";
            } else {
                uri = "/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";
            }

        }

        return uri;
    }

    /**
     * fontSize??pt
     * @param text
     * @param fontSize
     * @return
     */
    protected Dimension _calculateFontSize(String text, int fontSize) {
        if (text == null || text.equals("")) {
            return new Dimension(0, 0);
        } else {
            int length = text.length();
            return new Dimension((int) (fontSize * PT_2_PX_RATE * length), (int) (fontSize * PT_2_PX_RATE));
        }
    }

    /**
     * ?diagram element<group>?view port
     * @param diagramElm
     * @return
     */
    protected Bounds _getViewPortBounds(DiagramElement diagramElm) {
        Figure figure = diagramElm.getFigure();
        ModelElement wfElm = diagramElm.getWorkflowElementRef();
        int fontSize = DEFAULT_FONT_SIZE;
        if (figure.getTitleLabel() != null) {
            fontSize = figure.getTitleLabel().getFontSize();
        }
        if (wfElm instanceof StartNode || wfElm instanceof EndNode || wfElm instanceof Router) {

            String displayName = wfElm.getDisplayName();

            /*
             * displayName???namedisplayname??name
            if(displayName==null || displayName.trim().equals("")){
               displayName = nodeWrapper.getName();
            }
            */

            // bounds
            Dimension dimension = null;
            dimension = _calculateFontSize(displayName, fontSize);
            dimension.width = dimension.width + 4;//??

            Bounds bounds = figure.getBounds().copy();
            if (dimension.width > 0) {
                //
                bounds.setHeight(bounds.getHeight() + IconTextGap + dimension.height);

                if (dimension.width > bounds.getWidth()) {
                    int oldWidth = bounds.getWidth();
                    bounds.setWidth(dimension.width);
                    int newX = bounds.getX() - ((dimension.width - oldWidth) / 2);
                    bounds.setX(newX);
                }
            }
            return bounds;
        } else if (wfElm instanceof Activity) {
            Activity activity = (Activity) wfElm;

            //Activitybounds?Activity
            Bounds bounds = figure.getBounds().copy();

            bounds.setHeight(bounds.getHeight() + IMG_RADIUS + DEFAULT_FONT_SIZE + IconTextGap);

            return bounds;
        } else {
            Bounds bounds = figure.getBounds().copy();

            return bounds;
        }
    }

    protected void _init(WorkflowProcess workflowProcess, String subProcessName) throws SerializerException {
        this.workflowProcess = workflowProcess;
        this.subProcessName = subProcessName;
        try {
            String subProcessId = this.workflowProcess.getId() + WorkflowProcess.ID_SEPARATOR + this.subProcessName;

            _checkDiagram(this.workflowProcess, this.subProcessName);

            diagram = this.workflowProcess.getDiagramBySubProcessId(subProcessId);

            DocumentBuilder docBuilder = factory.newDocumentBuilder();
            document = docBuilder.newDocument();

        } catch (ParserConfigurationException e) {
            throw new SerializerException(e);
        }

    }

    protected String _makePointsSeq(Point fromAnchor, Point toAnchor, List<Point> pointList) {
        //linePointsfromAnchortoAnchor???
        if (Math.abs(fromAnchor.getX() - toAnchor.getX()) <= 1) {
            fromAnchor.setX(toAnchor.getX());
        }
        if (Math.abs(fromAnchor.getY() - toAnchor.getY()) <= 1) {
            fromAnchor.setY(toAnchor.getY());
        }

        StringBuffer pointSeqBuf = new StringBuffer();
        pointSeqBuf.append(fromAnchor.getX()).append(",").append(fromAnchor.getY()).append(" ");

        if (pointList != null && pointList.size() > 0) {
            for (Point p : pointList) {
                pointSeqBuf.append(p.getX()).append(",").append(p.getY()).append(" ");
            }
        }
        pointSeqBuf.append(toAnchor.getX()).append(",").append(toAnchor.getY());

        return pointSeqBuf.toString();
    }

    /**
     * ??diagram??diagram
     * 
     * @param process
     * @param subProcessName
     */
    protected void _checkDiagram(WorkflowProcess process, String subProcessId) {
        // TODO

    }

    protected String _getActivityImgUri(Activity activity) {
        ServiceBinding serviceBinding = activity.getServiceBinding();

        if (serviceBinding == null)
            return null;

        String serviceId = serviceBinding.getServiceId();

        ServiceDef serviceDef = this.workflowProcess.getService(serviceId);

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

        String svcClassName = serviceDef.getClass().getName();

        String pngUri = SERVICE_LOGO_CACHE.get(svcClassName);
        if (pngUri == null) {
            pngUri = "/" + svcClassName.replaceAll("\\.", "/") + ".png";

            InputStream inStream = this.getClass().getResourceAsStream(pngUri);

            if (inStream != null) {
                SERVICE_LOGO_CACHE.put(svcClassName, pngUri);
                return pngUri;
            } else {
                SERVICE_LOGO_CACHE.put(svcClassName, "_LOGO_NOT_FOUND_");
                return null;
            }

        } else if (pngUri.equals("_LOGO_NOT_FOUND_")) {
            return null;
        } else {
            return pngUri;
        }
    }

    public void setResourcePathPrefix(String s) {
        this.resourcePathPrefix = s;
    }

    public String serializeDiagramToStr(WorkflowProcess workflowProcess, String subProcessName, String encoding,
            boolean omitXmlDeclaration) {
        try {
            Document doc = this.serializeDiagramToDoc(workflowProcess, subProcessName);
            Transformer tf = TransformerFactory.newInstance().newTransformer();
            if (omitXmlDeclaration) {
                tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            }

            tf.setOutputProperty(OutputKeys.ENCODING, encoding);
            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

            StreamResult dest = new StreamResult(new StringWriter());
            tf.transform(new DOMSource(doc), dest);

            return dest.getWriter().toString();
        } catch (Exception e) {
            //TODO 
            e.printStackTrace();
        }

        return "";
    }
}