Auf dem Laufenden bleiben?
Erhalten Sie immer die neuesten Infos!

Bauen wir uns eine BPMN 2.0 Engine

Die Spatzen pfeifen es schon von den Dächern: Die BPMN 2.0 steht vor der Tür. Die neue Version heißt jetzt „Business Process Model and Notation“ und bringt einige Neuerungen mit. Eine der wichtigsten ist jedoch das sagenumwobene Metamodell sowie die Ausführungssemantik. Cool. Aber was ist das? Im Rahmen des Praxishandbuch BPMN, das wir gerade schreiben, haben wir uns damit natürlich ganz genau auseinandergesetzt. Heute möchte ich einmal zwei kleine Vorgeschmäcker geben: Ein Beispielprozess in BPMN 2.0 Syntax sowie die neusten Infos aus dem Maschinenraum – zur Entwicklung eines Prototyp einer BPMN 2.0 Process Engine.

Ein Bild sagt mehr als tausend Worte – und ein Beispiel mehr als jedes Schema

An dieser Stelle möchte ich eines vorneweg schicken: Mir sind einige graue Haare gewachsen als ich mich durch den BPMN 2.0 Spezifikationsentwurf gekämpft habe. Nun habe ich natürlich kein literarisches Meisterwerk erwartet. Überrascht hat mich dann aber, dass es so gut wie kein Beispiel-XML im gesamten Dokument gibt. Ich hoffe nicht zu lügen, ich meine es war genau ein Mini-Prozess. Vielleicht geht es ja nur mir so, aber ich kann Besipiel-XML-Dateien besser verstehen als weit verstreute XML-Schema-Bruchstücke (XSD). Naja, auch sonst sind Anwendungsbeispiele in der Spec spärlich gesäht. Aber gut, dafür gibt es dann ja auch unser Buch 🙂

Nun gut, also habe ich erst mal behende einen Beispielprozess aufgesetzt. Leider habe auch ich noch nicht alle Einzelheiten der Spec und des XML-Formats verstanden. Ich bin mir auch noch nicht sicher, ob der hier abgebildete Prozess wirklich hundertprozentig richtig ist, daher bitte einfach melden, wenn jemand anderer Meinung ist!

Der Prozess, den ich mir vorgenommen habe, entstammt natürlich unserem Buch, es ist ein kleiner Teilprozess für die Lieferung von Ware. Die Story ist ganz simpel: Die eigentliche Tourenplanung – welche Ware in welchem LKW zum Kunden geht – macht ein dafür ausgelegtes System. Wir rufen nur einen Service auf, damit unsere Ware berücksichtigt wird und werden benachrichtigt, wenn die Ware versendet ist. Eventuell benachrichtigen wir dann den Kunden über den Liefertermin, im Beispiel erfolgt dies durch einen Kundenbetreuer. Der Prozess ist hier dargestellt:

