Aufruf der Activiti Engine und seiner Services – Teil 3

Für Sie interessant:

 

Open Source Businesslösungen

In dem Seminar Open Source Businesslösungen lernen Sie kompetente Entscheidungen für den Einsatz von speziellen Open Source Lösungen zu treffen.

Dies ist der dritte und letzte Teil einer Artikel-Serie zur Prozessautomatisierung mit BPMN und Activiti.

Im einleitenden ersten Teil geht es um die vorbereitenden Tätigkeiten, die notwendig sind, um die angebotenen Dienste zur Steuerung der Prozessautomatisierung der Laufzeitumgebung nutzen zu können.

Der zweite Teil dreht sich um die Modellierung und Einbindung eines BPMN-Prozesses.

Es sind bereits alle nötigen Voraussetzungen geschaffen und der in BPMN-modellierte Prozess eingebunden. Nun stellt sich die Frage, wie dieser Prozess, bzw. eine Instanz des Prozesses, aus einem Java-Projekt heraus gestartet und gesteuert werden kann.

Die ProcessEngine und seine Services

Die Abbildung 1 zeigt den Aufbau und die Abhängigkeiten der Activiti Engine. Die XML-Datei activiti.cfg.xml und die Konfiguration(-bean) ProcessEngineConfiguration sind schon aus den vorherigen Kapiteln bekannt. Sie bilden die Grundlage für die Erstellung einer ProcessEngine. Eine Instanz der ProcessEngine bietet sieben Dienste zur Prozessautomatisierung an. Im Folgenden werden exemplarisch der programmatische Aufruf sowie die vier wichtigsten Dienste und ihr Nutzen aufgezeigt.

ProcessEngine

Zuerst wird die ProcessEngine, also die Laufzeitumgebung, selbst benötigt. Sie lässt sich mit nachfolgendem Statement erstellen. Die Methode getDefaultProcessEngine der ProcessEngines-Klasse liefert als Rückgabe eine Referenz auf das erstellte ProcessEngine-Objekt. Mit diesem Objekt erfolgt wiederum später der Zugriff auf die verschiedenen Services.

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

RepositoryService

Das Repository der ProcessEngine ist das zentrale Ablagefach für BPMN-Modelle. Mittels RepositoryService erfolgt der Zugriff auf selbiges. So können unter anderem neue Modelle hinein geladen (Deployment) oder bestehende gelöscht werden.
Eine Referenz auf den RepositoryService wird über das ProcessEngine-Objekt mit folgendem Statement eingeholt:

RespositoryService repositoryService = processEngine.getRepositoryService();

Damit später eine Prozessinstanz vom modellierten Prozess gestartet werden kann, muss zunächst das BPMN-Modell „deployt“, d. h. in das Repository geladen werden. Beim Deployment-Vorgang überprüft der Service das Modell automatisch auf Korrektheit. Ist das Modell fehlerhaft, kann es nicht ins Repository geladen werden und eine Fehlermeldung wird ausgegeben. Das folgende Statement zeigt den Deployment-Aufruf für den o. g. Beispiel-Prozess:

repositoryService.createDeployment().addClasspathResource("ModelCastingProcess.bpmn20.xml").deploy();

RuntimeService

Falls das Modell erfolgreich „deployt“ werden konnte, kann mit Hilfe des RuntimeServices  eine Instanz des Prozesses gestartet werden. Der Dienst übernimmt neben dem Starten auch das Stoppen von laufenden Prozessen. Zudem lassen sich so genannte Prozessvariablen, also Variablen, die im Kontext der aktuellen Prozess-Instanz gespeichert werden, definieren.

Aber zunächst wird eine Referenz benötigt:

RuntimeService runtimeService = processEngine.getRuntimeService();

Im Beispiel sind noch vor Start des Prozesses die Daten einer Bewerberin vorhanden. Da sie wichtig für den Verlauf des Prozesses sind, werden Sie vor dem Prozessstart als Prozessvariablen erfasst. Name, E-Mail-Adresse, Größe, Gewicht und die Bild-URL werden in einer Map gespeichert:

