Funkcje pozwalają na deklaratywne przetwarzanie danych bez konieczności pisania własnego kodu. Rozwiązanie to opiera się na wywoływaniu wybranej funkcji (użytkownicy mogą dostarczać własne specyficzne implementacje) i przekazaniu wyniku tej funkcji dalej np. do zadania automatycznego. W przypadku podstawowych działań matematycznych, kwotowych, tekstowych czy logicznych możliwe jest zrealizowanie prostych przekształceń bez napisania linijki kodu.

 

Tworzone funkcje powinny być ja najbardziej ogólne i elastyczne. Pozwoli to na wykorzystanie ich w większej liczbie przypadków. System pozwala na rejestrowanie i wykorzystywanie predefiniowanych funkcji zarówno po stronie serwera jak i po stronie przeglądarki.

Spis wbudowanych funkcji systemowych dostępny jest na stronie: Dostępne funkcje

FunctionAPI

Wszystkie operacje związane z działaniami na funkcjach stanowią FunctionAPI.

 

 W tworzonych akcjach po stronie przeglądarki wspierany jest standard ECMAScript 6.

Rejestracja funkcji

Funkcja musi zawsze być zarejestrowana po stronie serwera oraz może dodatkowo być zarejestrowana po stronie przeglądarki, gdy chcemy, aby była też tam wykorzystywana.

Rejestracja na serwerze

Rejestracja funkcji dostępnych w systemie odbywa się podczas uruchomienia systemu oraz dynamicznie dla dynamicznych zasobów, takich jak wtyczki. Za rejestrację i przechowywanie funkcji odpowiada . Podczas rejestracji wyszukiwane są najpierw wszystkie klasy oznaczone adnotacją @, następnie w tych klasach wyszukiwane są metody oznaczone adnotacją @ i zostają one zarejestrowane jako funkcje.

 

Rejestrowana funkcja  musi:

Poniższy przykład przedstawia definicję prostej funkcji zwracającej wartość większej liczby.

@Functions
public class BasicFunctions
{
    @Function
    public Integer maxOf( Integer a, Integer b )
    {
        return Math.max( a, b );
    }
}

Można określić, czy funkcja dotyczy tylko serwera (można jej użyć tylko na serwerze), czy tylko przeglądarki (można jej użyć tylko w javascript), czy obu miejsc. Odpowiada za to parametr accessibility, który można ustawić w adnotacji @. Parametr jest typu @ i może przyjmować następujące wartości:

Brak ustawionego parametru accessibility odpowiada wartości ALL.

Poniższy przykład pokazuje definicję funkcji, która jest dostępna tylko dla komponentów serwerowych. Funkcja zwraca imię i nazwisko użytkownika na podstawie jego loginu.

@Functions
public class BasicFunctions
{
    @Function( accessibility = FunctionAccessibility.SERVER )
    public String userFullName( String userName )
    {
        User user = userService.getUser( userName );
        if ( user == null )
        {
            return null;
        }
        return user.getFullName();
    }
}

Jeżeli robimy funkcję tylko dla przeglądarki, to na serwerze również musi być funkcja zdefiniowana, ale jej implementacja nie musi nic robić. Służyć ona ma tylko do pobrania nazwy i parametrów funkcji i wyświetlania jej w PWE.

Kontekst funkcji

Kontekst funkcji zawiera identyfikator oraz definicję aktualnie przetwarzanego procesu i zadania. Pobranie kontekstu możliwe jest tylko po stronie serwera za pomocą poniższego kodu.

FunctionContext context = FunctionContext.current(); // statyczne pobranie kontekstu
 
String processId = context.getProcessId(); // id procesu
String activityId = context.getActivityId(); // id zadania
String processDefId = context.getProcessDefId(); // id definicji procesu
String activityDefId = context.getActivityDefId(); // id definicji zadania

Rejestracja po stronie przeglądarki

Używanie stworzonej funkcji po stronie przeglądarki (na formularzu zadania) wymaga od programisty dostarczenia jej implementacji w języku JavaScript. Taka implementacja wykorzystywana jest podczas dynamicznych obliczeń po stronie przeglądarki klienta.

W przypadku funkcji z implementacją JavaScript należy dodatkowo wskazać poprzez adnotację  gdzie znajduje się skrypt, który zawiera implementacje tych funkcji. Należy wskazać bezwzględną ścieżkę do zasobu w classpath. Zasób przechowywany w src/main/resources/functions/basic-functions.js wskażemy tak:

@Functions
@FunctionsScript("/functions/basic-functions.js")
public class BasicFunctions
{
    ...
}

Funkcje rejestrowane są z wykorzystaniem API  (skrócona nazwa PW.Functions):

// funkcja "max" która zwraca obiekt typu "float" i przyjmuje 2 parametry typu "float"
PW.Functions.register("max", "float", ["float", "float"], function(value1, value2){
	return Math.max(value1, value2);
});
 
