Wprowadzenie

Funkcja modułu i definicje podstawowych pojęć

Moduł proc wspomaga obsługę przetwarzania dowolnych elementów, posiadających pewien wewnętrzny stan. Zbiór możliwych stanów oraz relacje pomiędzy nimi muszą być możliwe do opisania za pomocą grafu, którego wierzchołki stanowią stany, a krawędziami są relacje pomiędzy stanami. Krawędzie będą w dalszej części opisu nazywane przejściami a graf stanów i przejść będzie określany jako proces. Proces jest realizowany w pewnym systemie. Proces stanowi więc pewien szablon, schemat możliwych zmian stanów pewnych elementów. Może istnieć wiele elementów, których stany zmieniają się w sposób określony przez proces, ale każdy z tych elementów może w pewnej wybranej chwili czasu mieć stan dowolny spośród zdefiniowanych w procesie. Elementy będą nazywane instancjami procesu.

Powodem powstania modułu była konieczność sformalizowania opisu stanów oraz przejść, co umożliwia dekompozycję procesu i powiązanie występujących w procesie czynności z konkretnymi stanami i przejściami, a tym samym pozwala zapanować nad dużą ilością czynności w procesie. Jednocześnie moduł był projektowany tak, aby w jak najmniejszym stopniu ograniczać swobodę i możliwości użytkownika podczas realizacji różnorodnych procesów.

Podstawowym zadaniem modułu proc jest wspomaganie realizacji procesów biznesowych w technologii jPalio, co określa sposób realizacji czynności w procesie. Przyjmuje się, że instancja procesu znajdująca się w określonym stanie jest w pewnien sposób prezentowana użytkownikowi systemu. Do tego celu wykorzystywana jest wybrana strona html wykonana w jPalio. Na stronie tej umieszczane są informacje związane ze stanem instancji oraz kontrolki umożliwiające użytkownikowi wyzwolenie akcji polegającej na przeniesieniu instancji procesu do innego stanu, czyli wykonanie przejścia. Wyzwolenie akcji powoduje submit formularza html na tą samą stronę jPalio, na której umieszczona była przezentacja danego stanu. Odpowiednia funkcja z modułu proc wykrywa wyzwolenie akcji, wykonuje czynności związane z przejściem i wywołuje obiekty odpowiedzialne za przezentację instancji procesu w nowym stanie. Następnie użytkownik może wykonać kolejną akcję i sekwencja czynności powtarza się. Instancja w dowolnym stanie może być prezentowana dowolną ilość razy, co oznacza, że można wielokrotnie wyświetlać prezentację instancji w danym stanie bez podejmowania żadnych akcji albo w dowolnym momencie przerwać realizację procesu, np. przechodząc do innej strony html, na następnie ponownie wyświetlając stronę z prezentacją instancji w danym stanie i wykonując kolejne akcje w procesie.

  Przykład:
  
  Pewien proces sprzedażowy składa się z czterech stanów:
  A - wprowadzenie danych klienta,
  B - wprowadzenie danych zamówienia,
  C - realizacja zamówienia,
  D - zamówienie zrealizowane,
  graf stanów jest więc bardzo prosty A -> B -> C -> D.
  Instancją procesu jest tu zamówienie klienta (zgłoszenie).
  
  Rozpoczęcie składania zamówienia przez klienta powoduje utworzenie zgłoszenia (instancji
  procesu), któremu nadawany jest stan A i przejście na stronę, na której przezentowane
  jest zgłoszenie w stanie A. Prezentacja zgłoszenia w stanie A zawiera formularz do
  wprowadzania danych klienta oraz przycisk "zapisz". Kliknięcie przycisku "zapisz"
  powoduje submit formularza na tą samą stronę, wykrycie przejścia do stanu B, wykonanie
  akcji związanej z przejściem ze stanu A do stanu B (zapis formularza z danymi klienta),
  zmianę stanu zgłoszenia z A na B oraz wyświetlenie zgłoszenia w stanie B. Prezentacja
  zgłoszenia w stanie B zawiera formularz z danymi zamówienia oraz kolejny przycisk zapisz.
  Kliknięcie przycisku "zapisz" powoduje submit formularza na tą samą stronę, wykrycie
  przejścia do stanu C, wykonanie akcji związanej z przejściem ze stanu B do stanu C
  (zapis formularza z danymi zamówienia), zmianę stanu zgłoszenia z B na C oraz
  wyświetlenie zgłoszenia w stanie C. W tym momencie klient przerywa realizację procesu,
  przechodząc na inną stronę lub zamykając okienko przeglądarki. Każde zgłoszenie dodane
  w ten sposób przez klienta oprócz stanu posiada pewien jednoznaczny identyfikator.
  
  Pracownik obsługujący proces sprzedaży dysponuje listą zgłoszeń klientów.
  Wybiera jedno ze zgłoszeń i otwiera stronę, na której będzie ono prezentowane w swoim
  bieżącym stanie, na ogół C. Do strony przekazywany jest identyfikator zgłoszenia, na
  podstawie którego moduł proc może określić stan, w jakim się ono znajduje. W stanie C
  wyświetlane są zarówno dane klienta, jak i dane zgłoszenia oraz przycisk "zgłoszenie
  zrealizowane". Pracownik wykonuje czynności związane z realizacją zamówienia i klika
  przycisk "zapisz", co powoduje submit formularza na tą samą stronę, wykrycie przejścia
  do stanu D, wykonanie akcji związanej z przejściem ze stanu C do stanu D (jeśli
  jakakolwiek jest określona), zmianę stanu zgłoszenia z C na D oraz wyświetlenie
  zgłoszenia w stanie D. W stanie D nie są określone żadne przejścia, może być tam
  prezentowane to samo co w stanie C, ale nie są wyświetlane żadne przyciski.

