Neue Open Source BPM für Java-Entwicklers: camunda BPM 7.0

Bernd Rücker

Mit camunda BPM gibt es ein BPMS unter Apache Open Source Lizenz. Es ist keine proprietäre Black-Box BPM-Suite sondern eine leichtgewichtige „embeddable“ Java Process Engine inklusive notwendiger Tools für den Enterprise Einsatz. Es kann sowohl in Plain-Java, Spring oder Tomcat Umgebungen als auch in Java EE Containern wie JBoss, Glassfish, Websphere oder Weblogic eingesetzt werden. Zeit sich das Ganze einmal genauer anzuschauen und es auch gegen vergleichbare Projekte (wie z.B. Activiti) abzugrenzen. In der nächsten Ausgabe des Java Magazins folgt ein ausführlicher Artikel von dem es heute bereits einen Auszug vorab gibt – und in der darauffolgenden Ausgabe dann ein Erfahrungsbericht von Zalando mit der Plattform.

In den letzten Jahren hat sich viel getan im BPM Bereich. Der Modellierungsstandard BPMN (Business Process Model and Notation) ist weltweit akzeptiert und wird nicht mehr in Frage gestellt. Seit Version 2.0 definiert er auch die so genannte Ausführungssemantik und kann von Process Engines direkt verarbeitet werden – ohne Übersetzung in eine andere Sprache wie BPEL oder jPDL.

Auch sind die Engines an sich sehr gereift und dank Open Source für jedermann verfügbar. Ein Trend hat sich dabei in unserer Projektpraxis als über die Maßen erfolgreich bewährt: „Embeddable Java Process Engines“.

Open Source für JAVA

Nachdem wir jahrelang an JBoss jBPM und Activiti mit entwickelt haben, haben wir Anfang des Jahres dann unser eigenes Open Source Projekt ins Leben gerufen: camunda BPM. Das Ziel ist es unsere Vision rund um „BPM + Java“ in der Breite zur Verfügung zu stellen – denn die Projekterfahrung hat uns recht gegeben, dass hier offensichtlich Bedarf besteht.

Abb. 1: Komponenten der camunda BPM Plattform

Abb. 1 stellt die Komponenten der camunda BPM Plattform dar. Das Projekt liegt zeitgemäß auf GitHub [1]. Aber für alle, die BPM, BPMN oder Workflow-Engines nicht so genau kennen starten wir mit einem kleinen Beispiel.

Rechnungseingangsprozess

Es mag ein abgegriffenes Beispiel sein – aber dafür ist es übersichtlich. Und ich hatte es auch schon öfter beim Kunden unter der Nase. Abb. 2 zeigt den umzusetzenden Prozess, Prozess und Workflow sehe ich von den Begriffen her synonym in diesem Zusammenhang.

Abb. 2: BPMN 2.0 Prozessmodell im camunda modeler (Eclipse Plug-In)

Der Prozess wird durch eine eingehende Rechnung gestartet (StartEvent). Daraufhin bekommt die Team-Assistenz eine Aufgabe zugewiesen, um zu bestimmen, wer die Rechnung freigeben soll (UserTask). Dann folgt die Rechnungsfreigabe an sich (UserTask) – je nach Ergebnis entscheidet die Engine wo es weiter geht (ExclusiveGateway). Ist die Rechnung freigegeben, dann wird sie in der Buchhaltung erfasst (UserTask) und danach wird die Rechnung vollautomatisch archiviert (ServiceTask).

Ein typischer Prozess also, er enthält Aufgaben für Menschen aber auch die vollautomatische Orchestrierung von Services. In dem Modell werden noch zusätzliche Attribute hinterlegt – wie in Abb. 3 angedeutet. Diese werden von der Process Engine zur Automatisierung gelesen und sind im Gegensatz zum Rest des Models nicht standardisiert.

Abb. 3: Attribute für die Ausführung

Moment, ist ein Standard nicht was Gutes? Natürlich, aber nicht um jeden Preis. Mit diesen so genannten Extensions – die übrigens vom Standard erlaubt sind – können wir die Engine ganz nah an Java bringen. Das ist zwar nicht mehr Hersteller- oder Plattformunabhängig, die dadurch reduzierte Komplexität ist uns das aber Wert – als Vergleich gibt es in [2] ein Beispiel für den standardisierten Aufruf eines WebServices, dort wird schnell ersichtlich was ich meine.

Was heißt dann aber Java-nah?

