Package org.jbpm.designer.bpmn2.impl

Source Code of org.jbpm.designer.bpmn2.impl.Bpmn2JsonMarshaller

/*
* Copyright 2010 JBoss Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.designer.bpmn2.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;

import bpsim.*;
import bpsim.impl.BpsimPackageImpl;
import org.jboss.drools.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator;
import org.eclipse.bpmn2.*;
import org.eclipse.bpmn2.Error;
import org.eclipse.bpmn2.Process;
import org.eclipse.bpmn2.di.BPMNDiagram;
import org.eclipse.bpmn2.di.BPMNEdge;
import org.eclipse.bpmn2.di.BPMNPlane;
import org.eclipse.bpmn2.di.BPMNShape;
import org.eclipse.dd.dc.Bounds;
import org.eclipse.dd.dc.Point;
import org.eclipse.dd.di.DiagramElement;
import org.eclipse.emf.ecore.util.FeatureMap;
import org.jboss.drools.impl.DroolsPackageImpl;
import org.jbpm.designer.web.profile.IDiagramProfile;

/**
* @author Antoine Toulme
* @author Tihomir Surdilovic
*
* a marshaller to transform BPMN 2.0 elements into JSON format.
*
*/
public class Bpmn2JsonMarshaller {
  public static final String defaultBgColor_Activities = "#fafad2";
  public static final String defaultBgColor_Events = "#f5deb3";
    public static final String defaultBgColor_StartEvents = "#9acd32";
    public static final String defaultBgColor_EndEvents = "#ff6347";
    public static final String defaultBgColor_DataObjects = "#C0C0C0";
    public static final String defaultBgColor_CatchingEvents = "#f5deb3";
    public static final String defaultBgColor_ThrowingEvents = "#8cabff";
    public static final String defaultBgColor_Gateways = "#f0e68c";
    public static final String defaultBgColor_Swimlanes = "#ffffff";

  public static final String defaultBrColor = "#000000";
    public static final String defaultBrColor_CatchingEvents = "#a0522d";
    public static final String defaultBrColor_ThrowingEvents = "#008cec";
    public static final String defaultBrColor_Gateways = "#a67f00";

  public static final String defaultFontColor = "#000000";
  public static final String defaultSequenceflowColor = "#000000";

    private static final List<String> defaultTypesList = Arrays.asList("Object", "Boolean", "Float", "Integer", "List", "String");
 
  private Map<String, DiagramElement> _diagramElements = new HashMap<String, DiagramElement>();
  private Map<String,Association> _diagramAssociations = new HashMap<String, Association>();
  private Scenario _simulationScenario = null;
  private static final Logger _logger = LoggerFactory.getLogger(Bpmn2JsonMarshaller.class);
  private IDiagramProfile profile;
 
  public void setProfile(IDiagramProfile profile) {
      this.profile = profile;
  }

    public String marshall(Definitions def, String preProcessingData) throws IOException {
      DroolsPackageImpl.init();
        BpsimPackageImpl.init();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        JsonFactory f = new JsonFactory();
        JsonGenerator generator = f.createJsonGenerator(baos, JsonEncoding.UTF8);
        if(def.getRelationships() != null && def.getRelationships().size() > 0) {
          // current support for single relationship
          Relationship relationship = def.getRelationships().get(0);
            for(ExtensionAttributeValue extattrval : relationship.getExtensionValues()) {
                FeatureMap extensionElements = extattrval.getValue();
                @SuppressWarnings("unchecked")
                List<BPSimDataType> bpsimExtensions = (List<BPSimDataType>) extensionElements.get(BpsimPackage.Literals.DOCUMENT_ROOT__BP_SIM_DATA, true);
                if(bpsimExtensions != null && bpsimExtensions.size() > 0) {
                    BPSimDataType processAnalysis = bpsimExtensions.get(0);
                  if(processAnalysis.getScenario() != null && processAnalysis.getScenario().size() > 0) {
                    _simulationScenario = processAnalysis.getScenario().get(0);
                  }
                }
          }
         
        }
        if(preProcessingData == null || preProcessingData.length() < 1) {
            preProcessingData = "ReadOnlyService";
        }
        marshallDefinitions(def, generator, preProcessingData);
        generator.close();
       
        return baos.toString("UTF-8");
    }
   
    private void linkSequenceFlows(List<FlowElement> flowElements) {
      Map<String, FlowNode> nodes = new HashMap<String, FlowNode>();
      for (FlowElement flowElement: flowElements) {
        if (flowElement instanceof FlowNode) {
          nodes.put(flowElement.getId(), (FlowNode) flowElement);
          if (flowElement instanceof SubProcess) {
            linkSequenceFlows(((SubProcess) flowElement).getFlowElements());
          }
        }
      }
      for (FlowElement flowElement: flowElements) {
        if (flowElement instanceof SequenceFlow) {
          SequenceFlow sequenceFlow = (SequenceFlow) flowElement;
          if (sequenceFlow.getSourceRef() == null && sequenceFlow.getTargetRef() == null) {
            String id = sequenceFlow.getId();
            try {
              String[] subids = id.split("-_");
              String id1 = subids[0];
              String id2 = "_" + subids[1];
              FlowNode source = nodes.get(id1);
              if (source != null) {
                sequenceFlow.setSourceRef(source);
              }
              FlowNode target = nodes.get(id2);
              if (target != null) {
                sequenceFlow.setTargetRef(target);
              }
            } catch (Throwable t) {
              // Do nothing
            }
          }
        }
      }
    }
   
    protected void marshallDefinitions(Definitions def, JsonGenerator generator, String preProcessingData) throws JsonGenerationException, IOException {
        try{
          generator.writeStartObject();
          generator.writeObjectField("resourceId", def.getId());
          /**
           * "properties":{"name":"",
           * "documentation":"",
           * "auditing":"",
           * "monitoring":"",
           * "executable":"true",
           * "package":"com.sample",
           * "vardefs":"a,b,c,d",
           * "lanes" : "a,b,c",
           * "id":"",
           * "version":"",
           * "author":"",
           * "language":"",
           * "namespaces":"",
           * "targetnamespace":"",
           * "expressionlanguage":"",
           * "typelanguage":"",
           * "creationdate":"",
           * "modificationdate":""
           * }
           */
          Map<String, Object> props = new LinkedHashMap<String, Object>();
          props.put("namespaces", "");
          //props.put("targetnamespace", def.getTargetNamespace());
          props.put("targetnamespace", "http://www.omg.org/bpmn20");
          props.put("typelanguage", def.getTypeLanguage());
          props.put("name",unescapeXML(def.getName()));
          props.put("id", def.getId());
          props.put("expressionlanguage", def.getExpressionLanguage());
            // backwards compat for BZ 1048191
            if( def.getDocumentation() != null && def.getDocumentation().size() > 0 ) {
                props.put("documentation", def.getDocumentation().get(0).getText());
            }

          for (RootElement rootElement : def.getRootElements()) {
              if (rootElement instanceof Process) {
                  // have to wait for process node to finish properties and stencil marshalling
                  props.put("executable", ((Process) rootElement).isIsExecutable() + "");
                  props.put("id", rootElement.getId());
                    if( rootElement.getDocumentation() != null && rootElement.getDocumentation().size() > 0 ) {
                        props.put("documentation", rootElement.getDocumentation().get(0).getText());
                    }
                    Process pr = (Process) rootElement;
                    if(pr.getName() != null && pr.getName().length() > 0) {
                        props.put("processn", unescapeXML(((Process) rootElement).getName()));
                    }

                  List<Property> processProperties = ((Process) rootElement).getProperties();
                  if(processProperties != null && processProperties.size() > 0) {
                      String propVal = "";
                      for(int i=0; i<processProperties.size(); i++) {
                          Property p = processProperties.get(i);
                          propVal += p.getId();
                          // check the structureRef value
                          if(p.getItemSubjectRef() != null && p.getItemSubjectRef().getStructureRef() != null) {
                              propVal += ":" + p.getItemSubjectRef().getStructureRef();
                          }
                          if(i != processProperties.size()-1) {
                              propVal += ",";
                          }
                      }
                      props.put("vardefs", propVal);
                  }
                 
                  // packageName and version and adHoc are jbpm-specific extension attribute
                  Iterator<FeatureMap.Entry> iter = ((Process) rootElement).getAnyAttribute().iterator();
                  while(iter.hasNext()) {
                      FeatureMap.Entry entry = iter.next();
                      if(entry.getEStructuralFeature().getName().equals("packageName")) {
                          props.put("package", entry.getValue());
                      }
                     
                      if(entry.getEStructuralFeature().getName().equals("version")) {
                            props.put("version", entry.getValue());
                        }
                     
                      if(entry.getEStructuralFeature().getName().equals("adHoc")) {
                        props.put("adhocprocess", entry.getValue());
                      }
                  }
                 
                  // process imports, custom description and globals extension elements
                    String allImports = "";
                  if((rootElement).getExtensionValues() != null && (rootElement).getExtensionValues().size() > 0) {
                      String importsStr = "";
                      String globalsStr = "";

                      for(ExtensionAttributeValue extattrval : rootElement.getExtensionValues()) {
                          FeatureMap extensionElements = extattrval.getValue();
                         
                          @SuppressWarnings("unchecked")
                          List<ImportType> importExtensions = (List<ImportType>) extensionElements
                                                               .get(DroolsPackage.Literals.DOCUMENT_ROOT__IMPORT, true);
                          @SuppressWarnings("unchecked")
                          List<GlobalType> globalExtensions = (List<GlobalType>) extensionElements
                                                            .get(DroolsPackage.Literals.DOCUMENT_ROOT__GLOBAL, true);

                            List<MetaDataType> metadataExtensions = (List<MetaDataType>) extensionElements
                                    .get(DroolsPackage.Literals.DOCUMENT_ROOT__META_DATA, true);
                     
                          for(ImportType importType : importExtensions) {
                              importsStr += importType.getName();
                              importsStr += "|default,";
                          }
                         
                          for(GlobalType globalType : globalExtensions) {
                              globalsStr += (globalType.getIdentifier() + ":" + globalType.getType());
                              globalsStr += ",";
                          }

                            for(MetaDataType metaType : metadataExtensions) {
                                props.put("customdescription", metaType.getMetaValue());
                            }
                      }
                        allImports += importsStr;
                      if(globalsStr.length() > 0) {
                          if(globalsStr.endsWith(",")) {
                              globalsStr = globalsStr.substring(0, globalsStr.length() - 1);
                          }
                          props.put("globals", globalsStr);
                      }
                  }
                    // definitions imports (wsdl)
                    List<org.eclipse.bpmn2.Import> wsdlImports = def.getImports();
                    if(wsdlImports != null) {
                        for(org.eclipse.bpmn2.Import imp : wsdlImports) {
                            allImports += imp.getLocation() + "|" + imp.getNamespace() + "|wsdl,";
                        }
                    }
                    if(allImports.endsWith(",")) {
                        allImports = allImports.substring(0, allImports.length() - 1);
                    }
                    props.put("imports", allImports);

                  // simulation
                  if(_simulationScenario != null && _simulationScenario.getScenarioParameters() != null) {
                    props.put("currency", _simulationScenario.getScenarioParameters().getBaseCurrencyUnit() == null ? "" : _simulationScenario.getScenarioParameters().getBaseCurrencyUnit());
                    props.put("timeunit", _simulationScenario.getScenarioParameters().getBaseTimeUnit().getName());
                  }
                  marshallProperties(props, generator);
                  marshallStencil("BPMNDiagram", generator);
                linkSequenceFlows(((Process) rootElement).getFlowElements());
                  marshallProcess((Process) rootElement, def, generator, preProcessingData);
              } else if (rootElement instanceof Interface) {
                  // TODO
              } else if (rootElement instanceof ItemDefinition) {
                    // TODO
                } else if (rootElement instanceof Resource) {
                  // TODO
              } else if (rootElement instanceof Error) {
                  // TODO
              } else if (rootElement instanceof Message) {
                  // TODO
              } else if (rootElement instanceof Signal) {
                    // TODO
                } else if (rootElement instanceof Escalation) {
                    // TODO
                } else if (rootElement instanceof Collaboration) {
                 
                } else {
                  _logger.warn("Unknown root element " + rootElement + ". This element will not be parsed.");
              }
          }
         
          generator.writeObjectFieldStart("stencilset");
          generator.writeObjectField("url", this.profile.getStencilSetURL());
          generator.writeObjectField("namespace", this.profile.getStencilSetNamespaceURL());
          generator.writeEndObject();
          generator.writeArrayFieldStart("ssextensions");
          generator.writeObject(this.profile.getStencilSetExtensionURL());
          generator.writeEndArray();
          generator.writeEndObject();
        } finally {
          _diagramElements.clear();
        }
    }
   
   
    /** protected void marshallMessage(Message message, Definitions def, JsonGenerator generator) throws JsonGenerationException, IOException {
        Map<String, Object> properties = new LinkedHashMap<String, Object>();
       
        generator.writeStartObject();
        generator.writeObjectField("resourceId", message.getId());
       
        properties.put("name", message.getName());
        if(message.getDocumentation() != null && message.getDocumentation().size() > 0) {
            properties.put("documentation", message.getDocumentation().get(0).getText());
        }
       
        marshallProperties(properties, generator);
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", "Message");
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();
        generator.writeArrayFieldStart("outgoing");
        generator.writeEndArray();
       
        generator.writeEndObject();
    } **/

    protected void marshallCallableElement(CallableElement callableElement, Definitions def, JsonGenerator generator) throws JsonGenerationException, IOException {
        generator.writeStartObject();
        generator.writeObjectField("resourceId", callableElement.getId());
       
        if (callableElement instanceof Choreography) {
            marshallChoreography((Choreography) callableElement, generator);
        } else if (callableElement instanceof Conversation) {
            marshallConversation((Conversation) callableElement, generator);
        } else if (callableElement instanceof GlobalChoreographyTask) {
            marshallGlobalChoreographyTask((GlobalChoreographyTask) callableElement, generator);
        } else if (callableElement instanceof GlobalTask) {
            marshallGlobalTask((GlobalTask) callableElement, generator);
        } else if (callableElement instanceof Process) {
            marshallProcess((Process) callableElement, def, generator, "");
        } else {
            throw new UnsupportedOperationException("TODO"); //TODO!
        }
        generator.writeEndObject();
    }

    protected void marshallProcess(Process process, Definitions def, JsonGenerator generator, String preProcessingData) throws JsonGenerationException, IOException {
      BPMNPlane plane = null;
      for (BPMNDiagram d: def.getDiagrams()) {
        if (d != null) {
          BPMNPlane p = d.getPlane();
          if (p != null) {
            if (p.getBpmnElement() == process) {
              plane = p;
              break;
            }
          }
        }
      }
      if (plane == null) {
        throw new IllegalArgumentException("Could not find BPMNDI information");
      }
        generator.writeArrayFieldStart("childShapes");
       
        List<String> laneFlowElementsIds = new ArrayList<String>();
        for(LaneSet laneSet : process.getLaneSets()) {
          for(Lane lane : laneSet.getLanes()) {
            // we only want to marshall lanes if we have the bpmndi info for them!
            if(findDiagramElement(plane, lane) != null) {
              laneFlowElementsIds.addAll( marshallLanes(lane, plane, generator, 0, 0, preProcessingData, def) );
            }
          }
        }
        for (FlowElement flowElement: process.getFlowElements()) {
          if( !laneFlowElementsIds.contains(flowElement.getId()) ) {
            marshallFlowElement(flowElement, plane, generator, 0, 0, preProcessingData, def);
          }
        }
       
        for (Artifact artifact: process.getArtifacts()) {
          marshallArtifact(artifact, plane, generator, 0, 0, preProcessingData, def);
        }
       
        generator.writeEndArray();
    }
   
