Ostatnia aktualizacja: 18/06/2026
Wtyczka jest bundlem OSGi instalowanym w środowisku OSGi. Może być ona dynamicznie:
Wtyczka posiada własny kontekst, który pełni rolę kontenera komponentów wtyczki, serwisów, kontrolerów. Możliwe jest wstrzykiwanie zależności i korzystanie z możliwości SpringFramework.
Zobacz również: Implementacja modułów >
Deskryptor wtyczki to plik XML który dostarcza podstawowe informacje o wtyczce oraz jest miejscem na deklaracje wykorzystywanych modułów. Plik ten jest wymagany, ponieważ dostarcza informacje o wtyczce (jej unikalny identyfikator i wyświetlaną nazwę).
Deskryptor ma następującą strukturę:
<?xml version="1.0" encoding="UTF-8"?>
<plugin key="com.suncode.plugin-tutorial" name="Tutorial Plugin">
<plugin-details>
<description>
<localized language="en">Description</localized>
<localized language="pl">Opis</localized>
</description>
<author>Suncode</author>
<requirements>
<plusworkflow>3.2.200, 4.1.120, 4.2.8</plusworkflow>
<com.suncode.plugin-dbexplorer>2.0.24</com.suncode.plugin-dbexplorer>
<com.suncode.plugin-pwe>2.3.63</com.suncode.plugin-pwe>
</requirements>
<free-license>XXXXXXXXXXXXXXXXXXXXX</free-license>
<changelog>https://docs.plusworkflow.pl/confluence/display/UNICMP/Change+Log+cuf-components</changelog>
<documentation>https://docs.plusworkflow.pl/confluence/display/UNICMP/Cuf-components</documentation>
</plugin-details>
<!-- Wszystkie kolejne elementy stanowią deklaracje modułów -->
</plugin>
| Element | Opis |
| requirements | Pozwala na określenie wymaganych zależności wtyczka. Zależność systemowa plusworfklow powinna być zgodna co do wersji z wersją parenta określoną w pom.xml. |
| free-license | Pozwala na przypisanie wtyczce darmowej licencji — wtyczki posiadające ten wpis będą instalowały się jako "Darmowe" Wtyczki bez tej sekcji są płatne. Licencje są powiązane z identyfikatorem wtyczki |
| changelog | Pozwala na wskazanie URLa do changeloga danej wtyczki. Link będzie dostępny do kliknięcia z poziomu centrum aktualizacji. Uwaga: link powinien wskazywać na zasoby publiczne, dostępne bez konieczności logowania. |
| documentation | Pozwala na wskazanie URL z dokumentacją wtyczki. Link będzie dostępny z poziomu centrum aktualizacji. |
Wtyczka może także zdefiniować PluginHook, jeżeli potrzebne jest wywołanie akcji przy starcie i zatrzymaniu wtyczki:
<?xml version="1.0" encoding="UTF-8"?>
<plugin key="com.suncode.plugin-tutorial" name="Tutorial Plugin" hook="com.suncode.plugin.tutorial.Hook">
<!-- ... -->
</plugin>
Wtyczka może zdefiniować swoje wymagania, które są sprawdzane podczas:
Wymagania są dzielone na:
Plik suncode-plugin.xml musi znajdować się w głównym katalogu pliku jar.
<?xml version="1.0" encoding="UTF-8"?>
<plugin key="com.suncode.plugin-tutorial" name="Tutorial Plugin">
<plugin-details>
<requirements>
<!-- Wymaganie 'mandatory' na system PlusWorkflow -->
<plusworkflow>3.2.50</plusworkflow>
<!-- Wymaganie 'optional' na wtyczke o kluczu "com.suncode.plugin.pluginX" -->
<com.suncode.plugin.pluginX optional="true">1.1</com.suncode.plugin.pluginX>
</requirements>
</plugin-details>
</plugin>
Ten rozdział pokazuje, jak korzystać z API mechanizmu wtyczek. Zarządzanie wtyczkami z poziomu systemu, znajduje się w zakładce Wtyczki.
Głównym komponentem mechanizmu wtyczek jest PluginFramework. W systemie PlusWorkflow należy pobrać ten obiekt z kontekstu aplikacji:
@Component
public class SomeComponent {
@Autowired
private PluginFramework framework;
/**
...
*/
}
import com.suncode.plugin.framework.PluginFramework;
import com.suncode.pwfl.util.SpringContext;
public class SomeClass {
public static void doSomething(){
PluginFramework framework = SpringContext.getBean( PluginFramework.class );
/**
...
*/
}
}
Poniżej przedstawiono wykonywanie kilku podstawowych operacji:
// pobrany w dowolny sposób
// PluginFramework framework = ...
// 1. Instalacja wtyczki z podanego pliku
File pluginFile = new File("/fakepath");
Plugin plugin = framework.installPlugin( pluginFile );
// 2. Aktualizacja wtyczki
File updatedPluginFile = new File("/fakepath");
plugin.update( updatedPluginFile );
// 3. Uruchomienie wtyczki
plugin.start();
plugin.getState(); // PluginState.ACTIVE
// 4. Pobranie tłumaczenia
// zwraca "message1" jeżeli moduł I18N nie jest obecny, w przeciwnym wypadku zwraca znalezione tłumaczenie
plugin.getMessage("message1");
// 5. Zatrzymanie wtyczki
plugin.stop();
plugin.getState(); // PluginState.STOPPED
Każda wtyczka ma własny kontekst aplikacji (ApplicationContext), w którym rejestrowane są jej komponenty, kontrolery, importowane serwisy etc. Dzięki temu wtyczka może być pisana tak jak każda inna aplikacja wykorzystująca SpringFramework.
Kontekst może być konfigurowany na 2 sposoby:
Jeżeli wtyczka zawiera plik /META-INF/spring/plugin-context.xml, to na jego podstawie tworzony jest XmlOsgiPluginContext.
Plik konfiguracji jest standardowym plikiem konfiguracji kontekstu aplikacji springframework i może wyglądać następująco:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- Włączenie skanowania wtyczki w poszukiwaniu @Component -->
<context:component-scan base-package="com.suncode.plugin.tutorial" />
</beans>
Od SpringFramework 3 możliwa jest konfiguracja kontekstu aplikacji w całości używając klas Java oznaczonych adnotacją @Configuration.
Jeżeli mechanizm wtyczek nie znajdzie pliku /META-INF/spring/plugin-context.xml to stworzy domyślny kontekst aplikacji, który skanuje całą wtyczkę w poszukiwaniu klas @Component (a więc również @Configuration).
Przykładowa konfiguracja (rejestruje tylko 1 bean klasy String):
package com.suncode.plugin.tutorial;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config {
@Bean
public String someString() {
return "asd";
}
}
Wtyczki mają możliwość korzystania z serwisów (komponentów) systemowych lub z innych wtyczek. Mogą również udostępniać swoje serwisy innym zainstalowanym wtyczkom.
Praktycznie każda wtyczka musi mieć dostęp do serwisów/komponentów PlusWorkflow. Wszystkie działania na użytkownikach, procesach wymagają odpowiednich serwisów. System Plus Workflow udostępnia mechanizmowi wtyczek wszystkie serwisy obecne w kontekście aplikacji.
Import tych powinien odbywać się poprzez moduł component-import.
<!-- Import serwisu UserService -->
<component-import key="userService" source="system" interface="com.suncode.pwfl.administration.user.UserService" />
Taka instrukcja spowoduje dodanie do kontekstu wtyczki wrappera tego serwisu.
Aby wykorzystać ten serwis, należy pobrać go z kontekstu wtyczki wykorzystując np. wstrzykiwanie zależności (@Autowired)
import com.suncode.pwfl.administration.user.UserService;
@Component
public class ServiceConsumer {
@Autowired
private UserService userService;
public void printUserInfo(){
User user = userService.get('admin');
System.out.println("User 'admin' full name is: " + user.getFullName());
}
}
Import serwisów z innych wtyczek wygląda podobnie:
<!-- Import serwisu MessageService -->
<component-import key="messageService" source="plugin" interface="com.suncode.plugin.test.MessageService" />
Wtyczki, które pozwalają na integracje lub udostępniają pewną specyficzną funkcjonalność, powinny udostępnić swoje serwisy innym wtyczką.
Udostępnianie serwisów często jest jedyną możliwością na przykład ze względu na transakcyjność i dostęp do skonfigurowanej bazy danych.
Wtyczka może udostępnić każdy swój komponent z kontekstu wtyczki. W tym celu komponent ten musi zostać oznaczony adnotacją Provides
import com.suncode.plugin.test.TestService;
@Service
@Provides(TestService.class)
public class TestServiceImpl implements TestService {
/**
...
*/
}
Po uruchomieniu wtyczki podany serwis (w rezultacie jego instancja) zostanie zarejestrowana w ServiceRegistry pod kluczem com.suncode.plugin.test.TestService.
Ze względu na to, że pod podaną nazwą klasy może być zarejestrowane wiele serwisów, możemy sprecyzować właściwości serwisu, aby konsument mógł pobrać ten właściwy używając filtrów.
@Provides(value = DashboardService.class, properties = { @ServiceProperty(name = "language", value = "pl") })
Każdy udostępniony serwis (poprzez adnotację @Provides) rejestrowany jest z właściwością plugin zawierającą klucz wtyczki, która zarejestrowała ten serwis. Dzięki temu utworzyć odpowiedni filtr aby, na przykład pobrać serwis z konkretnej wtyczki:
<component-import key="someService" source="plugin" interface="com.suncode.smth.Service"
filter="(plugin=com.suncode.plugin-test)" />
Wtyczki systemu Plus Workflow mogą serwować dynamiczne strony http zbudowane przy pomocy biblioteki Freemarker. Na tej stronie zostaną przedstawione podstawy tworzenia takich widoków.
Freemarker jest alternatywą dla JSP, które nie może zostać zintegrowane w mechanizm wtyczek z wielu powodów. Szablony Freemarker są tworzone dynamicznie i nie wymagają kompilacji do klas Java.
Strony tworzone są dynamicznie poprzez wstawianie wartości obiektów z modelu prosto do szablonu. Model jest uzupełniany np. atrybutami żądania (HttpServletRequest) tak jak w przypadku JSP.
Uzupełnienie modelu odbywa się zazwyczaj w kontrolerze:
@Controller
public class HelloController {
// Wynik tych 2 metod będzie taki sam
@RequestMapping("/hello")
public String sayHello(Model model){
model.addAttribute( "username", "World" );
return "hello"; // /views/hello.ftl
}
@RequestMapping("/hello2")
public String sayHello(HttpServletRequest request){
request.setAttribute( "username", "World" );
return "hello"; // /views/hello.ftl
}
}
Szablon:
<h1>Hello ${username}</h1>
Wynik:
<h1>Hello World</h1>
Każdy renderowany widok .ftl ma dostęp do pomocniczego obiektu PluginRequestContext, który ułatwia pobieranie tłumaczeń, ścieżek etc:
<!-- Pobranie ścieżki kontekstowej wtyczki: /{contextPath}/plugin/{id}/ -->
${pluginContext.pluginContextPath}
<!-- Pobranie adresu relatywnego do kontekstu wtyczki: /{contextPath}/plugin/{id}/hello -->
${pluginContext.getPluginContextUrl('hello')}
<!-- Pobranie ścieżki zasobów wtyczki: /{contextPath}/plugin/{id}/resources/{timestamp} -->
${pluginContext.pluginResourcesPath}
<!-- Pobranie ścieżki do zasobu wtyczki: /{contextPath}/plugin/{id}/resources/{timestamp}/hello.js -->
${pluginContext.getPluginResourcesUrl('hello.js')}
<!-- Pobranie contextPath: np. /PlusWorkflow -->
${pluginContext.contextPath}
<!-- Pobranie contextPath: np. /PlusWorkflow/Admin.do -->
${pluginContext.getContextUrl('Admin.do')}
<!-- Pobranie tłumaczenia klucza bez parametrów -->
${pluginContext.getMessage('messagekey')}
<!-- Pobranie tłumaczenia z parametrami -->
${pluginContext.getMessage('messagekey', ['somearg'])}
Wtyczka może zaimportować makro, które upraszcza operacje na obiektie PluginRequestContext.
<!-- Import makra -->
<#import "/plugin.ftl" as plugin/>
<!-- Pobranie adresu relatywnego do kontekstu wtyczki: /{contextPath}/plugin/{id}/hello -->
<@plugin.url 'hello'/>
<!-- Pobranie ścieżki do zasobu wtyczki: /{contextPath}/plugin/{id}/resources/{timestamp}/hello.js -->
<@plugin.resourceUrl 'hello.js'/>
<!-- Pobranie contextPath: np. /PlusWorkflow/Admin.do -->
<@plugin.systemUrl 'Admin.do'/>
<!-- Pobranie tłumaczenia klucza bez parametrów -->
<@plugin.message 'messagekey'/>
Freemarker umożliwia wywołania JspTagLib (np. displaytag, jstl).
jstl
<!-- Przypisanie do zmiennej "c" tagliba "JSTL" -->
<#assign c=JspTaglibs["http://java.sun.com/jsp/jstl/core"] />
<!-- <c:import...> -->
<@c.import charEncoding="UTF-8" url=someUrl />
displaytag
<!-- Przypisanie do zmiennej "display" tagliba "displaytag" -->
<#assign display=JspTaglibs["http://displaytag.sf.net"] />
<@display.table id="table" name="records" pagesize=20 partialList=true requestURI="someUrl">
<@display.column title=pluginContext.getMessage("Lp") class="small">${table_rowNum}</@display.column>
<!-- ... -->
</@display.table>
Widoki Freemarker generowane przez wtyczkę są domyślnie dekorowane tak, aby odpowiadały stylowi systemu Plus Workflow.
Domyślnie dekorowane są wszystkie żądania które:
X-Requested-With: XMLHTTPREQUEST)decorator nie jest obecny lub ma wartość inną niż noneW systemie dostępne są następujące dekoratory (nazwę używamy jako wartość parametru decorator):
| Nazwa | Opis | URL |
system |
Domyślny dekorator - wpisuje zawartość szablonu do obszaru body strony. Automatycznie wygenerowane zostanie nagłówek, menu systemowe, stopka. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=system |
empty |
Pusty dekorator - zawiera wszystkie skrypty oraz style css. Nie zawiera żadnej struktury takiej jak header czy footer. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=empty |
plain |
Prosty dekorator - zawiera tylko standardowe skrypty JavaScript | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=plain |
none |
Brak dekoratora. Wyświetlona zostanie tylko zawartość szablonu. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=none |
notlogged |
Dekorator strony logowania do wyświetlania informacji o nieprawidłowym logowaniu | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=notlogged |
Biblioteka PluginFramework dostarcza system wtyczek, które mogą dowolnie zwiększać funkcjonalność systemu, w którym zostaną zainstalowane. Architektura modułów pozwala w sposób deklaratywny na dostarczanie dowolnej funkcjonalności (na przykład wsparcie dla Spring MVC) dla wtyczki.
Mechanizm wtyczek opiera się na OSGi. Dzięki czemu wtyczki mogą być dynamicznie uruchamiane i aktualizowane oraz korzystanie z różnych wersji bibliotek.
Cała wymagana konfiguracja mechanizmu wtyczek musi znajdować się w pliku suncode-plugins.xml (w classpath).
Plik suncode-plugins.xml zawiera przede wszystkim konfigurację związaną z OSGi i widocznością klas systemowych we wtyczkach.
Przykładowa konfiguracja:
<?xml version='1.0' encoding='utf-8'?>
<suncode-plugins >
<home-directory>../plugins</home-directory>
<osgi strict-export="true">
<bootdelegation>
<!-- Core libs -->
<package>org.springframework.*</package>
<package>org.hibernate.*</package>
<!-- Proxy - wymagane jeżeli wykorzystujemy spring i hibernate-->
<package>javassist.*</package>
<package>org.aopalliance.*</package>
</bootdelegation>
<export>
<package version="1.4.0">org.apache.commons.io</package>
<package version="1.4.0">org.apache.commons.io.filefilter</package>
</export>
<exported-packages>
<pattern>com.**</pattern>
<pattern>org.**</pattern>
<pattern>net.**</pattern>
<pattern>javax.**</pattern>
</exported-packages>
<excluded-packages>
</excluded-packages>
</osgi>
</suncode-plugins>
Opis poszczególnych sekcji pliku konfiguracyjnego:
| Nazwa | Opis | Wymagany |
| home-directory |
Wskazuje katalog domowy mechanizmu wtyczek. W tym katalogu zapisywane będą wtyczki i inne wymagane ustawienia. Ścieżka może być absolutna, bądź relatywna do serwera. Mechanizm wtyczek nie korzysta z bazy danych. Wszystkie wymagane dane trzymane są w podanym katalogu. Usunięcie katalogu usunie wszystkie zainstalowane wtyczki.
|
✓ |
|
strict-export |
Definiuje, czy wersje eksportowanych pakietów mają pochodzić z manifestu w przypadku bundli OSGi. Flaga na wypadek problemów z kompatybilnością. Domyślnie true. |
|
| bootdelegation |
Ustawienie OSGi. Wskazuje, jakie klasy powinny być zawsze ładowanie z classloadera, który załadował ten mechanizm wtyczek. Ustawienie bootdelegation zawsze zawiera wpis com.suncode.plugin.framework.* - ładowanie wszystkich klas mechanizmu wtyczek z systemowego classloadera. Ustawienie tej właściwości konieczne jest w przypadku gdy wtyczki wykorzystują np. proxy - sekcja ImportPackages nie zawiera takiego pakietu i klasa nie zostanie znaleziona. Można uniknąć tego problemu ustawiając bootdelegation bądź dodając odpowiednie wpisy w MANIFEST.MF
VisualVM Profiler Jeżeli podczas używania Profilera VisualVM do profilowania wtyczek występują wyjątki ClassNotFoundException, to do bootdelegation należy dodać wpis: org.netbeans.lib.profiler.*
|
|
| export | Lista pakietów eksportowanych z systemu bez względu czy występują one w classpath czy też nie. Konfiguracja używana może być np. aby zdefiniować inną wersję eksportowanego pakietu. | |
| exported-packages |
Lista wzorców (w stylu ant) pakietów, które mają zostać wyeksportowane do środowiska OSGi. Skanowane są wszystkie pliki jar i katalogi w classpath. Dzięki temu, wtyczki mogą korzystać z klas głównego systemu. Wzorce są wyrażeniami w stylu ant:
W OSGi pakiety są także identyfikowane przez wersję. Dlatego exporter próbuje ustalić wersję pakietu, odczytując nazwę pliku jar lub informacje w MANIFEST.MF bądź w plikach tworzonych przez Maven'a.
Jeżeli klasy nie są zawarte w pliku jar, nie ma możliwości odczytania wersji pakietu. W takim wypadku przyporządkowywana jest im wersja 0.0.0
|
|
| excluded-packages | Lista wzorców (w stylu ant — tak jak w exported-packages) pakietów, które mają zostać wykluczone z eksportu do środowiska OSGi. |
Pierwsze uruchomienie mechanizmu wtyczek wiąże się ze stworzeniem katalogu domowego oraz skanem całego classpath w poszukiwaniu pakietów/klas spełniających podane wymagania. Jest to proces bardzo czasochłonny (nawet kilka minut - w zależności od maszyny).
Po pierwszym uruchomieniu tworzony jest cache pakietów, co przyśpiesza kolejne uruchomienia.
Plugin API wykorzystywane jest do zarządzania pojedynczą wtyczką.
Obiekt (com.suncode.plugin.framework.Plugin) reprezentuje wtyczkę i umożliwia sterowanie jej stanem oraz komunikację z mechanizmem wtyczek. Obiekt ten można otrzymać poprzez:
// dowolny komponent (wewnątrz wtyczki lub w systemie)
@Component
public class SomeComponent {
@Autowired
private PluginFramework framework;
public void method(){
Plugin plugin = framework.getPlugin("plugin-key");
}
}
Wstrzyknięcie (@Autowired) obiektu wtyczki do komponentu tej wtyczki. W taki sposób możemy pobrać obiekt aktualnej wtyczki:
// komponent wewnątrz wtyczki
@Component
public class SomePluginComponent {
@Autowired
private Plugin plugin;
public void method(){
plugin.getKey(); // klucz tej wtyczki
}
}
Konieczne jest jednoznaczne wyszczególnienie wszystkich pakietów wykorzystywanych przez wtyczkę. Aby uprościć ten proces, większość pracy może zostać wykonana automatycznie przez wtyczkę maven-bundle-plugin.
W sytuacji, gdy nazwa klasy zostanie podana w statycznym zasobie, takim jak suncode-plugin.xml, wtyczka nie jest w stanie samodzielnie uzyskać tych informacji. W takich przypadkach wymagane jest dodatkowe skonfigurowanie wtyczki w pliku pom.xml.
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
<!-- Importuj wszystkie pakiety wykorzystane w klasach oraz pakiet
"com.suncode.plugin.tutorial"-->
<Import-Package>*,com.suncode.plugin.tutorial</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
Wtyczka może być dynamicznie uruchamiana, zatrzymywana i aktualizowana poprzez wywołanie odpowiednich metod na obiekcie tej wtyczki:
Uruchomienie wtyczki:
Plugin plugin = ...
plugin.start();
System.out.println(plugin.getState()); // wypisuje ACTIVE
Zatrzymanie wtyczki:
Plugin plugin = ...
plugin.stop();
System.out.println(plugin.getState()); // wypisuje STOPPED
Aktualizacja wtyczki z podanego pliku:
Plugin plugin = ...
plugin.update(new File("ścieżka do pliku jar wtyczki"));
Odinstalowanie wtyczki:
Plugin plugin = ...
plugin.uninstall();
System.out.println(plugin.getState()); // wypisuje UNINSTALLED
Każda wtyczka zbudowana jest z klas Java oraz statycznych zasobów.
Ze względu na izolację wtyczek, odczyt zasobów może odbywać się tylko z wykorzystaniem przedstawionych metod.
Pobieranie pojedynczych zasobów:
Plugin plugin = ...
Resource resource = plugin.getResource("suncode-plugin.xml"); // deskryptor wtyczki
if(resource.exists()){
// zasób istnieje i można go odczytać
}
Wyszukiwanie zasobów:
Plugin plugin = ...
PluginContext context = plugin.getPluginContext();
// mappings/a.xml
// mappings/b.xml
// mappings/c.json
// mappings/sub/a.json
// mappings/sub/b.xml
// wszystkie pliki z katalogu mappings i podkatalogów
Resource[] resources = context.getResources( "mappings/**/*" );
// resources ma:
// mappings/a.xml
// mappings/b.xml
// mappings/c.json
// mappings/sub/a.json
// mappings/sub/b.xml
// wszystkie pliki xml z katalogu mappings
Resource[] resources = context.getResources( "mappings/*.xml" );
// resources ma:
// mappings/a.xml
// mappings/b.xml
Wzorzec zasobów jest wyrażeniem Ant. Więcej info w dokumentacji Springa PathMatchingPatternResolver.
PluginStore dostępny jest od wersji 1.0.5 mechanizmu wtyczek — PlusWorkflow 3.1.7
PluginStore pozwala na zapisywanie zasobów (np. plików) w lokalnym repozytorium wtyczki.
Pliki zapisane w takim repozytorium są stałe tzn. nie są usuwane podczas zatrzymywania wtyczki. Stanowi to alternatywę dla baz danych.
Domyślna implementacja PluginStore przechowuje pliki w systemie plików w katalogu: <plugin-framework-home>/data/<plugin-key>.
Pobieranie instancji store:
// z instancji wtyczki
PluginStore store = plugin.getPluginStore();
// poprzez @Autowired
@Autowired
private PluginStore store;
Komponent PluginStore może być pobrany zarówno z instancji wtyczki jak i z kontekstu tej wtyczki.
Zapis zasobów:
PluginStore store = ...
// zapis InputStream
PluginStoreResource resource = store.store("some/path/file.xml", inputStream);
resource.getPath(); // some/path/file.xml
resource.getInputStream();
Odczyt zasobów:
PluginStore store = ...
// pobranie zasobu
PluginStoreResource resource = store.read("some/path/file.xml")
if(resource == null){
// zasób nie istnieje
return;
}
// odczyt i poprawne zamknięcie
InputStream input = resource.getInputStream();
try{
// odczyt/kopiowanie etc.
}
finally{
input.close();
}
Usuwanie zasobów:
PluginStore store = ...
// usunięcie pojedynczego zasobu
store.delete("some/path/file.xml");
// wyczyszczenie całego store'a
store.clear();
Integracja z interfejsem użytkownika może odbywać się poprzez jego modyfikację lub rozszerzanie już istniejących funkcjonalności.
Moduł menu-entry umożliwia dodanie do istniejących menu własnych wpisów o określonych atrybutach. Sekcja zdefiniowana w tym module jednoznacznie identyfikuje menu, do którego chcesz dodać nasz wpis.
System Plus Workflow definiuje następujące sekcje:
.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9kemY4dnF2MjRlcWhnLmNsb3VkZnJvbnQubmV0L3VzZXJmaWxlcy8zNzc5Ni80ODE2My9ja2ZpbmRlci9pbWFnZXMvcXUvMjAyNS9vYnJheigyMSkucG5nIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzg1MzMyNTUyfX19XX0_&Signature=odauVjBbjDQZ-ziXed5EeF29CxWRSQ5q26quUKoHc8EiifgphF4BBlk8MMwt3GvPPIBS8oyDw600t1Jg148TabPDFXZBKFz0knNUZIh46HnCXi5F2F1EryUQx4Z2MUFDOLtJeUtXySlS5xkJK9M0UbFMIyZ4ekJ0yig5fgYJ~odYuaZ34oyS2hKDREIpJ2Qz9cSDAxSaqZjwyQb1B~-3iRkS76VmI98mnnbRIhwsRYY1kL9-wox53ksE~xYcI5Ub1TLClah6rbsxjw87Ot8fpXeQAd90bjienwMqZyOTeIyP-oMle7kkUQ9w6SbDRLLmXQbAxVCg~bjY-nXJ8hyuiw__&Key-Pair-Id=K2TK3EG287XSFC)
.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9kemY4dnF2MjRlcWhnLmNsb3VkZnJvbnQubmV0L3VzZXJmaWxlcy8zNzc5Ni80ODE2My9ja2ZpbmRlci9pbWFnZXMvcXUvMjAyNS9vYnJheigyMikucG5nIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzg1MzMyNTUyfX19XX0_&Signature=AhvUtwo~64SvppovR90W0DyaZx58D1FYJ7uIfxFaOZ~PfX-t5zIIljcRvpfGUyr~YupwooD8J5QDxvXYCZBV6JGxZosbwplOdEc98svucH7Xuup6jW0DIclMmTJxev5UryIsOR2qJTk0Zu0767XM5rgpUo5T0vl0fCBBvg6YUgZv4sL-9i2aB4XzsV7Rkp16g~QZiwG2mTAu0UIYoZ-VT1dJE-g9rGEvL9UdzzitZ7WzieUgRvyCXNmakZYHdr0PrJWpOwRCUik2cYYw~x2qDXdzxnPhG9hXsJ~06ayp7DVozj6eCrOJvYi1pmeZltsd6SiDgbgP7upcc-Yvf9KBZg__&Key-Pair-Id=K2TK3EG287XSFC)