Eine Sache ist in Abb. 3 zu sehen: Wir benutzen die Java Unified Expression Language (JUEL) die sehr mächtig und bekannt ist – beispielsweise aus JSF. Beim ServiceTask sieht man, dass wir Java-Klassen und Beans direkt referenzieren können, wobei dies sowohl CDI als auch z. B. Spring-Beans sein können – oder natürlich Blueprint wer es gerne OSGi-o-terisch möchte.

Ein zweiter Aspekt ist die Schnittstelle zur Process Engine, hier bietet camunda BPM ein Java API an, für das wir viel gelobt werden. Listing 1 zeigt einen JUnit-Testcase der einen Durchlauf des Prozesses über das API steuert. Der Testcase fährt im Hintergrund eine Process Engine mit In-Memory-Datenbank hoch, die nur für die Zeit der Testdurchführung lebt. Diese Leichtgewichtigkeit macht es auch ganz einfach, testgetrieben vorzugehen und sollte auch eingefleischte Process-Engine-Skeptiker überzeugen. Im User Guide [3] wird noch etwas genauer auf Testing eingegangen – inkl. Verweis auf geeignete Testscopes und Mocking im Kontext von Prozessautomatisierung. Darüber hinaus gibt es unter [4] eine Contribution einer „Fluent Testing API“ – die Tests dann noch lesbarer macht wie in Listing 2 gezeigt.

Listing 1: Ein JUnit-Testcase verwendet die Java API
public class InvoiceTestCase extends ProcessEngineTestCase {

  @Deployment(resources="invoice.bpmn")
  public void testHappyPath() {
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("invoice");

    List<Task> tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list();

    assertEquals(1, tasks.size());
    assertEquals("assignApprover", tasks.get(0).getTaskDefinitionKey());

    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("approver", "somebody");
    taskService.complete(tasks.get(0).getId(), variables);

    tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list();

    assertEquals(1, tasks.size());
    assertEquals("approveInvoice", tasks.get(0).getTaskDefinitionKey());
    assertEquals("somebody", tasks.get(0).getAssignee());

    variables = new HashMap<String, Object>();
    variables.put("approved", Boolean.TRUE);
    taskService.complete(tasks.get(0).getId(), variables);

    tasks = taskService.createTaskQuery().processInstanceId(pi.getId()).list();

    assertEquals(1, tasks.size());
    assertEquals("prepareBankTransfer", tasks.get(0).getTaskDefinitionKey());
    taskService.complete(tasks.get(0).getId());

    assertProcessEnded(pi.getId());
  }
}
Listing 2: Fluent Testing API
assertThat(processInstance()).isWaitingAt("review");
assertThat(processInstance().task()).isAssignedTo("piggie");
processInstance().task().claim(USER_STAFF);
processInstance().task().complete("approved", true);

Im Testcase ist auch zu sehen wie die Engine mit Daten umgeht: Es können zu jeder Zeit während der Laufzeit key/value Pairs geschrieben und gelesen werden. Das können sowohl primitive Datentypen oder serialisierbare Objekte sein. Dabei kann der Serialisierungsmechanismus in der Engine sogar ausgetauscht werden falls man statt Java-Byte-Arrays lieber XML Datenstrukturen in der Datenbank möchte. Eine Best-Practice ist aber sowieso möglichst wenige Daten in der Process Engine zu speichern – idealerweise nur Referenzen auf Entitäten, die dann im Fachsystem liegen.

Die Daten (Prozessvariablen) müssen nicht im Prozess deklariert werden sondern verhalten sich wie eine Map – was den Mechanismus sehr flexibel macht. In der Projektpraxis wird dann meist eine Bean (Java Klasse) geschrieben, die den Zugriff auf die Variablen regelt und das typsicher so dass es selten Probleme macht. Das ist allerdings der Grund, dass Daten in der BPMN-Abdeckungsübersicht in Abb. 4 als nicht unterstützt aufgeführt sind.

[ header = camunda BPM 7.0: Open Source BPM für den Werkzeugkasten des Java-Entwicklers – Teil 2 ]

Eine „Process Application“

Im Beispiel hatten wir einen Prozess erstellt und einen Unit-Test geschrieben. Wenn wir die Anwendung live bringen wollen, brauchen wir aber noch eine Oberfläche für die UserTasks und müssen die Anwendung sinnvoll packagen. Nun gibt es verschiedene Möglichkeiten eine vollständige Anwendung mit Process Engine zu bauen – die Hauptunterscheidung ist:

  • Embedded Process Engine: die Anwendung fährt die Engine selbst hoch oder
  • Shared Process Engine: die Engine wird durch den Container hochgefahren und durch die Anwendungen lediglich benutzt.

Abb. 4: Embedded vs. Shared Process Engine