    private void setCatchEventProperties(CatchEvent event, Map<String, Object> properties) {
        if(event.getOutputSet() != null) {
            List<DataOutput> dataOutputs = event.getOutputSet().getDataOutputRefs();
            StringBuffer doutbuff = new StringBuffer();
            for(DataOutput dout : dataOutputs) {
                doutbuff.append(dout.getName());
                doutbuff.append(",");
            }
            if(doutbuff.length() > 0) {
                doutbuff.setLength(doutbuff.length() - 1);
            }
            properties.put("dataoutput", doutbuff.toString());
       
            List<DataOutputAssociation> outputAssociations = event.getDataOutputAssociation();
            StringBuffer doutassociationbuff = new StringBuffer();
            for(DataOutputAssociation doa : outputAssociations) {
                String doaName = ((DataOutput)doa.getSourceRef().get(0)).getName();
                if(doaName != null && doaName.length() > 0) {
                    doutassociationbuff.append(((DataOutput)doa.getSourceRef().get(0)).getName());
                    doutassociationbuff.append("->");
                    doutassociationbuff.append(doa.getTargetRef().getId());
                    doutassociationbuff.append(",");
                }
            }
            if(doutassociationbuff.length() > 0) {
                doutassociationbuff.setLength(doutassociationbuff.length() - 1);
            }
            properties.put("dataoutputassociations", doutassociationbuff.toString());
        }
        // event definitions
        List<EventDefinition> eventdefs = event.getEventDefinitions();
        for(EventDefinition ed : eventdefs) {
            if(ed instanceof TimerEventDefinition) {
                TimerEventDefinition ted = (TimerEventDefinition) ed;
//                if(ted.getTimeDate() != null) {
//                    properties.put("timedate", ((FormalExpression) ted.getTimeDate()).getBody());
//                }
                if(ted.getTimeDuration() != null) {
                    properties.put("timeduration", ((FormalExpression) ted.getTimeDuration()).getBody());
                }
                if(ted.getTimeCycle() != null) {
                    properties.put("timecycle", ((FormalExpression) ted.getTimeCycle()).getBody());
                    if(((FormalExpression) ted.getTimeCycle()).getLanguage() != null) {
                      properties.put("timecyclelanguage", ((FormalExpression) ted.getTimeCycle()).getLanguage());
                    }
                }
            } else if( ed instanceof SignalEventDefinition) {
                if(((SignalEventDefinition) ed).getSignalRef() != null) {
                    properties.put("signalref", ((SignalEventDefinition) ed).getSignalRef());
                } else {
                    properties.put("signalref", "");
                }
            } else if( ed instanceof ErrorEventDefinition) {
                if(((ErrorEventDefinition) ed).getErrorRef() != null && ((ErrorEventDefinition) ed).getErrorRef().getErrorCode() != null) {
                    properties.put("errorref", ((ErrorEventDefinition) ed).getErrorRef().getErrorCode());
                } else {
                    properties.put("errorref", "");
                }
            } else if( ed instanceof ConditionalEventDefinition ) {
                FormalExpression conditionalExp = (FormalExpression) ((ConditionalEventDefinition) ed).getCondition();
                if(conditionalExp.getBody() != null) {
                    properties.put("conditionexpression", conditionalExp.getBody().replaceAll("\n", "\\\\n"));
                }
                if(conditionalExp.getLanguage() != null) {
                    String languageVal = conditionalExp.getLanguage();
                    if(languageVal.equals("http://www.jboss.org/drools/rule")) {
                        properties.put("conditionlanguage", "drools");
                    } else if(languageVal.equals("http://www.mvel.org/2.0")) {
                        properties.put("conditionlanguage", "mvel");
                    } else {
                        // default to drools
                        properties.put("conditionlanguage", "drools");
                    }
                }
            } else if( ed instanceof EscalationEventDefinition ) {
                if(((EscalationEventDefinition) ed).getEscalationRef() != null) {
                    Escalation esc = ((EscalationEventDefinition) ed).getEscalationRef();
                    if(esc.getEscalationCode() != null && esc.getEscalationCode().length() > 0) {
                        properties.put("escalationcode", esc.getEscalationCode());
                    } else {
                        properties.put("escalationcode", "");
                    }
                }
            } else if( ed instanceof MessageEventDefinition) {
                if(((MessageEventDefinition) ed).getMessageRef() != null) {
                    Message msg = ((MessageEventDefinition) ed).getMessageRef();
                    properties.put("messageref", msg.getId());
                }
            }  else if( ed instanceof CompensateEventDefinition) {
                if(((CompensateEventDefinition) ed).getActivityRef() != null) {
                    Activity act = ((CompensateEventDefinition) ed).getActivityRef();
                    properties.put("activityref", act.getName());
                }
            } 
        }
    }
   
    private void setThrowEventProperties(ThrowEvent event, Map<String, Object> properties) {
        if(event.getInputSet() != null) {
            List<DataInput> dataInputs = event.getInputSet().getDataInputRefs();
            StringBuffer dinbuff = new StringBuffer();
            for(DataInput din : dataInputs) {
                dinbuff.append(din.getName());
                dinbuff.append(",");
            }
            if(dinbuff.length() > 0) {
                dinbuff.setLength(dinbuff.length() - 1);
            }
            properties.put("datainput", dinbuff.toString());
           
            List<DataInputAssociation> inputAssociations = event.getDataInputAssociation();
            StringBuffer dinassociationbuff = new StringBuffer();
            for(DataInputAssociation din : inputAssociations) {
                if(din.getSourceRef().get(0).getId() != null && din.getSourceRef().get(0).getId().length() > 0) {
                    dinassociationbuff.append(din.getSourceRef().get(0).getId());
                    dinassociationbuff.append("->");
                    dinassociationbuff.append( ((DataInput)din.getTargetRef()).getName());
                    dinassociationbuff.append(",");
                }
            }
            if(dinassociationbuff.length() > 0) {
                dinassociationbuff.setLength(dinassociationbuff.length() - 1);
            }
            properties.put("datainputassociations", dinassociationbuff.toString());
        }
        // event definitions
        List<EventDefinition> eventdefs = event.getEventDefinitions();
        for(EventDefinition ed : eventdefs) {
            if(ed instanceof TimerEventDefinition) {
                TimerEventDefinition ted = (TimerEventDefinition) ed;
//                if(ted.getTimeDate() != null) {
//                    properties.put("timedate", ((FormalExpression) ted.getTimeDate()).getBody());
//                }
                if(ted.getTimeDuration() != null) {
                    properties.put("timeduration", ((FormalExpression) ted.getTimeDuration()).getBody());
                }
                if(ted.getTimeCycle() != null) {
                    properties.put("timecycle", ((FormalExpression) ted.getTimeCycle()).getBody());
                    if(((FormalExpression) ted.getTimeCycle()).getLanguage() != null) {
                      properties.put("timecyclelanguage", ((FormalExpression) ted.getTimeCycle()).getLanguage());
                    }
                }
            } else if( ed instanceof SignalEventDefinition) {
                if(((SignalEventDefinition) ed).getSignalRef() != null) {
                    properties.put("signalref", ((SignalEventDefinition) ed).getSignalRef());
                } else {
                    properties.put("signalref", "");
                }
            } else if( ed instanceof ErrorEventDefinition) {
                if(((ErrorEventDefinition) ed).getErrorRef() != null && ((ErrorEventDefinition) ed).getErrorRef().getErrorCode() != null) {
                    properties.put("errorref", ((ErrorEventDefinition) ed).getErrorRef().getErrorCode());
                } else {
                    properties.put("errorref", "");
                }
            } else if( ed instanceof ConditionalEventDefinition ) {
                FormalExpression conditionalExp = (FormalExpression) ((ConditionalEventDefinition) ed).getCondition();
                if(conditionalExp.getBody() != null) {
                    properties.put("conditionexpression", conditionalExp.getBody());
                }
                if(conditionalExp.getLanguage() != null) {
                    String languageVal = conditionalExp.getLanguage();
                    if(languageVal.equals("http://www.jboss.org/drools/rule")) {
                        properties.put("conditionlanguage", "drools");
                    } else if(languageVal.equals("http://www.mvel.org/2.0")) {
                        properties.put("conditionlanguage", "mvel");
                    } else {
                        // default to drools
                        properties.put("conditionlanguage", "drools");
                    }
                }
            } else if( ed instanceof EscalationEventDefinition ) {
                if(((EscalationEventDefinition) ed).getEscalationRef() != null) {
                    Escalation esc = ((EscalationEventDefinition) ed).getEscalationRef();
                    if(esc.getEscalationCode() != null && esc.getEscalationCode().length() > 0) {
                        properties.put("escalationcode", esc.getEscalationCode());
                    } else {
                        properties.put("escalationcode", "");
                    }
                }
            } else if( ed instanceof MessageEventDefinition) {
                if(((MessageEventDefinition) ed).getMessageRef() != null) {
                    Message msg = ((MessageEventDefinition) ed).getMessageRef();
                    properties.put("messageref", msg.getId());
                }
            }  else if( ed instanceof CompensateEventDefinition) {
                if(((CompensateEventDefinition) ed).getActivityRef() != null) {
                    Activity act = ((CompensateEventDefinition) ed).getActivityRef();
                    properties.put("activityref", act.getName());
                }
            } 
        }
    }
   
    private List<String> marshallLanes(Lane lane, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def) throws JsonGenerationException, IOException {
      Bounds bounds = ((BPMNShape) findDiagramElement(plane, lane)).getBounds();
      List<String> nodeRefIds = new ArrayList<String>();
      if(bounds != null) {
        generator.writeStartObject();
        generator.writeObjectField("resourceId", lane.getId());
        Map<String, Object> laneProperties = new LinkedHashMap<String, Object>();
        if(lane.getName() != null) {
          laneProperties.put("name", unescapeXML(lane.getName()));
        } else {
          laneProperties.put("name", "");
        }
       
        Iterator<FeatureMap.Entry> iter = lane.getAnyAttribute().iterator();
        boolean foundBgColor = false;
        boolean foundBrColor = false;
        boolean foundFontColor = false;
        boolean foundSelectable = false;
          while(iter.hasNext()) {
              FeatureMap.Entry entry = iter.next();
              if(entry.getEStructuralFeature().getName().equals("background-color")) {
                laneProperties.put("bgcolor", entry.getValue());
                foundBgColor = true;
              }
              if(entry.getEStructuralFeature().getName().equals("border-color")) {
                laneProperties.put("bordercolor", entry.getValue());
                foundBrColor = true;
              }
              if(entry.getEStructuralFeature().getName().equals("fontsize")) {
                laneProperties.put("fontsize", entry.getValue());
                foundBrColor = true;
              }
              if(entry.getEStructuralFeature().getName().equals("color")) {
                laneProperties.put("fontcolor", entry.getValue());
                foundFontColor = true;
              }
              if(entry.getEStructuralFeature().getName().equals("selectable")) {
                laneProperties.put("isselectable", entry.getValue());
                foundSelectable = true;
              }
          }
          if(!foundBgColor) {
            laneProperties.put("bgcolor", defaultBgColor_Swimlanes);
          }
         
          if(!foundBrColor) {
            laneProperties.put("bordercolor", defaultBrColor);
          }
         
          if(!foundFontColor) {
            laneProperties.put("fontcolor", defaultFontColor);
          }
         
          if(!foundSelectable) {
            laneProperties.put("isselectable", "true");
          }
       
        marshallProperties(laneProperties, generator);
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", "Lane");
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        for (FlowElement flowElement: lane.getFlowNodeRefs()) {
          nodeRefIds.add(flowElement.getId());
          // we dont want an offset here!
          marshallFlowElement(flowElement, plane, generator, 0, 0, preProcessingData, def);
        }
        generator.writeEndArray();
        generator.writeArrayFieldStart("outgoing");
        generator.writeEndArray();
        generator.writeObjectFieldStart("bounds");
        generator.writeObjectFieldStart("lowerRight");
        generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
        generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
        generator.writeEndObject();
        generator.writeObjectFieldStart("upperLeft");
        generator.writeObjectField("x", bounds.getX() - xOffset);
        generator.writeObjectField("y", bounds.getY() - yOffset);
        generator.writeEndObject();
        generator.writeEndObject();
        generator.writeEndObject();
      } else {
        // dont marshall the lane unless it has BPMNDI info (eclipse editor does not generate it for lanes currently.
        for (FlowElement flowElement: lane.getFlowNodeRefs()) {
          nodeRefIds.add(flowElement.getId());
          // we dont want an offset here!
          marshallFlowElement(flowElement, plane, generator, 0, 0, preProcessingData, def);
        }
      }
     
      return nodeRefIds;
    }
   
