Moduły


Wstęp

Moduły jPALIO pełnią funkcję bibliotek. Najczęściej jest to logicznie pogrupowany zestaw użytecznych metod, bądź też obudowanie zewnętrznych bibliotek realizujących określone funkcjonalności. W jPALIO można wyróżnić następujące typy modułów:

CORE Moduły podstawowe, automatycznie inicjalizowane przy starcie instancji jPALIO bez konieczności dodawania tych modułów w konfiguracji instancji. W języku jPALIO, wywołanie metod z tych modułów nie wymagaa podawania nazwy modułu.
np. Zamiast $text.trim(" some text ") można użyć trim(" some text ")
STANDARD Moduły standardowe, automatycznie inicjalizowane przy starcie instancji jPALIO bez konieczności dodawania tych modułów w konfiguracji instancji.
EXTERNAL Moduły dodatkowe, automatycznie inicjalizowane przy starcie instancji jPALIO tylko wtedy gdy w konfiguracji instancji zostaną one dodane.

jPALIO posiada liczny zestaw wbudowanych modułów, które zostały opisane w dedykowanych rozdziałach. Istnieje możliwość tworzenia własnych modułów. Tworzenie własnych modułów stanowi jeden ze sposobów rozszerzania funkcjonalności platformy jPALIO.

Bardzo dużą zaletą modułów jPALIO jest ujednolicenie sposobu korzystania z dostęonych funkcjonalności jPALIO. Ma to ogromne znaczenie szczególnie w przypadku modułów będących nakładką na zewnętrzne biblioteki. Biblioteki te posiadają zazwyczaj różne API wymagające poznania całej hierarchii klas (często bardzo skomplikowane). Moduły jPALIO zapewniają przystępny oraz jednolity sposób dostępu do funkcjonalności realizowanych przez dane biblioteki dzięki czemu programista nie traci niepotrzebnie czasu na poznawanie tych bibliotek.

W jaki sposób stworzyć własny moduł jPALIO?

Klasą bazową dla wszystkich modułów jPALIO jest klasa palio.modules.core.Module. Aby stworzyć własny moduł należy stworzyć klasę JAVA dziedziczącą po tej klasie.

UWAGA! Klasa modułu musi być umieszczona w pakiecie palio.modules. Jest to warunek konieczny aby moduł był widoczny w jPALIO.

W pierwszym etapie tworzenia modułu klasa modułu powinna wyglądać w następujący sposób:

package palio.modules;

import java.util.*;
import palio.*;
import palio.modules.core.*;

public class MyCustomModule extends Module {
    
    public MyCustomModule(Instance instance, Properties parameters) throws PalioException {
        super(instance, parameters);
    }
    
    @Override
    public String getVersion() {
        return "1.0.0";
    }

}

Kolejnym krokiem jest zarejestrowanie naszego modułu w Menadżerze Modułów jPALIO oraz określenie jakiego ma być typu (typy zostały opisane we wstępie). Aby to zrobić należy umieścić w klasie następujący blok statyczny:

// Registering myModule as standard type module
static {
    ModuleManager.registerModule("myModule", MyCustomModule.class, ModuleManager.MODULE_STANDARD);
}

// Registering myModule as external type module
static {
    ModuleManager.registerModule("myModule", MyCustomModule.class, ModuleManager.MODULE_EXTERNAL);
}

WAŻNE! Wielkość liter w nazwie modułu nie ma znaczenia.

Funkjonalności modułu implementowane są w metodach klasy modułu. Należy pamiętać o tym, że tylko metody publiczne będą widoczne. Poniżej przedstawiono przykład prostej metody.

public String echo(String someText) {
return someText;
}

 

Kompletna klasa modułu:

package palio.modules;

import java.util.*;
import palio.*;
import palio.modules.core.*;

public class MyCustomModule extends Module {

static {
ModuleManager.registerModule("myModule", MyCustomModule.class, ModuleManager.MODULE_STANDARD);
}

public MyCustomModule(Instance instance, Properties parameters) throws PalioException {
super(instance, parameters);
}

@Override
public String getVersion() {
return "1.0.0";
}

public String echo(String someText) {
return someText;
}
}

Tak stworzoną klasę należy skompilować i umieścić ją serwerze. W przypadku mało skomplikowanych modułów moża skopiować skompilowaną klasę do katalogu WEB-INF/classes/palio/modules. Zazwyczaj klasie modułu towarzyszą inne powiązane klasy stąd zalecanym sposobem wgrywania modułu na serwer jest zbudowanie archiwum JAR w którym powinny znaleźć się klasa modułu oraz wszystkie klasy powiązane a następnie wgranie go do katalogu WEB-INF/lib.

Przykład użycia modułu

Przykład wywołania w języku jPALIO

$myModule.echo("Hello jPALIO!")
$mymodule.echo("Hello jPALIO!")
$MYMODULE.echo("Hello jPALIO!")

Przykład wywołania w języku Groovy/JAVA

palio.Groovy.module("myModule").echo("Hello jPALIO!")
palio.Groovy.module("mymodule").echo("Hello jPALIO!")
palio.Groovy.module("MYMODULE").echo("Hello jPALIO!")

Wszystkie powyższe wywołania (zarówno w jPALIO i Groovy) wykonują dokładnie tą samą operację. Wywołują jednoargumentową metodę echo z modułu myModule.

Konfiguracja i parametryzowanie modułów

Moduły typu STANDARD nie wymagają umieszczania dodatkowych wpisów w konfiguracji instancji jPALIO. Są automatycznie inicjalizowane dla wszystkich instancji jPALIO. W przypadku modułów typu EXTERNAL wpis dotyczący danego modułu musi zostać umieszczony w konfiguracji instancji. Najprostsza konfiguracja modułu wygląda w sposób następujący:

