org.fireflow.pdl.fpdl.io.FPDLDeserializer.java Source code

Java tutorial

Introduction

Here is the source code for org.fireflow.pdl.fpdl.io.FPDLDeserializer.java

Source

/**
 * Copyright 2007-2011 ?
 * All rights reserved. 
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License 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 General Public License
 * along with this program. If not, see http://www.gnu.org/licenses. *
 */
package org.fireflow.pdl.fpdl.io;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fireflow.engine.context.RuntimeContext;
import org.fireflow.engine.invocation.TimerOperationName;
import org.fireflow.model.InvalidModelException;
import org.fireflow.model.ModelElement;
import org.fireflow.model.binding.Assignment;
import org.fireflow.model.binding.ServiceBinding;
import org.fireflow.model.binding.impl.AssignmentImpl;
import org.fireflow.model.binding.impl.ResourceBindingImpl;
import org.fireflow.model.binding.impl.ServiceBindingImpl;
import org.fireflow.model.data.Expression;
import org.fireflow.model.data.Property;
import org.fireflow.model.data.impl.ExpressionImpl;
import org.fireflow.model.data.impl.PropertyImpl;
import org.fireflow.model.io.DeserializerException;
import org.fireflow.model.io.Util4Deserializer;
import org.fireflow.model.io.resource.ResourceDeserializer;
import org.fireflow.model.io.service.ServiceParser;
import org.fireflow.model.misc.Duration;
import org.fireflow.model.process.WorkflowElement;
import org.fireflow.model.resourcedef.ResourceDef;
import org.fireflow.model.resourcedef.WorkItemAssignmentStrategy;
import org.fireflow.model.servicedef.ServiceDef;
import org.fireflow.pdl.fpdl.diagram.ActivityShape;
import org.fireflow.pdl.fpdl.diagram.AssociationShape;
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.MessageFlowShape;
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.TransitionShape;
import org.fireflow.pdl.fpdl.diagram.figure.Circle;
import org.fireflow.pdl.fpdl.diagram.figure.Line;
import org.fireflow.pdl.fpdl.diagram.figure.Rectangle;
import org.fireflow.pdl.fpdl.diagram.figure.impl.LineImpl;
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.FulfilStyle;
import org.fireflow.pdl.fpdl.diagram.figure.part.FulfilStyleImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.Label;
import org.fireflow.pdl.fpdl.diagram.figure.part.LabelImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.Point;
import org.fireflow.pdl.fpdl.diagram.impl.ActivityShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.AssociationShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.CommentShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.DiagramImpl;
import org.fireflow.pdl.fpdl.diagram.impl.EndNodeShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.GroupShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.LaneShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.MessageFlowShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.PoolShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.RouterShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.StartNodeShapeImpl;
import org.fireflow.pdl.fpdl.diagram.impl.TransitionShapeImpl;
import org.fireflow.pdl.fpdl.misc.LoopStrategy;
import org.fireflow.pdl.fpdl.process.Activity;
import org.fireflow.pdl.fpdl.process.EndNode;
import org.fireflow.pdl.fpdl.process.Import;
import org.fireflow.pdl.fpdl.process.Node;
import org.fireflow.pdl.fpdl.process.Router;
import org.fireflow.pdl.fpdl.process.StartNode;
import org.fireflow.pdl.fpdl.process.SubProcess;
import org.fireflow.pdl.fpdl.process.Transition;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.fireflow.pdl.fpdl.process.event.EventListenerDef;
import org.fireflow.pdl.fpdl.process.event.impl.EventListenerDefImpl;
import org.fireflow.pdl.fpdl.process.features.Feature;
import org.fireflow.pdl.fpdl.process.features.endnode.impl.ThrowCompensationFeatureImpl;
import org.fireflow.pdl.fpdl.process.features.endnode.impl.ThrowFaultFeatureImpl;
import org.fireflow.pdl.fpdl.process.features.endnode.impl.ThrowTerminationFeatureImpl;
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.impl.CatchCompensationFeatureImpl;
import org.fireflow.pdl.fpdl.process.features.startnode.impl.CatchFaultFeatureImpl;
import org.fireflow.pdl.fpdl.process.features.startnode.impl.TimerStartFeatureImpl;
import org.fireflow.pdl.fpdl.process.features.startnode.impl.WebserviceStartFeatureImpl;
import org.fireflow.pdl.fpdl.process.impl.ActivityImpl;
import org.fireflow.pdl.fpdl.process.impl.EndNodeImpl;
import org.fireflow.pdl.fpdl.process.impl.ImportImpl;
import org.fireflow.pdl.fpdl.process.impl.RouterImpl;
import org.fireflow.pdl.fpdl.process.impl.StartNodeImpl;
import org.fireflow.pdl.fpdl.process.impl.SubProcessImpl;
import org.fireflow.pdl.fpdl.process.impl.TransitionImpl;
import org.fireflow.pdl.fpdl.process.impl.WorkflowProcessImpl;
import org.firesoa.common.schema.NameSpaces;
import org.firesoa.common.util.ScriptLanguages;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 * @author ? nychen2000@163.com
 */
public class FPDLDeserializer implements FPDLNames {
    private static final Log log = LogFactory.getLog(FPDLDeserializer.class);
    private static final DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
    public static final String JDK_TRANSFORMER_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl";

    private boolean useJDKTransformerFactory = false;//??bug

    static {
        docBuilderFactory.setNamespaceAware(true);
        docBuilderFactory.setCoalescing(false);
    }
    private static ImportLoader defaultImportLoader = new ImportLoaderClasspathImpl();

    protected ImportLoader importLoader = defaultImportLoader;

    /**
     * 
     */
    public FPDLDeserializer() {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();

        if (JDK_TRANSFORMER_CLASS.equals(transformerFactory.getClass().getName())) {
            useJDKTransformerFactory = true;
        }
    }

    /**
     * @return the importLoader
     */
    public ImportLoader getImportLoader() {
        return importLoader;
    }

    /**
     * @param importLoader the importLoader to set
     */
    public void setImportLoader(ImportLoader importLoader) {
        this.importLoader = importLoader;
    }

    public WorkflowProcess deserialize(InputStream in)
            throws IOException, DeserializerException, InvalidModelException {
        try {
            DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();

            Document document = docBuilder.parse(in);

            String encoding = document.getXmlEncoding();
            log.info("Xml:" + encoding);

            final org.w3c.dom.Node pi = document
                    .createProcessingInstruction(StreamResult.PI_DISABLE_OUTPUT_ESCAPING, "");
            document.appendChild(pi);

            WorkflowProcess wp = deserialize(document);// ?
            return wp;
        } catch (ParserConfigurationException e) {
            throw new DeserializerException("Error parsing document.", e);
        } catch (SAXException e) {
            throw new DeserializerException("Error parsing document.", e);
        } finally {
        }
        // return parse(new InputStreamReader(in));
    }

    public WorkflowProcess parse(InputStream in, RuntimeContext ctx) {
        return null;
    }

    @SuppressWarnings("static-access")
    public WorkflowProcess deserialize(Document document)
            throws DeserializerException, InvalidModelException, IOException {
        Element workflowProcessElement = document.getDocumentElement();
        String processName = workflowProcessElement.getAttribute(NAME);
        String processDisplayName = workflowProcessElement.getAttribute(DISPLAY_NAME);

        // ?ID
        WorkflowProcessImpl wp = new WorkflowProcessImpl(processName, processDisplayName);

        // ???
        wp.setDescription(this.loadCDATA(Util4Deserializer.child(workflowProcessElement, DESCRIPTION)));

        // ?
        wp.setPackageId(workflowProcessElement.getAttribute(PACKAGE_ID));

        //?Import
        this.loadImports(wp, Util4Deserializer.children(workflowProcessElement, IMPORT));

        //?Service
        QName qname = new QName(SERVICE_NS_URI, SERVICES, SERVICE_NS_PREFIX);
        List<ServiceDef> serviceList = new ArrayList<ServiceDef>();
        ServiceParser.loadServices(serviceList, Util4Deserializer.child(workflowProcessElement, qname));
        if (serviceList != null) {
            for (ServiceDef serviceDef : serviceList) {
                wp.addService(serviceDef);
            }
        }

        //?Resource
        List<ResourceDef> resourcesList = new ArrayList<ResourceDef>();
        qname = new QName(RESOURCE_NS_URI, RESOURCES, RESOURCE_NS_PREFIX);
        ResourceDeserializer.loadResources(resourcesList, Util4Deserializer.child(workflowProcessElement, qname));
        if (resourcesList != null) {
            for (ResourceDef resourceDef : resourcesList) {
                wp.addResource(resourceDef);
            }
        }

        //?subflow
        Element subflowsElem = Util4Deserializer.child(workflowProcessElement, SUBPROCESSES);
        List<Element> subflowElementList = Util4Deserializer.children(subflowsElem, SUBPROCESS);

        if (subflowElementList != null) {
            for (Element subflowElm : subflowElementList) {
                this.loadSubflow(wp, subflowElm);
            }
        }

        //?diagrams
        Element diagramsElm = Util4Deserializer.child(workflowProcessElement, DIAGRAMS);
        List<Element> diagramsElementList = Util4Deserializer.children(diagramsElm, DIAGRAM);

        if (diagramsElementList != null) {
            for (Element diagramElm : diagramsElementList) {
                this.loadDiagram(wp, diagramElm);
            }
        }

        return wp;

    }