Wszystkie pozycje w menu mają swój order. Pierwszy systemowy wpis w menu ma order=0, każdy kolejny o 10 większy.
Zaleca się korzystanie z atrybutu order, nawet jeśli kolejność nie jest istotna. Inne wtyczki mogą próbować dodać elementy w pobliżu dodawanego wpisu, co stanie się trudniejsze, jeśli nie zostanie określona odpowiednia kolejność.
Kliknięcie na daną pozycję w menu spowoduje wyświetlenie w kontenerze odpowiednim dla każdego z menu zawartości, pobranej ze skonfigurowanego linku.
Dodatkowo Kreatory (Wizardy) korzystają z następujących sekcji:
.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9kemY4dnF2MjRlcWhnLmNsb3VkZnJvbnQubmV0L3VzZXJmaWxlcy8zNzc5Ni80ODE2My9ja2ZpbmRlci9pbWFnZXMvcXUvMjAyNS9vYnJheigyNCkucG5nIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzg1MzMyNTUyfX19XX0_&Signature=hwMhJpSMUGAdUF-AnTtbYgKsrzBIEM~2UTHTO3o8H9MP0zgYYn3wiU9IPQei4~KzknoMjy0q84XvJsOGIW3sAztn0Tmvp~S2U3mm7k6BsdM-wYjZy~y9MD60f8mzu6huyZxmtYHLEE0IWSwPujSHmKsYqCxJDkf43XuhQKdOHJ6nJUpJLas~3v8vzLfNcw0THl7wC7S7qfMSQl-l93QfB5InlvYiRBTc3ATpX9vPt3Kq4yIlne2z1~aOUYa6WnGI6D5gJPqkunVja4wtGEghH5CfUttHg8fd1dZxHCxnXjYJr-vM1fMA9Jo4Dz7-2XOBOBQU4PVMa1YJkJJIyY0apQ__&Key-Pair-Id=K2TK3EG287XSFC)
Widok domyślny użytkownika wyświetla się zaraz po zalogowaniu do systemu lub kliknięciu na pozycję Start w menu głównym.
Można umożliwić użytkownikowi wybranie widoku utworzonej wtyczki jako jego widoku domyślnego.
Odpowiedzialny jest za to moduł default-view.
Dla każdego zdefiniowanego modułu pojawi się możliwość wyboru tej opcji w wyborze widoku domyślnego:
.png?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiaHR0cHM6Ly9kemY4dnF2MjRlcWhnLmNsb3VkZnJvbnQubmV0L3VzZXJmaWxlcy8zNzc5Ni80ODE2My9ja2ZpbmRlci9pbWFnZXMvcXUvMjAyNS9vYnJheigyNSkucG5nIiwiQ29uZGl0aW9uIjp7IkRhdGVMZXNzVGhhbiI6eyJBV1M6RXBvY2hUaW1lIjoxNzg1MzMyNTUyfX19XX0_&Signature=NtXHpUg10LgaFjccPl5yIwr-i7a2OhciIcKLe7RlKPSSMKIIb~A1fXyxs5Pz0clqHUL9d-M9EZf3OFbq3oRQGvmli0REhpdISDgCBrtE1LopmA0ctpv~p9RmMDhbnynOCkQF4tvqQLoPQpAiuUpnSzeEW40dFHZ0rtLG3OcqceKs9Bwi5AnpN8vMl9gmLOphqnBEIjHUPMeU5kOaxmcHdtZq-eaMbCsCg6bI0qamO0FetZCuvDa9eJGJ2j62VjE8f7n~3Wt9IZYt9XDY0ZpH~W6vBaHOla7JBKDjvlwU3ddUMMczvzgZAlJ8VeCTiAuRuB0bfBmnW9CxtGU-9Dr0~w__&Key-Pair-Id=K2TK3EG287XSFC)