<module name="myModule"/>

 

W przypadku gdy nasz moduł korzysta z dodatkowych parametrów należy powyższy wpis rozszerzyć do postaci następującej:

<module name="myModule">    
<connectorName>data</connectorName>
<param1>param1Value</param1> <param2>param2Value</param2> ...
</module>

 

Dostęp do parametrów kofiguracyjnych modułu jest realizowany poprzez metodę getConfigParam z klasy bazowej. Poniżej przedstawiono przykład użycia.

public static final String DEFAULT_CONNECTOR_NAME = "data";
public static final String CONNECTOR_NAME_PARAM = "connectorName";
    
public String getConnectorName() {
    return getConfigParam(CONNECTOR_NAME_PARAM) != null ? 
getConfigParam(CONNECTOR_NAME_PARAM) : DEFAULT_CONNECTOR_NAME; }

Internacjonalizacja modułów

W przypadku gdy istnieje konieczność zinternacjonalizowania wyników działania danego modułu (najczęściej dotyczy to modułów generujących interfejs użytkownika np. wyświetlenie informacji walidatora formularza) można skorzystać ze wsparcia jakie oferuje bazowa klasa modułu. Mechanizm internacjonalizacji jest realizowany za pomocą modułu Lang.

Poniżej przedstawiono metody wspierające internacjonalizację:

public String getModuleTranslation(String key)
protected void setModuleTranslation(String key, String languageCode, String value) throws PalioException
protected void initModuleTranslations() throws PalioException

WAŻNE! Kategorią tłumaczeń dla danego modułu jest pełna nazwa klasy modułu

Metoda getModuleTranslation służy do pobierania tłumaczenia związanego z danym modułem, dla podanego klucza, dla bieżącego języka. W przypadku gdy w bazie danych tłumaczeń brakuje wpisów dot. modułu, wywoływana jest metoda initModuleTranslations, której zadaniem jest dodanie brakujących wpisów. Dodanie tych wpisów powinno być realizowane przy użyciu metody setModuleTranslation.

 

Przykładowa implementacja metody initModuleTranslations

protected void initModuleTranslations() throws PalioException    setModuleTranslation("invalidLoginOrPassword", "pl", "Nieprawidłowy login lub hasło");
setModuleTranslation("invalidLoginOrPassword", "en", "Invalid login or password");

setModuleTranslation("insufficientPrivileges", "pl", "Niewystarczające uprawnienia");
setModuleTranslation("insufficientPrivileges", "pl", "Insufficient privileges");
}

Przykładowe użycie metody getModuleTranslation

getModuleTranslation("invalidLoginOrPassword")

tring languageCode, String value) throws PalioException {
Lang lang = (Lang) this.instance.getModule("lang");
lang.insertTranslation(key, languageCode, getClass().getName(), value);
}

/**
* Jeżeli moduł korzysta z mechanizmu internacjonalizacji w metodzie tej można zainijalizować tłumaczenia niezbędne to prawidłowego
* działania modułu. Metoda powinna zawierać wywołania metody {@link #setModuleTranslation(String, String, String)}. Jest ona
* automatycznie wywoływana w metodzie {@link #getModuleTranslation(String)} wówczas gdy w bazie danych tłumaczeń nie ma kategorii
* odpowiadającej danemu modułowi (brak kategorii, której kod jest równy nazwie klasy danego modułu). Metoda ta wywoływana jest tylko
* raz.
*
* @throws PalioException
*/
protected void initModuleTranslations() throws PalioException {

}
    /**
* Zwraca tłumaczenie dla podanego klucza. Jeżeli w bazie danych tłumaczeń brakuje wpisów dot. modułu na rzecz którego została wywołana
* ta metoda (brak kategorii, której kod jest równy nazwie klasy danego modułu) zostaje wykonana metoda
* {@link #initModuleTranslations()}. W przypadku gdy podczas pobierania klucza wystąpi wyjątek, wyjątek jest logowany a zwracaną
* wartością jest podany klucz.
*
* @param key klucz
*/
public String getModuleTranslation(String key) {
try {
Lang lang = (Lang) this.instance.getModule("lang");
if (this.translationsNotInited)
synchronized (this) {
if (this.translationsNotInited) {
// if (!lang.categoryExists(getClass().getName())) {
initModuleTranslations();
this.translationsNotInited = false;
// }
}
}
return lang.getTranslation(key, getClass().getName());
} catch (PalioException ex) {
Logger.error(Instance.getCurrent().getInstance(), "[" + this.getClass().getName() + "] getting translation error for key: "
+ key, ex);
return key;
}
}

protected void setModuleTranslation(String key, String languageCode, String value) throws PalioException {
Lang lang = (Lang) this.instance.getModule("lang");
lang.insertTranslation(key, languageCode, getClass().getName(), value);
}

/**
* Jeżeli moduł korzysta z mechanizmu internacjonalizacji w metodzie tej można zainijalizować tłumaczenia niezbędne to prawidłowego
* działania modułu. Metoda powinna zawierać wywołania metody {@link #setModuleTranslation(String, String, String)}. Jest ona
* automatycznie wywoływana w metodzie {@link #getModuleTranslation(String)} wówczas gdy w bazie danych tłumaczeń nie ma kategorii
* odpowiadającej danemu modułowi (brak kategorii, której kod jest równy nazwie klasy danego modułu). Metoda ta wywoływana jest tylko
* raz.
*
* @throws PalioException
*/
protected void initModuleTranslations() throws PalioException {

}