首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析BPMN文件

解析BPMN文件
EN

Stack Overflow用户
提问于 2016-04-19 15:46:30
回答 2查看 4.9K关注 0票数 0

我的问题很简单。如何解析bpmn文件?Java中有没有这样做的包?我通过谷歌搜索找到了一个示例代码,但是没有main,也没有使用bpmn文件进行解析的方法。

代码语言:javascript
复制
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import javax.xml.namespace.QName;

import org.w3c.dom.Element;

import org.jbpm.api.JbpmException;
import org.jbpm.api.activity.ActivityBehaviour;
import org.jbpm.bpmn.common.Resource;
import org.jbpm.bpmn.common.ResourceParameter;
import org.jbpm.bpmn.flownodes.BpmnActivity;
import org.jbpm.bpmn.model.BpmnProcessDefinition;
import org.jbpm.bpmn.model.SequenceflowCondition;
import org.jbpm.bpmn.parser.BindingsParser;
import org.jbpm.internal.log.Log;
import org.jbpm.pvm.internal.cal.CronExpression;
import org.jbpm.pvm.internal.cal.Duration;
import org.jbpm.pvm.internal.env.EnvironmentImpl;
import org.jbpm.pvm.internal.model.ActivityImpl;
import org.jbpm.pvm.internal.model.CompositeElementImpl;
import org.jbpm.pvm.internal.model.ProcessDefinitionImpl;
import org.jbpm.pvm.internal.model.ScopeElementImpl;
import org.jbpm.pvm.internal.model.TimerDefinitionImpl;
import org.jbpm.pvm.internal.model.TransitionImpl;
import org.jbpm.pvm.internal.model.VariableDefinitionImpl;
import org.jbpm.pvm.internal.task.TaskDefinitionImpl;
import org.jbpm.pvm.internal.util.CollectionUtil;
import org.jbpm.pvm.internal.util.TagBinding;
import org.jbpm.pvm.internal.util.XmlUtil;
import org.jbpm.pvm.internal.xml.Bindings;
import org.jbpm.pvm.internal.xml.Parse;
import org.jbpm.pvm.internal.xml.Parser;

public class BpmnParser extends Parser {

  private static final Log log = Log.getLog(BpmnParser.class.getName());

  private static final String[] DEFAULT_ACTIVITIES_RESOURCES = { "jbpm.bpmn.flownodes.xml" };
  private static final String CATEGORY_ACTIVITY = "activity";
  private static final String[] SCHEMA_RESOURCES = { "BPMN20.xsd", "DiagramDefinition.xsd",
    "DiagramInterchange.xsd", "BpmnDi.xsd" };

  static BindingsParser bindingsParser = new BindingsParser();

  public BpmnParser() {
    // initialises bindings
    parseBindings();
    // Setting BPMN2 xsd schema
    setSchemaResources(SCHEMA_RESOURCES);
  }

  public Object parseDocumentElement(Element documentElement, Parse parse) {
    List<ProcessDefinitionImpl> processDefinitions = new ArrayList<ProcessDefinitionImpl>();

    parseDefinition(documentElement, parse);

    for (Element processElement : XmlUtil.elements(documentElement, "process")) {
      ProcessDefinitionImpl processDefinition = parseProcess(processElement, parse);
      processDefinitions.add(processDefinition);
    }

    return processDefinitions;
  }

  public ProcessDefinitionImpl parseProcess(Element processElement, Parse parse) {
    BpmnProcessDefinition processDefinition = new BpmnProcessDefinition();

    parse.contextStackPush(processDefinition);
    try {

      String id = XmlUtil.attribute(processElement, "id", parse);
      String name = XmlUtil.attribute(processElement, "name");

      if (id != null && !"".equals(id)) {
        processDefinition.setName(id);
      } else {
        parse.addProblem("Process has no or an empty id");
      }

      if (name != null) {
        processDefinition.setKey(name);
      }

      Element descriptionElement = XmlUtil.element(processElement, "documentation");
      if (descriptionElement != null) {
        String description = XmlUtil.getContentText(descriptionElement);
        processDefinition.setDescription(description);
      }

      parseResources((Element)processElement.getParentNode(), parse, processDefinition);

      parseInterfaces((Element)processElement.getParentNode(), parse, processDefinition);

      parseItemDefinitions((Element)processElement.getParentNode(), parse, processDefinition);

      parseMessages((Element)processElement.getParentNode(), parse, processDefinition);

      parseDataObjects(processElement, parse, processDefinition);

      // activities
      parseActivities(processElement, parse, processDefinition);

      // bind activities to their destinations
      parseSequenceFlow(processElement, parse, processDefinition);

    } finally {
      parse.contextStackPop();
    }

    return processDefinition;
  }