Moduł wymaga utworzenia w bazie tabel opisanych w rozdziale "schemat tabel". Skrypt tworzący tabele jest dostępny w rozdziale "skrypt tworzący tabele".

Strona prezentująca instancje procesu

Kod najprostszej strony, na której prezentowane są instancje procesu, wygląda następująco (przy założeniu, że wykonywany proces ma id 618):

  $// strona wyświetlająca zgłoszenia
  $// _RowID - id zgłoszenia do wyświetlenia (id instancji procesu)
  
  $=(@orderId, $toLong($toString($_RowID)) )
  $=(@executionStatus, $proc.executeProcess(618, $@orderId, (String)null) )

$proc.executeProcess() jest główną funkcją modułu proc, zawierającą dispatcher wykonujący wszystkie czynności związane z obsługą procesu oraz wywołujący obiekty wykonujące akcje w procesie.

Rodzaje obiektów i ich rola w procesie

Moduł proc wykorzystuje kilka rodzajów obiektów, realizujących różne funkcje w procesie. Obiekty te można podzielić na:

Obiekty wspólne dla procesu są pojedynczymi obiektami jpalio. Obiekty akcji dla stanów i przejść to obiekty złożone, tzn. każdy taki obiekt jest elementem złożonym z kilku obiektów jpalio, wykonywanych w określonej przez użytkownika kolejności.

Obiekty złożone zostały wprowadzone po to, aby nie powielać obiektów wykonujących pewne elementarne czynności związane ze stanami i z przejściami - można raz napisać zestaw takich obiektów a następnie budować z nich obiekty złożone dla stanów i przejść. Oczywiście podobną funkcjonalność można byłoby uzyskać bez wprowadzania obiektów złożonych, pisząc analogiczne obiekty z elementarnymi funkcjonalnościami, a następnie budując z nich funkcjonalność czynności związanej ze stanem lub przejściem wewnątrz obiektu jpalio. Rozwiązanie z obiektami złożonymi ma jednak tą zaletę, iż daje odpowiednio przeszkolonemu końcowemu użytkownikowi aplikacji możliwość modyfikacji procesu z poziomu inerfejsu.

Obiekty określane dla procesu

Są to obiekty zbudowane z pojedynczego obiektu jpalio. Dla każdego procesu jest określany tylko jeden taki obiekt każego rodzaju.

Obiekt stanu

Moduł proc pozostawia użytkownikowi pełną swobodę wyboru miejsca i sposobu przechowywania instancji procesu. Sposób przechowywania musi spełniać dwa warunki:

Najprostsza tabela spełniająca warunki przechowywania instancji procesów (np. zgłoszeń) wygląda następująco:

  create table orders (
    id number(30) not null constraints ord_id_pk primary key using index tablespace indx,
    state_nr number(12) not null
  );

Powyższe warunki wymuszają konieczność wprowadzenia pewnego interfejsu, za pomocą którego moduł proc będzie mógł odczytać lub zmienić stan instancji o danym identyfikatorze. Dlatego dla każdego procesu wymagane jest określenie tzw. obiektu stanu, który umożliwia wykonanie wymienionych operacji. Dzięki takiemu rozwiązaniu można przechowywać dane instancji w dowolnym miejscu, np. w tabeli bazodanowej lub w zmiennych sesyjnych.

  Rozwiązanie z obiektem stanu daje także możliwość realizacji fragmentów procesu bez
  zapisywania danych do bazy - można utworzyć instancję poprzez nadanie jej kolejnego
  identyfikatora oraz stanu początkowego, zapisać stan instancji w zmiennej sesyjnej
  o nazwie zawierającej identyfikator instancji i wykonywać proces do pewnego etapu,
  na którym dopiero tworzona jest właściwa instancja w bazie danych (rozwiązanie takie
  można wykorzystać np. do realizacji stron, na których klient odpowiada na pewien zestaw
  pytań przed właściwym dodaniem zgłoszenia).