Für die Serialisierung als XML gibt es nun zwei wichtige Aspekte:

  • Semantik: Welcher Service wird aufgerufen, wer kann die Aufgabe bearbeiten, wie wird die Entscheidung getroffen, ob die Lieferterminavisierung notwendig ist, usw.
  • Layout: Wie sieht das Diagram aus, wie sind die Elemente angeordnet.

    Die beiden Aspekte werden von BPMN 2.0 getrennt behandeln. Heute wollen wir uns für den Anfang nur die Semantik zu Gemüte führen, ein Blogpost zum Layout folgt noch. Die Spezifiaktion definiert ein XML-Schema für die Semantik. Unter der Annahme, dass wir das Tourenplanungssystem über Webservices ansprechen sieht der Beispiel-Prozess in etwa so aus, wobei ehrlicherweise noch ein paar Aspekte fehlen:

    <?xml version="1.0" encoding="UTF-8"?>
    <bpmn:definitions id="ShipmentDefinitions"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://schema.omg.org/spec/BPMN/2.0 BPMN20.xsd"
      xmlns:bpmn="http://schema.omg.org/spec/BPMN/2.0"
      xmlns:sample="http://sample.bpmn.camunda.com/"
      xmlns:xbpmn="http://bpmn.camunda.com/"
      xmlns:tns="http://sample.bpmn.camunda.com/"
      typeLanguage="http://www.w3.org/2001/XMLSchema"
      expressionLanguage="http://www.w3.org/1999/XPath"
      targetNamespace="http://sample.bpmn.camunda.com/">
    
      <!-- imports -->
      <bpmn:import namespace="http://sample.bpmn.camunda.com/" l
                   ocation="SampleService.xsd"
                   importType="http://www.w3.org/2001/XMLSchema"/>
      <bpmn:import namespace="http://sample.bpmn.camunda.com/"
                   location="SampleService.wsdl"
                   importType="http://schemas.xmlsoap.org/wsdl/soap/"/>
      <bpmn:import namespace="http://sample.bpmn.camunda.com/"
                   location="ShipmentProcessService.wsdl"
                   importType="http://schemas.xmlsoap.org/wsdl/soap/"/>
    
      <!-- definition structures for process variables -->
      <bpmn:itemDefinition id="lieferungDef" itemKind="Information"
                           structureRef="sample:shipment"/>
    
      <!-- definition structures for messages -->
      <bpmn:itemDefinition id="ProzessStartenDef" itemKind="Information"
                           structureRef="sample:startShipmentProces"/>
      <bpmn:itemDefinition id="LieferungAnlegenDef" itemKind="Information"
                           structureRef="sample:createShipment"/>
      <bpmn:itemDefinition id="KommissioniertDef" itemKind="Information"
                           structureRef="sample:notifyShipmentConsigned"/>
    
      <!-- messages -->
      <bpmn:message name="ProzessStarten" id="ProzessStartenNachricht"
                    structureRef="tns:ProzessStartenDef"/>
      <bpmn:message name="LieferungAnlegen" id="LieferungAnlegenNachricht"
                    structureRef="tns:LieferungAnlegenDef"/>
      <bpmn:message name="Kommissioniert" id="KommissioniertNachricht"
                    structureRef="tns:KommissioniertDef"/>
    
      <!-- end points - out of scope for BPMN -->
      <bpmn:endPoint id="ProzessEndpoint">
        <xbpmn:... />
      </bpmn:endPoint>
      <bpmn:endPoint id="LiefersystemEndpoint">
        <xbpmn:... />
      </bpmn:endPoint>
    
      <!-- interfaces -->
      <bpmn:interface id="ProzessInterface" name="Lieferprozess Schnittstelle">
        <bpmn:operation name="startShipmentProcess">
          <bpmn:inMessageRef>tns:ProzessStartenNachricht</bpmn:inMessageRef>
        </bpmn:operation>
        <bpmn:operation name="notifyShipmentConsigned">
          <bpmn:inMessageRef>tns:KommissioniertNachricht</bpmn:inMessageRef>
        </bpmn:operation>
      </bpmn:interface>
      <bpmn:interface id="LiefersystemInterface" name="Liefersystem Schnittstelle">
        <bpmn:operation name="createShiptment">
          <bpmn:inMessageRef>tns:LieferungAnlegenNachricht</bpmn:inMessageRef>
        </bpmn:operation>
      </bpmn:interface>
    
      <!-- Resources / Performers -->
      <bpmn:resource id="VertriebResource" name="Vertrieb"/>
    
      <!-- process definition -->
      <bpmn:process id="Shipment" name="Shipment">
        <bpmn:documentation id="doc1">Teilprozess der Lieferung</bpmn:documentation>
    
        <!-- process variables -->
        <bpmn:dataObject id="lieferungVariable" name="Lieferung"
                         itemSubjectRef="tns:lieferungDef"/>
    
        <!-- Start-Event -->
        <bpmn:startEvent id="Start">
          <bpmn:dataOutput id="ProzessStartOutput"
                           itemSubjectRef="tns:ProzessStartenNachricht"/>
          <bpmn:dataOutputAssociation>
            <bpmn:assignment>
              <bpmn:from xsi:type="bpmn:tFormalExpression">
                 getDataOutput('ProzessStartOutput')/shipment
              </bpmn:from>
              <bpmn:to xsi:type="bpmn:tFormalExpression">
                 getDataObject('lieferungVariable')
              </bpmn:to>
            </bpmn:assignment>
            <bpmn:sourceRef>ProzessStartOutput</bpmn:sourceRef>
            <bpmn:targetRef>tns:lieferungVariable</bpmn:targetRef>
          </bpmn:dataOutputAssociation>
          <bpmn:messageEventDefinition messageRef="tns:ProzessStartenNachricht">
            <bpmn:operationRef>tns:startShipmentProcess</bpmn:operationRef>
          </bpmn:messageEventDefinition>
        </bpmn:startEvent>
    
        <!-- Activity 1: Service Task -->
        <bpmn:serviceTask id="LieferungBuchen" name="Lieferung buchen"
                          implementation="WebService" operationRef="createShipment">
          <xbpmn:url/>
          <bpmn:ioSpecification>
            <bpmn:dataInput id="LieferungBuchenInput" isCollection="false"
                            itemSubjectRef="tns:LieferungAnlegenNachricht"/>
            <bpmn:inputSet>
              <bpmn:dataInputRefs>LieferungBuchenInput</bpmn:dataInputRefs>
            </bpmn:inputSet>
            <bpmn:outputSet/>
          </bpmn:ioSpecification>
          <bpmn:dataInputAssociation>
            <bpmn:assignment>
              <bpmn:from xsi:type="bpmn:tFormalExpression">
                 bpmn:getDataObject('lieferungVariable')
              </bpmn:from>
              <bpmn:to xsi:type="bpmn:tFormalExpression">
                 bpmn:getDataInput('LieferungBuchenInput'/shipment/
              </bpmn:to>
            </bpmn:assignment>
            <bpmn:sourceRef>tns:lieferungVariable</bpmn:sourceRef>
            <bpmn:targetRef>LieferungBuchenInput</bpmn:targetRef>
          </bpmn:dataInputAssociation>
        </bpmn:serviceTask>
    
        <!-- Activity 2: Receive Task -->
        <bpmn:receiveTask id="WartenAufLieferung"
                          name="Warten auf Lieferung"
                          instantiate="false"
                          implementation="WebService"
                          operationRef="notifyShipmentConsigned"
                          messageRef="tns:Kommissioniert">
          <bpmn:ioSpecification>
            <bpmn:dataOutput id="KommissioniertOutput"
                             itemSubjectRef="tns:KommissioniertNachricht"/>
            <bpmn:inputSet/>
            <bpmn:outputSet>
              <bpmn:dataOutputRefs>KommissioniertOutput</bpmn:dataOutputRefs>
            </bpmn:outputSet>
          </bpmn:ioSpecification>
    
          <bpmn:dataOutputAssociation>
            <bpmn:assignment>
              <bpmn:from xsi:type="bpmn:tFormalExpression">
                getDataOutput('KommissioniertOutput')/shipment
              </bpmn:from>
              <bpmn:to xsi:type="bpmn:tFormalExpression">
                getDataObject('lieferungVariable')
              </bpmn:to>
            </bpmn:assignment>
            <bpmn:sourceRef>KommissioniertOutput</bpmn:sourceRef>
            <bpmn:targetRef>tns:lieferungVariable</bpmn:targetRef>
          </bpmn:dataOutputAssociation>
        </bpmn:receiveTask>
    
        <!-- Gateway -->
        <bpmn:exclusiveGateway id="PruefeAvisierung" name="Avisierung benoetigt?"/>
    
        <!-- Activity 3: User Task -->
        <bpmn:userTask id="LieferterminAvisieren" name="Liefertermin avisieren"
                       implementation="other">
          <bpmn:potentialOwner resourceRef="tns:VertriebResource"/>
        </bpmn:userTask>
    
        <!-- End Events -->
        <bpmn:endEvent id="End" name="End"/>
    
        <!-- Sequence Flow -->
        <bpmn:sequenceFlow id="flow1" name="Start->LieferungBuchen"
                           sourceRef="Start" targetRef="LieferungBuchen" />
        <bpmn:sequenceFlow id="flow2"
                           sourceRef="LieferungBuchen" targetRef="WartenAufLieferung"/>
        <bpmn:sequenceFlow id="flow3"
                           sourceRef="WartenAufLieferung" targetRef="PruefeAvisierung"/>
        <bpmn:sequenceFlow id="flow4"
                           sourceRef="PruefeAvisierung" targetRef="LieferterminAvisieren">
          <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">
            getDataObject('lieferungVariable')/confirmationRequired=true
          </bpmn:conditionExpression>
        </bpmn:sequenceFlow>
        <bpmn:sequenceFlow id="flow5" sourceRef="PruefeAvisierung" targetRef="End">
          <bpmn:conditionExpression xsi:type="bpmn:tFormalExpression">
            not( getDataObject('lieferungVariable')/confirmationRequired=true )
          </bpmn:conditionExpression>
        </bpmn:sequenceFlow>
        <bpmn:sequenceFlow id="flow6"
                           sourceRef="LieferterminAvisieren" targetRef="End"/>
      </bpmn:process>
    
    </bpmn:definitions>

    Ich möchte das XML fast einmal für sich wirken lassen 🙂 Wie gesagt, sollte jemand einen Fehler finden oder sonst gute Hinweise haben, immer her damit!

    Einen Aspekt möchte ich hervorheben: Die BPMN 2.0 lässt offen, in welcher Technologie Daten vorliegen, Services angebunden werden und Ausdrücke ausgewertet werden. Somit kann man sich eine Engine vorstellen die sehr BPEL-ähnlich arbeitet, mit XML und Webservice, oder aber auch eine Engine, die an Java oder ähnliches gebunden ist. Das coole daran ist, dass man sich trotzdem im Standard bewegt und auch eher leichtgewichtige Workflow-Engines durchaus BPMN kompatibel sein können (naja, okay, der Standard ist dick, so leichtgewichtig ist die Engine dann auch nicht mehr ;-)).

    Der Nachteil ist natürlich, dass ich einen Prozess nur dann von einer Engine auf die nächste kippen kann, wenn diese die gleiche Technologie unterstützt.

    Ein Serviceaufruf könnte bei einer Java-Engine dann evtl. so aussehen:

    ...
    <import
      namespace="http://sample.bpmn.camunda.com/"
      location="services.jar"
      importType="http://java.sun.com/" />
    
      <!-- Datenstruktur -->
      <itemDefinition id="LieferungAnlegenDef" itemKind="Information"
                      structureRef="com.camunda.bpmn.sample.Shipment" />
      <message name="LieferungAnlegen" id="LieferungAnlegenNachricht"
               structureRef="com.camunda.bpmn.sample.LieferungAnlegen" />
    
      <!-- Schnittstelle -->
      <interface id="LiefersystemInterface" name="Liefersystem Schnittstelle">
        <operation name="createShiptment">
          <inMessageRef>LieferungAnlegenNachricht</inMessageRef>
        </operation>
      </interface>
      ...
      <process id="Lieferprozess" name="Lieferung">
        <serviceTask id="LieferungBuchen" name="Lieferung buchen"
                     implementation="other"
                     operationRef="createShipment">
    
          <ioSpecification>
            <dataInput id="LieferungBuchenInput" isCollection="false"
                       itemSubjectRef="LieferungAnlegenNachricht" />
            <inputSet>
              <dataInputRefs>LieferungBuchenInput</dataInputRefs>
            </inputSet>
            <outputSet />
          </ioSpecification>
    
          <dataInputAssociation>
            <assignment>
              <from xsi:type="tFormalExpression">#{lieferungVariable}</from>
              <to xsi:type="tFormalExpression">#{LieferungBuchenInput.shipment}</to>
            </assignment>
            <sourceRef>lieferungVariable</sourceRef>
            <targetRef>LieferungBuchenInput</targetRef>
          </dataInputAssociation>
    
        </serviceTask>
        ...

    Eine Open Source BPMN 2.0 Engine?

    Nun möchte ich noch mein zweites Versprechen einlösen und kurz aus dem Nähkästchen plaudern. Ich bin ja eher so der Typ, der Beispiele braucht und gerne etwas ausprobiert. Theorie und Spezifikationen sind schön und wichtig, aber in der IT muß es ja auch irgendwann irgendwie tatsächlich laufen. Also gut, dachte ich mir, baue ich mal nen Prototypen für ne BPMN 2.0 Engine.

    Um nicht von Null zu starten habe ich die JBoss jBPM Process Virtual Machine als Grundlage genommen. Dort sind bereits die wesentlichen Konzepte einer Process Engine umgesetzt. In zwei längeren Zugfahrten konnte ich so schon meinen ersten einfachen BPMN 2.0 Prozess ausführen. Also: Es geht! Problematisch werden dann eher die vielen schmutzigen Details, wovon die Spec einige zu bieten hat 😉

    Die Idee und der Prototyp wurde inzwischen aufgegriffen und im jBPM weiterentwickelt. Aktuell eher als Proof of concept und Prototyp. Da er Open Source für jeden verfügbar und einsehbar ist denke ich eine schöne Sache, um BPMN 2.0 den Menschen – naja, den IT-Menschen – näher zu bringen!

    Fazit BPMN 2.0 Ausführungssemantik

    Mein aktuelles Fazit zur Ausführungssemantik ist: Sehr mächtig, aber auch komplex. Im Prinzip ist es BPEL ähnlicher geworden, die Mächtigkeit ist vergleichbar, die Komplexität dann eben auch. Witzig in diesem Zusammenhang übrigens auch folgendes Zitat, dessen Urheber ich anstandsweise nicht nennen möchte: „It would be a mistake to conclude there was some OMG deep thinking behind these fine points in the spec.  More often it was one guy thinking about how his own company’s BPEL engine (now being converted to BPMN 2.0 engine) behaves, and no one else paying attention.“

    Doch BPMN hat aus meiner Sicht Vorteile gegenüber BPEL, dies sind vor allem:

    • Kontrollfluß als Graph: Man kann also tatsächlich fachlich modellieren und das direkt ausführen. Natürlich bringt das Probleme für Process Engine Hersteller mit sich (es hat ja seine Gründe, warum es BPEL gab), ich finde jedoch, sollen sich lieber Hersteller damit rumschlagen als der Nutzer der Werkzeuge!
    • Grafische Notation entspricht den fachlichen Modellen: Mit BPMN hat man in der technischen die gleiche Notation wie in der fachlichen Modellierun. Ich will damit nicht sagen, dass man das gleiche Modell verwendet (daran glauben wir nicht so richtig, auch das begründen wir ausführlich im Buch). Aber die Modelle sind sich ähnlich und Business und IT sprechen die gleiche Sprache (BPMN).
    • Keine feste Bindung an Webservices und XML: Auch wenn es die Standardeinstellungen sind, BPMN kann jede Technoligie ausführen. Damit können BPMN Engines auch in Szenarien und Architekturen zum Einsatz kommen, wo BPEL bisher ungeeignet war.

    BPMN 2.0 – ist das was für mich? Sollte ich auf BPEL setzen oder abwarten?

    Mit diesen Fragen sind wir zur Zeit häufig konfrontiert. Und dies ist verständlich. Das Investment in eine Process Engine ist groß, das Tool wird einen lange Jhre begleiten und nicht selten die gesamte Unternehmens-IT-Infrastruktur mit prägen. BPEL galt als führender Standard hat in Projekten aber oft enttäuscht. Proprietäre Ansätze sind zwar häufig sehr gut, können oder wollen aber politisch nicht durchgesetzt werden.

    Und jetzt kommt da BPMN 2.0. Wird jetzt alles besser? Sollte man eventuell auf eine BPMN 2.0 Engine warten? Oder noch BPEL kaufen? Oder was ganz anderes machen? Oder oder oder?

    Zu diesem Thema entwickeln wir gerade einen Webcast. Sind Sie interessiert an diesem Thema? Würden Sie daran gerne teilnehmen? Dann sprechen Sie uns an! Teilen Sie uns mit welche Fragen Sie beschätigen. Wir versuchen eine Antwort zu finden… Denn den Kopf in den Sand stecken nützt ja nichts 😉

    Und das Buch?

    Ach ja, das Buch. Wie bei Büchern so üblich sind wir leider etwas hinter dem Zeitplan. Irgendwie muss man dann ja doch auch noch etwas arbeiten, so nebenbei. Wir sind jedoch zuversichtlich, dass Manuskript bald – endlich – abgeben zu können. Abonnieren Sie doch unseren Newsletter, dann bekommen Sie den Erscheinungstermin auf jeden Fall mit!

    Sollten Sie Feedback zu diesem Artikel, der Ausführungssemanik oder meinen Beispielen haben noch einmal der Aufruf: Melden Sie sich einfach! Sie können vielleicht noch das Buch beeinflussen 😉 Gerne als Kommentar oder per Email: bernd.ruecker@camunda.com

    Schon gelesen?

    Scientific performance benchmark of open source BPMN engines

    Why BPMN is not enough

    Decision Model and Notation (DMN) – the new Business Rules Standard. An introduction by example.

    Neues Whitepaper: Der Mythos Zero-Coding BPM

    10 Kommentare

    Hinterlassen Sie eine Antwort