Abb. 5 zeigt diesen Unterschied. Als Daumenregel kann man sagen, dass wir die Shared Process Engine bevorzugen – denn dann muss sich der Anwendungsentwickler nicht um die Process Engine kümmern – diese ist Infrastruktur und wird auch vom Container als solche bereitgestellt. Ich vergleiche das gerne mit JPA – dies packt man (zumindest im Java EE Kontext) auch nicht mehr selbst ein – es ist einfach da.

Eine Shared Process Engine kann in einem Java EE 6 Container vollständig standardkonform betrieben werden, das bedeutet dass wir zum Beispiel Thread-Pools vom Container verwenden. In der Glassfish, Websphere und WebLogic Distribution verwenden wir dafür einen JCA Resource Adapter (RAR). Für den JBoss und Tomcat haben wir sogar spezifisch zugeschnittene Distributionen. Und noch eine kleine Anmerkung mit großer Wirkung am Rande: Natürlich klinken wir die Engine in die JTA Transaktionsteuerung ein – es können also wie gewohnt Transaktionen verwendet werden – auch Two Phase Commit (XA) ist kein Problem sofern es der Datenbanktreiber unterstützt.

Auf der Downloadseite des Projektes sind für die Container eigene Distributionen bereitgestellt in denen die Engine bereits installiert ist. Alternativ kann natürlich auch über die Installationsanleitung [3] die Engine in den eigenen Container eingebaut werden. Websphere und WebLogic Distributionen bleiben als einzige unseren Enterprise Kunden vorbehalten, denn nur Distributionen für Open Source Container sind selbst auch frei verfügbar.

Hat man einen so präparierten Container, kann man eine „Process Application“ deployen. Dazu muss einerseits eine Starter-Klasse wie in Listing 3 geschrieben und mit @ProcessApplication annotiert werden (ähnlich wie bei JAX-RS) und andererseits ein META-INF/processes.xml mit eingepackt werden (ähnlich wie das beans.xml bei CDI). Für Details kann ich dem Leser ans Herz legen, den „Get Started Guide“ in [5] unter die Lupe zu nehmen – dort sind auch die Maven Koordinaten zu finden um direkt loszulegen – auch mit einer Embedded Engine wenn gewünscht.

Listing 3: Starter-Klasse für ProcessApplication
@ProcessApplication("invoice-en")
public class InvoiceServletProcessApplication extends ServletProcessApplication {}
Oberflächen für unseren Prozess

Da die Process Engine über Java oder REST API steuerbar ist, kann man die BPM Oberflächen ganz einfach in die eigene UI-Technologie einbetten, da haben wir in Projekten von JSF über Vaadin, GWT und HTML5 bis zu PHP eigentlich schon alles gesehen. Was man typischerweise baut ist eine Aufgabenliste und Formulare für diese Aufgaben. Eine mögliche Alternative ist die mitgebrachte „camunda Taskliste“, dann muss man nur noch Formulare für die einzelnen Aufgaben bereitstellen. Dabei kann man die Technologie wieder frei wählen – in der Demoanwendung verwenden wir JSF, wie in Abb. 5 dargestellt. Als einfachere Alternative würde es auch reichen simple HTML Formulare zu definieren die dann angezeigt werden, auch dafür gibt es eine Demo.

Zum Prototyping kann die Taskliste übrigens auch ohne Formulare arbeiten und verwendet dann vollgenerische Formulare, in denen alle Prozessvariablen angezeigt und neue hinzugefügt werden können. Das ist ein sehr spannendes Thema, zu dem gerade im Forum eine Diskussion zwischen Contributoren geführt wird – wir freuen uns hier immer sehr über Feedback oder Beteiligung.

Abb. 5: camunda Tasklist und JSF-Formulare

Selber ausprobieren!

Die gesamte Anwendung ist als Projekt unter [6] zu finden und kann per Maven gebaut und danach direkt in den verschiedenen Containern deployed werden. Also los: ausprobieren!

Der kleine Abriss heute sollte einen ersten Einblick in camunda BPM geben. Im vollständigen Artikel gibt es dann noch mehr Informationen, unter anderem zu Vision und Roadmap des Open Source Projektes.

Geschrieben von
Bernd Rücker
Bernd Rücker
Bernd Rücker hat vor camunda BPM aktiv an der Entwicklung der Open Source Workflow Engines JBoss jBPM 3 und Activiti mitgearbeitet. Bernd begleitet seit 10 Jahren Kundenprojekte rund um BPM, Process Engines und Java Enterprise. Er ist Autor mehrerer Fachbücher, zahlreicher Zeitschriftenartikel und regelmäßiger Sprecher auf Konferenzen.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.