Obiekt stanu może być wywoływany więcej niż raz przy jednym wyświetleniu instancji procesu. Obiekt nie powinien nic wyświetlać. Zobacz szczegóły wywołania oraz szablon obiektu stanu.

Obiekt błędu

Podczas wykonywania procesu mogą zdarzyć się dwa rodzaje błędów:

  1. błędy (np. wyjątki) wewnątrz obiektów jpalio wykonujących czynności w procesie
  2. błędy wewnętrzne modułu proc związane:
    • ze błędami struktury procesu (np. brak definicji stanu o danym numerze)
    • z działaniem obiektu stanu (np. błędne działanie obiektu stanu polegające na nie zwróceniu wartości w odpowiedniej zmiennej globalnej)
    • z przekazywaniem niezbędnych zmiennych podczas submitów formularza (np. nie przekazanie id procesu przy submicie formularza)
    • z brakiem uprawnień użytkownika do stanu

Błędy pierwszego rodzaju są ignorowane przez moduł proc, tzn. wyjątki nie są łapane i sterowanie przechodzi do obiektów wywołujących metody modułu proc.

Do obsługi błędów drugiego rodzaju przeznaczony jest obiekt błędu. Obiekt ten jest wywoływany po wykryciu błędu z parametrami umożliwiającymi obsługę błędu, np. wyświetlenie komunikatu o braku uprawnień wraz z nagłówkiem i stopką używanymi w danym systemie.

Zobacz szczegóły wywołania oraz szablon obiektu błędu.

Obiekty określane dla stanów i przejść

Do wykonania czynności związanych ze stanami moduł proc używa następujących rodzajów obiektów:

Do wykonania czynności związanych z przejściami moduł proc używa następujących rodzajów obiektów:

Ze względu na fakt, iż obiekt jpalio może być wykonywany w ramach kilku obiektów złożonych i w różnym charakterze, proponowane jest dodawanie na końcu nazwy obiektu liter w nawiasach określających, jakie mogą być funkcje obiektu. Poponowany zestaw liter umieszczony jest na powyższych listach, na początku każdej pozycji. Obiekt używany jako presentation_object, stay_in_state_object i on_transition_object powinien mieć suffix nazwy o postaci "(PSO)".

Rola obiektów różnych rodzajów została przedstawiona na poniższym schemacie przykładowego przejścia ze stanu A, B lub C do stanu D.

Rys. Rodzaje i sposób użycia obiektów dla stanów i przejść.

Obiekt prezentacji

Jest to podstawowy obiekt dla stanu. Zawsze musi być określony. Funkcją tego obiektu jest prezentacja użytkownikowi systemu instancji procesu znajdującej się w określonym stanie, co najczęściej oznacza wyświetlenie formularza z danymi klienta, zgłoszenia itp.

Formularz prezentowany użytkownikowi na ogół wymaga odczytu danych. Należy zadbać, aby zawsze przy wyświetlaniu instancji procesu wszystkie dane formularza były odczytywane i ustawiane. Wymóg ten dotyczy także pól, które mają mieć wartość pustą, trzeba je podczas odczytu danych ustawić na null. Przy otwieraniu strony, na której prezentowania jest instancja, np. z listy dostępnych instancji, takie ustawianie wartości zmiennych globalnych na null jest czynnością nadmiarową. Należy jednak pamiętać, iż wyświetlenie instancji w danym stanie może się odbywać zaraz po wykonaniu przejścia za pomocą submitu, a wtedy założenie o domyślnie pustej wartości zmiennych globalnych nie musi być prawdziwe.

  Załóżmy, że pewien proces sprzedażowy zawiera stany F i G. Obiekt prezentacji dla
  stanu F zawiera formularz danych klienta z polem input o nazwie "type". Po kliknięciu
  przycisku wyzwalającego przejście do stanu G następuje zapis danych klienta i zmiana
  stanu zgłoszenia z F na G. Obiekt prezentacji w stanie G zawiera formularz z danymi
  zamówienia. W danych zamówienia także istnieje pole "type", które nie jest
  inicjalizowane, ponieważ oczekuje się wprowadzenia jego wartości przez użytkownika.
  Jeżeli otworzymy zgłoszenie znajdujące się w stanie G z listy zgłoszeń, to pole "type"
  będzie puste i formularz zadziała zgodnie z oczekiwaniami. Jeśli zgłoszenie w stanie G
  zostanie otworzone bezpośrednio po wykonaniu przejścia ze stanu F (po submicie
  formularza z danymi klienta), to wartość pola "type" w formularzu zamówienia będzie
  taka sama, jaka została podana w polu "type" w formularzu z danymi klienta. Aby
  zapobiec takiej sytuacji, należy przy odczycie danych dla formularza w stanie G ustawić
  wartość zmiennej "type" na null.

  Nie należy więc zapominać o inicjalizacji zmiennych, nawet pustych. Błędne
  zainicjowanie zmiennej jak w przykładzie na ogół nie spowoduje katastrofy, ale
  niekiedy konsekwencje mogą być poważniejsze, w zależności od funkcji
  niezainicjalizowanych zmiennych w obiekcie prezentacji.

