Kontynuuję cykl artykułów dotyczących jBPM.
W poprzednim artykule stworzyliśmy widok pokazujący wszystkie dostępne procesy biznesowe. Nadszedł czas aby spróbować uruchomić prosty proces.
Na początku utworzymy akcję, która stworzy instancję wybranego procesu biznesowego. W tym celu w edytorze pliku plugin.xml dodajemy koleją akcję do utworzonego wcześniej rozszerzenia org.eclipse.ui.actionSets. Wypełniamy atrybuty akcji podobnie jak w poprzednich akcjach, w polach id i class wpisujemy jbpm.actions.RunBPAction.
Aby nasza akcja mogła uzyskać informację jaki proces z listy procesów wybrał użytkownik, uzupełniamy metodę createPartControl klasy ProcessesViewer o linijkę ustawiającą nasz viewer jako dostawcę selekcji:
getSite().setSelectionProvider(viewer);
Następnie zadbajmy o to, aby nasza akcja była dostępna tylko wówczas, jeśli zaznaczono jeden element typu ProcessDefinition oraz żeby definicja wybranego procesu znajdowała się w naszej akcji w prywatnym polu:
private ProcessDefinition selectedDefinition;.
Aby to uzyskać w metodzie selectionChanged naszej akcji umieszczamy następujący kod:
if (!selection.isEmpty() && selection instanceof StructuredSelection && ((StructuredSelection) selection).size() == 1 && ((StructuredSelection) selection).getFirstElement() instanceof ProcessDefinition) {
action.setEnabled(true);
selectedDefinition = (ProcessDefinition) ((StructuredSelection) selection).getFirstElement();
} else {
action.setEnabled(false);
}
Teraz już możemy utworzyć instancję wybranego procesu oraz wreszcie go uruchomić. W metodzie run naszej akcji dodajmy:
ProcessInstance processInstance = selectedDefinition.createProcessInstance();
Token token = processInstance.getRootToken();
while (!token.hasEnded()) {
System.out.println(token.getNode().getName());
token.signal();
}
Wypróbujmy działanie na dowolnym procesie i zabierzmy się wreszcie za tworzenie i obsługę bardziej skomplikowanej aplikacji.
Utwórzmy nowy proces biznesowy i na jego podstawie rozwiniemy naszą aplikację o kolejne niezbędne elementy:
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="" name="first-process">
<start-state name="start">
<transition to="co-dalej"></transition>
</start-state>
<decision name="co-dalej">
<handler class="jbpm.handlers.MyDecisionHandler"></handler>
<transition to="cos-jeszcze" name="jeszcze cos"></transition>
<transition to="end" name="konczymy"></transition>
</decision>
<task-node name="cos-jeszcze">
<task name="komunikat" description="testowy komunikat">
<assignment class="jbpm.handlers.MyAssignmentHandler" />
</task>
<transition to="end"></transition>
</task-node>
<end-state name="end"></end-state>
</process-definition>
Jak widać nasz prosty proces rozpoczyna się decyzją co robić dalej, którą obsługiwać ma klasa MyDecisionHandler. Następnie w zależności od dokonanego wyboru kończy działanie lub wykonuje dodatkowe zadanie.
Aby obsłużyć element decyzyjny stwórzmy klasę MyDecisionHandler. Będzie ona implementować interfejs org.jbpm.graph.node.DecisionHandler:
public class MyDecisionHandler implements DecisionHandler {
public String decide(ExecutionContext ec) throws Exception {
final List<Transition> listaOdpowiedzi = ec.getNode().getLeavingTransitionsList();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Dialog dialog = new Dialog(shell) {
protected void createButtonsForButtonBar(Composite parent) {
int i =0;
for (Iterator<Transition> iterator = listaOdpowiedzi.iterator(); iterator.hasNext();) {
Transition tr = iterator.next();
createButton(parent, i, tr.getName(), false);
i++;
}
}
protected void buttonPressed(int buttonId) {
setReturnCode(buttonId);
close();
}
};
int odpowiedz = dialog.open();
MessageDialog.openInformation(shell, "Jbpm Plug-in", "wybrałeś " +listaOdpowiedzi.get(odpowiedz).getName());
return listaOdpowiedzi.get(odpowiedz).getName();
}
}
Klasa pobiera listę możliwych odpowiedzi i tworzy dialog zawierający przyciski odpowiadające kolejnym możliwym ścieżkom procesu. Jak widzimy w kodzie aplikacji nie podajemy, jaka implementacja interfejsu org.jbpm.graph.node.DecisionHandler ma zostać użyta, wszystko zostało określone w definicji procesu. Jest to jedna z ważniejszych cech programowania zorientowanego na grafy.
Stwórzmy teraz klasę MyAssignmentHandler, która obsłuży nasze dodatkowe zadanie. Zadanie to będzie polegało na wyświetleniu komunikatu zawierającego w treści opis (description) zadania. Klasa MyAssignmentHandler będzie implementować interfejs org.jbpm.taskmgmt.def.AssignmentHandler:
public class MyAssignmentHandler implements AssignmentHandler {
public void assign(Assignable assignable, ExecutionContext ec) throws Exception {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MessageDialog.openInformation(shell, ec.getTask().getName(), ec.getTask().getDescription());
}
}
W ten sposób stworzyliśmy kod niezbędny do obsłużenia całego zdefiniowanego wcześniej procesu. Widzimy, że jeśli stworzymy odpowiednią ilość kontrolek obsługujących wymagane akcje i interakcje z użytkownikiem, będziemy mogli programować procesy biznesowe przy pomocy grafów jBPM, bez linijki kodu w Javie.
Opisane tu rzeczy są tylko drobnym wycinkiem możliwości środowiska jBPM. Środowisko to jest naprawdę bogate, dobrze przemyślane i rozszerzalne. Wszystkich, których temat zainteresował odsyłam do dokumentacji projektu i własnych testów.