  // /////////////////////////////////////////////////////////////////////////////////////////

  protected void parseBindings() {
    Bindings bindings = new Bindings();
    setBindings(bindings);

    for (String activityResource : DEFAULT_ACTIVITIES_RESOURCES) {
      Enumeration<URL> resourceUrls = getResources(activityResource);
      if (resourceUrls.hasMoreElements()) {
        while (resourceUrls.hasMoreElements()) {
          URL resourceUrl = resourceUrls.nextElement();
          log.trace("loading bpmn activities from resource: " + resourceUrl);
          List<?> activityBindings = (List<?>) bindingsParser.createParse()
            .setUrl(resourceUrl)
            .execute()
            .checkErrors("bpmn activities from " + resourceUrl.toString())
            .getDocumentObject();

          for (TagBinding binding: CollectionUtil.checkList(activityBindings, TagBinding.class)) {
            binding.setCategory(CATEGORY_ACTIVITY);
            bindings.addBinding(binding);
          }
        }
      } else {
        log.trace("skipping unavailable activities resource: " + activityResource);
      }
    }
  }

  protected Enumeration<URL> getResources(String resourceName) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    Enumeration<URL> resourceUrls;
    try {
      resourceUrls = classLoader.getResources(resourceName);

      if (!resourceUrls.hasMoreElements()) {
        resourceUrls = BpmnParser.class.getClassLoader().getResources(resourceName);
      }
    } catch (Exception e) {
      throw new JbpmException("couldn't get resource urls for "+resourceName, e);
    }
    return resourceUrls;
  }

  private void parseDataObjects(Element element, Parse parse, BpmnProcessDefinition processDefinition) {
    List<VariableDefinitionImpl> variableDefinitions = new ArrayList<VariableDefinitionImpl>();

    for (Element dataElement : XmlUtil.elements(element, "dataObject")) {
      VariableDefinitionImpl variableDefinition = new VariableDefinitionImpl();

      String name = XmlUtil.attribute(dataElement, "id", parse);
      variableDefinition.setName(name);

      String typeRef = XmlUtil.attribute(dataElement, "itemSubjectRef");
      variableDefinition.setTypeName(processDefinition.getType(typeRef));

      variableDefinitions.add(variableDefinition);
    }

    processDefinition.setVariableDefinition(variableDefinitions);
  }

  public void parseActivities(Element element, Parse parse, CompositeElementImpl compositeElement) {
    List<Element> elements = XmlUtil.elements(element);
    for (Element nestedElement : elements) {
      String tagName = nestedElement.getLocalName();
      String name = XmlUtil.attribute(nestedElement, "name");
      String id = XmlUtil.attribute(nestedElement, "id", parse);

      TagBinding activityBinding = (TagBinding) getBinding(nestedElement, CATEGORY_ACTIVITY);
      if (activityBinding == null) {
        if (!"sequenceFlow".equals(tagName)) {
          log.debug("unrecognized activity: " + tagName);
        }
        continue;
      }

      ActivityImpl activity = compositeElement.createActivity();
      parse.contextStackPush(activity);
      try {
        activity.setType(activityBinding.getTagName());
        activity.setName(id);
        activity.setDescription(name);

        if (log.isDebugEnabled()) {
          log.debug("Parsing Activity: " + name + "(id=" + id + ")");
        }

        ActivityBehaviour activityBehaviour = (ActivityBehaviour) activityBinding.parse(nestedElement, parse, this);
        activity.setActivityBehaviour(activityBehaviour);
      } finally {
        parse.contextStackPop();
      }
    }
  }

  public void parseSequenceFlow(Element element, Parse parse, BpmnProcessDefinition processDefinition) {
    List<Element> transitionElements = XmlUtil.elements(element, "sequenceFlow");
    for (Element transitionElement : transitionElements) {

      // Parse attributes
      String transitionName = XmlUtil.attribute(transitionElement, "name");
      String transitionId = XmlUtil.attribute(transitionElement, "id", parse);
      String sourceRef = XmlUtil.attribute(transitionElement, "sourceRef", parse);
      String targetRef = XmlUtil.attribute(transitionElement, "targetRef", parse);

      if (log.isDebugEnabled()) {
        log.debug(transitionId + ": " + sourceRef + " -> " + targetRef);
      }

      // Create new outgoing transition on sourceActivity
      ActivityImpl sourceActivity = processDefinition.findActivity(sourceRef);
      TransitionImpl transition = null;
      if (sourceActivity != null) {
        transition = sourceActivity.createOutgoingTransition();
        transition.setName(transitionId);
        transition.setDescription(transitionName);
      } else {
        parse.addProblem("SourceRef " + sourceRef + " cannot be found");
      }

      // Create incoming transition on targetActivity
      ActivityImpl destinationActivity = processDefinition.findActivity(targetRef);
      if (destinationActivity != null) {
        destinationActivity.addIncomingTransition(transition);
      } else {
        parse.addProblem("TargetRef '" + targetRef + "' cannot be found");
      }

      // Set default sequence flow if applicable
      try {
        // If something went wrong parsing the activity, there is no behaviour and an exception is thrown in .getBehaviour()
        ActivityBehaviour behaviour = sourceActivity.getActivityBehaviour();
        if (behaviour instanceof BpmnActivity) {
          BpmnActivity bpmnActivity = (BpmnActivity) behaviour;
          String defaultSeqFlow = bpmnActivity.getDefault();
          if (bpmnActivity.isDefaultEnabled() && defaultSeqFlow != null) {
            if (transitionId.equals(defaultSeqFlow)) {
              processDefinition.findActivity(sourceRef).setDefaultOutgoingTransition(transition);
            }
          } else {
            processDefinition.findActivity(sourceRef).setDefaultOutgoingTransition(null);
          }
        } else {
          // Other flownodes do not have default sequenceFlows, so set it to null
          processDefinition.findActivity(sourceRef).setDefaultOutgoingTransition(null);
        }

      } catch (JbpmException je) {
        // catch it and only re-throw if not this specific exception.
        if (!je.getMessage().contains("no behaviour on")) {
          throw je;
        }
      }

      parseConditionOnSequenceFlow(parse, transitionElement, transitionId, transition);

      processDefinition.addSequenceFlow(transitionId, transition);
    }
  }

  public void parseConditionOnSequenceFlow(Parse parse, Element transitionElement, String transitionId, TransitionImpl transition) {
    Element conditionElement = XmlUtil.element(transitionElement, "conditionExpression");
    if (conditionElement != null) {
      String type = conditionElement.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "type");
      if ("bpmn:tFormalExpression".equals(type) || "tFormalExpression".equals(type)) {

        String expr = conditionElement.getTextContent();
        String lang = XmlUtil.attribute(conditionElement, "language");
        // TODO: add looking up the default language in the document under definitions if lang  is null.

        if (expr != null) {
          expr = expr.trim();
        }

        SequenceflowCondition condition = new SequenceflowCondition();
        condition.setExpression(expr);
        condition.setLanguage(lang);
        transition.setCondition(condition);

      } else {
        parse.addProblem("Type of the conditionExpression on sequenceFlow with id=" +
                transitionId + " is of onsupported type 'bpmn:tExpression'", transitionElement);
      }
    }
  }

  public void parseDefinition(Element documentElement, Parse parse) {
    parseImports(documentElement, parse);
  }

  public TaskDefinitionImpl parseTaskDefinition(Element element, Parse parse, ScopeElementImpl scopeElement) {
    TaskDefinitionImpl taskDefinition = new TaskDefinitionImpl();

    String taskName = XmlUtil.attribute(element, "name");
    taskDefinition.setName(taskName);

    BpmnProcessDefinition processDefinition = parse.contextStackFind(BpmnProcessDefinition.class);
    if (processDefinition.getTaskDefinition(taskName) != null) {
      parse.addProblem("duplicate task name " + taskName, element);
    } else {
      processDefinition.addTaskDefinitionImpl(taskDefinition);
    }

    return taskDefinition;
  }

  /**
   * Parses a <timerEventDefinition> element:
   *    * sets dueDate if 'timeDate' is used
   *    * sets duedateDescription if a duration expression is used
   *    * set cronExpression if a cron expression is used
   *
   * @param timerEventDefinitionElement The XML element that defines the timer definition
   * @param activity The activity on which the timer definition must be created
   * @param eventId The id of the event on which the timer is defined
   */
  public TimerDefinitionImpl parseTimerEventDefinition(Element timerEventDefinitionElement, Parse parse, String eventId) {

    Element timeDate = XmlUtil.element(timerEventDefinitionElement, "timeDate");
    Element timeCycle = XmlUtil.element(timerEventDefinitionElement, "timeCycle");

    if ( (timeDate != null && timeCycle != null)
            || (timeDate == null && timeCycle == null) ) {
      parse.addProblem("timerEventDefinition for event '" + eventId +
              "' requires either a timeDate or a timeCycle definition (but not both)");
      return null;
    }

    TimerDefinitionImpl timerDefinition = new TimerDefinitionImpl();

    if (timeDate != null) {
      parseTimeDate(eventId, parse, timeDate, timerDefinition);
    }

    if (timeCycle != null) {
      parseTimeCycle(eventId, parse, timeCycle, timerDefinition);
    }

    return timerDefinition;
  }

  protected void parseTimeDate(String catchEventId, Parse parse, Element timeDate, TimerDefinitionImpl timerDefinition) {
    String dueDateTime = timeDate.getTextContent();
    String dueDateTimeFormatText = (String) EnvironmentImpl.getFromCurrent("jbpm.duedatetime.format", false);
    if (dueDateTimeFormatText==null) {
      dueDateTimeFormatText = "dd/MM/yyyy HH:mm:ss";
    }
    SimpleDateFormat dateFormat = new SimpleDateFormat(dueDateTimeFormatText);
    try {
      Date duedatetimeDate = dateFormat.parse(dueDateTime);
      timerDefinition.setDueDate(duedatetimeDate);
    } catch (ParseException e) {
      parse.addProblem("couldn't parse timeDate '"+ dueDateTime
              + "' on intermediate catch timer event " + catchEventId, e);
    }
  }

  protected void parseTimeCycle(String catchEventId, Parse parse, Element timeCycle, TimerDefinitionImpl timerDefinition) {
    String cycleExpression = timeCycle.getTextContent();
    if (Duration.isValidExpression(cycleExpression)) {
      timerDefinition.setDueDateDescription(cycleExpression);
    } else if (CronExpression.isValidExpression(cycleExpression)) {
      timerDefinition.setCronExpression(cycleExpression);
    } else {
      parse.addProblem("couldn't parse timeDate duration '"+ cycleExpression
              + "' on intermediate catch timer event " + catchEventId);
    }
  }

  public void parseResources(Element documentElement, Parse parse, BpmnProcessDefinition processDefinition) {

    for (Element resourceElement : XmlUtil.elements(documentElement, "resource")) {

      Resource resource = new Resource();

      resource.setId(XmlUtil.attribute(resourceElement, "id"));
      resource.setName(XmlUtil.attribute(resourceElement, "name"));

      for (Element resourceParameterElement : XmlUtil.elements(documentElement, "resourceParameter")) {

        ResourceParameter resourceParameter = new ResourceParameter();
        resourceParameter.setId(XmlUtil.attribute(resourceParameterElement, "id"));
        resourceParameter.setName(XmlUtil.attribute(resourceParameterElement, "name"));
        resourceParameter.setType(QName.valueOf(XmlUtil.attribute(resourceParameterElement, "name")));

        resource.getParameters().put(XmlUtil.attribute(resourceParameterElement, "name"), resourceParameter);
      }

      processDefinition.getResources().put(resource.getName(), resource);
    }

  }

  public void parseInterfaces(Element documentElement, Parse parse, BpmnProcessDefinition processDefinition) {

    for (Element interfaceElement : XmlUtil.elements(documentElement, "interface")) {
      for (Element operationElement : XmlUtil.elements(interfaceElement, "operation")) {
        processDefinition.getOperations().put(XmlUtil.attribute(operationElement, "id"), operationElement);
      }
      processDefinition.getInterfaces().put(XmlUtil.attribute(interfaceElement, "id"), interfaceElement);
    }
  }

  public void parseMessages(Element documentElement, Parse parse, BpmnProcessDefinition processDefinition) {

    for (Element messageElement : XmlUtil.elements(documentElement, "message")) {
      processDefinition.getMessages().put(XmlUtil.attribute(messageElement, "id"), messageElement);
    }
  }

  public void parseItemDefinitions(Element documentElement, Parse parse, BpmnProcessDefinition processDefinition) {

    for (Element itemDefinitionElement : XmlUtil.elements(documentElement, "itemDefinition")) {
      processDefinition.getItemDefinitions().put(XmlUtil.attribute(itemDefinitionElement, "id"), itemDefinitionElement);
    }

  }

  public void parseImports(Element documentElement, Parse parse) {

  }

}
EN

回答 2

Stack Overflow用户

发布于 2016-04-23 04:53:35

可以使用several products来解析BPMN文件。jBPM是一种开源的Java选择。

真正的问题是,一旦被解析,你想用它做什么。您可能希望实际执行业务流程,而我将利用前面提到的产品之一来执行,而不是重新发明轮子。

票数 1
EN

Stack Overflow用户

发布于 2016-04-19 20:23:10

由于BPMN使用XML文件来实现互操作性,因此您可以使用任何标准的Java XML解析器(可以参考JAXP tutorial)。

您可以从BPMN specification page获取所有XML schema。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36711819

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档