Jeżeli dane w formularzu są edytowane przez użytkownika systemu, a po wyzwoleniu akcji przejścia sprawdzane i zapisywane za pomocą obiektu przejścia, to pojawia się dodatkowy problem: do prawidłowej realizacji odczytu danych dla formularza w danym stanie konieczne jest wykrycie, czy poprzedzający submit spowodował zmianę stanu. Wynika to z faktu, iż sprawdzenie formularza w obiekcie przejścia może spowodować, iż zmiana stanu nie zostanie wykonana (np. z powodu błędnych danych w formularzu). Wtedy mimo wykonanego submitu, dane formularza nie powinny ponownie się odczytywać.

Najprostszym sposobem uzyskania poprawnego odczytu danych jest użycie następującej konstrukcji:

- w obiekcie stanu, w części dotyczącej zmiany stanu, należy umieścić polecenie ustawiające zmienną, która nie jest używana w żadnym innym miejscu, np: $=(stateChangeFlag, "Y") - w obiekcie prezentacji sprawdzać zmienną stateChangeFlag oraz zmienną informującą o wykonanym odczycie: ... $if( $or($isNull($readFlag), $isNotNull($stateChangeFlag)) ,{ $// odczytaj dane formularza $*sellProcess.stateF.form.read }) ... <form method="post" action="$page.url($currentPageCode())"> <input type="hidden" name="readFlag" value="Y"> </form> ... Warunek $isNull($readFlag) spowoduje odczyt danych formularza przy wyświetlaniu zgłoszenia otworzonego z listy zgłoszeń, warunek $isNotNull($stateChangeFlag) spowoduje odczyt podczas wyświetlania formularza po zmianie stanu.

Do poprawnego działania modułu proc wymagane jest, aby submitowany formularz, zawarty w obiekcie prezentacji, przekazywał dodatkowe ukryte zmienne. Odpowiednie pola hidden wyświetlane są przez funkcję proc.displayHiddenFields(), np.:

  <input type="hidden" name="ProcessExecutionInstanceId" value="2">
  <input type="hidden" name="ProcessExecutionProcessId" value="618">

Dzięki przekazaniu tych zmiennych funkcja proc.executeProcess() wywoływana na stronie prezentującej instancje procesu może po submicie określić, jakiej instancji i wykonywanej wg jakiego procesu dotyczy wywołanie funkcji (niektóre argumenty typowego wywołania, np. proc.executeProcess(681, $_RowID, (String)null), po wykonaniu submitu na ogół są równe null).

  Wywołanie funkcji proc.displayHiddenFields() wewnątrz submitowanego formularza jest
  najprostszym sposobem przekazania wymaganych zmiennych. Zaleca się jednak przekazywanie
  tych zmiennych w parametrach URLa podawanego w argumencie action znacznika <form>.
  Takie rozwiązanie jest znacznie bezpieczniejsze - na stronie chronionej uprawnieniami
  i sumą kontrolną nie jest wtedy możliwe manipulowanie identyfikatorem aktualnie
  procesowanej instancji. Przykładowe rozwiązanie tego typu może wyglądać następująco:
    <form method="post" name="orderForm" id="orderForm"
      action="$page.url($currentPageCode(), null, 
      $+(["&ProcessExecutionInstanceId=", $toString($ProcessExecutionInstanceId),
      "&ProcessExecutionProcessId=", $toString($ProcessExecutionProcessId)) ]) )">

Oprócz pól ukrytych, formularz wyświetlany przez obiekt prezentacji powinien zawierać także elementy umożliwiające wyzwolenie akcji zmiany stanu instancji. Na ogół wyświetlane są w tym celu przyciski o odpowiednich nazwach, jednak dostępne są także inne sposoby wyzwalania przejścia. Do wyświetlania omawianych elementów służą funkcje:

Każda powyższych funkcji sprawdza przed wyświetleniem każdego przejścia uprawnienia użytkownika do wykonania przejścia oraz dodatkowy warunek wyświetlania przejścia, o ile jest on określony (więcej w opisie obiektu warunku).

W wyborze jednej z powyższych funkcji może pomóc znajomość sposobu wykrywania przejścia przez funkcję executeProcess(). Aby wykryć przejście funkcja ta sprawdza zmienną o nazwie _ActionTransition. Oczekiwaną wartością zmiennej jest id przejścia z tabeli j_transitions. Jeśli zmienna ta ma wartość null, to sprawdzane są zmienne _ActionTransitionXX (gdzie XX to id przejścia) - wartość różna od null oznacza wykonanie przejścia o id zawartym w nazwie zmiennej. Zmienna _ActionTransition ma wyższy priorytet niż _ActionTransitionXX.