    protected void loadDiagram(WorkflowProcess wp, Element diagramElm) throws DeserializerException {
        if (diagramElm == null)
            return;

        String id = diagramElm.getAttribute(ID);
        String subflowId = diagramElm.getAttribute(REF);
        String direction = diagramElm.getAttribute(DIRECTION);
        String snapEnabled = diagramElm.getAttribute(SNAP_ENABLED);
        String gridEnabled = diagramElm.getAttribute(GRID_ENABLED);
        String rulerEnabled = diagramElm.getAttribute(RULER_ENABLED);

        SubProcess subProcess = wp.getLocalSubProcess(subflowId);

        Diagram diagram = new DiagramImpl(id, subProcess);
        if (!StringUtils.isEmpty(direction)) {
            diagram.setDirection(direction);
        }

        try {
            diagram.setGridEnabled(Boolean.parseBoolean(gridEnabled));
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        try {
            diagram.setRulerEnabled(Boolean.parseBoolean(rulerEnabled));
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        try {
            diagram.setSnapEnabled(Boolean.parseBoolean(snapEnabled));
        } catch (Exception e) {
            log.error(e.getMessage());
        }

        wp.addDiagram(diagram);

        //1?load
        List<Element> childElmList = Util4Deserializer.children(diagramElm, NODE);
        if (childElmList != null) {
            for (Element childElm : childElmList) {
                String type = childElm.getAttribute(TYPE);
                if (type == null)
                    type = "";

                if (ACTIVITY.equals(type)) {
                    ActivityShape activityShape = loadActivityShape(subProcess, childElm);
                    diagram.addProcessNodeShape(activityShape);
                } else if (START_NODE.equals(type)) {
                    StartNodeShape startNodeShape = loadStartNodeShape(subProcess, childElm);
                    diagram.addProcessNodeShape(startNodeShape);
                } else if (END_NODE.equals(type)) {
                    EndNodeShape endNodeShape = loadEndNodeShape(subProcess, childElm);
                    diagram.addProcessNodeShape(endNodeShape);
                } else if (ROUTER.equals(type)) {
                    RouterShape routerShape = loadRouterShape(subProcess, childElm);
                    diagram.addProcessNodeShape(routerShape);
                } else if (GROUP.equals(type)) {
                    GroupShape groupShape = loadGroupShapeWithoutConnector(subProcess, childElm);
                    diagram.addGroup(groupShape);
                } else if (type.equals(POOL)) {
                    PoolShape poolShape = loadPoolShapeWithoutConnector(subProcess, diagram, childElm);
                    diagram.addPool(poolShape);
                } else if (type.equals(COMMENT)) {
                    CommentShape commentShape = loadCommentShape(childElm);
                    diagram.addComment(commentShape);
                }
            }
        }

        //2??load?
        /*
        if (childElmList!=null){
           for (Element childElm : childElmList){
        String type = childElm.getAttribute(TYPE);
        String elmId = childElm.getAttribute(ID);
        if (GROUP.equals(type)){
           GroupShape groupShape = (GroupShape)diagram.findChild(elmId);
           this.loadConnectorsInGroupShape(diagram, childElm, groupShape);
        }
        else if (type.equals(POOL)){
           PoolShape poolShape = (PoolShape)diagram.findChild(elmId);
           loadConnectorsInPoolShape(diagram,childElm,poolShape);
        }
           }
        }
        */

        childElmList = Util4Deserializer.children(diagramElm, CONNECTOR);
        if (childElmList != null) {
            for (Element childElm : childElmList) {
                String type = childElm.getAttribute(TYPE);
                if (type == null)
                    type = "";
                if (TRANSITION.equals(type)) {
                    TransitionShape transitionShape = loadTransitionShape(subProcess, diagram, childElm);
                    ProcessNodeShape from = (ProcessNodeShape) transitionShape.getFromNode();
                    if (from != null) {
                        from.getLeavingTransitionShapes().add(transitionShape);
                    }
                    ProcessNodeShape to = (ProcessNodeShape) transitionShape.getToNode();
                    if (to != null) {
                        to.getEnteringTransitionShapes().add(transitionShape);
                    }
                    diagram.addTransition(transitionShape);
                } else if (type.equals(MESSAGEFLOW)) {
                    MessageFlowShape messageFlow = this.loadMessageFlowShape(diagram, childElm);
                    NodeShape from = messageFlow.getFromNode();
                    if (from != null) {
                        from.getLeavingMessageFlowShapes().add(messageFlow);
                    }
                    NodeShape to = messageFlow.getToNode();
                    if (to != null) {
                        to.getEnteringMessageFlowShapes().add(messageFlow);
                    }
                    diagram.addMessageFlow(messageFlow);
                } else if (type.equals(ASSOCIATION)) {
                    AssociationShape association = loadAssociationShape(diagram, childElm);
                    NodeShape from = association.getFromNode();
                    if (from != null) {
                        from.getLeavingAssociationShapes().add(association);
                    }
                    NodeShape to = association.getToNode();
                    if (to != null) {
                        to.getEnteringAssociationShapes().add(association);
                    }

                    diagram.addAssociation(association);
                }
            }
        }
    }

    protected GroupShape loadGroupShapeWithoutConnector(SubProcess subProcess, Element groupElement) {
        String id = groupElement.getAttribute(ID);
        GroupShape groupShape = new GroupShapeImpl(id);

        Element figureElement = Util4Deserializer.child(groupElement, FIGURE);
        Element rectElm = Util4Deserializer.child(figureElement, RECTANGLE);
        this.loadRectangle(groupShape, rectElm);

        //?fulfilstyle==null?bound0
        Rectangle rect = (Rectangle) groupShape.getFigure();
        if (rect.getFulfilStyle() == null) {
            FulfilStyle style = new FulfilStyleImpl();
            rect.setFulfilStyle(style);
        }

        List<Element> childElmList = Util4Deserializer.children(groupElement, NODE);
        if (childElmList != null) {
            for (Element childElm : childElmList) {
                String type = childElm.getAttribute(TYPE);
                if (type == null)
                    type = "";
                if (ACTIVITY.equals(type)) {
                    ActivityShape activityShape = loadActivityShape(subProcess, childElm);
                    groupShape.addProcessNodeShape(activityShape);
                } else if (START_NODE.equals(type)) {
                    StartNodeShape startNodeShape = loadStartNodeShape(subProcess, childElm);
                    groupShape.addProcessNodeShape(startNodeShape);
                } else if (END_NODE.equals(type)) {
                    EndNodeShape endNodeShape = loadEndNodeShape(subProcess, childElm);
                    groupShape.addProcessNodeShape(endNodeShape);
                } else if (ROUTER.equals(type)) {
                    RouterShape routerShape = loadRouterShape(subProcess, childElm);
                    groupShape.addProcessNodeShape(routerShape);
                } else if (COMMENT.equals(type)) {
                    CommentShape commentShape = this.loadCommentShape(childElm);
                    groupShape.addComment(commentShape);
                }

            }
        }

        return groupShape;
    }

    /* diagram
    protected void loadConnectorsInGroupShape(Diagram diagram ,Element groupElement,GroupShape groupShape){
       List<Element> childElmList = Util4Deserializer.children(groupElement, CONNECTOR);
       if (childElmList!=null){
     for (Element childElm : childElmList){
        String type = childElm.getAttribute(TYPE);
        if (type==null) type="";
        if (TRANSITION.equals(type)){
           TransitionShape transitionShape = loadTransitionShape(diagram,childElm);
           groupShape.addTransition(transitionShape);   
        }
        else if (ASSOCIATION.equals(type)){
           AssociationShape associationShape = this.loadAssociationShape(diagram, childElm);
           groupShape.addAssociation(associationShape);
        }
     }
       }
    }
    */
    protected PoolShape loadPoolShapeWithoutConnector(SubProcess subProcess, Diagram diagram, Element poolElm) {
        if (poolElm == null) {
            return null;
        }

        String id = poolElm.getAttribute(ID);
        String wfElementRef = poolElm.getAttribute(REF);

        PoolShape pool = new PoolShapeImpl(id);

        if (!StringUtils.isEmpty(wfElementRef)) {
            ModelElement modelElm = subProcess == null ? null : subProcess.findWFElementById(wfElementRef);
            pool.setWorkflowElementRef(modelElm);
        }

        Element figureElement = Util4Deserializer.child(poolElm, FIGURE);
        Element planeElm = Util4Deserializer.child(figureElement, RECTANGLE);
        this.loadRectangle(pool, planeElm);

        //?fulfilstyle==null?bound0
        Rectangle rect = (Rectangle) pool.getFigure();
        if (rect.getFulfilStyle() == null) {
            FulfilStyle style = new FulfilStyleImpl();
            rect.setFulfilStyle(style);
        }

        //
        List<Element> children = Util4Deserializer.children(poolElm, NODE);
        if (children != null) {
            for (Element child : children) {
                String type = child.getAttribute(TYPE);
                if (type == null)
                    type = "";

                if (LANE.equals(type)) {
                    LaneShape lane = loadLaneShape(subProcess, child);
                    pool.addLane(lane);
                }
            }
        }

        return pool;
    }

    /* diagram?
    protected void loadConnectorsInPoolShape(Diagram diagram ,Element poolElement,PoolShape poolShape){
       List<Element> childElmList = Util4Deserializer.children(poolElement, CONNECTOR);
       if (childElmList!=null){
     for (Element childElm : childElmList){
        String type = childElm.getAttribute(TYPE);
        if (type==null) type="";
        if (TRANSITION.equals(type)){
           TransitionShape transitionShape = loadTransitionShape(diagram,childElm);
           poolShape.addTransition(transitionShape);   
        }
        else if (ASSOCIATION.equals(type)){
           AssociationShape associationShape = this.loadAssociationShape(diagram, childElm);
           poolShape.addAssociation(associationShape);
        }
     }
       }
       List<Element> children = Util4Deserializer.children(poolElement, NODE);
       if (children!=null){
     for (Element child : children){
        String type = child.getAttribute(TYPE);
        String elmId = child.getAttribute(ID);
        if (GROUP.equals(type)){
           GroupShape groupShape = (GroupShape)diagram.findChild(elmId);
           this.loadConnectorsInGroupShape(diagram, child, groupShape);
        }
     }
       }
    }
    */

    protected TransitionShape loadTransitionShape(SubProcess subProcess, Diagram diagram, Element transitionElm) {
        if (transitionElm == null)
            return null;

        String id = transitionElm.getAttribute(ID);
        String ref = transitionElm.getAttribute(REF);
        String from = transitionElm.getAttribute(FROM);
        String to = transitionElm.getAttribute(TO);

        ModelElement modelElm = subProcess == null ? null : subProcess.findWFElementById(ref);

        DiagramElement fromElm = diagram.findChild(from);
        DiagramElement toElm = diagram.findChild(to);

        TransitionShape transitionShape = new TransitionShapeImpl(id);
        transitionShape.setWorkflowElementRef(modelElm);
        transitionShape.setFromNode((ProcessNodeShape) fromElm);
        transitionShape.setToNode((ProcessNodeShape) toElm);

        Element figureElement = Util4Deserializer.child(transitionElm, FIGURE);
        Element lineElm = Util4Deserializer.child(figureElement, LINE);
        this.loadLine(transitionShape, lineElm);

        return transitionShape;
    }

    protected RouterShape loadRouterShape(SubProcess subProcess, Element routerShapeElm) {
        if (routerShapeElm == null)
            return null;

        String id = routerShapeElm.getAttribute(ID);
        String ref = routerShapeElm.getAttribute(REF);
        ModelElement modelElm = subProcess == null ? null : subProcess.findWFElementById(ref);

        RouterShape routerShape = new RouterShapeImpl(id);
        routerShape.setWorkflowElementRef(modelElm);

        Element figureElement = Util4Deserializer.child(routerShapeElm, FIGURE);
        Element rectElm = Util4Deserializer.child(figureElement, RECTANGLE);
        this.loadRectangle(routerShape, rectElm);

        return routerShape;
    }

    protected EndNodeShape loadEndNodeShape(SubProcess subProcess, Element endNodeShapeElm) {
        if (endNodeShapeElm == null)
            return null;
        String id = endNodeShapeElm.getAttribute(ID);
        String ref = endNodeShapeElm.getAttribute(REF);
        ModelElement modelElm = subProcess == null ? null : subProcess.findWFElementById(ref);

        EndNodeShape endNodeShape = new EndNodeShapeImpl(id);
        endNodeShape.setWorkflowElementRef(modelElm);

        Element figureElement = Util4Deserializer.child(endNodeShapeElm, FIGURE);
        Element circleElm = Util4Deserializer.child(figureElement, CIRCLE);
        loadCircle(endNodeShape, circleElm);

        return endNodeShape;
    }

    protected StartNodeShape loadStartNodeShape(SubProcess subProcess, Element startNodeShapeElm) {
        if (startNodeShapeElm == null)
            return null;

        String id = startNodeShapeElm.getAttribute(ID);
        String ref = startNodeShapeElm.getAttribute(REF);
        ModelElement modelElm = subProcess == null ? null : subProcess.findWFElementById(ref);

        StartNodeShape startNodeShape = new StartNodeShapeImpl(id);
        startNodeShape.setWorkflowElementRef(modelElm);

        Element figureElement = Util4Deserializer.child(startNodeShapeElm, FIGURE);
        Element circleElm = Util4Deserializer.child(figureElement, CIRCLE);
        loadCircle(startNodeShape, circleElm);

        return startNodeShape;
    }

    protected void loadCircle(DiagramElement diagramElm, Element circleElm) {
        if (circleElm == null)
            return;
        Circle circle = (Circle) diagramElm.getFigure();

        Element titleElm = Util4Deserializer.child(circleElm, TITLE);
        if (titleElm != null) {
            Element labelElm = Util4Deserializer.child(titleElm, LABEL);
            Label lb = this.loadLabel(labelElm);
            if (lb != null) {
                circle.getTitleLabel().setFontColor(lb.getFontColor());
                circle.getTitleLabel().setFontName(lb.getFontName());
                circle.getTitleLabel().setFontSize(lb.getFontSize());
                circle.getTitleLabel().setText(lb.getText());
                circle.getTitleLabel().setTextDirection(lb.getTextDirection());
                circle.getTitleLabel().setFontStyle(lb.getFontStyle());
            }
        }

        Element boundsElm = Util4Deserializer.child(circleElm, BOUNDS);
        if (boundsElm != null) {
            Bounds bounds = loadBounds(boundsElm);
            if (bounds != null) {
                circle.getBounds().setX(bounds.getX());
                circle.getBounds().setY(bounds.getY());
                circle.getBounds().setWidth(bounds.getWidth());
                circle.getBounds().setHeight(bounds.getHeight());
                circle.getBounds().setLineType(bounds.getLineType());
                circle.getBounds().setThick(bounds.getThick());
                circle.getBounds().setColor(bounds.getColor());
                circle.getBounds().setCornerRadius(bounds.getCornerRadius());
                circle.getBounds().setDashArray(bounds.getDashArray());
            }

        }

        Element fulfilStyleElm = Util4Deserializer.child(circleElm, FULFIL_STYLE);
        FulfilStyle fulfilStyle = this.loadFulfilStyle(fulfilStyleElm);
        circle.setFulfilStyle(fulfilStyle);
    }

    protected ActivityShape loadActivityShape(SubProcess subProcess, Element activityShapeElm) {
        if (activityShapeElm == null) {
            return null;
        }

        String id = activityShapeElm.getAttribute(ID);
        String ref = activityShapeElm.getAttribute(REF);

        ModelElement modelElement = subProcess == null ? null : subProcess.findWFElementById(ref);

        ActivityShape activityShape = new ActivityShapeImpl(id);
        activityShape.setWorkflowElementRef(modelElement);

        Element figureElement = Util4Deserializer.child(activityShapeElm, FIGURE);
        Element rectElm = Util4Deserializer.child(figureElement, RECTANGLE);
        this.loadRectangle(activityShape, rectElm);

        //?fulfilstyle==null?bound0
        Rectangle rect = (Rectangle) activityShape.getFigure();
        if (rect.getFulfilStyle() == null) {
            FulfilStyle style = new FulfilStyleImpl();
            rect.setFulfilStyle(style);
        }

        if (rect.getContentLabel() == null) {
            Label contentLb = new LabelImpl();
            contentLb.setText(Label.CONTENT_FROM_WORKFLOW_ELEMENT);
            rect.setContentLabel(contentLb);
        }

        List<Element> attachedStartNodeList = Util4Deserializer.children(activityShapeElm, NODE);
        if (attachedStartNodeList != null) {
            for (Element startNodeElm : attachedStartNodeList) {
                StartNodeShape startNodeShape = this.loadStartNodeShape(subProcess, startNodeElm);
                activityShape.addAttachedStartNodeShape(startNodeShape);
            }
        }

        return activityShape;
    }

    protected LaneShape loadLaneShape(SubProcess subProcess, Element laneElm) {
        if (laneElm == null)
            return null;
        String id = laneElm.getAttribute(ID);
        LaneShape lane = new LaneShapeImpl(id);

        Element figureElement = Util4Deserializer.child(laneElm, FIGURE);
        Element planeElm = Util4Deserializer.child(figureElement, RECTANGLE);
        this.loadRectangle(lane, planeElm);

        //?fulfilstyle==null?bound0
        Rectangle rect = (Rectangle) lane.getFigure();
        if (rect.getFulfilStyle() == null) {
            FulfilStyle style = new FulfilStyleImpl();
            rect.setFulfilStyle(style);
        }

        //
        List<Element> children = Util4Deserializer.children(laneElm, NODE);
        if (children != null) {
            for (Element child : children) {
                String type = child.getAttribute(TYPE);
                if (type == null)
                    type = "";

                if (ACTIVITY.equals(type)) {
                    ActivityShape activityShape = loadActivityShape(subProcess, child);
                    lane.addProcessNodeShape(activityShape);
                } else if (START_NODE.equals(type)) {
                    StartNodeShape startNodeShape = loadStartNodeShape(subProcess, child);
                    lane.addProcessNodeShape(startNodeShape);
                } else if (END_NODE.equals(type)) {
                    EndNodeShape endNodeShape = loadEndNodeShape(subProcess, child);
                    lane.addProcessNodeShape(endNodeShape);
                } else if (ROUTER.equals(type)) {
                    RouterShape routerShape = loadRouterShape(subProcess, child);
                    lane.addProcessNodeShape(routerShape);
                } else if (COMMENT.equals(type)) {
                    CommentShape commentShape = this.loadCommentShape(child);
                    lane.addComment(commentShape);
                } else if (GROUP.equals(type)) {
                    GroupShape groupShape = this.loadGroupShapeWithoutConnector(subProcess, child);
                    lane.addGroup(groupShape);
                }
            }
        }

        return lane;
    }

    /*
    protected void loadPlane(DiagramElement diagramElm, Element planeElm){
       if (planeElm==null) return ;
       Plane plane = new PlaneImpl();
       diagramElm.setShape(plane);
           
       Element labelElm = Util4Deserializer.child(planeElm, LABEL);
       Label lb = this.loadLabel(labelElm);
       plane.setLabel(lb);
           
       Element boundsElm = Util4Deserializer.child(planeElm, BOUNDS);
       Bounds bounds = this.loadBounds(boundsElm);
       plane.setBounds(bounds);
           
       Element fulfilStyleElm = Util4Deserializer.child(planeElm, FULFIL_STYLE);
       FulfilStyle fulfilStyle = this.loadFulfilStyle(fulfilStyleElm);
       plane.setFulfilStyle(fulfilStyle);
    }
    */
    protected CommentShape loadCommentShape(Element commentElm) {
        if (commentElm == null)
            return null;
        String id = commentElm.getAttribute(ID);
        CommentShape comment = new CommentShapeImpl(id);

        Element figureElement = Util4Deserializer.child(commentElm, FIGURE);
        Element rectElm = Util4Deserializer.child(figureElement, RECTANGLE);
        loadRectangle(comment, rectElm);

        //?fulfilstyle==null?bound0
        Rectangle rect = (Rectangle) comment.getFigure();
        if (rect.getFulfilStyle() == null) {
            FulfilStyle style = new FulfilStyleImpl();
            rect.setFulfilStyle(style);
        }

        //contentLabel?
        if (rect.getContentLabel() == null) {
            Label contentLb = new LabelImpl();
            contentLb.setText("");
            rect.setContentLabel(contentLb);
        }

        return comment;
    }

    protected void loadRectangle(DiagramElement diagramElm, Element rectElm) {
        if (rectElm == null)
            return;
        Rectangle rect = (Rectangle) diagramElm.getFigure();

        Element titleElm = Util4Deserializer.child(rectElm, TITLE);
        if (titleElm != null) {
            Element labelElm = Util4Deserializer.child(titleElm, LABEL);
            Label lb = this.loadLabel(labelElm);
            if (lb != null) {
                rect.getTitleLabel().setFontColor(lb.getFontColor());
                rect.getTitleLabel().setFontName(lb.getFontName());
                rect.getTitleLabel().setFontSize(lb.getFontSize());
                rect.getTitleLabel().setText(lb.getText());
                rect.getTitleLabel().setTextDirection(lb.getTextDirection());
                rect.getTitleLabel().setFontStyle(lb.getFontStyle());
            }
        }

        Element contentElm = Util4Deserializer.child(rectElm, CONTENT);
        if (contentElm != null) {
            Element labelElm = Util4Deserializer.child(contentElm, LABEL);
            Label lb = this.loadLabel(labelElm);
            rect.setContentLabel(lb);
        } else {
            rect.setContentLabel(null);
        }

        Element boundsElm = Util4Deserializer.child(rectElm, BOUNDS);
        if (boundsElm != null) {
            Bounds bounds = loadBounds(boundsElm);
            if (bounds != null) {
                rect.getBounds().setX(bounds.getX());
                rect.getBounds().setY(bounds.getY());
                rect.getBounds().setWidth(bounds.getWidth());
                rect.getBounds().setHeight(bounds.getHeight());
                rect.getBounds().setLineType(bounds.getLineType());
                rect.getBounds().setThick(bounds.getThick());
                rect.getBounds().setColor(bounds.getColor());
                rect.getBounds().setCornerRadius(bounds.getCornerRadius());
                rect.getBounds().setDashArray(bounds.getDashArray());
            }

        }

        Element fulfilElm = Util4Deserializer.child(rectElm, FULFIL_STYLE);
        if (fulfilElm != null) {
            FulfilStyle fulfilStyle = loadFulfilStyle(fulfilElm);
            rect.setFulfilStyle(fulfilStyle);
        } else {
            rect.setFulfilStyle(null);
        }
    }

    protected Bounds loadBounds(Element boundsElm) {
        if (boundsElm == null)
            return null;
        Bounds bounds = new BoundsImpl();

        String x = boundsElm.getAttribute(X);
        try {
            bounds.setX(Integer.parseInt(x));
        } catch (Exception e) {

        }
        String y = boundsElm.getAttribute(Y);
        try {
            bounds.setY(Integer.parseInt(y));
        } catch (Exception e) {

        }

        String height = boundsElm.getAttribute(HEIGHT);
        if (StringUtils.isNumeric(height)) {
            bounds.setHeight(Integer.parseInt(height));
        }

        String width = boundsElm.getAttribute(WIDTH);
        if (StringUtils.isNumeric(width)) {
            bounds.setWidth(Integer.parseInt(width));
        }

        Element boundsStyleElm = Util4Deserializer.child(boundsElm, BORDER_STYLE);
        if (boundsStyleElm != null) {

            String color = boundsStyleElm.getAttribute(COLOR);
            if (!StringUtils.isEmpty(color)) {
                bounds.setColor(color);
            }

            String lineType = boundsStyleElm.getAttribute(LINE_TYPE);
            if (!StringUtils.isEmpty(lineType)) {
                bounds.setLineType(lineType);
            }

            String thick = boundsStyleElm.getAttribute(THICK);
            if (StringUtils.isNumeric(thick)) {
                bounds.setThick(Integer.parseInt(thick));
            }

            String radius = boundsStyleElm.getAttribute(RADIUS);
            if (!StringUtils.isEmpty(radius) && StringUtils.isNumeric(radius)) {
                bounds.setCornerRadius(Integer.parseInt(radius));
            }

            String dashArr = boundsStyleElm.getAttribute(DASH_ARRAY);
            if (!StringUtils.isEmpty(dashArr)) {
                bounds.setDashArray(dashArr);
            }
        } else {
            bounds.setThick(-1);
            bounds.setColor(null);
            bounds.setLineType(null);
            bounds.setCornerRadius(0);
        }
        return bounds;
    }

    protected FulfilStyle loadFulfilStyle(Element fulfilStyleElm) {
        if (fulfilStyleElm == null)
            return null;

        FulfilStyle fulfilStyle = new FulfilStyleImpl();
        String color1 = fulfilStyleElm.getAttribute(COLOR + "1");
        if (color1 != null) {
            fulfilStyle.setColor1(color1);
        }

        String color2 = fulfilStyleElm.getAttribute(COLOR + "2");
        if (color2 != null) {
            fulfilStyle.setColor2(color2);
        }

        String gradientStyle = fulfilStyleElm.getAttribute(GRADIENT_STYLE);
        if (gradientStyle != null) {
            fulfilStyle.setGradientStyle(gradientStyle);
        }

        return fulfilStyle;
    }

    protected AssociationShape loadAssociationShape(Diagram diagram, Element associationElm) {
        String id = associationElm.getAttribute(ID);
        String from = associationElm.getAttribute(FROM);
        String to = associationElm.getAttribute(TO);

        DiagramElement fromElm = diagram.findChild(from);
        DiagramElement toElm = diagram.findChild(to);

        AssociationShape associationShape = new AssociationShapeImpl(id);
        associationShape.setFromNode((NodeShape) fromElm);
        associationShape.setToNode((NodeShape) toElm);

        Element figureElement = Util4Deserializer.child(associationElm, FIGURE);
        Element lineElm = Util4Deserializer.child(figureElement, LINE);
        loadLine(associationShape, lineElm);

        return associationShape;
    }

    protected MessageFlowShape loadMessageFlowShape(Diagram diagram, Element messageFlowElm) {
        String id = messageFlowElm.getAttribute(ID);
        String from = messageFlowElm.getAttribute(FROM);
        String to = messageFlowElm.getAttribute(TO);
        DiagramElement fromElm = diagram.findChild(from);
        DiagramElement toElm = diagram.findChild(to);

        MessageFlowShape messageFlow = new MessageFlowShapeImpl(id);
        messageFlow.setFromNode((NodeShape) fromElm);
        messageFlow.setToNode((NodeShape) toElm);

        Element figureElement = Util4Deserializer.child(messageFlowElm, FIGURE);
        Element lineElm = Util4Deserializer.child(figureElement, LINE);
        loadLine(messageFlow, lineElm);

        return messageFlow;

    }

    protected void loadLine(DiagramElement diagramElm, Element lineElm) {
        Line line = (Line) diagramElm.getFigure();

        Element titleElm = Util4Deserializer.child(lineElm, TITLE);
        if (titleElm != null) {
            Element labelElm = Util4Deserializer.child(titleElm, LABEL);
            Label lb = this.loadLabel(labelElm);
            if (lb != null) {
                line.getTitleLabel().setFontColor(lb.getFontColor());
                line.getTitleLabel().setFontName(lb.getFontName());
                line.getTitleLabel().setFontSize(lb.getFontSize());
                line.getTitleLabel().setText(lb.getText());
                line.getTitleLabel().setTextDirection(lb.getTextDirection());
                line.getTitleLabel().setFontStyle(lb.getFontStyle());
            }
        }

        Element boundsElm = Util4Deserializer.child(lineElm, BOUNDS);
        if (boundsElm != null) {
            Bounds bounds = loadBounds(boundsElm);
            if (bounds != null) {
                line.getBounds().setX(bounds.getX());
                line.getBounds().setY(bounds.getY());
                line.getBounds().setWidth(bounds.getWidth());
                line.getBounds().setHeight(bounds.getHeight());
                line.getBounds().setLineType(bounds.getLineType());
                line.getBounds().setThick(bounds.getThick());
                line.getBounds().setColor(bounds.getColor());
                line.getBounds().setCornerRadius(bounds.getCornerRadius());
                line.getBounds().setDashArray(bounds.getDashArray());
            }

        }

        String position = lineElm.getAttribute(LABEL_POSITION);

        if (!StringUtils.isEmpty(position)) {
            Point p = Point.fromString(position);
            if (p != null) {
                line.getLabelPosition().setX(p.getX());
                line.getLabelPosition().setY(p.getY());
            }
        }

        String pointListStr = lineElm.getAttribute(POINT_LIST);
        if (!StringUtils.isEmpty(pointListStr)) {
            List<Point> l = string2PointList(pointListStr);
            line.getPoints().clear();
            line.getPoints().addAll(l);
        }

    }

    private List<Point> string2PointList(String s) {
        StringTokenizer tokenizer = new StringTokenizer(s, ";");
        List<Point> l = new ArrayList<Point>();
        while (tokenizer.hasMoreTokens()) {
            String tmp = tokenizer.nextToken();
            Point p = Point.fromString(tmp);
            l.add(p);
        }
        return l;
    }

    protected Label loadLabel(Element labelElm) {
        if (labelElm == null)
            return null;
        Label lb = new LabelImpl();

        String direction = labelElm.getAttribute(TEXT_DIRECTION);
        if (!StringUtils.isEmpty(direction)) {
            lb.setTextDirection(direction);
        }

        String fontName = labelElm.getAttribute(FONT_NAME);
        if (!StringUtils.isEmpty(fontName)) {
            lb.setFontName(fontName);
        }

        String color = labelElm.getAttribute(COLOR);
        if (!StringUtils.isEmpty(color)) {
            lb.setFontColor(color);
        }

        String weight = labelElm.getAttribute(FONT_STYLE);
        if (!StringUtils.isEmpty(weight)) {
            lb.setFontStyle(weight);
        }

        String size = labelElm.getAttribute(SIZE);
        if (!StringUtils.isEmpty(size)) {
            try {
                lb.setFontSize(Integer.parseInt(size));
            } catch (Exception e) {

            }
        }

        String txt = this.loadCDATA(labelElm);
        lb.setText(txt);

        return lb;
    }

    protected void loadSubflow(WorkflowProcess wp, Element subflowElement) throws DeserializerException {
        String name = subflowElement.getAttribute(NAME);
        String displayName = subflowElement.getAttribute(DISPLAY_NAME);

        SubProcess subflow = new SubProcessImpl(wp, name, displayName);

        //
        // ?datafields
        this.loadProperties(subflow, subflow.getProperties(),
                Util4Deserializer.child(subflowElement, this.PROPERTIES));

        // ?duration
        subflow.setDuration(this.createDuration(subflowElement.getAttribute(DURATION)));

        // ,?????
        loadActivities(subflow, subflow.getActivities(), Util4Deserializer.child(subflowElement, ACTIVITIES));

        // ??
        loadRouters(subflow, subflow.getRouters(), Util4Deserializer.child(subflowElement, ROUTERS));
        // ?
        loadEndNodes(subflow, subflow.getEndNodes(), Util4Deserializer.child(subflowElement, END_NODES));

        // 
        loadStartNodes(subflow, subflow.getStartNodes(), Util4Deserializer.child(subflowElement, START_NODES));

        // 
        loadTransitions(subflow, subflow.getTransitions(), Util4Deserializer.child(subflowElement, TRANSITIONS));

        //entry
        String entryNodeId = subflowElement.getAttribute(ENTRY);
        WorkflowElement entryNode = subflow.findWFElementById(entryNodeId);
        if (entryNode != null) {

            subflow.setEntry((Node) entryNode);
        }

        //activityattached nodes
        List<StartNode> startNodes = subflow.getStartNodes();
        for (StartNode startNode : startNodes) {
            Feature feature = startNode.getFeature();
            if (feature != null) {
                if (feature instanceof TimerStartFeature) {
                    Activity act = ((TimerStartFeature) feature).getAttachedToActivity();
                    if (act != null) {
                        act.getAttachedStartNodes().add(startNode);
                    }
                } else if (feature instanceof CatchFaultFeature) {
                    Activity act = ((CatchFaultFeature) feature).getAttachedToActivity();
                    if (act != null) {
                        act.getAttachedStartNodes().add(startNode);
                    }
                }

                else if (feature instanceof CatchCompensationFeature) {
                    Activity act = ((CatchCompensationFeature) feature).getAttachedToActivity();
                    if (act != null) {
                        act.getAttachedStartNodes().add(startNode);
                    }
                }
            }
        }

        // ?
        loadEventListeners(subflow, subflow.getEventListeners(),
                Util4Deserializer.child(subflowElement, EVENT_LISTENERS));
        // 
        Map<String, String> extAttrs = subflow.getExtendedAttributes();
        loadExtendedAttributes(extAttrs, Util4Deserializer.child(subflowElement, EXTENDED_ATTRIBUTES));

        subflow.setDescription(loadCDATA(Util4Deserializer.child(subflowElement, DESCRIPTION)));
        wp.addSubProcess(subflow);

    }

    protected void loadImports(WorkflowProcess wp, List<Element> importElems)
            throws InvalidModelException, DeserializerException, IOException {
        if (importElems == null) {
            return;
        }

        for (Element importElm : importElems) {
            String type = importElm.getAttribute(IMPORT_TYPE);
            if (Import.SERVICES_IMPORT.equals(type)) {
                /* 20140106 ResourceRepository?
                ImportImpl<ServiceDef> serviceImport = new ImportImpl<ServiceDef>(wp);
                serviceImport.setImportType(type);
                serviceImport.setLocation(importElm.getAttribute(LOCATION));
                    
                List<ServiceDef> services = this.importLoader.loadServices(serviceImport.getLocation());
                serviceImport.setContents(services);
                    
                wp.getImportsForService().add(serviceImport);
                */
            } else if (Import.RESOURCES_IMPORT.equals(type)) {
                /* 20140106 ResourceRepository?
                ImportImpl<ResourceDef> resourceImport = new ImportImpl<ResourceDef>(wp);
                resourceImport.setImportType(type);
                resourceImport.setLocation(importElm.getAttribute(LOCATION));
                    
                List<ResourceDef> resources = this.importLoader.loadResources(resourceImport.getLocation());
                resourceImport.setContents(resources);
                    
                wp.getImportsForResource().add(resourceImport);
                */
            } else if (Import.PROCESS_IMPORT.equals(type)) {
                ImportImpl processImport = new ImportImpl(wp);
                processImport.setImportType(type);
                processImport.setLocation(importElm.getAttribute(LOCATION));
                processImport.setPackageId(importElm.getAttribute(PACKAGE_ID));
                processImport.setId(importElm.getAttribute(ID));
                processImport.setName(importElm.getAttribute(NAME));
                processImport.setDisplayName(importElm.getAttribute(DISPLAY_NAME));

                wp.addImport(processImport);

            }
        }
    }

    /**
     * duration string?5 HOUR, 5 BUSINESS DAY 
     * @param durationStr
     * @return
     */
    protected Duration createDuration(String durationStr) {
        if (StringUtils.isEmpty(durationStr))
            return null;
        StringTokenizer tokenizer = new StringTokenizer(durationStr, " ");
        String valueStr = null;
        String unit = null;
        String business = null;
        if (tokenizer.countTokens() == 2) {
            valueStr = tokenizer.nextToken();
            unit = tokenizer.nextToken();
        } else if (tokenizer.countTokens() == 3) {
            valueStr = tokenizer.nextToken();
            business = tokenizer.nextToken();
            unit = tokenizer.nextToken();
        }
        if (!StringUtils.isEmpty(valueStr)) {
            try {
                int value = Integer.parseInt(valueStr);
                Duration du = new Duration(value, unit);
                if (!StringUtils.isEmpty(business)) {
                    du.setBusinessTime(true);
                }
                return du;
            } catch (Exception e) {
                log.error(e);
                return null;
            }

        } else {
            log.error("Error duration attribute:" + durationStr);
        }
        return null;

    }

    protected Duration createDuration_deprecated(Element durationElem) {
        if (durationElem == null)
            return null;

        String _v = durationElem.getAttribute(VALUE);
        int intV = -1;
        if (_v != null) {
            try {
                intV = Integer.parseInt(_v);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        String unit = durationElem.getAttribute(UNIT);

        String _isBizTime = durationElem.getAttribute(IS_BUSINESS_TIME);
        boolean isBizTime = false;
        if (_isBizTime != null) {
            try {
                isBizTime = Boolean.parseBoolean(_isBizTime);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        Duration du = new Duration(intV, unit);
        du.setBusinessTime(isBizTime);
        return du;
    }

    /**
     * @param listeners
     * @param element
     */
    protected void loadEventListeners(ModelElement parent, List<EventListenerDef> listeners, Element element) {
        listeners.clear();
        if (element == null) {
            return;
        }
        if (element == null) {
            return;
        }
        List<Element> listenerElms = Util4Deserializer.children(element, EVENT_LISTENER);
        Iterator<Element> iter = listenerElms.iterator();
        while (iter.hasNext()) {
            Element elm = iter.next();
            EventListenerDefImpl listener = new EventListenerDefImpl();
            listener.setParent(parent);
            listener.setName(elm.getAttribute(NAME));
            listener.setDisplayName(elm.getAttribute(DISPLAY_NAME));
            //listener.setBizCategory(elm.getAttribute(PACKAGE_ID));
            listener.setDescription(this.loadCDATA(Util4Deserializer.child(elm, DESCRIPTION)));
            listener.setListenerBeanName(elm.getAttribute(BEAN_NAME));
            listener.setListenerClassName(elm.getAttribute(CLASS_NAME));
            listeners.add(listener);
        }
    }

    /**
     * @param subflow
     * @param element
     * @throws DeserializerException
     */
    protected void loadStartNodes(SubProcess subflow, List<StartNode> startNodes, Element startNodesElem)
            throws DeserializerException {
        if (startNodesElem == null) {
            return;
        }
        List<Element> startNodeElements = Util4Deserializer.children(startNodesElem, START_NODE);
        startNodes.clear();
        Iterator<Element> iter = startNodeElements.iterator();
        while (iter.hasNext()) {
            Element startNodeElem = iter.next();

            StartNode startNode = new StartNodeImpl(subflow, startNodeElem.getAttribute(NAME));

            startNode.setDescription(loadCDATA(Util4Deserializer.child(startNodeElem, DESCRIPTION)));
            startNode.setDisplayName(startNodeElem.getAttribute(DISPLAY_NAME));

            Element decoratorElem = Util4Deserializer.child(startNodeElem, FEATURES);
            if (decoratorElem != null) {
                boolean find = false;
                Element normalStartFeatureElm = Util4Deserializer.child(decoratorElem, NORMAL_START_FEATURE);
                if (normalStartFeatureElm != null) {
                    //
                    find = true;
                }

                Element catchCompensationFeatureElm = Util4Deserializer.child(decoratorElem,
                        CATCH_COMPENSATION_FEATURE);
                if (catchCompensationFeatureElm != null && !find) {
                    CatchCompensationFeatureImpl catchCompensationFeature = new CatchCompensationFeatureImpl();
                    catchCompensationFeature
                            .setCompensationCode(catchCompensationFeatureElm.getAttribute(COMPENSATION_CODE));

                    String attachedToActId = catchCompensationFeatureElm.getAttribute(ATTACHED_TO_ACTIVITY);
                    if (attachedToActId != null) {
                        catchCompensationFeature
                                .setAttachedToActivity((Activity) subflow.findWFElementById(attachedToActId));
                    }

                    startNode.setFeature(catchCompensationFeature);
                    find = true;
                }

                Element catchFaultFeatureElm = Util4Deserializer.child(decoratorElem, CATCH_FAULT_FEATURE);
                if (catchFaultFeatureElm != null && !find) {
                    CatchFaultFeatureImpl catchFaultFeature = new CatchFaultFeatureImpl();
                    catchFaultFeature.setErrorCode(catchFaultFeatureElm.getAttribute(ERROR_CODE));

                    String attachedToActId = catchFaultFeatureElm.getAttribute(ATTACHED_TO_ACTIVITY);
                    if (attachedToActId != null) {
                        catchFaultFeature
                                .setAttachedToActivity((Activity) subflow.findWFElementById(attachedToActId));
                    }

                    startNode.setFeature(catchFaultFeature);
                    find = true;
                }

                Element timerStartFeatureElm = Util4Deserializer.child(decoratorElem, TIMER_START_FEATURE);
                if (timerStartFeatureElm != null && !find) {
                    TimerStartFeatureImpl timerStartDec = new TimerStartFeatureImpl();

                    String timerOperationName = timerStartFeatureElm.getAttribute(TIMER_OPERATION_NAME);
                    timerStartDec.setTimerOperationName(TimerOperationName.fromValue(timerOperationName));

                    String attachedToActId = timerStartFeatureElm.getAttribute(ATTACHED_TO_ACTIVITY);
                    if (attachedToActId != null) {
                        timerStartDec.setAttachedToActivity((Activity) subflow.findWFElementById(attachedToActId));
                    }

                    String cancelAttachedToAct = timerStartFeatureElm.getAttribute(IS_CANCEL_ATTACHED_TO_ACTIVITY);
                    if (cancelAttachedToAct != null) {
                        try {
                            timerStartDec.setCancelAttachedToActivity(Boolean.parseBoolean(cancelAttachedToAct));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                    Element startTimeElem = Util4Deserializer.child(timerStartFeatureElm, START_TIME_EXPRESSION);
                    if (startTimeElem != null) {
                        timerStartDec.setStartTimeExpression(
                                this.createExpression(Util4Deserializer.child(startTimeElem, EXPRESSION)));
                    }

                    Element endTimeElem = Util4Deserializer.child(timerStartFeatureElm, END_TIME_EXPRESSION);
                    if (endTimeElem != null) {
                        timerStartDec.setEndTimeExpression(
                                this.createExpression(Util4Deserializer.child(endTimeElem, EXPRESSION)));
                    }

                    Element intervalElem = Util4Deserializer.child(timerStartFeatureElm,
                            REPEAT_INTERVAL_EXPRESSION);
                    if (intervalElem != null) {
                        timerStartDec.setRepeatIntervalExpression(
                                this.createExpression(Util4Deserializer.child(intervalElem, EXPRESSION)));
                    }

                    Element repeatCountElem = Util4Deserializer.child(timerStartFeatureElm,
                            REPEAT_COUNT_EXPRESSION);
                    if (repeatCountElem != null) {
                        timerStartDec.setRepeatCountExpression(
                                this.createExpression(Util4Deserializer.child(repeatCountElem, EXPRESSION)));
                    }

                    Element cronElem = Util4Deserializer.child(timerStartFeatureElm, CRON_EXPRESSION);
                    if (cronElem != null) {
                        timerStartDec.setCronExpression(
                                this.createExpression(Util4Deserializer.child(cronElem, EXPRESSION)));
                    }
                    startNode.setFeature(timerStartDec);
                    find = true;
                }

                Element webserviceStartElement = Util4Deserializer.child(decoratorElem, WEBSERVICE_START_FEATURE);
                if (webserviceStartElement != null && !find) {
                    WebserviceStartFeatureImpl wsStartFeatureImpl = new WebserviceStartFeatureImpl();
                    ServiceBinding serviceBinding = this.loadServiceBinding(subflow,
                            Util4Deserializer.child(webserviceStartElement, SERVICE_BINDING));
                    wsStartFeatureImpl.setServiceBinding(serviceBinding);
                    startNode.setFeature(wsStartFeatureImpl);
                }
            }

            loadExtendedAttributes(startNode.getExtendedAttributes(),
                    Util4Deserializer.child(startNodeElem, EXTENDED_ATTRIBUTES));

            startNodes.add(startNode);
        }
    }

    /**
     * @param subflow
     * @param endNodes
     * @param element
     * @throws DeserializerException
     */
    protected void loadEndNodes(SubProcess subflow, List<EndNode> endNodes, Element endNodesElem)
            throws DeserializerException {

        if (endNodesElem == null) {
            return;
        }
        endNodes.clear();

        List<Element> endNodesElms = Util4Deserializer.children(endNodesElem, END_NODE);
        Iterator<Element> iter = endNodesElms.iterator();
        while (iter.hasNext()) {
            Element elm = iter.next();
            EndNode endNode = new EndNodeImpl(subflow, elm.getAttribute(NAME));

            endNode.setDescription(loadCDATA(Util4Deserializer.child(elm, DESCRIPTION)));
            endNode.setDisplayName(elm.getAttribute(DISPLAY_NAME));

            Element featuresElem = Util4Deserializer.child(elm, FEATURES);
            if (featuresElem != null) {
                boolean find = false;
                Element normalEndFeatureElm = Util4Deserializer.child(featuresElem, NORMAL_END_FEATURE);
                if (normalEndFeatureElm != null) {
                    //
                    find = true;
                }

                Element throwCompensationFeatureElm = Util4Deserializer.child(featuresElem,
                        THROW_COMPENSATION_FEATURE);
                if (throwCompensationFeatureElm != null && !find) {
                    ThrowCompensationFeatureImpl throwCompensationFeature = new ThrowCompensationFeatureImpl();
                    String compensationCodes = throwCompensationFeatureElm.getAttribute(COMPENSATION_CODES);
                    if (compensationCodes != null) {
                        StringTokenizer tokenizer = new StringTokenizer(compensationCodes, ",");
                        while (tokenizer.hasMoreTokens()) {
                            throwCompensationFeature.addCompensationCode(tokenizer.nextToken());
                        }
                    } else {
                        //?compensation code
                        throwCompensationFeature
                                .addCompensationCode(CatchCompensationFeature.CATCH_ALL_COMPENSATION);
                    }
                    endNode.setFeature(throwCompensationFeature);
                    find = true;
                }

                Element throwFaultFeatureElm = Util4Deserializer.child(featuresElem, THROW_FAULT_FEATURE);
                if (throwFaultFeatureElm != null && !find) {
                    ThrowFaultFeatureImpl throwFaultFeature = new ThrowFaultFeatureImpl();
                    throwFaultFeature.setErrorCode(throwFaultFeatureElm.getAttribute(ERROR_CODE));

                    endNode.setFeature(throwFaultFeature);
                    find = true;
                }

                Element throwTerminationFeatureElm = Util4Deserializer.child(featuresElem,
                        THROW_TERMINATION_FEATURE);
                if (throwTerminationFeatureElm != null && !find) {
                    endNode.setFeature(new ThrowTerminationFeatureImpl());
                    find = true;
                }
            }

            loadExtendedAttributes(endNode.getExtendedAttributes(),
                    Util4Deserializer.child(elm, EXTENDED_ATTRIBUTES));
            endNodes.add(endNode);
        }
    }

    /**
     * @param wp
     * @param routers
     * @param element
     * @throws DeserializerException
     */
    protected void loadRouters(SubProcess wp, List<Router> routers, Element element) throws DeserializerException {

        if (element == null) {
            return;
        }
        routers.clear();

        List<Element> synchronizerElms = Util4Deserializer.children(element, ROUTER);
        Iterator<Element> iter = synchronizerElms.iterator();
        while (iter.hasNext()) {
            Element elm = iter.next();
            Router router = new RouterImpl(wp, elm.getAttribute(NAME));

            router.setDescription(this.loadCDATA(Util4Deserializer.child(elm, DESCRIPTION)));
            router.setDisplayName(elm.getAttribute(DISPLAY_NAME));

            loadExtendedAttributes(router.getExtendedAttributes(),
                    Util4Deserializer.child(elm, EXTENDED_ATTRIBUTES));

            Element featuresElm = Util4Deserializer.child(elm, FEATURES);
            if (featuresElm != null) {
                Element fElm = Util4Deserializer.child(featuresElm, DEFAULT_ROUTER_FEATURE);
                if (fElm != null) {
                    router.setFeature(new DefaultRouterFeature());
                }

                fElm = Util4Deserializer.child(featuresElm, ANDJOIN_ANDSPLIT_FEATURE);
                if (fElm != null) {
                    router.setFeature(new AndJoinAndSplitRouterFeature());
                }
                fElm = Util4Deserializer.child(featuresElm, XORJOIN_XORSPLIT_FEATURE);
                if (fElm != null) {
                    router.setFeature(new XOrJoinXOrSplitRouterFeature());
                }
                fElm = Util4Deserializer.child(featuresElm, ORJOIN_ORSPLIT_FEATURE);
                if (fElm != null) {
                    router.setFeature(new OrJoinOrSplitRouterFeature());
                }
                fElm = Util4Deserializer.child(featuresElm, CUSTOMIZED_JOIN_SPLIT_FEATURE);
                if (fElm != null) {
                    CustomizedRouterFeature routerFeature = new CustomizedRouterFeature();
                    router.setFeature(routerFeature);
                    String joinEvaluator = Util4Deserializer.elementAsString(fElm, JOIN_EVALUATOR);
                    if (!StringUtils.isEmpty(joinEvaluator)) {
                        routerFeature.setJoinEvaluatorClass(joinEvaluator);
                    }
                    String splitEvaluator = Util4Deserializer.elementAsString(fElm, SPLIT_EVALUATOR);
                    if (!StringUtils.isEmpty(splitEvaluator)) {
                        routerFeature.setSplitEvaluatorClass(splitEvaluator);
                    }

                }
            }

            routers.add(router);
        }
    }

    /**
     * @param subflow
     * @param activities
     * @param element
     * @throws DeserializerException
     */
    protected void loadActivities(SubProcess subflow, List<Activity> activities, Element element)
            throws DeserializerException {

        if (element == null) {
            // log.debug("Activites element was null");
            return;
        }

        List<Element> activitElements = Util4Deserializer.children(element, ACTIVITY);
        activities.clear();
        Iterator<Element> iter = activitElements.iterator();
        while (iter.hasNext()) {
            Element activityElement = iter.next();

            ActivityImpl activity = new ActivityImpl(subflow, activityElement.getAttribute(NAME));

            activity.setDisplayName(activityElement.getAttribute(DISPLAY_NAME));
            activity.setDescription(loadCDATA(Util4Deserializer.child(activityElement, DESCRIPTION)));

            Duration du = this.createDuration(activityElement.getAttribute(DURATION));
            activity.setDuration(du);
            activity.setPriority(activityElement.getAttribute(PRIORITY));
            String loopStrategy = activityElement.getAttribute(LOOP_STRATEGY);
            activity.setLoopStrategy(LoopStrategy.fromValue(loopStrategy));

            //Load Service Binding
            activity.setServiceBinding(
                    loadServiceBinding(subflow, Util4Deserializer.child(activityElement, SERVICE_BINDING)));

            //Load Resource Binding
            loadResourceBinding(subflow, activity, Util4Deserializer.child(activityElement, RESOURCE_BINDING));

            loadEventListeners(activity, activity.getEventListeners(),
                    Util4Deserializer.child(activityElement, EVENT_LISTENERS));

            loadEventListeners(activity, activity.getWorkItemEventListeners(),
                    Util4Deserializer.child(activityElement, WORKITEM_EVENT_LISTENERS));

            loadExtendedAttributes(activity.getExtendedAttributes(),
                    Util4Deserializer.child(activityElement, EXTENDED_ATTRIBUTES));

            //Load Porperties
            this.loadProperties(activity, activity.getProperties(),
                    Util4Deserializer.child(activityElement, PROPERTIES));

            activities.add(activity);
        }
    }

    protected void loadResourceBinding(SubProcess subflow, Activity activity, Element resourceBindingElem)
            throws DeserializerException {
        if (resourceBindingElem == null)
            return;

        WorkflowProcess workflowProcess = (WorkflowProcess) subflow.getParent();

        ResourceBindingImpl resourceBinding = new ResourceBindingImpl();
        resourceBinding.setDisplayName(resourceBindingElem.getAttribute(DISPLAY_NAME));
        String assignmentStrategy = resourceBindingElem.getAttribute(ASSIGNMENT_STRATEGY);
        resourceBinding.setAssignmentStrategy(WorkItemAssignmentStrategy.fromValue(assignmentStrategy));

        Element administratorsElem = Util4Deserializer.child(resourceBindingElem, ADMINISTRATORS);
        if (administratorsElem != null) {
            List<Element> resourceRefElems = Util4Deserializer.children(administratorsElem, RESOURCE_REF);
            if (resourceRefElems != null) {
                for (Element elm : resourceRefElems) {
                    String resourceId = elm.getAttribute(RESOURCE_ID);

                    ResourceDef resource = workflowProcess.getResource(resourceId);
                    if (resource == null) {
                        throw new DeserializerException("Resource not found,resource id = " + resourceId);
                    }

                    //               Element prameterAssignmentsElem = Util4Deserializer.child(elm, PARAMETER_ASSIGNMENTS);
                    //               if (prameterAssignmentsElem!=null){
                    //                  List<Element> parameterAssignmentElems = Util4Deserializer.children(prameterAssignmentsElem, PARAMETER_ASSIGNMENT);
                    //                  for (Element parameterAssignmentElm : parameterAssignmentElems){
                    //                     AssignmentImpl assignment = new AssignmentImpl();
                    //                     Element fromElm = Util4Deserializer.child(parameterAssignmentElm, FROM);
                    //                     
                    //                     assignment.setFrom(this.createExpression(Util4Deserializer.child(fromElm, EXPRESSION)));
                    //                     
                    //                     
                    //                     assignment.setTo(Util4Deserializer.elementAsString(parameterAssignmentElm,TO));
                    //                     
                    //                     resourceRef.getParameterAssignments().add(assignment);
                    //                  }
                    //               }

                    resourceBinding.addAdministratorRef(resourceId);
                } //for (Element elm : resourceRefElems)
            }
        }

        Element potentialOwnersElem = Util4Deserializer.child(resourceBindingElem, POTENTIAL_OWNERS);
        if (potentialOwnersElem != null) {
            List<Element> resourceRefElems = Util4Deserializer.children(potentialOwnersElem, RESOURCE_REF);
            if (resourceRefElems != null) {
                for (Element elm : resourceRefElems) {

                    String resourceId = elm.getAttribute(RESOURCE_ID);

                    ResourceDef resource = workflowProcess.getResource(resourceId);
                    if (resource == null) {
                        throw new DeserializerException("Resource not found,resource id = " + resourceId);
                    }

                    //               Element prameterAssignmentsElem = Util4Deserializer.child(elm, PARAMETER_ASSIGNMENTS);
                    //               if (prameterAssignmentsElem!=null){
                    //                  List<Element> parameterAssignmentElems = Util4Deserializer.children(prameterAssignmentsElem, PARAMETER_ASSIGNMENT);
                    //                  for (Element parameterAssignmentElm : parameterAssignmentElems){
                    //                     ParameterAssignmentImpl assignment = new ParameterAssignmentImpl();
                    //                     Element fromElm = Util4Deserializer.child(parameterAssignmentElm, FROM);
                    //                     
                    //                     assignment.setFrom(this.createExpression(Util4Deserializer.child(fromElm, EXPRESSION)));
                    //                     assignment.setTo(Util4Deserializer.elementAsString(parameterAssignmentElm,TO));
                    //                     
                    //                     resourceRef.getParameterAssignments().add(assignment);
                    //                  }
                    //               }

                    resourceBinding.addPotentialOwnerRef(resource.getId());
                } //for (Element elm : resourceRefElems)
            }
        }

        Element readersElem = Util4Deserializer.child(resourceBindingElem, READERS);
        if (readersElem != null) {
            List<Element> resourceRefElems = Util4Deserializer.children(readersElem, RESOURCE_REF);
            if (resourceRefElems != null) {
                for (Element elm : resourceRefElems) {
                    String resourceId = elm.getAttribute(RESOURCE_ID);

                    ResourceDef resource = workflowProcess.getResource(resourceId);
                    if (resource == null) {
                        throw new DeserializerException("Resource not found,resource id = " + resourceId);
                    }

                    //               Element prameterAssignmentsElem = Util4Deserializer.child(elm, PARAMETER_ASSIGNMENTS);
                    //               if (prameterAssignmentsElem!=null){
                    //                  List<Element> parameterAssignmentElems = Util4Deserializer.children(prameterAssignmentsElem, PARAMETER_ASSIGNMENT);
                    //                  for (Element parameterAssignmentElm : parameterAssignmentElems){
                    //                     ParameterAssignmentImpl assignment = new ParameterAssignmentImpl();
                    //                     Element fromElm = Util4Deserializer.child(parameterAssignmentElm, FROM);
                    //                     
                    //                     assignment.setFrom(this.createExpression(Util4Deserializer.child(fromElm, EXPRESSION)));
                    //                     assignment.setTo(Util4Deserializer.elementAsString(parameterAssignmentElm,TO));
                    //                     
                    //                     resourceRef.getParameterAssignments().add(assignment);
                    //                  }
                    //               }

                    resourceBinding.addReaderRef(resource.getId());
                } //for (Element elm : resourceRefElems)
            }
        }

        activity.setResourceBinding(resourceBinding);
    }

    protected ServiceBinding loadServiceBinding(SubProcess subflow, Element serviceBindingElem)
            throws DeserializerException {
        if (serviceBindingElem == null)
            return null;
        WorkflowProcess workflowProcess = (WorkflowProcess) subflow.getParent();

        ServiceBindingImpl serviceBinding = new ServiceBindingImpl();
        serviceBinding.setServiceId(serviceBindingElem.getAttribute(SERVICE_ID));
        serviceBinding.setOperationName(serviceBindingElem.getAttribute(OPERATION_NAME));

        //ServiceBinding?Service?Operation???id??2012-06-10
        //      ServiceDef service = workflowProcess.getService(serviceBinding.getServiceId());
        //      if (service==null){
        //         throw new DeserializerException("Service not found ,id=["+serviceBinding.getServiceId()+"]");
        //      }
        //      serviceBinding.setService(service);

        //      if (service.getInterface()==null) return serviceBinding;//interface2012-02-03 
        //      InterfaceDef interfaceDef = service.getInterface();
        //      OperationDef op = interfaceDef.getOperation(serviceBinding.getOperationName());
        //      if (op==null){
        //         throw new DeserializerException("Operation not found ,service id=["+serviceBinding.getServiceId()+"],opreation name=["+serviceBinding.getOperationName()+"]");
        //      }
        //      serviceBinding.setOperation(op);

        Element inputAssignmentsElem = Util4Deserializer.child(serviceBindingElem, INPUT_ASSIGNMENTS);
        if (inputAssignmentsElem != null) {
            List<Element> inputAssignmentElems = Util4Deserializer.children(inputAssignmentsElem, INPUT_ASSIGNMENT);
            if (inputAssignmentElems != null) {
                for (Element inputAssignmentElm : inputAssignmentElems) {
                    Assignment inputAssignment = new AssignmentImpl();
                    Element fromElm = Util4Deserializer.child(inputAssignmentElm, FROM);
                    Expression from = this.createExpression(Util4Deserializer.child(fromElm, EXPRESSION));
                    inputAssignment.setFrom(from);
                    Element toElm = Util4Deserializer.child(inputAssignmentElm, TO);
                    Expression to = this.createExpression(Util4Deserializer.child(toElm, EXPRESSION));
                    inputAssignment.setTo(to);

                    serviceBinding.getInputAssignments().add(inputAssignment);
                }
            }
        }

        Element outputAssignmentsElem = Util4Deserializer.child(serviceBindingElem, OUTPUT_ASSIGNMENTS);
        if (outputAssignmentsElem != null) {
            List<Element> outputAssignmentElems = Util4Deserializer.children(outputAssignmentsElem,
                    OUTPUT_ASSIGNMENT);
            if (outputAssignmentElems != null) {
                for (Element outputAssignmentElm : outputAssignmentElems) {
                    AssignmentImpl outputAssignment = new AssignmentImpl();
                    Element fromElm = Util4Deserializer.child(outputAssignmentElm, FROM);
                    Expression from = this.createExpression(Util4Deserializer.child(fromElm, EXPRESSION));

                    outputAssignment.setFrom(from);

                    Element toElm = Util4Deserializer.child(outputAssignmentElm, TO);
                    Expression to = this.createExpression(Util4Deserializer.child(toElm, EXPRESSION));
                    outputAssignment.setTo(to);
                    serviceBinding.getOutputAssignments().add(outputAssignment);
                }
            }
        }
        return serviceBinding;
        //      Element propOverridesElem = Util4Deserializer.child(serviceBindingElem, PROP_OVERRIDES);
        //      if (propOverridesElem!=null){
        //         List<Element> propOverrideElems = Util4Deserializer.children(propOverridesElem, PROP_OVERRIDE);
        //         if (propOverrideElems!=null){
        //            for (Element propOverrideElm : propOverrideElems){
        //               PropOverrideImpl propOverride = new PropOverrideImpl();
        //               propOverride.setPropGroupName(propOverrideElm.getAttribute(PROP_GROUP_NAME));
        //               propOverride.setPropName(propOverrideElm.getAttribute(PROP_NAME));
        //               propOverride.setValue(propOverrideElm.getAttribute(VALUE));
        //               
        //               serviceBinding.getPropOverrides().add(propOverride);
        //            }
        //         }
        //      }
        //      

    }

    /**
     * @param subflow
     * @param transitionsElement
     * @throws DeserializerException
     */
    protected void loadTransitions(SubProcess subflow, List<Transition> transitions, Element transitionsElement)
            throws DeserializerException {

        if (transitionsElement == null) {
            return;
        }

        transitions.clear();

        List<Element> transitionElements = Util4Deserializer.children(transitionsElement, TRANSITION);

        Iterator<Element> iter = transitionElements.iterator();
        while (iter.hasNext()) {
            Element transitionElement = iter.next();
            Transition transition = createTransition(subflow, transitionElement);
            transitions.add(transition);
            Node fromNode = transition.getFromNode();
            Node toNode = transition.getToNode();
            if (fromNode != null) {
                fromNode.getLeavingTransitions().add(transition);
            }
            if (toNode != null) {
                toNode.getEnteringTransitions().add(transition);
            }
        }
    }

    /**
     * @param subflow
     * @param element
     * @return
     * @throws DeserializerException
     */
    protected Transition createTransition(SubProcess subflow, Element element) throws DeserializerException {
        String fromNodeId = element.getAttribute(FROM);
        String toNodeId = element.getAttribute(TO);
        Node fromNode = (Node) subflow.findWFElementById(fromNodeId);
        Node toNode = (Node) subflow.findWFElementById(toNodeId);

        TransitionImpl transition = new TransitionImpl(subflow, element.getAttribute(NAME), fromNode, toNode);

        transition.setDisplayName(element.getAttribute(DISPLAY_NAME));
        transition.setDescription(this.loadCDATA(Util4Deserializer.child(element, DESCRIPTION)));

        String isLoop = element.getAttribute(IS_LOOP);
        if (isLoop != null) {
            try {
                transition.setIsLoop(Boolean.parseBoolean(isLoop));
            } catch (Exception e) {

            }
        }

        String isDefault = element.getAttribute(IS_DEFAULT);
        if (isDefault != null) {
            try {
                transition.setDefault(Boolean.parseBoolean(isDefault));
            } catch (Exception e) {

            }
        }

        Element conditionElement = Util4Deserializer.child(element, CONDITION);

        if (conditionElement != null) {
            Element expressionElem = Util4Deserializer.child(conditionElement, EXPRESSION);
            transition.setCondition(createExpression(expressionElem));
        }

        // load extended attributes
        Map<String, String> extAttrs = transition.getExtendedAttributes();
        loadExtendedAttributes(extAttrs, Util4Deserializer.child(element, EXTENDED_ATTRIBUTES));

        return transition;
    }

    protected Expression createExpression(Element expressionElement) {
        if (expressionElement != null) {
            ExpressionImpl exp = new ExpressionImpl();
            exp.setLanguage(expressionElement.getAttribute(LANGUAGE));
            exp.setName(expressionElement.getAttribute(NAME));
            exp.setDisplayName(expressionElement.getAttribute(DISPLAY_NAME));
            String dataTypeStr = expressionElement.getAttribute(DATA_TYPE);
            if (dataTypeStr != null && !dataTypeStr.trim().equals("")) {
                QName qname = QName.valueOf(dataTypeStr);
                exp.setDataType(qname);
            }

            Element bodyElement = Util4Deserializer.child(expressionElement, BODY);

            String body = this.loadCDATA(bodyElement);
            exp.setBody(body);

            Element namespacePrefixUriMapElem = Util4Deserializer.child(expressionElement,
                    this.NAMESPACE_PREFIX_URI_MAP);

            if (namespacePrefixUriMapElem != null) {
                List<Element> children = Util4Deserializer.children(namespacePrefixUriMapElem, ENTRY);
                if (children != null && children.size() > 0) {
                    for (Element elem : children) {
                        String prefix = elem.getAttribute(NAME);
                        String uri = elem.getAttribute(VALUE);
                        exp.getNamespaceMap().put(prefix, uri);
                    }
                }
            }

            return exp;
        } else {
            ExpressionImpl exp = new ExpressionImpl();
            exp.setLanguage(ScriptLanguages.UNIFIEDJEXL.name());
            exp.setDataType(
                    new QName(NameSpaces.JAVA.getUri(), String.class.getName(), NameSpaces.JAVA.getPrefix()));
            exp.setName("WorkItemSubject");
            exp.setDisplayName("");// 
            exp.setBody("");
            return exp;
        }
    }

    /**
     * @param parent
     * @param dataFields
     * @param propertiesElement
     * @throws DeserializerException
     */
    protected void loadProperties(WorkflowElement parent, List<Property> dataFields, Element propertiesElement)
            throws DeserializerException {

        if (propertiesElement == null) {
            return;
        }

        List<Element> datafieldsElement = Util4Deserializer.children(propertiesElement, PROPERTY);
        dataFields.clear();
        Iterator<Element> iter = datafieldsElement.iterator();
        while (iter.hasNext()) {
            Element dataFieldElement = iter.next();
            dataFields.add(createProperty(parent, dataFieldElement));
        }
    }

    /**
     * @param parent
     * @param element
     * @return
     * @throws DeserializerException
     */
    protected Property createProperty(WorkflowElement parent, Element element) throws DeserializerException {
        if (element == null) {
            return null;
        }
        String dataTypeStr = element.getAttribute(DATA_TYPE);
        QName dataType = QName.valueOf(dataTypeStr);
        if (dataType == null) {
            dataType = new QName(NameSpaces.JAVA.getUri(), "java.lang.String");
        }

        Property dataField = new PropertyImpl(parent, element.getAttribute(NAME));

        dataField.setDataType(dataType);

        dataField.setDisplayName(element.getAttribute(DISPLAY_NAME));
        dataField.setInitialValueAsString(element.getAttribute(INIT_VALUE));
        dataField.setDescription(loadCDATA(Util4Deserializer.child(element, DESCRIPTION)));

        return dataField;
    }

    /**
     * @param extendedAttributes
     * @param element
     * @throws DeserializerException
     */
    protected void loadExtendedAttributes(Map<String, String> extendedAttributes, Element element)
            throws DeserializerException {

        if (element == null) {
            return;
        }
        extendedAttributes.clear();
        List<Element> extendAttributeElementsList = Util4Deserializer.children(element, EXTENDED_ATTRIBUTE);
        Iterator<Element> iter = extendAttributeElementsList.iterator();
        while (iter.hasNext()) {
            Element extAttrElement = iter.next();
            String name = extAttrElement.getAttribute(NAME);
            String value = extAttrElement.getAttribute(VALUE);

            extendedAttributes.put(name, value);

        }
    }

    protected String loadCDATA(Element cdataElement) {
        if (cdataElement == null) {
            return "";
        } else {
            String data = cdataElement.getTextContent();
            if (data == null)
                return data;
            else {
                if (data.trim().equals(Label.CONTENT_FROM_WORKFLOW_ELEMENT)) {
                    return Label.CONTENT_FROM_WORKFLOW_ELEMENT;
                } else if (data.trim().equals(Label.CONTENT_IGNORE)) {
                    return Label.CONTENT_IGNORE;
                } else if (useJDKTransformerFactory) {
                    if (data.startsWith(" ")) {
                        return data.substring(1);//
                    }
                }
                return data;
            }

        }
    }
}