Map<String, Object> variables = new HashMap<String, Object>();
variables.put("name", "inga");
variables.put("mailAddress", "inga@email.com");
variables.put("height", String.valueOf(180));
variables.put("weight", String.valueOf(64.6));
variables.put("imageURL", "http://PATH/TO/IMAGE.jpg");

Beim Starten einer Prozess-Instanz muss, neben der Map mit den Prozessvariablen, auch der Name des BPMN-Modells übergeben werden. Ein Aufruf sieht folgendermaßen aus:

ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("ModelCastingProcess", variables);

Als Rückgabe wird eine Referenz auf die gestartete Prozess-Instanz (ProcessInstance) geliefert.

Die Instanz zum Beispiel-Prozess wird nun starten. Anschließend wird die Engine dem Sequenzfluss vom Startpunkt innerhalb des Modells folgen und zur ersten ServiceTask „check ability for modeling“, dem Aufruf des CheckAbilityServices, kommen. Der Aufruf wird ausgeführt und das Ergebnis (hasPotential), wie oben gezeigt, als Prozessvariable gespeichert.
Bei den in Abbildung 6 definierten Bewerberdaten, erkennt der CheckAbilityService, dass ein Potential zum Modeln besteht. Dadurch verfolgt die ProcessEngine den Sequenzfluss bis zur UserTask „check appearance“. Die rote Markierung innerhalb der folgenden Abbildung soll den Weg des automatischen Prozessablaufs nochmal verdeutlichen:

Weg nach Start der Prozess-Instanz

TaskService

Der TaskService bietet Zugriff auf die einzelnen Aktivitäten (ServiceTasks, UserTasks, ScriptTasks etc.) innerhalb eines Prozessablaufs. Es können Aktivitäten abgeschlossen, neue standalone-Aktivitäten gestartet oder UserTasks bestimmten Personen(-gruppen) zugewiesen werden.

Auch hier liefert die ProcessEngine eine Instanz vom Service:

TaskService taskService = processEngine.getTaskService();

Ebenso können beim Abschließen von Aktivitäten weitere Prozessvariablen definiert werden.
Im Beispiel wird beim Abschließen der UserTask übergeben, ob eine Einladung verschickt werden soll oder nicht. Also ob der Mitarbeiter, nach Ansicht des Bewerberfotos, die Bewerberin in einem persönlichen Gespräch nochmal näher kennen lernen möchte oder eben nicht.
Es wird eine Map mit der entsprechenden Prozessvariable erzeugt.

Map<String, Object> taskVariables = new HashMap<String, Object>();
taskVariables.put("sendInvitationMail", true);

Fast alle Services der Activiti Engine bieten umfangreiche Abfrage-Möglichkeiten für die Suche nach Activiti-Entitäten an. Mit dem TaskService kann z. B. nach Aktivitäten gesucht werden, wie das nachfolgende Statement zeigt:

Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.complete(task.getId(), taskVariables);

In dem Beispiel lässt sich mit Hilfe der Prozess-Instanz-Id die noch abzuschließende UserTask ermitteln und anschließend abschließen. Der complete-Methode werden neben der UserTask-Id noch die neuen definierten Prozessvariablen übergeben.

Mit dem manuellen Abschließen der UserTask innerhalb des Beispiel-Prozesses kann die ProcessEngine wieder die Arbeit übernehmen und die letzte Aktivität (ServiceTask „send Invitation“) ausführen. Anschließend ist die laufende Prozess-Instanz beim Endpunkt angekommen und terminiert. Folgende Abbildung zeigt nochmal den gesamten Weg (roter Pfeil), den die Prozess-Instanz verfolgt hat:

Pfad innerhalb der ausgeführten Prozess-Instanz

HistoryService