Wyświetlanie elementów umożliwiających wyzwolenie akcji nie jest oczywiście obowiązkowe - brak tych elementów może być zabiegiem celowym, służącym np. do uzyskania formularza tylko do odczytu dla użytkownika o zbyt małych uprawnieniach.

Wykrywanie przejść oparte o analizę bazodanowego identyfikatora przejścia przekazanego przy pomocy _ActionTransition lub_ActionTransitionXX oraz ograniczenie listy analizowanych przejść do listy przejść dostępnych w stanie bieżącym w pewnym stopniu zabezpiecza procesowanie instancji przed wielokrotnym wykonaniem akcji podczas odświeżania strony w przeglądarce. Wyjątkiem jest tu sytuacja, w której przejście jest pętlą w grafie (przejście prowadzi do tego samego stanu, w którym jest określone).

  W stanie F istnieją przejścia o identyfikatorach 7,8,9. Użytkownik systemu klika
  przycisk o nazwie _ActionTransition8 i wykonuje przejście o id=8 do stanu G. W stanie
  G istnieją przejścia o identyfikatorach 10 i 11. Wykonanie odświeżania strony w przeglądarce
  powoduje, że zostanie ponownie wysłany formularz ze stanu F z ustawioną zmienną _ActionTransition8,
  ale tym razem przejście (ani obiekt akcji w nim określony) nie wykona się, gdyż instancja procesu
  znajduje się już w stanie G, w którym nie ma przejścia o id=8. Zostanie tylko wyświetlona instancja
  procesu w stanie G.

Zobacz szczegóły wywołania oraz szablon obiektu prezentacji.

Obiekt pozostania w stanie