// funkcja "upper" która zwraca obiekt typu "string" i przyjmuje 1 parametry typu "string"
PW.Functions.register("upper", "string", ["string"], function(text){
	return text.toUpperCase();
});

Podczas rejestracji funkcji niezbędne jest zdefiniowanie:

Tak zarejestrowana funkcja zostanie wywołana tylko dla wywołań z argumentami które będą pasowały do zdefiniowanych typów. Możliwe typy opisane są w Wbudowane typy.

Rejestracja we wtyczce

Rejestracja funkcji we wtyczce jest taka sama jak zostało to opisane powyżej, jednak należy dodatkowo zaznaczyć, że wtyczka ta udostępnia funkcje do zarejestrowania. W tym celu należy w pliku suncode-plugin.xml dodać wpis:

<functions key="functions" />

Taki wpis spowoduje automatyczne wyszukanie wszystkich zdefiniowanych we wtyczce funkcji.

Tłumaczenia opisów funkcji i parametrów

Funkcje tłumaczone są automatycznie, jeżeli dostępne są tłumaczenia funkcji stworzone z wykorzystaniem mechanizmu internacjonalizacji. Poniżej opisano zasady tworzenia kluczy tłumaczeń.

Tłumaczeniu podlegają:

Klucze tłumaczeń funkcji muszą być tworzone z zachowaniem następujących zasad:

Tłumaczony elementSzablon
Opis funkcji

function.<name>

gdzie

  • <name> - nazwa funkcji
Nazwa parametru

function.<name>.param.<paramName>.name

gdzie

  • <name> - nazwa funkcji
  • <paramName> nazwa parametru
Opis parametru

function.<name>.param.<paramName>.desc

gdzie

  • <name> - nazwa funkcji
  • <paramName> nazwa parametru
Opis dla przestarzałej funkcji

function.<name>.deprecated.description

gdzie

  • <name> - nazwa funkcji

Przykład:

Dla funkcji zdefiniowanej w następujący sposób:

@Function
public boolean isHoliday(LocalDate date) {
	// implementacja
}

Tłumaczenia wyglądały będą następująco:

function.isHoliday=Sprawdza czy data wskazuje dzień wolny od pracy
function.isHoliday.param.date.name=Data
function.isHoliday.param.date.desc=Sprawdzana data

Dla przestarzałej funkcji zdefiniowanej w następujący sposób:

@Function
@Deprecated
public boolean isHoliday(LocalDate date) {
	// implementacja
}

Tłumaczenia wyglądały będą następująco:

function.isHoliday=Sprawdza czy data wskazuje dzień wolny od pracy
function.isHoliday.param.date.name=Data
function.isHoliday.param.date.desc=Sprawdzana data
function.isHoliday.deprecated.description=Funkcja jest przestarzała i należy korzystać z funkcji isHoliday(LocalDate date, Locale locale)

Tłumaczenie przeciążeń funkcji

Każda funkcja może mieć wiele przeciążeń, które przyjmują inne parametry. Może istnieć potrzeba nadania innych opisów dla tych parametrów lub innego opisu funkcji. Jest to możliwe poprzez dodanie do nazwy funkcji wykorzystywanej w kluczu tłumaczenia typów parametrów rozdzielonych podkreślnikiem (_). Domyślnym tłumaczeniem jest to bez typów parametrów.

Nazwy typów dostępne są tutaj: Wbudowane typy

Przykład:

Dla funkcji zdefiniowanej w następujący sposób:

@Function
public boolean isHoliday(LocalDate date) {
	// implementacja
}
 
@Function
public boolean isHoliday(LocalDate[] dates) {
	// implementacja
}
 
@Function
public boolean isHoliday(LocalDate[] dates, boolean all) {
	// implementacja
}

Tłumaczenia wyglądały będą następująco:

function.isHoliday=Sprawdza czy data wskazuje dzień wolny od pracy
function.isHoliday.param.date.name=Data
function.isHoliday.param.date.desc=Sprawdzana data
 
function.isHoliday_date[]=Sprawdza czy wszystkie podane daty to dni wolne od pracy
function.isHoliday_date[].param.dates.name=Daty
function.isHoliday_date[].param.dates.desc=Sprawdzane daty
 
function.isHoliday_date[]_boolean=Sprawdza czy podane daty to dni wolne od pracy
function.isHoliday_date[]_boolean.param.dates.name=Daty
function.isHoliday_date[]_boolean.param.dates.desc=Sprawdzane daty
function.isHoliday_date[]_boolean.param.all.name=Wszystkie
function.isHoliday_date[]_boolean.param.all.desc=Zaznacz jeżeli chcesz aby wszystkie daty były dniami wolnymi od pracy