    protected void marshallFlowElement(FlowElement flowElement, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def) throws JsonGenerationException, IOException {
      generator.writeStartObject();
      generator.writeObjectField("resourceId", flowElement.getId());
     
      Map<String, Object> flowElementProperties = new LinkedHashMap<String, Object>();
      Iterator<FeatureMap.Entry> iter = flowElement.getAnyAttribute().iterator();
      boolean foundBgColor = false;
      boolean foundBrColor = false;
      boolean foundFontColor = false;
      boolean foundSelectable = false;
        while(iter.hasNext()) {
            FeatureMap.Entry entry = iter.next();
            if(entry.getEStructuralFeature().getName().equals("background-color")) {
              flowElementProperties.put("bgcolor", entry.getValue());
              foundBgColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("border-color")) {
              flowElementProperties.put("bordercolor", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("fontsize")) {
              flowElementProperties.put("fontsize", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("color")) {
              flowElementProperties.put("fontcolor", entry.getValue());
              foundFontColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("selectable")) {
              flowElementProperties.put("isselectable", entry.getValue());
              foundSelectable = true;
            }
        }
        if(!foundBgColor) {
          if(flowElement instanceof Activity || flowElement instanceof SubProcess ) {
            flowElementProperties.put("bgcolor", defaultBgColor_Activities);
          } else if(flowElement instanceof StartEvent) {
                flowElementProperties.put("bgcolor", defaultBgColor_StartEvents);
            } else if(flowElement instanceof EndEvent) {
                flowElementProperties.put("bgcolor", defaultBgColor_EndEvents);
            else if(flowElement instanceof DataObject) {
                flowElementProperties.put("bgcolor", defaultBgColor_DataObjects);
            } else if(flowElement instanceof CatchEvent) {
                flowElementProperties.put("bgcolor", defaultBgColor_CatchingEvents);
            } else if(flowElement instanceof ThrowEvent) {
                flowElementProperties.put("bgcolor", defaultBgColor_ThrowingEvents);
            } else if(flowElement instanceof Gateway) {
                flowElementProperties.put("bgcolor", defaultBgColor_Gateways);
            } else if(flowElement instanceof Lane) {
                flowElementProperties.put("bgcolor", defaultBgColor_Swimlanes);
            } else {
            flowElementProperties.put("bgcolor", defaultBgColor_Events);
          }
        }

        if(!foundBrColor) {
            if(flowElement instanceof CatchEvent && !(flowElement instanceof StartEvent)) {
                flowElementProperties.put("bordercolor", defaultBrColor_CatchingEvents);
            } else if(flowElement instanceof ThrowEvent && !(flowElement instanceof EndEvent)) {
                flowElementProperties.put("bordercolor", defaultBrColor_ThrowingEvents);
            } else if(flowElement instanceof Gateway) {
                flowElementProperties.put("bordercolor", defaultBrColor_Gateways);
            } else {
                flowElementProperties.put("bordercolor", defaultBrColor);
            }
        }

        if(!foundFontColor) {
          flowElementProperties.put("fontcolor", defaultFontColor);
        }
       
        if(!foundSelectable) {
          flowElementProperties.put("isselectable", "true");
        }

        Map<String, Object> catchEventProperties = new LinkedHashMap<String, Object>(flowElementProperties);
      Map<String, Object> throwEventProperties = new LinkedHashMap<String, Object>(flowElementProperties);
      if(flowElement instanceof CatchEvent) {
          setCatchEventProperties((CatchEvent) flowElement, catchEventProperties);
      }
      if(flowElement instanceof ThrowEvent) {
          setThrowEventProperties((ThrowEvent) flowElement, throwEventProperties);
      }
      if (flowElement instanceof StartEvent) {
        marshallStartEvent((StartEvent) flowElement, plane, generator, xOffset, yOffset, catchEventProperties);
      } else if (flowElement instanceof EndEvent) {
        marshallEndEvent((EndEvent) flowElement, plane, generator, xOffset, yOffset, throwEventProperties);
      } else if (flowElement instanceof IntermediateThrowEvent) {
        marshallIntermediateThrowEvent((IntermediateThrowEvent) flowElement, plane, generator, xOffset, yOffset, throwEventProperties);
      } else if (flowElement instanceof IntermediateCatchEvent) {
        marshallIntermediateCatchEvent((IntermediateCatchEvent) flowElement, plane, generator, xOffset, yOffset, catchEventProperties);
      } else if (flowElement instanceof BoundaryEvent) {
        marshallBoundaryEvent((BoundaryEvent) flowElement, plane, generator, xOffset, yOffset, catchEventProperties);
      } else if (flowElement instanceof Task) {
        marshallTask((Task) flowElement, plane, generator, xOffset, yOffset, preProcessingData, def, flowElementProperties);
      } else if (flowElement instanceof SequenceFlow) {
        marshallSequenceFlow((SequenceFlow) flowElement, plane, generator, xOffset, yOffset);
      } else if (flowElement instanceof ParallelGateway) {
        marshallParallelGateway((ParallelGateway) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof ExclusiveGateway) {
        marshallExclusiveGateway((ExclusiveGateway) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof InclusiveGateway) {
        marshallInclusiveGateway((InclusiveGateway) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof EventBasedGateway) {
        marshallEventBasedGateway((EventBasedGateway) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof ComplexGateway) {
        marshallComplexGateway((ComplexGateway) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof CallActivity) {
        marshallCallActivity((CallActivity) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
      } else if (flowElement instanceof SubProcess) {
          if(flowElement instanceof AdHocSubProcess) {
              marshallSubProcess((AdHocSubProcess) flowElement, plane, generator, xOffset, yOffset, preProcessingData, def, flowElementProperties);
          } else {
              marshallSubProcess((SubProcess) flowElement, plane, generator, xOffset, yOffset, preProcessingData, def, flowElementProperties);
          }
      } else if (flowElement instanceof DataObject) {
        // only marshall if we can find DI info for it - BZ 800346
        if(findDiagramElement(plane, (DataObject) flowElement) != null) {
          marshallDataObject((DataObject) flowElement, plane, generator, xOffset, yOffset, flowElementProperties);
        } else {
          _logger.info("Could not marshall Data Object " + (DataObject) flowElement + " because no DI information could be found.");
        }
      } else {
        throw new UnsupportedOperationException("Unknown flow element " + flowElement);
      }
      generator.writeEndObject();
    }
   
    protected void marshallStartEvent(StartEvent startEvent, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> properties) throws JsonGenerationException, IOException {
        List<EventDefinition> eventDefinitions = startEvent.getEventDefinitions();
        properties.put("isinterrupting", startEvent.isIsInterrupting());
      if (eventDefinitions == null || eventDefinitions.size() == 0) {
        marshallNode(startEvent, properties, "StartNoneEvent", plane, generator, xOffset, yOffset);
      } else if (eventDefinitions.size() == 1) {
        EventDefinition eventDefinition = eventDefinitions.get(0);
        if (eventDefinition instanceof ConditionalEventDefinition) {
          marshallNode(startEvent, properties, "StartConditionalEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof SignalEventDefinition) {
          marshallNode(startEvent, properties, "StartSignalEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof MessageEventDefinition) {
          marshallNode(startEvent, properties, "StartMessageEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof TimerEventDefinition) {
          marshallNode(startEvent, properties, "StartTimerEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof ErrorEventDefinition) {
            marshallNode(startEvent, properties, "StartErrorEvent", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof ConditionalEventDefinition) {
            marshallNode(startEvent, properties, "StartConditionalEvent", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof EscalationEventDefinition) {
                marshallNode(startEvent, properties, "StartEscalationEvent", plane, generator, xOffset, yOffset);
            } else if(eventDefinition instanceof CompensateEventDefinition) {
                marshallNode(startEvent, properties, "StartCompensationEvent", plane, generator, xOffset, yOffset);
            }
        else {
          throw new UnsupportedOperationException("Event definition not supported: " + eventDefinition);
        }
      } else {
        throw new UnsupportedOperationException("Multiple event definitions not supported for start event");
      }
    }
   
    protected void marshallEndEvent(EndEvent endEvent, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> properties) throws JsonGenerationException, IOException {
      List<EventDefinition> eventDefinitions = endEvent.getEventDefinitions();
      if (eventDefinitions == null || eventDefinitions.size() == 0) {
        marshallNode(endEvent, properties, "EndNoneEvent", plane, generator, xOffset, yOffset);
      } else if (eventDefinitions.size() == 1) {
        EventDefinition eventDefinition = eventDefinitions.get(0);
        if (eventDefinition instanceof TerminateEventDefinition) {
          marshallNode(endEvent, properties, "EndTerminateEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof SignalEventDefinition) {
          marshallNode(endEvent, properties, "EndSignalEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof MessageEventDefinition) {
          marshallNode(endEvent, properties, "EndMessageEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof ErrorEventDefinition) {
          marshallNode(endEvent, properties, "EndErrorEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof EscalationEventDefinition) {
          marshallNode(endEvent, properties, "EndEscalationEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof CompensateEventDefinition) {
          marshallNode(endEvent, properties, "EndCompensationEvent", plane, generator, xOffset, yOffset);
            } else if(eventDefinition instanceof CancelEventDefinition) {
                marshallNode(endEvent, properties, "EndCancelEvent", plane, generator, xOffset, yOffset);
        } else {
          throw new UnsupportedOperationException("Event definition not supported: " + eventDefinition);
        }
      } else {
        throw new UnsupportedOperationException("Multiple event definitions not supported for end event");
      }
    }
   
    protected void marshallIntermediateCatchEvent(IntermediateCatchEvent catchEvent, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> properties) throws JsonGenerationException, IOException {
      List<EventDefinition> eventDefinitions = catchEvent.getEventDefinitions();
        // simulation properties
        if(_simulationScenario != null) {
            for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(catchEvent.getId())) {
                    TimeParameters timeParams = eleType.getTimeParameters();
                    Parameter processingTime = timeParams.getProcessingTime();
                    if (processingTime == null) {
                        continue;
                    }
                    ParameterValue paramValue =  processingTime.getParameterValue().get(0);
                    if(paramValue instanceof NormalDistributionType) {
                        NormalDistributionType ndt = (NormalDistributionType) paramValue;
                        properties.put("mean", ndt.getMean());
                        properties.put("standarddeviation", ndt.getStandardDeviation());
                        properties.put("distributiontype", "normal");
                    } else if(paramValue instanceof UniformDistributionType) {
                        UniformDistributionType udt = (UniformDistributionType) paramValue;
                        properties.put("min", udt.getMin());
                        properties.put("max", udt.getMax());
                        properties.put("distributiontype", "uniform");

                        // bpsim 1.0 has not support for random distribution type
//                    } else if(paramValue instanceof RandomDistributionType) {
//                        RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                        properties.put("min", rdt.getMin());
//                        properties.put("max", rdt.getMax());
//                        properties.put("distributiontype", "random");
                    } else if(paramValue instanceof PoissonDistributionType) {
                        PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                        properties.put("mean", pdt.getMean());
                        properties.put("distributiontype", "poisson");
                    }
                    // bpsim 1.0 has no support for individual time unit
//                    if(timeParams.getTimeUnit() != null) {
//                        properties.put("timeunit", timeParams.getTimeUnit().getName());
//                    }
                }
            }
        }
      if (eventDefinitions.size() == 1) {
        EventDefinition eventDefinition = eventDefinitions.get(0);
        if (eventDefinition instanceof SignalEventDefinition) {
          marshallNode(catchEvent, properties, "IntermediateSignalEventCatching", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof MessageEventDefinition) {
          marshallNode(catchEvent, properties, "IntermediateMessageEventCatching", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof TimerEventDefinition) {
          marshallNode(catchEvent, properties, "IntermediateTimerEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof ConditionalEventDefinition) {
          marshallNode(catchEvent, properties, "IntermediateConditionalEvent", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof ErrorEventDefinition) {
            marshallNode(catchEvent, properties, "IntermediateErrorEvent", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof EscalationEventDefinition) {
                marshallNode(catchEvent, properties, "IntermediateEscalationEvent", plane, generator, xOffset, yOffset);
            } else if(eventDefinition instanceof CompensateEventDefinition) {
                marshallNode(catchEvent, properties, "IntermediateCompensationEventCatching", plane, generator, xOffset, yOffset);
            }
        else {
          throw new UnsupportedOperationException("Event definition not supported: " + eventDefinition);
        }
      } else {
        throw new UnsupportedOperationException("Intermediate catch event does not have event definition.");
      }
    }
   
    protected void marshallBoundaryEvent(BoundaryEvent boundaryEvent, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> catchEventProperties) throws JsonGenerationException, IOException {
      List<EventDefinition> eventDefinitions = boundaryEvent.getEventDefinitions();
      if(boundaryEvent.isCancelActivity()) {
        catchEventProperties.put("boundarycancelactivity", "true");
      } else {
        catchEventProperties.put("boundarycancelactivity", "false");
      }
        // simulation properties
        if(_simulationScenario != null) {
            for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(boundaryEvent.getId())) {
                    TimeParameters timeParams = eleType.getTimeParameters();
                    Parameter processingTime = timeParams.getProcessingTime();
                    if (processingTime == null) {
                        continue;
                    }
                    ParameterValue paramValue =  processingTime.getParameterValue().get(0);
                    if(paramValue instanceof NormalDistributionType) {
                        NormalDistributionType ndt = (NormalDistributionType) paramValue;
                        catchEventProperties.put("mean", ndt.getMean());
                        catchEventProperties.put("standarddeviation", ndt.getStandardDeviation());
                        catchEventProperties.put("distributiontype", "normal");
                    } else if(paramValue instanceof UniformDistributionType) {
                        UniformDistributionType udt = (UniformDistributionType) paramValue;
                        catchEventProperties.put("min", udt.getMin());
                        catchEventProperties.put("max", udt.getMax());
                        catchEventProperties.put("distributiontype", "uniform");

                        // bpsim 1.0 has not support for random distribution type
//                    } else if(paramValue instanceof RandomDistributionType) {
//                        RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                        properties.put("min", rdt.getMin());
//                        properties.put("max", rdt.getMax());
//                        properties.put("distributiontype", "random");
                    } else if(paramValue instanceof PoissonDistributionType) {
                        PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                        catchEventProperties.put("mean", pdt.getMean());
                        catchEventProperties.put("distributiontype", "poisson");
                    }
                    ControlParameters controlParams = eleType.getControlParameters();
                    if(controlParams != null) {
                        Parameter probabilityParam = controlParams.getProbability();
                        if(probabilityParam != null && probabilityParam.getParameterValue() != null) {
                            FloatingParameterType valType = (FloatingParameterType) probabilityParam.getParameterValue().get(0);
                            catchEventProperties.put("probability", valType.getValue());
                        }
                    }
                }
            }
        }
      if (eventDefinitions.size() == 1) {
        EventDefinition eventDefinition = eventDefinitions.get(0);
        if (eventDefinition instanceof SignalEventDefinition) {
          marshallNode(boundaryEvent, catchEventProperties, "IntermediateSignalEventCatching", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof EscalationEventDefinition) {
          marshallNode(boundaryEvent, catchEventProperties, "IntermediateEscalationEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof ErrorEventDefinition) {
          marshallNode(boundaryEvent, catchEventProperties, "IntermediateErrorEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof TimerEventDefinition) {
          marshallNode(boundaryEvent, catchEventProperties, "IntermediateTimerEvent", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof CompensateEventDefinition) {
          marshallNode(boundaryEvent, catchEventProperties, "IntermediateCompensationEventCatching", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof ConditionalEventDefinition) {
            marshallNode(boundaryEvent, catchEventProperties, "IntermediateConditionalEvent", plane, generator, xOffset, yOffset);
        } else if(eventDefinition instanceof MessageEventDefinition) {
            marshallNode(boundaryEvent, catchEventProperties, "IntermediateMessageEventCatching", plane, generator, xOffset, yOffset);
        }else {
          throw new UnsupportedOperationException("Event definition not supported: " + eventDefinition);
        }
      } else {
        throw new UnsupportedOperationException("None or multiple event definitions not supported for boundary event");
      }
    }
   
    protected void marshallIntermediateThrowEvent(IntermediateThrowEvent throwEvent, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> properties) throws JsonGenerationException, IOException {
      List<EventDefinition> eventDefinitions = throwEvent.getEventDefinitions();

        // simulation properties
        if(_simulationScenario != null) {
            for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(throwEvent.getId())) {
                    TimeParameters timeParams = eleType.getTimeParameters();
                    Parameter processingTime = timeParams.getProcessingTime();
                    if (processingTime == null) {
                        continue;
                    }
                    ParameterValue paramValue =  processingTime.getParameterValue().get(0);
                    if(paramValue instanceof NormalDistributionType) {
                        NormalDistributionType ndt = (NormalDistributionType) paramValue;
                        properties.put("mean", ndt.getMean());
                        properties.put("standarddeviation", ndt.getStandardDeviation());
                        properties.put("distributiontype", "normal");
                    } else if(paramValue instanceof UniformDistributionType) {
                        UniformDistributionType udt = (UniformDistributionType) paramValue;
                        properties.put("min", udt.getMin());
                        properties.put("max", udt.getMax());
                        properties.put("distributiontype", "uniform");

                        // bpsim 1.0 has not support for random distribution type
//                    } else if(paramValue instanceof RandomDistributionType) {
//                        RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                        properties.put("min", rdt.getMin());
//                        properties.put("max", rdt.getMax());
//                        properties.put("distributiontype", "random");
                    } else if(paramValue instanceof PoissonDistributionType) {
                        PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                        properties.put("mean", pdt.getMean());
                        properties.put("distributiontype", "poisson");
                    }
                    // bpsim 1.0 has no support for individual time unit
//                    if(timeParams.getTimeUnit() != null) {
//                        properties.put("timeunit", timeParams.getTimeUnit().getName());
//                    }
                }
            }
        }

        if (eventDefinitions.size() == 0) {
      marshallNode(throwEvent, properties, "IntermediateEvent", plane, generator, xOffset, yOffset);
      } else if (eventDefinitions.size() == 1) {
        EventDefinition eventDefinition = eventDefinitions.get(0);
        if (eventDefinition instanceof SignalEventDefinition) {
          marshallNode(throwEvent, properties, "IntermediateSignalEventThrowing", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof MessageEventDefinition) {
          marshallNode(throwEvent, properties, "IntermediateMessageEventThrowing", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof EscalationEventDefinition) {
          marshallNode(throwEvent, properties, "IntermediateEscalationEventThrowing", plane, generator, xOffset, yOffset);
        } else if (eventDefinition instanceof CompensateEventDefinition) {
          marshallNode(throwEvent, properties, "IntermediateCompensationEventThrowing", plane, generator, xOffset, yOffset);
        } else {
          throw new UnsupportedOperationException("Event definition not supported: " + eventDefinition);
        }
      } else {
        throw new UnsupportedOperationException("None or multiple event definitions not supported for intermediate throw event");
      }
    }
   
    protected void marshallCallActivity(CallActivity callActivity, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      Map<String, Object> properties = new LinkedHashMap<String, Object>(flowElementProperties);
     
      Iterator<FeatureMap.Entry> iter = callActivity.getAnyAttribute().iterator();
        while(iter.hasNext()) {
            FeatureMap.Entry entry = iter.next();
            if(entry.getEStructuralFeature().getName().equals("independent")) {
                properties.put("independent", entry.getValue());
            }
           
            if(entry.getEStructuralFeature().getName().equals("waitForCompletion")) {
                properties.put("waitforcompletion", entry.getValue());
            }
        }
       
        if(callActivity.getCalledElement() != null && callActivity.getCalledElement().length() > 0) {
          properties.put("calledelement", callActivity.getCalledElement());
        }
       
        // data inputs
        if(callActivity.getIoSpecification() != null) {
            List<InputSet> inputSetList = callActivity.getIoSpecification().getInputSets();
            StringBuilder dataInBuffer = new StringBuilder();
            for(InputSet inset : inputSetList) {
                List<DataInput> dataInputList =  inset.getDataInputRefs();
                for(DataInput dataIn : dataInputList) {
                    if(dataIn.getName() != null) {
                        dataInBuffer.append(dataIn.getName());
                        if(dataIn.getItemSubjectRef() != null && dataIn.getItemSubjectRef().getStructureRef() != null && dataIn.getItemSubjectRef().getStructureRef().length() > 0) {
                          dataInBuffer.append(":").append(dataIn.getItemSubjectRef().getStructureRef());
                        }
                        dataInBuffer.append(",");
                    }
                }
            }
            if(dataInBuffer.length() > 0) {
                dataInBuffer.setLength(dataInBuffer.length() - 1);
            }
            properties.put("datainputset", dataInBuffer.toString());
        }
       
        // data outputs
        if(callActivity.getIoSpecification() != null) {
            List<OutputSet> outputSetList = callActivity.getIoSpecification().getOutputSets();
            StringBuilder dataOutBuffer = new StringBuilder();
            for(OutputSet outset : outputSetList) {
                List<DataOutput> dataOutputList =  outset.getDataOutputRefs();
                for(DataOutput dataOut : dataOutputList) {
                    dataOutBuffer.append(dataOut.getName());
                    if(dataOut.getItemSubjectRef() != null && dataOut.getItemSubjectRef().getStructureRef() != null && dataOut.getItemSubjectRef().getStructureRef().length() > 0) {
                      dataOutBuffer.append(":").append(dataOut.getItemSubjectRef().getStructureRef());
                    }
                    dataOutBuffer.append(",");
                }
            }
            if(dataOutBuffer.length() > 0) {
                dataOutBuffer.setLength(dataOutBuffer.length() - 1);
            }
            properties.put("dataoutputset", dataOutBuffer.toString());
        }
       
        // assignments
        StringBuilder associationBuff = new StringBuilder();
        List<DataInputAssociation> inputAssociations = callActivity.getDataInputAssociations();
        List<DataOutputAssociation> outputAssociations = callActivity.getDataOutputAssociations();
        List<String> uniDirectionalAssociations = new ArrayList<String>();
        //List<String> biDirectionalAssociations = new ArrayList<String>();
       
        for(DataInputAssociation datain : inputAssociations) {
            String lhsAssociation = "";
            if(datain.getSourceRef() != null && datain.getSourceRef().size() > 0) {
              if(datain.getTransformation() != null && datain.getTransformation().getBody() != null) {
                lhsAssociation = datain.getTransformation().getBody();
              } else {
                lhsAssociation = datain.getSourceRef().get(0).getId();
              }
            }
           
            String rhsAssociation = "";
            if(datain.getTargetRef() != null) {
                rhsAssociation = ((DataInput) datain.getTargetRef()).getName();
            }
           
            //boolean isBiDirectional = false;
            boolean isAssignment = false;
           
            if(datain.getAssignment() != null && datain.getAssignment().size() > 0) {
                isAssignment = true;
            }
//            else {
//                // check if this is a bi-directional association
//                for(DataOutputAssociation dataout : outputAssociations) {
//                    if(dataout.getTargetRef().getId().equals(lhsAssociation) &&
//                       ((DataOutput) dataout.getSourceRef().get(0)).getName().equals(rhsAssociation)) {
//                        isBiDirectional = true;
//                        break;
//                    }
//                }
//            }
           
            if(isAssignment) {
              // only know how to deal with formal expressions
              if( datain.getAssignment().get(0).getFrom() instanceof FormalExpression) {
                String associationValue = ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody();
                if(associationValue == null) {
                  associationValue = "";
                }
                String replacer = associationValue.replaceAll(",", "##");
                associationBuff.append(rhsAssociation).append("=").append(replacer);
                  associationBuff.append(",");
              }
            }
//            else if(isBiDirectional) {
//                associationBuff.append(lhsAssociation).append("<->").append(rhsAssociation);
//                associationBuff.append(",");
//                biDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
//            }
            else {
                if(lhsAssociation != null && lhsAssociation.length() > 0) {
                    associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                    associationBuff.append(",");
                    uniDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
                }
            }
        }
       
        for(DataOutputAssociation dataout : outputAssociations) {
            if(dataout.getSourceRef().size() > 0) {
                String lhsAssociation = ((DataOutput) dataout.getSourceRef().get(0)).getName();
                String rhsAssociation = dataout.getTargetRef().getId();
               
                boolean wasBiDirectional = false;
                // check if we already addressed this association as bidirectional
//                for(String bda : biDirectionalAssociations) {
//                    String[] dbaparts = bda.split( ",\\s*" );
//                    if(dbaparts[0].equals(rhsAssociation) && dbaparts[1].equals(lhsAssociation)) {
//                        wasBiDirectional = true;
//                        break;
//                    }
//                }
               
                if(dataout.getTransformation() != null && dataout.getTransformation().getBody() != null) {
                  rhsAssociation = dataout.getTransformation().getBody().replaceAll("=", "||");
                }
               
                if(!wasBiDirectional) {
                    if(lhsAssociation != null && lhsAssociation.length() > 0) {
                        associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                        associationBuff.append(",");
                    }
                }
            }
        }
       
        String assignmentString = associationBuff.toString();
        if(assignmentString.endsWith(",")) {
            assignmentString = assignmentString.substring(0, assignmentString.length() - 1);
        }
        properties.put("assignments", assignmentString);
       
        // on-entry and on-exit actions
        if(callActivity.getExtensionValues() != null && callActivity.getExtensionValues().size() > 0) {
           
            String onEntryStr = "";
            String onExitStr = "";
            for(ExtensionAttributeValue extattrval : callActivity.getExtensionValues()) {
           
                FeatureMap extensionElements = extattrval.getValue();
       
                @SuppressWarnings("unchecked")
                List<OnEntryScriptType> onEntryExtensions = (List<OnEntryScriptType>) extensionElements
                                                     .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_ENTRY_SCRIPT, true);
       
                @SuppressWarnings("unchecked")
                List<OnExitScriptType> onExitExtensions = (List<OnExitScriptType>) extensionElements
                                                  .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_EXIT_SCRIPT, true);
           
                for(OnEntryScriptType onEntryScript : onEntryExtensions) {
                    onEntryStr += onEntryScript.getScript();
                    onEntryStr += "|";
               
                    if(onEntryScript.getScriptFormat() != null) {
                        String format = onEntryScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        properties.put("script_language", formatToWrite);
                    }
                }
               
                for(OnExitScriptType onExitScript : onExitExtensions) {
                    onExitStr += onExitScript.getScript();
                    onExitStr += "|";
                   
                    if(onExitScript.getScriptFormat() != null) {
                        String format = onExitScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        if(properties.get("script_language") != null) {
                            properties.put("script_language", formatToWrite);
                        }
                    }
                }
            }
            if(onEntryStr.length() > 0) {
                if(onEntryStr.endsWith("|")) {
                    onEntryStr = onEntryStr.substring(0, onEntryStr.length() - 1);
                }
                properties.put("onentryactions", onEntryStr);
            }
            if(onExitStr.length() > 0) {
                if(onExitStr.endsWith("|")) {
                    onExitStr = onExitStr.substring(0, onExitStr.length() - 1);
                }
                properties.put("onexitactions", onExitStr);
            }
        }

        // simulation properties
        if(_simulationScenario != null) {
            for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(callActivity.getId())) {
                    TimeParameters timeParams = eleType.getTimeParameters();
                    Parameter processingTime = timeParams.getProcessingTime();
                    ParameterValue paramValue =  processingTime.getParameterValue().get(0);
                    if(paramValue instanceof NormalDistributionType) {
                        NormalDistributionType ndt = (NormalDistributionType) paramValue;
                        properties.put("mean", ndt.getMean());
                        properties.put("standarddeviation", ndt.getStandardDeviation());
                        properties.put("distributiontype", "normal");
                    } else if(paramValue instanceof UniformDistributionType) {
                        UniformDistributionType udt = (UniformDistributionType) paramValue;
                        properties.put("min", udt.getMin());
                        properties.put("max", udt.getMax());
                        properties.put("distributiontype", "uniform");

                        // bpsim 1.0 does not support random distribution
//              } else if(paramValue instanceof RandomDistributionType) {
//                RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                properties.put("min", rdt.getMin());
//                properties.put("max", rdt.getMax());
//                properties.put("distributiontype", "random");
                    } else if(paramValue instanceof PoissonDistributionType) {
                        PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                        properties.put("mean", pdt.getMean());
                        properties.put("distributiontype", "poisson");
                    }
                    // bpsim 1.0 has no support for individual time unit
//              if(timeParams.getTimeUnit() != null) {
//                properties.put("timeunit", timeParams.getTimeUnit().getName());
//              }
                    if(timeParams.getWaitTime() != null) {
                        FloatingParameterType waittimeType = (FloatingParameterType) timeParams.getWaitTime().getParameterValue().get(0);
                        properties.put("waittime", waittimeType.getValue());
                    }

                    CostParameters costParams = eleType.getCostParameters();
                    if(costParams != null) {
                        if(costParams.getUnitCost() != null) {
                            FloatingParameterType unitCostVal = (FloatingParameterType) costParams.getUnitCost().getParameterValue().get(0);
                            properties.put("unitcost", unitCostVal.getValue());
                        }
                        // bpsim 1.0 does not support individual currency
                        //properties.put("currency", costParams.getUnitCost() == null ? "" : costParams.getUnitCost());
                    }
                }
            }
        }
     
        marshallNode(callActivity, properties, "ReusableSubprocess", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallTask(Task task, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
        Map<String, Object> properties = new LinkedHashMap<String, Object>(flowElementProperties);
      String taskType = "None";
      if (task instanceof BusinessRuleTask) {
        taskType = "Business Rule";
        Iterator<FeatureMap.Entry> iter = task.getAnyAttribute().iterator();
            while(iter.hasNext()) {
                FeatureMap.Entry entry = iter.next();
                if(entry.getEStructuralFeature().getName().equals("ruleFlowGroup")) {
                    properties.put("ruleflowgroup", entry.getValue());
                }
            }
      } else if (task instanceof ScriptTask) {
        ScriptTask scriptTask = (ScriptTask) task;
        properties.put("script", scriptTask.getScript() != null ? scriptTask.getScript().replace("\\", "\\\\").replace("\n", "\\n") : "");
        String format = scriptTask.getScriptFormat();
        if(format != null && format.length() > 0) {
          String formatToWrite = "";
                if(format.equals("http://www.java.com/java")) {
                    formatToWrite = "java";
                } else if(format.equals("http://www.mvel.org/2.0")) {
                    formatToWrite = "mvel";
                } else {
                  // default to java
                    formatToWrite = "java";
                }
                properties.put("script_language", formatToWrite);
        }
        taskType = "Script";
      } else if (task instanceof ServiceTask) {
        taskType = "Service";
        ServiceTask serviceTask = (ServiceTask) task;
        if(serviceTask.getOperationRef() != null && serviceTask.getImplementation() != null) {
                properties.put("serviceimplementation", serviceTask.getImplementation());
                properties.put("serviceoperation", serviceTask.getOperationRef().getName() == null ? serviceTask.getOperationRef().getImplementationRef() : serviceTask.getOperationRef().getName());
            if(def != null) {
                List<RootElement> roots = def.getRootElements();
                for(RootElement root : roots) {
                    if(root instanceof Interface) {
                        Interface inter = (Interface) root;
                        List<Operation> interOperations = inter.getOperations();
                        for(Operation interOper : interOperations) {
                            if(interOper.getId().equals(serviceTask.getOperationRef().getId())) {
                                properties.put("serviceinterface", inter.getName() == null ? inter.getImplementationRef() : inter.getName());
                            }
                        }
                    }
                }
            }
        }
      } else if (task instanceof ManualTask) {
        taskType = "Manual";
      } else if (task instanceof UserTask) {
        taskType = "User";
        // get the user task actors
        List<ResourceRole> roles = task.getResources();
        StringBuilder sb = new StringBuilder();
        for(ResourceRole role : roles) {
            if(role instanceof PotentialOwner) {
                FormalExpression fe = (FormalExpression) ( (PotentialOwner)role).getResourceAssignmentExpression().getExpression();
                if(fe.getBody() != null && fe.getBody().length() > 0) {
                    sb.append(fe.getBody());
                    sb.append(",");
                }
            }
        }
        if(sb.length() > 0) {
            sb.setLength(sb.length() - 1);
        }
        properties.put("actors", sb.toString());

        // simulation properties
        if(_simulationScenario != null) {
          for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(task.getId())) {
                  CostParameters costParams = eleType.getCostParameters();
                        FloatingParameterType unitCostVal = (FloatingParameterType) costParams.getUnitCost().getParameterValue().get(0);
                  properties.put("unitcost", unitCostVal.getValue());
                        // bpsim does not support individual currency
                  //properties.put("currency", costParams.getUnitCost() == null ? "" : costParams.getUnitCost());
                  ResourceParameters resourceParams = eleType.getResourceParameters();
                  FloatingParameterType quantityVal = (FloatingParameterType) resourceParams.getQuantity().getParameterValue().get(0);
                  properties.put("quantity", quantityVal.getValue());
                  FloatingParameterType workingHoursVal = (FloatingParameterType) resourceParams.getAvailability().getParameterValue().get(0);
                  properties.put("workinghours", workingHoursVal.getValue());
                }
          }
        }
      } else if (task instanceof SendTask) {
        taskType = "Send";
        SendTask st = (SendTask) task;
        if(st.getMessageRef() != null) {
          properties.put("messageref", st.getMessageRef().getId());
        }
      } else if (task instanceof ReceiveTask) {
        taskType = "Receive";
        ReceiveTask rt = (ReceiveTask) task;
        if(rt.getMessageRef() != null) {
          properties.put("messageref", rt.getMessageRef().getId());
        }
      }

        if(task.getIoSpecification() != null && task.getIoSpecification().getDataInputs() != null) {
            List<DataInput> taskDataInputs = task.getIoSpecification().getDataInputs();
            for(DataInput din : taskDataInputs) {
                if(din.getName() != null && din.getName().equals("TaskName")) {
                    List<DataInputAssociation> taskDataInputAssociations = task.getDataInputAssociations();
                    for(DataInputAssociation dia : taskDataInputAssociations) {
                        if(dia.getTargetRef() != null && dia.getTargetRef().getId().equals(din.getId())) {
                            properties.put("taskname", ((FormalExpression) dia.getAssignment().get(0).getFrom()).getBody());
                        }
                    }
                    break;
                }
            }
        }
       
        // check if we are dealing with a custom task
        if(isCustomElement((String) properties.get("taskname"), preProcessingData)) {
            properties.put("tasktype", properties.get("taskname"));
        } else {
            properties.put("tasktype", taskType);
        }

        // multiple instance
        if(task.getLoopCharacteristics() != null) {
            properties.put("multipleinstance", "true");
            MultiInstanceLoopCharacteristics taskmi = (MultiInstanceLoopCharacteristics) task.getLoopCharacteristics();
            if(taskmi.getLoopDataInputRef() != null) {
                ItemAwareElement iedatainput = taskmi.getLoopDataInputRef();

                List<DataInputAssociation> taskInputAssociations = task.getDataInputAssociations();
                for(DataInputAssociation dia : taskInputAssociations) {
                    if(dia.getTargetRef().equals(iedatainput)) {
                        properties.put("multipleinstancecollectioninput", dia.getSourceRef().get(0).getId());
                        break;
                    }
                }
            }
            if(taskmi.getLoopDataOutputRef() != null) {
                ItemAwareElement iedataoutput = taskmi.getLoopDataOutputRef();

                List<DataOutputAssociation> taskOutputAssociations = task.getDataOutputAssociations();
                for(DataOutputAssociation dout : taskOutputAssociations) {
                    if(dout.getSourceRef().get(0).equals(iedataoutput)) {
                        properties.put("multipleinstancecollectionoutput", dout.getTargetRef().getId());
                        break;
                    }
                }
            }

            if(taskmi.getInputDataItem() != null) {
                List<DataInput> taskDataInputs = task.getIoSpecification().getDataInputs();
                for(DataInput din: taskDataInputs) {
                    if(din.getItemSubjectRef().getId().equals(taskmi.getInputDataItem().getItemSubjectRef().getId())) {
                        properties.put("multipleinstancedatainput", din.getName());
                    }
                }
            }

            if(taskmi.getOutputDataItem() != null) {
                List<DataOutput> taskDataOutputs = task.getIoSpecification().getDataOutputs();
                for(DataOutput dout : taskDataOutputs) {
                    if(dout.getItemSubjectRef().getId().equals(taskmi.getOutputDataItem().getItemSubjectRef().getId())) {
                        properties.put("multipleinstancedataoutput", dout.getName());
                    }
                }
            }
        } else {
            properties.put("multipleinstance", "false");
        }
       
        // data inputs
        DataInput groupDataInput = null;
        DataInput skippableDataInput = null;
        DataInput commentDataInput = null;
        DataInput contentDataInput = null;
        DataInput priorityDataInput = null;
        DataInput localeDataInput = null;
        DataInput createdByDataInput = null;
        DataInput notCompletedReassignInput = null;
        DataInput notStartedReassignInput = null;
        DataInput notCompletedNotificationInput = null;
        DataInput notStartedNotificationInput = null;
        if(task.getIoSpecification() != null) {
            List<InputSet> inputSetList = task.getIoSpecification().getInputSets();
            StringBuilder dataInBuffer = new StringBuilder();
            for(InputSet inset : inputSetList) {
                List<DataInput> dataInputList =  inset.getDataInputRefs();
                for(DataInput dataIn : dataInputList) {
                    // dont add "TaskName" as that is added manually
                    if(dataIn.getName() != null && !dataIn.getName().equals("TaskName") && !dataIn.getName().equals("miinputCollection")) {
                        dataInBuffer.append(dataIn.getName());
                        if(dataIn.getItemSubjectRef() != null && dataIn.getItemSubjectRef().getStructureRef() != null && dataIn.getItemSubjectRef().getStructureRef().length() > 0) {
                          dataInBuffer.append(":").append(dataIn.getItemSubjectRef().getStructureRef());
                        }
                        dataInBuffer.append(",");
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("GroupId")) {
                      groupDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("Skippable")) {
                      skippableDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("Comment")) {
                      commentDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("Content")) {
                      contentDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("Priority")) {
                      priorityDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("Locale")) {
                        localeDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("CreatedBy")) {
                        createdByDataInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("NotCompletedReassign")) {
                        notCompletedReassignInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("NotStartedReassign")) {
                        notStartedReassignInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("NotCompletedNotify")) {
                        notCompletedNotificationInput = dataIn;
                    }
                    if(dataIn.getName() != null && dataIn.getName().equals("NotStartedNotify")) {
                        notStartedNotificationInput = dataIn;
                    }
                }
            }
            if(dataInBuffer.length() > 0) {
                dataInBuffer.setLength(dataInBuffer.length() - 1);
            }
            properties.put("datainputset", dataInBuffer.toString());
        }
       
        // data outputs
        if(task.getIoSpecification() != null) {
            List<OutputSet> outputSetList = task.getIoSpecification().getOutputSets();
            StringBuilder dataOutBuffer = new StringBuilder();
            for(OutputSet outset : outputSetList) {
                List<DataOutput> dataOutputList =  outset.getDataOutputRefs();
                for(DataOutput dataOut : dataOutputList) {
                    if(!dataOut.getName().equals("mioutputCollection")) {
                        dataOutBuffer.append(dataOut.getName());
                        if(dataOut.getItemSubjectRef() != null && dataOut.getItemSubjectRef().getStructureRef() != null && dataOut.getItemSubjectRef().getStructureRef().length() > 0) {
                            dataOutBuffer.append(":").append(dataOut.getItemSubjectRef().getStructureRef());
                        }
                        dataOutBuffer.append(",");
                    }
                }
            }
            if(dataOutBuffer.length() > 0) {
                dataOutBuffer.setLength(dataOutBuffer.length() - 1);
            }
            properties.put("dataoutputset", dataOutBuffer.toString());
        }
       
        // assignments
        StringBuilder associationBuff = new StringBuilder();
        List<DataInputAssociation> inputAssociations = task.getDataInputAssociations();
        List<DataOutputAssociation> outputAssociations = task.getDataOutputAssociations();
        List<String> uniDirectionalAssociations = new ArrayList<String>();
        //List<String> biDirectionalAssociations = new ArrayList<String>();
       
        for(DataInputAssociation datain : inputAssociations) {

            boolean proceed = true;
            if(task.getLoopCharacteristics() != null) {
                MultiInstanceLoopCharacteristics taskMultiLoop = (MultiInstanceLoopCharacteristics) task.getLoopCharacteristics();
                // dont include associations that include mi loop data inputs
                if(datain.getSourceRef().get(0).getId().equals(taskMultiLoop.getInputDataItem().getId())) {
                    proceed = false;
                }
                // dont include associations that include loopDataInputRef as target
                if(datain.getTargetRef().equals(taskMultiLoop.getLoopDataInputRef())) {
                    proceed = false;
                }
            }

            if(proceed) {
                String lhsAssociation = "";
                if(datain.getSourceRef() != null && datain.getSourceRef().size() > 0) {
                    if(datain.getTransformation() != null && datain.getTransformation().getBody() != null) {
                        lhsAssociation = datain.getTransformation().getBody();
                    } else {
                        lhsAssociation = datain.getSourceRef().get(0).getId();
                    }
                }

                String rhsAssociation = "";
                if(datain.getTargetRef() != null) {
                    rhsAssociation = ((DataInput) datain.getTargetRef()).getName();
                }

                //boolean isBiDirectional = false;
                boolean isAssignment = false;

                if(datain.getAssignment() != null && datain.getAssignment().size() > 0) {
                    isAssignment = true;
                }
    //            else {
    //                // check if this is a bi-directional association
    //                for(DataOutputAssociation dataout : outputAssociations) {
    //                    if(dataout.getTargetRef().getId().equals(lhsAssociation) &&
    //                       ((DataOutput) dataout.getSourceRef().get(0)).getName().equals(rhsAssociation)) {
    //                        isBiDirectional = true;
    //                        break;
    //                    }
    //                }
    //            }

                if(isAssignment) {
                    // only know how to deal with formal expressions
                    if( datain.getAssignment().get(0).getFrom() instanceof FormalExpression) {
                        String associationValue = ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody();
                        if(associationValue == null) {
                            associationValue = "";
                        }

                        // don't include properties that have their independent input editors:
                        if(!(rhsAssociation.equals("GroupId") ||
                           rhsAssociation.equals("Skippable") ||
                           rhsAssociation.equals("Comment") ||
                           rhsAssociation.equals("Priority") ||
                           rhsAssociation.equals("Content") ||
                           rhsAssociation.equals("TaskName"||
                           rhsAssociation.equals("Locale") ||
                           rhsAssociation.equals("CreatedBy") ||
                           rhsAssociation.equals("NotCompletedReassign") ||
                           rhsAssociation.equals("NotStartedReassign") ||
                           rhsAssociation.equals("NotCompletedNotify") ||
                           rhsAssociation.equals("NotStartedNotify")
                           )) {
                            String replacer = associationValue.replaceAll(",", "##");
                            associationBuff.append(rhsAssociation).append("=").append(replacer);
                            associationBuff.append(",");
                        }

                        if(rhsAssociation.equalsIgnoreCase("TaskName")) {
                            properties.put("taskname", associationValue);
                        }

                        if (groupDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                        ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(groupDataInput.getId())) {
                            properties.put("groupid", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody() == null ? "" : ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (skippableDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                        ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(skippableDataInput.getId())) {
                            properties.put("skippable", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (commentDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                        ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(commentDataInput.getId())) {
                            properties.put("comment", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (priorityDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                        ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(priorityDataInput.getId())) {
                            properties.put("priority", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody() == null ? "" : ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (contentDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(contentDataInput.getId())) {
                            properties.put("content", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (localeDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(localeDataInput.getId())) {
                            properties.put("locale", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (createdByDataInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(createdByDataInput.getId())) {
                             properties.put("createdby", ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody());
                        }
                        if (notCompletedReassignInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(notCompletedReassignInput.getId())) {
                            properties.put("tmpreassignmentnotcompleted", updateReassignmentAndNotificationInput( ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody(), "not-completed" ));
                        }
                        if (notStartedReassignInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(notStartedReassignInput.getId())) {
                            properties.put("tmpreassignmentnotstarted", updateReassignmentAndNotificationInput( ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody(), "not-started" ));
                        }
                        if (notCompletedNotificationInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(notCompletedNotificationInput.getId())) {
                            properties.put("tmpnotificationnotcompleted", updateReassignmentAndNotificationInput( ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody(), "not-completed" ));
                        }
                        if (notStartedNotificationInput != null && datain.getAssignment().get(0).getTo() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody() != null &&
                                ((FormalExpression) datain.getAssignment().get(0).getTo()).getBody().equals(notStartedNotificationInput.getId())) {
                            properties.put("tmpnotificationnotstarted", updateReassignmentAndNotificationInput( ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody(), "not-started" ));
                        }
                    }
                }
    //            else if(isBiDirectional) {
    //                associationBuff.append(lhsAssociation).append("<->").append(rhsAssociation);
    //                associationBuff.append(",");
    //                biDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
    //            }
                else {
                    if(lhsAssociation != null && lhsAssociation.length() > 0) {
                        associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                        associationBuff.append(",");
                        uniDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
                    }
                    uniDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);

//                    if(contentDataInput != null) {
//                        if(rhsAssociation.equals(contentDataInput.getName())) {
//                            properties.put("content", lhsAssociation);
//                        }
//                    }
                }
            }
        }

        if(properties.get("tmpreassignmentnotcompleted") != null && ((String)properties.get("tmpreassignmentnotcompleted")).length() > 0 && properties.get("tmpreassignmentnotstarted") != null && ((String) properties.get("tmpreassignmentnotstarted")).length() > 0) {
            properties.put("reassignment", properties.get("tmpreassignmentnotcompleted") + "^" + properties.get("tmpreassignmentnotstarted"));
        } else if(properties.get("tmpreassignmentnotcompleted") != null && ((String) properties.get("tmpreassignmentnotcompleted")).length() > 0) {
            properties.put("reassignment", properties.get("tmpreassignmentnotcompleted"));
        } else if(properties.get("tmpreassignmentnotstarted") != null && ((String) properties.get("tmpreassignmentnotstarted")).length() > 0) {
            properties.put("reassignment", properties.get("tmpreassignmentnotstarted"));
        }

        if(properties.get("tmpnotificationnotcompleted") != null && ((String)properties.get("tmpnotificationnotcompleted")).length() > 0 && properties.get("tmpnotificationnotstarted") != null && ((String) properties.get("tmpnotificationnotstarted")).length() > 0) {
            properties.put("notifications", properties.get("tmpnotificationnotcompleted") + "^" + properties.get("tmpnotificationnotstarted"));
        } else if(properties.get("tmpnotificationnotcompleted") != null && ((String) properties.get("tmpnotificationnotcompleted")).length() > 0) {
            properties.put("notifications", properties.get("tmpnotificationnotcompleted"));
        } else if(properties.get("tmpnotificationnotstarted") != null && ((String) properties.get("tmpnotificationnotstarted")).length() > 0) {
            properties.put("notifications", properties.get("tmpnotificationnotstarted"));
        }

        for(DataOutputAssociation dataout : outputAssociations) {
            boolean proceed = true;
            if(task.getLoopCharacteristics() != null) {
                MultiInstanceLoopCharacteristics taskMultiLoop = (MultiInstanceLoopCharacteristics) task.getLoopCharacteristics();
                // dont include associations that include mi loop data outputs
                if(dataout.getTargetRef().getId().equals(taskMultiLoop.getOutputDataItem().getId())) {
                    proceed = false;
                }
                // dont include associations that include loopDataOutputRef as source
                if(dataout.getSourceRef().get(0).equals(taskMultiLoop.getLoopDataOutputRef())) {
                    proceed = false;
                }
            }

            if(proceed) {
                if(dataout.getSourceRef().size() > 0) {
                    String lhsAssociation = ((DataOutput) dataout.getSourceRef().get(0)).getName();
                    String rhsAssociation = dataout.getTargetRef().getId();

                    boolean wasBiDirectional = false;
                    // check if we already addressed this association as bidirectional
    //                for(String bda : biDirectionalAssociations) {
    //                    String[] dbaparts = bda.split( ",\\s*" );
    //                    if(dbaparts[0].equals(rhsAssociation) && dbaparts[1].equals(lhsAssociation)) {
    //                        wasBiDirectional = true;
    //                        break;
    //                    }
    //                }

                    if(dataout.getTransformation() != null && dataout.getTransformation().getBody() != null) {
                        rhsAssociation = dataout.getTransformation().getBody().replaceAll("=", "||");
                    }

                    if(!wasBiDirectional) {
                        if(lhsAssociation != null && lhsAssociation.length() > 0) {
                            associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                            associationBuff.append(",");
                        }
                    }
                }
            }
        }
       
        String assignmentString = associationBuff.toString();
        if(assignmentString.endsWith(",")) {
            assignmentString = assignmentString.substring(0, assignmentString.length() - 1);
        }
        properties.put("assignments", assignmentString);
       
        // on-entry and on-exit actions
        if(task.getExtensionValues() != null && task.getExtensionValues().size() > 0) {
           
            String onEntryStr = "";
            String onExitStr = "";
            for(ExtensionAttributeValue extattrval : task.getExtensionValues()) {
           
                FeatureMap extensionElements = extattrval.getValue();
       
                @SuppressWarnings("unchecked")
                List<OnEntryScriptType> onEntryExtensions = (List<OnEntryScriptType>) extensionElements
                                                     .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_ENTRY_SCRIPT, true);
       
                @SuppressWarnings("unchecked")
                List<OnExitScriptType> onExitExtensions = (List<OnExitScriptType>) extensionElements
                                                  .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_EXIT_SCRIPT, true);
           
                for(OnEntryScriptType onEntryScript : onEntryExtensions) {
                    onEntryStr += onEntryScript.getScript();
                    onEntryStr += "|";
               
                    if(onEntryScript.getScriptFormat() != null) {
                        String format = onEntryScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        properties.put("script_language", formatToWrite);
                    }
                }
               
                for(OnExitScriptType onExitScript : onExitExtensions) {
                    onExitStr += onExitScript.getScript();
                    onExitStr += "|";
                   
                    if(onExitScript.getScriptFormat() != null) {
                        String format = onExitScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        if(properties.get("script_language") != null) {
                            properties.put("script_language", formatToWrite);
                        }
                    }
                }
            }
            if(onEntryStr.length() > 0) {
                if(onEntryStr.endsWith("|")) {
                    onEntryStr = onEntryStr.substring(0, onEntryStr.length() - 1);
                }
                properties.put("onentryactions", onEntryStr);
            }
            if(onExitStr.length() > 0) {
                if(onExitStr.endsWith("|")) {
                    onExitStr = onExitStr.substring(0, onExitStr.length() - 1);
                }
                properties.put("onexitactions", onExitStr);
            }
        }
       
        // simulation properties
        if(_simulationScenario != null) {
          for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
            if(eleType.getElementRef().equals(task.getId())) {
              TimeParameters timeParams = eleType.getTimeParameters();
              Parameter processingTime = timeParams.getProcessingTime();
              ParameterValue paramValue =  processingTime.getParameterValue().get(0);
              if(paramValue instanceof NormalDistributionType) {
                NormalDistributionType ndt = (NormalDistributionType) paramValue;
                properties.put("mean", ndt.getMean());
                properties.put("standarddeviation", ndt.getStandardDeviation());
                properties.put("distributiontype", "normal");
              } else if(paramValue instanceof UniformDistributionType) {
                UniformDistributionType udt = (UniformDistributionType) paramValue;
                properties.put("min", udt.getMin());
                properties.put("max", udt.getMax());
                properties.put("distributiontype", "uniform");

                    // bpsim 1.0 does not support random distribution
//              } else if(paramValue instanceof RandomDistributionType) {
//                RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                properties.put("min", rdt.getMin());
//                properties.put("max", rdt.getMax());
//                properties.put("distributiontype", "random");
              } else if(paramValue instanceof PoissonDistributionType) {
                PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                properties.put("mean", pdt.getMean());
                properties.put("distributiontype", "poisson");
              }
                    // bpsim 1.0 has no support for individual time unit
//              if(timeParams.getTimeUnit() != null) {
//                properties.put("timeunit", timeParams.getTimeUnit().getName());
//              }
                    if(timeParams.getWaitTime() != null) {
                        FloatingParameterType waittimeType = (FloatingParameterType) timeParams.getWaitTime().getParameterValue().get(0);
                        properties.put("waittime", waittimeType.getValue());
                    }

                    CostParameters costParams = eleType.getCostParameters();
                    if(costParams != null) {
                        if(costParams.getUnitCost() != null) {
                            FloatingParameterType unitCostVal = (FloatingParameterType) costParams.getUnitCost().getParameterValue().get(0);
                            properties.put("unitcost", unitCostVal.getValue());
                        }
                        // bpsim 1.0 does not support individual currency
                        //properties.put("currency", costParams.getUnitCost() == null ? "" : costParams.getUnitCost());
                    }
            }
          }
        }
       
        // marshall the node out
        if(isCustomElement((String) properties.get("taskname"), preProcessingData)) {
            marshallNode(task, properties, (String) properties.get("taskname"), plane, generator, xOffset, yOffset);
        } else {
            marshallNode(task, properties, "Task", plane, generator, xOffset, yOffset);
        }
    }
   
    protected void marshallParallelGateway(ParallelGateway gateway, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      marshallNode(gateway, flowElementProperties, "ParallelGateway", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallExclusiveGateway(ExclusiveGateway gateway, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      if(gateway.getDefault() != null) {
            SequenceFlow defsf = gateway.getDefault();
            String defGatewayStr = "";
            if(defsf.getName() != null && defsf.getName().length() > 0) {
                defGatewayStr = defsf.getName() + " : " + defsf.getId();
            } else {
                defGatewayStr = defsf.getId();
            }
        flowElementProperties.put("defaultgate", defGatewayStr);
      }
      marshallNode(gateway, flowElementProperties, "Exclusive_Databased_Gateway", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallInclusiveGateway(InclusiveGateway gateway, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      if(gateway.getDefault() != null) {
            SequenceFlow defsf = gateway.getDefault();
            String defGatewayStr = "";
            if(defsf.getName() != null && defsf.getName().length() > 0) {
                defGatewayStr = defsf.getName() + " : " + defsf.getId();
            } else {
                defGatewayStr = defsf.getId();
            }
        flowElementProperties.put("defaultgate", defGatewayStr);
      }
      marshallNode(gateway, flowElementProperties, "InclusiveGateway", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallEventBasedGateway(EventBasedGateway gateway, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      marshallNode(gateway, flowElementProperties, "EventbasedGateway", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallComplexGateway(ComplexGateway gateway, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      marshallNode(gateway, flowElementProperties, "ComplexGateway", plane, generator, xOffset, yOffset);
    }
   
    protected void marshallNode(FlowNode node, Map<String, Object> properties, String stencil, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset) throws JsonGenerationException, IOException {
      if (properties == null) {
        properties = new LinkedHashMap<String, Object>();
      }
        if(node.getDocumentation() != null && node.getDocumentation().size() > 0) {
            properties.put("documentation", node.getDocumentation().get(0).getText());
        }
        if(node.getName() != null) {
          properties.put("name", unescapeXML(node.getName()));
        } else {
          properties.put("name", "");
        }
        marshallProperties(properties, generator);
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", stencil);
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();
        generator.writeArrayFieldStart("outgoing");
        for (SequenceFlow outgoing: node.getOutgoing()) {
          generator.writeStartObject();
          generator.writeObjectField("resourceId", outgoing.getId());
          generator.writeEndObject();
        }
        // we need to also add associations as outgoing elements
        Process process = (Process) plane.getBpmnElement();
        for (Artifact artifact : process.getArtifacts()) {
          if (artifact instanceof Association){
                Association association = (Association) artifact;
                if (association.getSourceRef().getId().equals(node.getId())) {
                  generator.writeStartObject();
                  generator.writeObjectField("resourceId", association.getId());
                  generator.writeEndObject();
                }
          }
        }
        // and boundary events for activities
        for(FlowElement fe : process.getFlowElements()) {
          if(fe instanceof BoundaryEvent) {
            if(((BoundaryEvent) fe).getAttachedToRef().getId().equals(node.getId())) {
              generator.writeStartObject();
                    generator.writeObjectField("resourceId", fe.getId());
                    generator.writeEndObject();
            }
          }
        }
        generator.writeEndArray();
       
        // boundary events have a docker
        if(node instanceof BoundaryEvent) {
          // find the edge associated with this boundary event
          for (DiagramElement element: plane.getPlaneElement()) {
            if(element instanceof BPMNEdge && ((BPMNEdge) element).getBpmnElement() == node) {
              List<Point> waypoints = ((BPMNEdge) element).getWaypoint();
              if(waypoints != null && waypoints.size() > 0) {
                    // one per boundary event
                    Point p = waypoints.get(0);
                    if(p != null) {
                      generator.writeArrayFieldStart("dockers");
                            generator.writeStartObject();
                            generator.writeObjectField("x", p.getX());
                            generator.writeObjectField("y", p.getY());
                            generator.writeEndObject();
                            generator.writeEndArray();
                    }
                  }
            }
          }
        }
       
        BPMNShape shape = (BPMNShape) findDiagramElement(plane, node);
        Bounds bounds = shape.getBounds();
        correctEventNodeSize(shape);
        generator.writeObjectFieldStart("bounds");
        generator.writeObjectFieldStart("lowerRight");
        generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
        generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
        generator.writeEndObject();
        generator.writeObjectFieldStart("upperLeft");
        generator.writeObjectField("x", bounds.getX() - xOffset);
        generator.writeObjectField("y", bounds.getY() - yOffset);
        generator.writeEndObject();
        generator.writeEndObject();
    }
   
    private void correctEventNodeSize(BPMNShape shape) {
      BaseElement element = shape.getBpmnElement();
    if (element instanceof Event) {
      Bounds bounds = shape.getBounds();
      float width = bounds.getWidth();
      float height = bounds.getHeight();
      if (width != 30 || height != 30) {
        bounds.setWidth(30);
        bounds.setHeight(30);
        float x = bounds.getX();
        float y = bounds.getY();
          x = x - ((30 - width)/2);
          y = y - ((30 - height)/2);
        bounds.setX(x);
        bounds.setY(y);
      }
    } else if (element instanceof Gateway) {
      Bounds bounds = shape.getBounds();
      float width = bounds.getWidth();
      float height = bounds.getHeight();
      if (width != 40 || height != 40) {
        bounds.setWidth(40);
        bounds.setHeight(40);
        float x = bounds.getX();
        float y = bounds.getY();
          x = x - ((40 - width)/2);
          y = y - ((40 - height)/2);
        bounds.setX(x);
        bounds.setY(y);
      }
      }
    }
   
    protected void marshallDataObject(DataObject dataObject, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      Map<String, Object> properties = new LinkedHashMap<String, Object>(flowElementProperties);
        if(dataObject.getDocumentation() != null && dataObject.getDocumentation().size() > 0) {
            properties.put("documentation", dataObject.getDocumentation().get(0).getText());
        }
        if(dataObject.getName() != null && dataObject.getName().length() > 0) {
        properties.put("name", unescapeXML(dataObject.getName()));
      } else {
            // we need a name, use id instead
        properties.put("name", dataObject.getId());
      }
    if(dataObject.getItemSubjectRef().getStructureRef() != null && dataObject.getItemSubjectRef().getStructureRef().length() > 0) {
            if(defaultTypesList.contains(dataObject.getItemSubjectRef().getStructureRef())) {
          properties.put("standardtype", dataObject.getItemSubjectRef().getStructureRef());
            } else {
                properties.put("customtype", dataObject.getItemSubjectRef().getStructureRef());
            }
    }

        Association outgoingAssociaton = findOutgoingAssociation(plane, dataObject);
        Association incomingAssociation = null;

        Process process = (Process) plane.getBpmnElement();
        for (Artifact artifact : process.getArtifacts()) {
            if (artifact instanceof Association){
                Association association = (Association) artifact;
                if (association.getTargetRef() == dataObject){
                    incomingAssociation = association;
                }
            }
        }

        if(outgoingAssociaton != null && incomingAssociation == null) {
            properties.put("input_output", "Input");
        }

        if(outgoingAssociaton == null && incomingAssociation != null) {
            properties.put("input_output", "Output");
        }

    marshallProperties(properties, generator);
     
    generator.writeObjectFieldStart("stencil");
      generator.writeObjectField("id", "DataObject");
      generator.writeEndObject();
      generator.writeArrayFieldStart("childShapes");
      generator.writeEndArray();
      generator.writeArrayFieldStart("outgoing");

        List<Association> associations = findOutgoingAssociations(plane, dataObject);
        if(associations != null) {
            for(Association as : associations) {
                generator.writeStartObject();
                generator.writeObjectField("resourceId", as.getId());
                generator.writeEndObject();
            }
        }

      generator.writeEndArray();
     
      Bounds bounds = ((BPMNShape) findDiagramElement(plane, dataObject)).getBounds();
      generator.writeObjectFieldStart("bounds");
      generator.writeObjectFieldStart("lowerRight");
      generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
      generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
      generator.writeEndObject();
      generator.writeObjectFieldStart("upperLeft");
      generator.writeObjectField("x", bounds.getX() - xOffset);
      generator.writeObjectField("y", bounds.getY() - yOffset);
      generator.writeEndObject();
      generator.writeEndObject();
  }
   
    protected void marshallSubProcess(SubProcess subProcess, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def, Map<String, Object> flowElementProperties) throws JsonGenerationException, IOException {
      Map<String, Object> properties = new LinkedHashMap<String, Object>(flowElementProperties);
    if(subProcess.getName() != null) {
      properties.put("name", unescapeXML(subProcess.getName()));
    } else {
      properties.put("name", "");
    }
    if(subProcess instanceof AdHocSubProcess) {
      AdHocSubProcess ahsp = (AdHocSubProcess) subProcess;
      if(ahsp.getOrdering().equals(AdHocOrdering.PARALLEL)) {
        properties.put("adhocordering", "Parallel");
      } else if(ahsp.getOrdering().equals(AdHocOrdering.SEQUENTIAL)) {
        properties.put("adhocordering", "Sequential");
      } else {
        // default to parallel
        properties.put("adhocordering", "Parallel");
      }
      if(ahsp.getCompletionCondition() != null) {
        properties.put("adhoccompletioncondition", ((FormalExpression) ahsp.getCompletionCondition()).getBody().replaceAll("\n", "\\\\n"));
      }
    }

    // data inputs
        if(subProcess.getIoSpecification() != null) {
            List<InputSet> inputSetList = subProcess.getIoSpecification().getInputSets();
            StringBuilder dataInBuffer = new StringBuilder();
            for(InputSet inset : inputSetList) {
                List<DataInput> dataInputList =  inset.getDataInputRefs();
                for(DataInput dataIn : dataInputList) {
                  if(dataIn.getName() != null) {
                        dataInBuffer.append(dataIn.getName());
                        if(dataIn.getItemSubjectRef() != null && dataIn.getItemSubjectRef().getStructureRef() != null && dataIn.getItemSubjectRef().getStructureRef().length() > 0) {
                          dataInBuffer.append(":").append(dataIn.getItemSubjectRef().getStructureRef());
                        }
                        dataInBuffer.append(",");
                    }
                }
            }
            if(dataInBuffer.length() > 0) {
                dataInBuffer.setLength(dataInBuffer.length() - 1);
            }
            properties.put("datainputset", dataInBuffer.toString());
        }
       
        // data outputs
        if(subProcess.getIoSpecification() != null) {
            List<OutputSet> outputSetList = subProcess.getIoSpecification().getOutputSets();
            StringBuilder dataOutBuffer = new StringBuilder();
            for(OutputSet outset : outputSetList) {
                List<DataOutput> dataOutputList =  outset.getDataOutputRefs();
                for(DataOutput dataOut : dataOutputList) {
                    dataOutBuffer.append(dataOut.getName());
                    if(dataOut.getItemSubjectRef() != null && dataOut.getItemSubjectRef().getStructureRef() != null && dataOut.getItemSubjectRef().getStructureRef().length() > 0) {
                      dataOutBuffer.append(":").append(dataOut.getItemSubjectRef().getStructureRef());
                    }
                    dataOutBuffer.append(",");
                }
            }
            if(dataOutBuffer.length() > 0) {
                dataOutBuffer.setLength(dataOutBuffer.length() - 1);
            }
            properties.put("dataoutputset", dataOutBuffer.toString());
        }
       
        // assignments
        StringBuilder associationBuff = new StringBuilder();
        List<DataInputAssociation> inputAssociations = subProcess.getDataInputAssociations();
        List<DataOutputAssociation> outputAssociations = subProcess.getDataOutputAssociations();
        List<String> uniDirectionalAssociations = new ArrayList<String>();
        //List<String> biDirectionalAssociations = new ArrayList<String>();
       
        for(DataInputAssociation datain : inputAssociations) {
            String lhsAssociation = "";
            if(datain.getSourceRef() != null && datain.getSourceRef().size() > 0) {
              if(datain.getTransformation() != null && datain.getTransformation().getBody() != null) {
                lhsAssociation = datain.getTransformation().getBody();
              } else {
                lhsAssociation = datain.getSourceRef().get(0).getId();
              }
            }
           
            String rhsAssociation = "";
            if(datain.getTargetRef() != null) {
                rhsAssociation = ((DataInput) datain.getTargetRef()).getName();
            }
           
            //boolean isBiDirectional = false;
            boolean isAssignment = false;
           
            if(datain.getAssignment() != null && datain.getAssignment().size() > 0) {
                isAssignment = true;
            }
//            else {
//                // check if this is a bi-directional association
//                for(DataOutputAssociation dataout : outputAssociations) {
//                    if(dataout.getTargetRef().getId().equals(lhsAssociation) &&
//                       ((DataOutput) dataout.getSourceRef().get(0)).getName().equals(rhsAssociation)) {
//                        isBiDirectional = true;
//                        break;
//                    }
//                }
//            }
           
            if(isAssignment) {
              // only know how to deal with formal expressions
              if( datain.getAssignment().get(0).getFrom() instanceof FormalExpression) {
                String associationValue = ((FormalExpression) datain.getAssignment().get(0).getFrom()).getBody();
                if(associationValue == null) {
                  associationValue = "";
                }
                String replacer = associationValue.replaceAll(",", "##");
                associationBuff.append(rhsAssociation).append("=").append(replacer);
                  associationBuff.append(",");
              }
            }
//            else if(isBiDirectional) {
//                associationBuff.append(lhsAssociation).append("<->").append(rhsAssociation);
//                associationBuff.append(",");
//                biDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
//            }
            else {
                if(lhsAssociation != null && lhsAssociation.length() > 0) {
                    associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                    associationBuff.append(",");
                    uniDirectionalAssociations.add(lhsAssociation + "," + rhsAssociation);
                }
            }
        }
       
        for(DataOutputAssociation dataout : outputAssociations) {
            if(dataout.getSourceRef().size() > 0) {
                String lhsAssociation = ((DataOutput) dataout.getSourceRef().get(0)).getName();
                String rhsAssociation = dataout.getTargetRef().getId();
               
                boolean wasBiDirectional = false;
                // check if we already addressed this association as bidirectional
//                for(String bda : biDirectionalAssociations) {
//                    String[] dbaparts = bda.split( ",\\s*" );
//                    if(dbaparts[0].equals(rhsAssociation) && dbaparts[1].equals(lhsAssociation)) {
//                        wasBiDirectional = true;
//                        break;
//                    }
//                }
               
                if(dataout.getTransformation() != null && dataout.getTransformation().getBody() != null) {
                  rhsAssociation = dataout.getTransformation().getBody().replaceAll("=", "||");
                }
               
                if(!wasBiDirectional) {
                    if(lhsAssociation != null && lhsAssociation.length() > 0) {
                        associationBuff.append(lhsAssociation).append("->").append(rhsAssociation);
                        associationBuff.append(",");
                    }
                }
            }
        }
       
        String assignmentString = associationBuff.toString();
        if(assignmentString.endsWith(",")) {
            assignmentString = assignmentString.substring(0, assignmentString.length() - 1);
        }
        properties.put("assignments", assignmentString);
       
        // on-entry and on-exit actions
        if(subProcess.getExtensionValues() != null && subProcess.getExtensionValues().size() > 0) {
           
            String onEntryStr = "";
            String onExitStr = "";
            for(ExtensionAttributeValue extattrval : subProcess.getExtensionValues()) {
           
                FeatureMap extensionElements = extattrval.getValue();
       
                @SuppressWarnings("unchecked")
                List<OnEntryScriptType> onEntryExtensions = (List<OnEntryScriptType>) extensionElements
                                                     .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_ENTRY_SCRIPT, true);
       
                @SuppressWarnings("unchecked")
                List<OnExitScriptType> onExitExtensions = (List<OnExitScriptType>) extensionElements
                                                  .get(DroolsPackage.Literals.DOCUMENT_ROOT__ON_EXIT_SCRIPT, true);
           
                for(OnEntryScriptType onEntryScript : onEntryExtensions) {
                    onEntryStr += onEntryScript.getScript();
                    onEntryStr += "|";
               
                    if(onEntryScript.getScriptFormat() != null) {
                        String format = onEntryScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        properties.put("script_language", formatToWrite);
                    }
                }
               
                for(OnExitScriptType onExitScript : onExitExtensions) {
                    onExitStr += onExitScript.getScript();
                    onExitStr += "|";
                   
                    if(onExitScript.getScriptFormat() != null) {
                        String format = onExitScript.getScriptFormat();
                        String formatToWrite = "";
                        if(format.equals("http://www.java.com/java")) {
                            formatToWrite = "java";
                        } else if(format.equals("http://www.mvel.org/2.0")) {
                            formatToWrite = "mvel";
                        } else {
                            formatToWrite = "java";
                        }
                        if(properties.get("script_language") != null) {
                            properties.put("script_language", formatToWrite);
                        }
                    }
                }
            }
            if(onEntryStr.length() > 0) {
                if(onEntryStr.endsWith("|")) {
                    onEntryStr = onEntryStr.substring(0, onEntryStr.length() - 1);
                }
                properties.put("onentryactions", onEntryStr);
            }
            if(onExitStr.length() > 0) {
                if(onExitStr.endsWith("|")) {
                    onExitStr = onExitStr.substring(0, onExitStr.length() - 1);
                }
                properties.put("onexitactions", onExitStr);
            }
        }
       
        // loop characteristics
        boolean haveValidLoopCharacteristics = false;
        if(subProcess.getLoopCharacteristics() != null && subProcess.getLoopCharacteristics() instanceof MultiInstanceLoopCharacteristics) {

            MultiInstanceLoopCharacteristics taskmi = (MultiInstanceLoopCharacteristics) subProcess.getLoopCharacteristics();
            if(taskmi.getLoopDataInputRef() != null) {
                ItemAwareElement iedatainput = taskmi.getLoopDataInputRef();

                List<DataInputAssociation> taskInputAssociations = subProcess.getDataInputAssociations();
                for(DataInputAssociation dia : taskInputAssociations) {
                    if(dia.getTargetRef().equals(iedatainput)) {
                        properties.put("multipleinstancecollectioninput", dia.getSourceRef().get(0).getId());
                        break;
                    }
                }
            }
            if(taskmi.getLoopDataOutputRef() != null) {
                ItemAwareElement iedataoutput = taskmi.getLoopDataOutputRef();

                List<DataOutputAssociation> taskOutputAssociations = subProcess.getDataOutputAssociations();
                for(DataOutputAssociation dout : taskOutputAssociations) {
                    if(dout.getSourceRef().get(0).equals(iedataoutput)) {
                        properties.put("multipleinstancecollectionoutput", dout.getTargetRef().getId());
                        break;
                    }
                }
            }

            if(taskmi.getInputDataItem() != null) {
                List<DataInput> taskDataInputs = subProcess.getIoSpecification().getDataInputs();
                for(DataInput din: taskDataInputs) {

                    if (din.getItemSubjectRef() == null) {
                        // for backward compatibility as the where only input supported
                        properties.put("multipleinstancedatainput", taskmi.getInputDataItem().getId());
                        haveValidLoopCharacteristics = true;
                    }
                    if(din.getItemSubjectRef() != null && din.getItemSubjectRef().getId().equals(taskmi.getInputDataItem().getItemSubjectRef().getId())) {
                        properties.put("multipleinstancedatainput", din.getName());
                        haveValidLoopCharacteristics = true;
                        break;
                    }
                }
            }

            if(taskmi.getOutputDataItem() != null) {
                List<DataOutput> taskDataOutputs = subProcess.getIoSpecification().getDataOutputs();
                for(DataOutput dout : taskDataOutputs) {
                    if(dout.getItemSubjectRef() == null) {
                        properties.put("multipleinstancedataoutput", taskmi.getOutputDataItem().getId());
                        haveValidLoopCharacteristics = true;
                        break;
                    }

                    if(dout.getItemSubjectRef()!= null && dout.getItemSubjectRef().getId().equals(taskmi.getOutputDataItem().getItemSubjectRef().getId())) {
                        properties.put("multipleinstancedataoutput", dout.getName());
                        haveValidLoopCharacteristics = true;
                        break;
                    }
                }
            }
        }
       
        // properties
        List<Property> processProperties = subProcess.getProperties();
        if(processProperties != null && processProperties.size() > 0) {
            String propVal = "";
            for(int i=0; i<processProperties.size(); i++) {
                Property p = processProperties.get(i);
                propVal += p.getId();
                // check the structureRef value
                if(p.getItemSubjectRef() != null && p.getItemSubjectRef().getStructureRef() != null) {
                    propVal += ":" + p.getItemSubjectRef().getStructureRef();
                }
                if(i != processProperties.size()-1) {
                    propVal += ",";
                }
            }
            properties.put("vardefs", propVal);
        }

        // simulation properties
        if(_simulationScenario != null) {
            for(ElementParameters eleType : _simulationScenario.getElementParameters()) {
                if(eleType.getElementRef().equals(subProcess.getId())) {
                    TimeParameters timeParams = eleType.getTimeParameters();
                    Parameter processingTime = timeParams.getProcessingTime();
                    ParameterValue paramValue =  processingTime.getParameterValue().get(0);
                    if(paramValue instanceof NormalDistributionType) {
                        NormalDistributionType ndt = (NormalDistributionType) paramValue;
                        properties.put("mean", ndt.getMean());
                        properties.put("standarddeviation", ndt.getStandardDeviation());
                        properties.put("distributiontype", "normal");
                    } else if(paramValue instanceof UniformDistributionType) {
                        UniformDistributionType udt = (UniformDistributionType) paramValue;
                        properties.put("min", udt.getMin());
                        properties.put("max", udt.getMax());
                        properties.put("distributiontype", "uniform");

                        // bpsim 1.0 does not support random distribution
//              } else if(paramValue instanceof RandomDistributionType) {
//                RandomDistributionType rdt = (RandomDistributionType) paramValue;
//                properties.put("min", rdt.getMin());
//                properties.put("max", rdt.getMax());
//                properties.put("distributiontype", "random");
                    } else if(paramValue instanceof PoissonDistributionType) {
                        PoissonDistributionType pdt = (PoissonDistributionType) paramValue;
                        properties.put("mean", pdt.getMean());
                        properties.put("distributiontype", "poisson");
                    }
                    // bpsim 1.0 has no support for individual time unit
//              if(timeParams.getTimeUnit() != null) {
//                properties.put("timeunit", timeParams.getTimeUnit().getName());
//              }
                    if(timeParams.getWaitTime() != null) {
                        FloatingParameterType waittimeType = (FloatingParameterType) timeParams.getWaitTime().getParameterValue().get(0);
                        properties.put("waittime", waittimeType.getValue());
                    }

                    CostParameters costParams = eleType.getCostParameters();
                    if(costParams != null) {
                        if(costParams.getUnitCost() != null) {
                            FloatingParameterType unitCostVal = (FloatingParameterType) costParams.getUnitCost().getParameterValue().get(0);
                            properties.put("unitcost", unitCostVal.getValue());
                        }
                        // bpsim 1.0 does not support individual currency
                        //properties.put("currency", costParams.getUnitCost() == null ? "" : costParams.getUnitCost());
                    }
                }
            }
        }
   
      marshallProperties(properties, generator);
      generator.writeObjectFieldStart("stencil");
      if(subProcess instanceof AdHocSubProcess) {
          generator.writeObjectField("id", "AdHocSubprocess");
      } else {
            if(subProcess.isTriggeredByEvent()) {
                generator.writeObjectField("id", "EventSubprocess");
            } else {
                if(haveValidLoopCharacteristics) {
                    generator.writeObjectField("id", "MultipleInstanceSubprocess");
                } else {
                    generator.writeObjectField("id", "Subprocess");
                }
            }
      }
      generator.writeEndObject();
      generator.writeArrayFieldStart("childShapes");
      Bounds bounds = ((BPMNShape) findDiagramElement(plane, subProcess)).getBounds();
      for (FlowElement flowElement: subProcess.getFlowElements()) {
        // dont want to set the offset
        marshallFlowElement(flowElement, plane, generator, 0, 0, preProcessingData, def);
      }
      for (Artifact artifact: subProcess.getArtifacts()) {
        marshallArtifact(artifact, plane, generator, 0, 0, preProcessingData, def);
      }
      generator.writeEndArray();
      generator.writeArrayFieldStart("outgoing");
      for (BoundaryEvent boundaryEvent: subProcess.getBoundaryEventRefs()) {
          generator.writeStartObject();
          generator.writeObjectField("resourceId", boundaryEvent.getId());
          generator.writeEndObject();
        }
      for (SequenceFlow outgoing: subProcess.getOutgoing()) {
          generator.writeStartObject();
          generator.writeObjectField("resourceId", outgoing.getId());
          generator.writeEndObject();
        }
      // subprocess boundary events
      Process process = (Process) plane.getBpmnElement();
        for(FlowElement fe : process.getFlowElements()) {
          if(fe instanceof BoundaryEvent) {
            if(((BoundaryEvent) fe).getAttachedToRef().getId().equals(subProcess.getId())) {
              generator.writeStartObject();
                    generator.writeObjectField("resourceId", fe.getId());
                    generator.writeEndObject();
            }
          }
        }
      generator.writeEndArray();
     
      generator.writeObjectFieldStart("bounds");
      generator.writeObjectFieldStart("lowerRight");
      generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
      generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
      generator.writeEndObject();
      generator.writeObjectFieldStart("upperLeft");
      generator.writeObjectField("x", bounds.getX() - xOffset);
      generator.writeObjectField("y", bounds.getY() - yOffset);
      generator.writeEndObject();
      generator.writeEndObject();
  }
   
    protected void marshallSequenceFlow(SequenceFlow sequenceFlow, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset) throws JsonGenerationException, IOException {
      // dont marshal "dangling" sequence flow..better to just omit than fail
        if(sequenceFlow.getSourceRef() == null || sequenceFlow.getTargetRef() == null) {
            return;
        }

        Map<String, Object> properties = new LinkedHashMap<String, Object>();
      // check null for sequence flow name
      if(sequenceFlow.getName() != null && !"".equals(sequenceFlow.getName())) {
          properties.put("name", unescapeXML(sequenceFlow.getName()));
      } else {
          properties.put("name", "");
      }
      if(sequenceFlow.getDocumentation() != null && sequenceFlow.getDocumentation().size() > 0) {
            properties.put("documentation", sequenceFlow.getDocumentation().get(0).getText());
        }

        if(sequenceFlow.isIsImmediate()) {
            properties.put("isimmediate", "true");
        } else {
            properties.put("isimmediate", "false");
        }
     
      Expression conditionExpression = sequenceFlow.getConditionExpression();
      if (conditionExpression instanceof FormalExpression) {
          if(((FormalExpression) conditionExpression).getBody() != null) {
              properties.put("conditionexpression", ((FormalExpression) conditionExpression).getBody().replaceAll("\n", "\\\\n"));
          }
          if(((FormalExpression) conditionExpression).getLanguage() != null) {
              String cd = ((FormalExpression) conditionExpression).getLanguage();
              String cdStr = "";
              if(cd.equalsIgnoreCase("http://www.java.com/java")) {
                  cdStr = "java";
              } else if(cd.equalsIgnoreCase("http://www.jboss.org/drools/rule")) {
                  cdStr = "drools";
              } else if(cd.equalsIgnoreCase("http://www.mvel.org/2.0")) {
                  cdStr = "mvel";
              } else {
                  // default to mvel
                  cdStr = "mvel";
              }
              properties.put("conditionexpressionlanguage", cdStr);
          }
      }

        boolean foundBgColor = false;
      boolean foundBrColor = false;
      boolean foundFontColor = false;
      boolean foundSelectable = false;
      Iterator<FeatureMap.Entry> iter = sequenceFlow.getAnyAttribute().iterator();
        while(iter.hasNext()) {
            FeatureMap.Entry entry = iter.next();
            if(entry.getEStructuralFeature().getName().equals("priority")) {
                String priorityStr = String.valueOf(entry.getValue());
                if(priorityStr != null) {
                    try {
                        Integer priorityInt = Integer.parseInt(priorityStr);
                        if(priorityInt >= 1) {
                            properties.put("priority", entry.getValue());
                        } else {
                            _logger.error("Priority must be equal or greater than 1.");
                        }
                    } catch (NumberFormatException e) {
                        _logger.error("Priority must be a number.");
                    }
                }
            }
            if(entry.getEStructuralFeature().getName().equals("background-color")) {
              properties.put("bgcolor", entry.getValue());
              foundBgColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("border-color")) {
              properties.put("bordercolor", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("fontsize")) {
              properties.put("fontsize", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("color")) {
              properties.put("fontcolor", entry.getValue());
              foundFontColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("selectable")) {
              properties.put("isselectable", entry.getValue());
              foundSelectable = true;
            }
        }
        if(!foundBgColor) {
          properties.put("bgcolor", defaultSequenceflowColor);
        }
       
        if(!foundBrColor) {
          properties.put("bordercolor", defaultSequenceflowColor);
        }
       
        if(!foundFontColor) {
          properties.put("fontcolor", defaultSequenceflowColor);
        }
       
        if(!foundSelectable) {
          properties.put("isselectable", "true");
        }
       
        // simulation properties
        if(_simulationScenario != null) {
          List<ElementParameters> elementParams = _simulationScenario.getElementParameters();
          for(ElementParameters eleType : elementParams) {
            if(eleType.getElementRef().equals(sequenceFlow.getId())) {
              FloatingParameterType valType = (FloatingParameterType) eleType.getControlParameters().getProbability().getParameterValue().get(0);
              properties.put("probability", valType.getValue());
            }
          }
        }
     
        marshallProperties(properties, generator);
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", "SequenceFlow");
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();

        generator.writeArrayFieldStart("outgoing");
        generator.writeStartObject();
        generator.writeObjectField("resourceId", sequenceFlow.getTargetRef().getId());
        generator.writeEndObject();
        generator.writeEndArray();
       
        Bounds sourceBounds = ((BPMNShape) findDiagramElement(plane, sequenceFlow.getSourceRef())).getBounds();
        Bounds targetBounds = ((BPMNShape) findDiagramElement(plane, sequenceFlow.getTargetRef())).getBounds();
        generator.writeArrayFieldStart("dockers");
        generator.writeStartObject();
        generator.writeObjectField("x", sourceBounds.getWidth() / 2);
        generator.writeObjectField("y", sourceBounds.getHeight() / 2);
        generator.writeEndObject();
        List<Point> waypoints = ((BPMNEdge) findDiagramElement(plane, sequenceFlow)).getWaypoint();
        for (int i = 1; i < waypoints.size() - 1; i++) {
          Point waypoint = waypoints.get(i);
            generator.writeStartObject();
            generator.writeObjectField("x", waypoint.getX());
            generator.writeObjectField("y", waypoint.getY());
            generator.writeEndObject();
        }
        generator.writeStartObject();
        generator.writeObjectField("x", targetBounds.getWidth() / 2);
        generator.writeObjectField("y", targetBounds.getHeight() / 2);
        generator.writeEndObject();
        generator.writeEndArray();
    }
   
    private DiagramElement findDiagramElement(BPMNPlane plane, BaseElement baseElement) {
      DiagramElement result = _diagramElements.get(baseElement.getId());
      if (result != null) {
        return result;
      }
      for (DiagramElement element: plane.getPlaneElement()) {
          if ((element instanceof BPMNEdge && ((BPMNEdge) element).getBpmnElement() == baseElement) ||
          (element instanceof BPMNShape && ((BPMNShape) element).getBpmnElement() == baseElement)) {
            _diagramElements.put(baseElement.getId(), element);
            return element;
          }
        }
      _logger.info("Could not find BPMNDI information for " + baseElement);
      return null;
    }
   
    protected void marshallGlobalTask(GlobalTask globalTask, JsonGenerator generator) {
        if (globalTask instanceof GlobalBusinessRuleTask) {
           
        } else if (globalTask instanceof GlobalManualTask) {
           
        } else if (globalTask instanceof GlobalScriptTask) {
           
        } else if (globalTask instanceof GlobalUserTask) {
           
        } else {
           
        }
    }

    protected void marshallGlobalChoreographyTask(GlobalChoreographyTask callableElement, JsonGenerator generator) {
        throw new UnsupportedOperationException("TODO"); //TODO!
    }

    protected void marshallConversation(Conversation callableElement, JsonGenerator generator) {
        throw new UnsupportedOperationException("TODO"); //TODO!
    }

    protected void marshallChoreography(Choreography callableElement, JsonGenerator generator) {
        throw new UnsupportedOperationException("TODO"); //TODO!
    }
   
    protected void marshallProperties(Map<String, Object> properties, JsonGenerator generator) throws JsonGenerationException, IOException {
        generator.writeObjectFieldStart("properties");
        for (Entry<String, Object> entry : properties.entrySet()) {
            generator.writeObjectField(entry.getKey(), String.valueOf(entry.getValue()));
        }
        generator.writeEndObject();
    }
   
    protected void marshallArtifact(Artifact artifact, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def) throws IOException {
      generator.writeStartObject();
      generator.writeObjectField("resourceId", artifact.getId());
      if (artifact instanceof Association) {
        marshallAssociation((Association)artifact, plane, generator, xOffset, yOffset, preProcessingData, def);
      } else if (artifact instanceof TextAnnotation) {
        marshallTextAnnotation((TextAnnotation) artifact, plane, generator, xOffset, yOffset, preProcessingData, def);
      } else if (artifact instanceof Group) {
        marshallGroup((Group) artifact, plane, generator, xOffset, yOffset, preProcessingData, def);
      }
      generator.writeEndObject();
    }
   
    protected void marshallAssociation(Association association, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions def) throws JsonGenerationException, IOException {
      Map<String, Object> properties = new LinkedHashMap<String, Object>();
        Iterator<FeatureMap.Entry> iter = association.getAnyAttribute().iterator();
        boolean foundBrColor = false;
        while(iter.hasNext()) {
            FeatureMap.Entry entry = iter.next();
            if(entry.getEStructuralFeature().getName().equals("type")) {
              properties.put("type", entry.getValue());
            }
            if(entry.getEStructuralFeature().getName().equals("bordercolor")) {
              properties.put("bordercolor", entry.getValue());
              foundBrColor = true;
            }
        }
        if(!foundBrColor) {
          properties.put("bordercolor", defaultSequenceflowColor);
        }
        if(association.getDocumentation() != null && association.getDocumentation().size() > 0) {
            properties.put("documentation", association.getDocumentation().get(0).getText());
        }
       
        marshallProperties(properties, generator);
        generator.writeObjectFieldStart("stencil");
        if(association.getAssociationDirection().equals(AssociationDirection.ONE)) {
          generator.writeObjectField("id", "Association_Unidirectional");
        } else if(association.getAssociationDirection().equals(AssociationDirection.BOTH)) {
          generator.writeObjectField("id", "Association_Bidirectional");
        } else {
          generator.writeObjectField("id", "Association_Undirected");
        }
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();
        generator.writeArrayFieldStart("outgoing");
        generator.writeStartObject();
        generator.writeObjectField("resourceId", association.getTargetRef().getId());
        generator.writeEndObject();
        generator.writeEndArray();
       
        Bounds sourceBounds = ((BPMNShape) findDiagramElement(plane, association.getSourceRef())).getBounds();

        Bounds targetBounds = null;
        float tbx = 0;
        float tby = 0;
        if(findDiagramElement(plane, association.getTargetRef()) instanceof BPMNShape) {
            targetBounds = ((BPMNShape) findDiagramElement(plane, association.getTargetRef())).getBounds();
        } else if(findDiagramElement(plane, association.getTargetRef()) instanceof BPMNEdge) {
            // connect it to first waypoint on edge
            List<Point> waypoints = ((BPMNEdge) findDiagramElement(plane, association.getTargetRef())).getWaypoint();
            if(waypoints != null && waypoints.size() > 0) {
                tbx = waypoints.get(0).getX();
                tby = waypoints.get(0).getY();
            }

        }
        generator.writeArrayFieldStart("dockers");
        generator.writeStartObject();
        generator.writeObjectField("x", sourceBounds.getWidth() / 2);
        generator.writeObjectField("y", sourceBounds.getHeight() / 2);
        generator.writeEndObject();
        List<Point> waypoints = ((BPMNEdge) findDiagramElement(plane, association)).getWaypoint();
        for (int i = 1; i < waypoints.size() - 1; i++) {
          Point waypoint = waypoints.get(i);
            generator.writeStartObject();
            generator.writeObjectField("x", waypoint.getX());
            generator.writeObjectField("y", waypoint.getY());
            generator.writeEndObject();
        }
        if(targetBounds != null) {
            generator.writeStartObject();
            generator.writeObjectField("x", targetBounds.getWidth() / 2);
            generator.writeObjectField("y", targetBounds.getHeight() / 2);
            generator.writeEndObject();
            generator.writeEndArray();
        } else {
            generator.writeStartObject();
            generator.writeObjectField("x", tbx);
            generator.writeObjectField("y", tby);
            generator.writeEndObject();
            generator.writeEndArray();
        }
    }

    protected void marshallTextAnnotation(TextAnnotation textAnnotation, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions defthrows JsonGenerationException, IOException{
      Map<String, Object> properties = new LinkedHashMap<String, Object>();
      properties.put("name", textAnnotation.getText());
        if(textAnnotation.getDocumentation() != null && textAnnotation.getDocumentation().size() > 0) {
            properties.put("documentation", textAnnotation.getDocumentation().get(0).getText());
        }
      properties.put("artifacttype", "Annotation");
     
      Iterator<FeatureMap.Entry> iter = textAnnotation.getAnyAttribute().iterator();
      boolean foundBrColor = false;
      boolean foundFontColor = false;
        while(iter.hasNext()) {
            FeatureMap.Entry entry = iter.next();
            if(entry.getEStructuralFeature().getName().equals("border-color")) {
              properties.put("bordercolor", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("fontsize")) {
              properties.put("fontsize", entry.getValue());
              foundBrColor = true;
            }
            if(entry.getEStructuralFeature().getName().equals("color")) {
              properties.put("fontcolor", entry.getValue());
              foundFontColor = true;
            }
        }
       
        if(!foundBrColor) {
          properties.put("bordercolor", defaultBrColor);
        }
       
        if(!foundFontColor) {
          properties.put("fontcolor", defaultFontColor);
        }
     
      marshallProperties(properties, generator);
       
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", "TextAnnotation");
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();
   
      generator.writeArrayFieldStart("outgoing");
      if(findOutgoingAssociation(plane, textAnnotation) != null) {
        generator.writeStartObject();
        generator.writeObjectField("resourceId", findOutgoingAssociation(plane, textAnnotation).getId());
        generator.writeEndObject();
      }
      generator.writeEndArray();
   
      Bounds bounds = ((BPMNShape) findDiagramElement(plane, textAnnotation)).getBounds();
      generator.writeObjectFieldStart("bounds");
      generator.writeObjectFieldStart("lowerRight");
      generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
      generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
      generator.writeEndObject();
      generator.writeObjectFieldStart("upperLeft");
      generator.writeObjectField("x", bounds.getX() - xOffset);
      generator.writeObjectField("y", bounds.getY() - yOffset);
      generator.writeEndObject();
      generator.writeEndObject();
    }
   
    protected void marshallGroup(Group group, BPMNPlane plane, JsonGenerator generator, int xOffset, int yOffset, String preProcessingData, Definitions defthrows JsonGenerationException, IOException{
      Map<String, Object> properties = new LinkedHashMap<String, Object>();
      if(group.getCategoryValueRef() != null && group.getCategoryValueRef().getValue() != null) {
        properties.put("name", unescapeXML(group.getCategoryValueRef().getValue()));
      }
     
      marshallProperties(properties, generator);
       
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", "Group");
        generator.writeEndObject();
        generator.writeArrayFieldStart("childShapes");
        generator.writeEndArray();
   
      generator.writeArrayFieldStart("outgoing");
      if(findOutgoingAssociation(plane, group) != null) {
        generator.writeStartObject();
        generator.writeObjectField("resourceId", findOutgoingAssociation(plane, group).getId());
        generator.writeEndObject();
      }
      generator.writeEndArray();
   
      Bounds bounds = ((BPMNShape) findDiagramElement(plane, group)).getBounds();
      generator.writeObjectFieldStart("bounds");
      generator.writeObjectFieldStart("lowerRight");
      generator.writeObjectField("x", bounds.getX() + bounds.getWidth() - xOffset);
      generator.writeObjectField("y", bounds.getY() + bounds.getHeight() - yOffset);
      generator.writeEndObject();
      generator.writeObjectFieldStart("upperLeft");
      generator.writeObjectField("x", bounds.getX() - xOffset);
      generator.writeObjectField("y", bounds.getY() - yOffset);
      generator.writeEndObject();
      generator.writeEndObject();
    }
   
    protected Association findOutgoingAssociation(BPMNPlane plane, BaseElement baseElement) {
      Association result = _diagramAssociations.get(baseElement.getId());
      if (result != null) {
        return result;
      }
        if (!(plane.getBpmnElement() instanceof Process)){
            throw new IllegalArgumentException("Don't know how to get associations from a non-Process Diagram");
        }
       
        Process process = (Process) plane.getBpmnElement();
        for (Artifact artifact : process.getArtifacts()) {
            if (artifact instanceof Association){
                Association association = (Association) artifact;
                if (association.getSourceRef() == baseElement){
                    _diagramAssociations.put(baseElement.getId(), association);
                    return association;
                }
            }
        }
        return null;
    }

    protected List<Association> findOutgoingAssociations(BPMNPlane plane, BaseElement baseElement) {
        List<Association> retList = new ArrayList<Association>();
        if (!(plane.getBpmnElement() instanceof Process)){
            throw new IllegalArgumentException("Don't know how to get associations from a non-Process Diagram");
        }

        Process process = (Process) plane.getBpmnElement();
        for (Artifact artifact : process.getArtifacts()) {
            if (artifact instanceof Association){
                Association association = (Association) artifact;
                if (association.getSourceRef() == baseElement){
                    retList.add(association);
                }
            }
        }
        return retList;
    }
   
    protected void marshallStencil(String stencilId, JsonGenerator generator) throws JsonGenerationException, IOException {
        generator.writeObjectFieldStart("stencil");
        generator.writeObjectField("id", stencilId);
        generator.writeEndObject();
    }
   
    private boolean isCustomElement(String taskType, String preProcessingData) {
        if(taskType != null && taskType.length() > 0 && preProcessingData != null && preProcessingData.length() > 0) {
            String[] preProcessingDataElements = preProcessingData.split( ",\\s*" );
            for(String preProcessingDataElement : preProcessingDataElements) {
                if(taskType.equals(preProcessingDataElement)) {
                    return true;
                }
            }
        }
        return false;
    }

  private static String unescapeXML(String str) {
    if (str == null || str.length() == 0)
      return "";

    StringBuffer buf = new StringBuffer();
    int len = str.length();
    for (int i = 0; i < len; ++i) {
      char c = str.charAt(i);
      if (c == '&') {
        int pos = str.indexOf(";", i);
        if (pos == -1) { // Really evil
          buf.append('&');
        } else if (str.charAt(i + 1) == '#') {
          int val = Integer.parseInt(str.substring(i + 2, pos), 16);
          buf.append((char) val);
          i = pos;
        } else {
          String substr = str.substring(i, pos + 1);
          if (substr.equals("&amp;"))
            buf.append('&');
          else if (substr.equals("&lt;"))
            buf.append('<');
          else if (substr.equals("&gt;"))
            buf.append('>');
          else if (substr.equals("&quot;"))
            buf.append('"');
          else if (substr.equals("&apos;"))
            buf.append('\'');
          else
            // ????
            buf.append(substr);
          i = pos;
        }
      } else {
        buf.append(c);
      }
    }
    return buf.toString();
  }

    private String updateReassignmentAndNotificationInput(String inputStr, String type) {
        if(inputStr != null && inputStr.length() > 0) {
            String ret = "";
            String[] parts = inputStr.split( "\\^\\s*" );
            for(String nextPart : parts) {
                ret += nextPart + "@" + type + "^";
            }
            if(ret.endsWith("^")) {
                ret = ret.substring(0, ret.length() - 1);
            }
            return ret;
        } else {
            return "";
        }
    }
}
TOP

Related Classes of org.jbpm.designer.bpmn2.impl.Bpmn2JsonMarshaller

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.