Obiekt pozostania w stanie służy do zakomunikowania użytkownikowi systemu, iż nie bierze on udziału w dalszym przetwarzaniu instancji procesu. Typowym zadaniem obiektu jest wyświetlenie informacji dla użytkownika systemu oraz elementu umożliwiającego przeniesienie do innego miejsca w systemie, np. strony głównej. Jest on wywoływany zamiast obiektu prezentacji, gdy w danych przejścia została zaznaczona flaga "po wykonaniu przejścia pozostań w stanie" (zobacz opis interfejsu html). Wykonywany obiekt pozostania w stanie jest określany w opisie stanu z którego nastąpiło przejście z zaznaczoną flagą pozostania w stanie.

  Typowe zastosowanie obiektu pozostania w stanie:
  W pewnym procesie użytkownik (X) systemu, np. klient, wprowadza w stanie F dane
  zamówienia i zapisuje je, wykonując przejście ze stanu F do G. Zgłoszenie w stanie G
  procesowane jest przez innego użytkownika systemu (Y), np. pracownika. Użytkownik X
  nie ma uprawnień do oglądania zgłoszeń w stanie G. Aby użytkownik X nie zobaczył
  komunikatu błędu o braku uprawnień do zgłoszeń w stanie G należy zaznaczyć w opisie
  przejścia zapisującego dane zamówienia (F->G) flagę pozostania w stanie oraz określić
  obiekt pozostania w stanie dla stanu F. Dzięki temu po zmianie stanu z F na G
  użytkownik X zobaczy obiekt pozostania w stanie z odpowiednim komunikatem (np. "Twoje
  zamówienie zostało przyjęte. Dziękujemy i zapraszamy ponownie.") oraz nie zostanie
  podjęta próba wyświetlenia zgłoszenia w stanie G, co powodowałoby błąd braku uprawnień.

Określenie obiektu w opisie stanu nie jest wymagane. Zobacz szczegóły wywołania oraz szablon obiektu pozostania w stanie.

Obiekt inicjalizacji stanu

Obiekt inicjalizacji stanu jest wykonywany po wykonaniu przejścia (przy zmianie stanu instancji na stan, dla którego obiekt inicjalizacji jest określony), ale raz na każde wykonane przejście. Zadaniem obiektu jest wykonanie czynności inicjalizacyjnych dla instancji w danym stanie, np. przygotowanie wpisów w bazie danych wymaganych przez instancję procesu na danym etapie procesowania.

  Obiekt inicjalizacji nie jest dobrym miejscem np. na odczyt danych formularza
  wyświetlanego przez obiekt prezentacji - podczas wyświetlania zgłoszenia w stanie G,
  wybranego z listy zgłoszeń, obiekt inicjalizacji nie wykona się. Zostanie natomiast
  wywołany po udanym wykonaniu przejścia ze stanu F do stanu G, ale przed wyświetleniem
  obiektu prezentacji określonego dla stanu G lub obiektu pozostania w stanie określonego
  dla stanu F.
  
  Obiektu inicjalizacji można użyć np. do przygotowania w stanie G wpisów w bazie danych,
  które są wymagane przez stan G i stany kolejne, a więc powinny istnieć już w stanie G
  np. ze względu na wyświetlanie ich wartości w formularzu, ale będą stopniowo wypełniane
  i modyfikowane podczas wykonywania akcji określonych w stanach kolejnych względem stanu G.

Określenie obiektu w opisie stanu nie jest wymagane. Obiekt nie powinien nic wyświetlać. Zobacz szczegóły wywołania oraz szablon obiektu inicjalizacji stanu.

Obiekt sprawdzania zakończenia podprocesów

Opis funkcji, jakie spełnia obiekt sprawdzania zakończenia podprocesów, zawarty jest w rozdziale Sposób realizacji podprocesów.

Określenie obiektu w opisie stanu nie jest wymagane. Obiekt nie powinien nic wyświetlać. Zobacz szczegóły wywołania oraz szablon obiektu sprawdzania zakończenia podprocesów.

Obiekt oczekiwania na zakończenie podprocesów

Opis funkcji, jakie spełnia obiekt oczekiwania na zakończenie podprocesów, zawarty jest w rozdziale Sposób realizacji podprocesów.

Określenie obiektu w opisie stanu nie jest wymagane. Zobacz szczegóły wywołania oraz szablon obiektu oczekiwania na zakończenie podprocesów.

Obiekt przejścia

Jest to obiekt, w którym wykonywane są akcje związane z przejściem. Można tu umieścić dowolną akcję, np. sprawdzenie i zapis formularza, utworzenie podprocesu, wygenerowanie zdarzania skierowanego do systemu zewnętrznego itp.

W obiekcie przejścia nie należy umieszczać akcji zmiany stanu instancji. Zmiana stanu jest wykonywana przy pomocy obiektu stanu przez moduł proc po wykonaniu obiektu przejścia.

W obiekcie przejścia istnieje możliwość ustawienia flagi informującej moduł proc o tym, iż akcja związana z przejściem nie została wykonana poprawnie (np. podano błędne dane w formularzu), a tym samym przejście nie powinno wykonać się.

Określenie obiektu w opisie przejścia nie jest wymagane. Obiekt nie powinien nic wyświetlać. Zobacz szczegóły wywołania oraz szablon obiektu przejścia.

Obiekt warunku

Obiekt warunku służy do sprawdzenia, czy można wyświetlić przejście do którego jest przypisany. Obiekt ten, o ile jest określony, jest wywoływany przez funkcje displayTransitionsButtons(), displayTransitionsOptions(), displayTransitions(), displayTransitionButton(), displayTransition().

Obiekt nie jest wywoływany w momencie wykonania przejścia.

  Obiekt warunku może służyć np. do wyświetlania wybranego przejścia tylko w pewnym
  przedziale czasowym, np. od 8 do 16. Jeżeli istotne jest, aby ten sam warunek był
  sprawdzany także w momencie wykonywania (a nie wyświetlania) przejścia, należy utworzyć
  odpowiedni obiekt przejścia.

Określenie obiektu w opisie przejścia nie jest wymagane. Jeśli nie podano obiektu, domyślnie przyjmuje się, że przejście zawsze jest możliwe (o ile user ma prawa do przejścia). Obiekt nie powinien nic wyświetlać. Zobacz szczegóły wywołania oraz szablon obiektu warunku.

System uprawnień

W module proc można określić uprawnienia zarówno do stanów jak i przejść procesu. Uprawnienia kojarzone są z rolami jpalio a nie z przywilejami. Uprawnienia są sprawdzane przez funkcje modułu proc przed wykonaniem obiektu prezentacji lub oczekiwania na zakończenie podprocesów (uprawnienia dla stanu) oraz przed wykonaniem obiektu warunku i obiektu przejścia (uprawnienia do przejścia). W przypadku, gdy użytkownik systemu nie posiada uprawnień do wyświetlenia stanu lub wykonania przejścia, wywoływany jest obiekt błędu.

Oprócz samego faktu istnienia uprawnienia do stanu i przejścia jest możliwe określenie typu uprawnienia. Typ uprawnienia jest jednoliterowy.

  Typy uprawnień można wykorzystać np. do określania sposobu wyświetlania formularza.
  Przyjmijmy, iż wykorzystywane są dwa typy uprawnień do stanu (E od "edit" i V od "view").
  Używając interfejsu do konstrukcji procesów można
  określić, że użytkownicy posiadający rolę X mają uprawnienie E do stanu F, a użytkownicy
  posiadający rolę Y mają uprawnienie V do stanu F. Używając w obiekcie prezentacji
  skojarzonym ze stanem F następującej konstrukcji:
  ...
  $=(@stateNr, $toLong($toString($3)) )
  ...
  $// sprawdź uprawnienia
  $=(isReadonly, true)
  $if( $proc.hasRightForState($user.userID(), $proc.getStateIdByNumber($proc.getProcessExecutingProcessId(),$@stateNr), "E") ,{
    $=(isReadonly, false)
  })

można sterować z poziomu interfejsu wyświetlaniem formularza do edycji albo formularza   tylko do odczytu w zależności od posiadanych przez użytkownika ról.

Moduł proc obsługuje dwa niezależne zestawy uprawnień do stanów i przejść. Funkcje związane z drugim zestawem uprawnień posiadają w swojej nazwie słowo "owner", co jest zaszłością wynikającą ze sposobu użycia drugiego zestawu uprawnień w jednym z portali, podczas rozwijania którego był rozwijany także moduł proc.

  Drugi zestaw uprawnień można wykorzystać, jeśli użytkownik ma mieć różne uprawnienia
  do dokumentów w pewnym stanie w zależności od pewnego warunku. Przykładem może być
  tu procesowanie podań, np. o urlop. Dokument taki po złożeniu zatwierdza osoba
  nadrzędna. Jeżeli zatwierdzenie dokumentu następuje w stanie F i w system pozwala
  wysłać dokument do zatwierdzenia tylko do osoby nadrzędnej, to każdy użytkownik
  powinien móc zatwierdzić wszystkie podania o urlop znajdujące się w stanie F które
  może przejrzeć oprócz tych, które sam złożył.

Sposób realizacji podprocesów

Podprocesem w module proc może być fragment procesu głównego, inny proces lub dowolny inny byt nie związany z modułem proc. Aby uprościć obsługę podprocesów, zostały wprowadzone dwa obiekty: obiekt sprawdzania zakończenia podprocesów i obiekt oczekiwania na zakończenie podprocesów. Załóżmy, iż pewien proces ma postać jak na rysunku poniżej.

Rys. Przykład procesu z podprocesami.

Przejście ze stanu A do stanu B tworzy podproces nr 2 (jest to akcja wykonywana całkowicie przez użytkownika wewnątrz obiektu przejścia). Przejście ze stanu B do stanu C tworzy podproces nr 1. Przez pewnien czas realizacja procesu głównego i podprocesów przebiega niezależnie. Konstrukcja procesu wymaga, aby przed realizacją czynności przewidzianych w dla stanu G oba podprocesy zostały zakończone, a więc przed wykonaniem obiektu prezentacji dla stanu G należy sprawdzić, czy oba podprocesy zostały zakończone. Taką funkcjonalność można osiągnąć poprzez odpowiednią konstrukcję obiektu prezentacji w stanie G, jednakże znacząco komplikuje to kod takiego obiektu. W module proc obsługą przedstawionej sytuacji zajmuje się wspomniany obiekt sprawdzania zakończenia podprocesów i obiekt oczekiwania na zakończenie podprocesów.

Obiekt sprawdzania zakończenia podprocesów jest wywoływany przed obiektem prezentacji (o ile jest określony, wywołanie następuje zarówno po zmianie stanu instancji na stan, w którym obiekt jest określony, jak i przy wyświetlaniu instancji znajdującej się w stanie, w którym obiekt jest określony). Użytkownik powinien w tym obiekcie wykonać sprawdzenie stanu podprocesów i zwrócić informację, czy zostały one zakończone czy nie. Konstrukcja warunku przez użytkownika daje pełną dowolność określenia sposobu oczekiwania na podprocesy, obiekt ten oprócz sprawdzania zakończenia podprocesów może sprawdzać także np. fakt zajścia pewnego zdarzenia w systemie zewnętrznym.

Jeśli obiekt sprawdzania zakończenia podprocesów zwróci informację, iż podprocesy zostały zakończone, to wykonywany jest obiekt prezentacji. W przeciwnym wypadku wykonywany jest obiekt oczekiwania na zakończenie podprocesów, w którym można wyświetlić użytkownikowi systemu informację o oczekiwaniu na zakończenie podprocesów, np. "Podproces nr 1 został zakończony. Zgłoszenie oczekuje na zakończenie podprocesu nr 2.".

Metody przechowywania podprocesów w bazie

Użytkownik może dowolnie przechowywać podprocesy, w sposób wynikający ze struktury systemu. Tabele przechowujące instancje procesu muszą przechowywać także numer stanu.

Struktura tabel przechowujących instancje procesu może być powiązana z procesami na wiele różnych sposobów. Najbardziej typowe przypadki przedstawione są poniżej.

Rys. Hierarchiczna struktura instancji procesu.

Organizacja hierarchiczna jest wygodna, gdy instancja procesu zawiera wiele małych podprocesów ściśle zależnych od procesu głównego. Wtedy zarówno proces główny, jak i podprocesy wygodnie jest zrealizować za pomocą jednego procesu w module proc, przy czym podprocesy określa się jako fragmenty procesu nie łączące się ze sobą ani z procesem głównym. Dla takiej struktury wystarczy jeden obiekt stanu (odczyt i zmiana stanu polega na odczycie i zapisie tego samego pola z tej samej tabeli zarówno dla wszystkich podprocesów jak i procesu głównego). Zaletą takiej struktury jest także to, że nie ma ograniczenia na głębokość zagnieżdżania podprocesów - można wykonać podproces typu "zapytanie do", który można zawierać kolejne podprocesy "zapytanie do" itd. Uzyskuje się wtedy drzewo zapytań o dowolnej głębokości, każde zapytanie procesowane niezależnie, bez modyfikacji struktury bazy. W koncepcji hierarchicznej można także przechowywać dane instancji w jednej tabeli, ale procesy zrealizować jako osobne, każdemu przypisując ten sam obiekt stanu i podając odpowiedni identyfikator procesu w wywołaniu funkcji $executeProcess(), zależny od typu instancji.

Rys. Rozproszona struktura instancji procesu.

Druga typowa struktura, przedstawiona na rysunku powyżej, powinna być używana, gdy w systemie istnieje wiele dużych procesów luźno ze sobą powiązanych. Ze względu na przechowywanie instancji procesów różnego rodzaju w osobnych tabelach, wygodnie jest zrealizować każdy proces lub podproces jako osobny proces w module proc. Wtedy dla każdego procesu w module proc można przypisać obiekt stanu czytający i zapisujący stan z odpowiedniej tabeli.

Oczywiście istnieje możliwość dowolnego łączenia powyższych koncepcji, np. zrealizowania niektórych podprocesów jako fragmentów procesów a niektórych jako niezależne procesy albo przechowywania części instancji w strukturze hierarchicznej a części w osobnych tabelach.

Zewnętrzne wykonywanie przejść

Oprócz wyzwalania przejść przez użytkownika podczas wykonania procesu możliwe jest także zewnętrzne (względem procesu) wykonanie przejść, np. przejścia wykonywane przez zadanie jpalio. Do zewnętrznego wykonania przejścia służy funkcja executeTransition(). Podczas wykonania executeTransition() sprawdzane są uprawnienia użytkownika do stanu, wykonywany jest obiekt przejścia (o ile został określony), następnie stan instancji jest zmieniany za pomocą obiektu stanu oraz wykonywany jest obiekt inicjalizacji.

Możliwe jest też przeniesienie instancji do stanu za pomocą funkcji moveInstanceToState(). Podczas przenoszenia do stanu nie są sprawdzane żadne prawa, nie jest wykonywany obiekt przejścia, a przejście pomiędzy bieżącym stanem procesu i docelowym nie musi być określone. Stan obiektu jest zmieniany za pomocą obiektu stanu. Wykonywany jest też obiekt inicjalizacji dla nowego stanu, o ile jest podany.

Zalecane jest odwoływanie się do przejść za pomocą ich identyfikatorów tekstowych (j_transitions.text_id) a nie numerycznych (j_transitions.id).

Uproszczony schemat działania funkcji executeProcess()

Uproszczony schemat działania funkcji $proc.executeProcess() umieszczony jest poniżej.

Rys. Uproszczony schemat działania funkcji executeProcess().

Dokument zawiera także szczegółowy schemat wykonania funkcji executeProcess().

Transakcyjność

Dostępne są dwie metody wykonania przejść w procesach - z zapewnieniem transakcyjności i bez.

Jeżeli transakcyjność jest włączona, to wyrzucenie wyjątku w jakimkolwiek obiekcie jpalio składającym się na obiekty przejścia lub inicjalizacji stanu spowoduje wykonanie rollbacka i wyrzucenie wyjątku przez metodę proc.executeProcess(). Przy włączonej transakcyjności podczas wykonywania przejścia można także dodawać konektory do transakcji z pomocą odpowiedniej metody modułu sql.

Bez włączonej transakcyjności wyjątki nie są przechwytywane, nie powodują przerwania wykonania przejścia a do ich obsługi używane są standardowe mechanizmy jPALIO. Każde polecenie z modułu sql jest wykonywane w osobnej, izolowanej transakcji. Wykonanie procesu bez włączonej transakcyjności może być stosowane w punktach synchronizacji procesu z systememi zewnętrznymi.

Wersję z transakcyjnością i bez przedstawia poniższy przykład:

$=(@executionStatus, $proc.executeProcess(618, $@orderId, (String)null) )  // bez transakcyjności
$=(@executionStatus, $proc.executeProcess(618, $@orderId, (String)null), true)  // z transakcyjnością

Cache opisu procesów

W obecnej wersji modułu struktura procesu nie jest buforowana, a więc większość funkcji modułu proc operuje bezpośrednio na bazie danych.

Internacjonalizacja

W obecnej wersji modułu nie są dostępne tłumaczenia standardowych komunikatów błędów.