Was bislang noch gar nicht erwähnt wurde: das umfassende Reporting innerhalb der Activiti Engine. Die Laufzeitumgebung ist in der Lage, umfassende Informationen zu einer Prozess-Instanz zu speichern, wie z. B. Start- und Endzeit der Prozess-Instanz, welcher Benutzer welche UserTask bearbeitet hat, die Ausführungsdauer der Prozess-Instanz/einer Aktivität, welchen Pfaden die Prozess-Instanz gefolgt ist usw.
Diese Informationen lassen sich mit Hilfe des HistoryServices abrufen. Hierzu wird zunächst eine Referenz benötigt:

HistoryService historyService = processEngine.getHistoryService();

Zu jeder abgeschlossenen Prozess-Instanz (ProcessInstance) lässt sich mittels einer Abfrage das dazugehörige HistoricProcessInstance-Objekt holen. Es beinhaltet alle gespeicherten Informationen.

HistoricProcessInstance historicProcessInstance = historyService
        .createHistoricProcessInstanceQuery()
        .processInstanceId(processInstance.getId()).singleResult();

Das HistoricProcessInstance-Object bietet für das Abrufen der historischen Informationen verschiedene get-Methoden, wie z .B. für die Start-, End- und Laufzeit:

Logger.getLogger(Main.class.getName()).log(Level.INFO,
        "Starttime: " + historicProcessInstance.getStartTime());
Logger.getLogger(Main.class.getName()).lo(Level.INFO,
        "Endtime: " + historicProcessInstance.getEndTime());
Logger.getLogger(Main.class.getName()).log(
        Level.INFO,
        "Duration (in ms): " + historicProcessInstance.getDurationInMillis());

Fazit und Ausblick

Dieser Blogartikel hat im Wesentlichen zwei Dinge aufgezeigt: Zum einen wurden die  generellen Vorteile einer Prozessautomatisierung (z. B. kürzere Implementierungszyklen, leichte Anpassbarkeit, etc.) deutlich und zum anderen wurde anhand eines Beispiels demonstriert, wie leicht sich die Prozessautomatisierung mit BPMN und Activiti umsetzen lässt.

Allerdings wurden bei weitem nicht alle Komponenten und Funktionen aus dem Activiti-Umfeld vorgestellt. Die Activiti Engine lässt sich nämlich hervorragend mit anderen Java-Technologien kombinieren, wie z. B. mit dem Spring-Framework oder der Contexts and Dependency Injection (CDI) von Java. Ein Adapter-Bau, wie in dem gezeigten Beispiel, ist damit nicht mehr nötig.
Für den Einsatz in einer serviceorientierten Architektur (SOA) ist die Activiti Engine ebenfalls prädestiniert. Und ein Aufruf von Webservices (SOAP oder REST) lässt sich auch mit wenig Aufwand realisieren.

Ein weiterer, mächtiger Bereich wurde nur sehr oberflächlich thematisiert, nämlich die Reporting- und Monitoring-Möglichkeiten der Activiti Engine. Gerade die daraus gewonnenen Informationen sind für eine Prozessanalyse und die anschließende Prozessoptimierung extrem wichtig. Sie können zur besseren Bewertung von Prozessabläufen genutzt werden, wodurch sich Verbesserungspotential schneller erkennen lässt.

Kurzum: Activiti bietet einen Funktionsumfang, der kaum noch Wünsche offen lässt und im Bereich der Prozessautomatisierung fast einzigartig ist.

Abseits der vielen Vorteile einer Prozessautomatisierung zeigt dieser Artikel darüber hinaus, dass eine vollständige Prozessautomatisierung ausschließlich durch den Fachbereich auf Grundlage von BPMN und ohne das Zutun eines Entwicklers sehr schwer bzw. gar nicht realisierbar ist.
Das mag die Softwareentwickler beruhigen, denn das heißt, dass sie nach wie vor dringend benötigt werden in der Prozessautomatisierung!

Artikel-Serie „Prozessautomatisierung mit BPMN und Activiti“

Bei diesem Blog-Eintrag handelt es sich um den dritten und letzten Beitrag zum Thema „Prozessautomatisierung mit BPMN und Activiti“.

Den einleitenden Teil 1 des Artikels finden Sie hier .

Teil 2 über die Modellierung und Einbindung eines BPMN-Prozesses finden Sie hier .