...
Obidve časti využívajú princípy mapovania D2000 Unival-u popísané v nasledujúcej časti.
Kotva | ||||
---|---|---|---|---|
|
Transformácie hodnôt typu unival na základné Java typy a späť je jedným zo základných kameňov pokročilého mapovania.
Unival hodnota je kompozitná, skladá sa z hodnoty a viacerých atribútov. V mnohých prípadoch je však zaujímavá len hodnota samotná, prípadne indikátor jej platnosti, ale len málokedy ďalšie atribúty. Hodnota a jednotlivé atribúty sa preto mapujú na objekty základných Java typov každý zvlášť.
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
Atribút platnosť hodnoty a hodnota samotná sú vzájomne veľmi silne previazané. Unival buď obsahuje platnú hodnotu, alebo má hodnotu neplatnú a vtedy sa správa, ako keby hodnotu vôbec nemal. Z toho dôvodu sú hodnota a atribút platnosť hodnoty mapované spoločne na objektové typy. Napríklad celočíselná hodnota je mapovaná typom Integer. Ak je hodnota unival-u platná, mapuje sa na hodnotu, ak je neplatná, mapuje sa ako null
.
...
D2000 typ | Java typ |
Logický ( | VBool, BooleanAnotácie JAPI pre pokročilé mapovanie na objekty D20001 |
Celočíselný ( | Integer |
Reálny ( | Double |
Absolútny čas ( | |
Relatívny čas ( | Double |
Text ( | String |
Štruktúrovaný ( | List<T>Anotácie JAPI pre pokročilé mapovanie na objekty D20003 |
Kotva | ||||
---|---|---|---|---|
|
Pre mapovanie unival atribútov slúžia anotácie ParameterAttribute
, ReturnAttribute
, ColumnAttribute
. Ich spoločným znakom je, že sú parametrizované typom unival atribútu, na ktorý definujú väzbu. Rovnako ako hodnota unival-u, aj atribúty sú mapované výlučne na objektové typy. Avšak pokus o transformáciu prázdneho odkazu (null) na hodnotu unival atribútu je vyhodnotený ako chyba. Nasledujúca tabuľka obsahuje zoznam podporovaných transformácií:
...
Zoznam podporovaných atribútov je krátky, obsahuje len mapovania, ktoré boli doteraz potrebné. V budúcnosti bude tento zoznam rozšírený na požiadanie.
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
Štruktúrované Unival hodnoty sú štandardným spôsobom reprezentované typom UnivalRecord
, ktorého hodnotová časť obsahuje objekt typu sk.ipesoft.d2000.datatable.Table
. Pre mnohé aplikácie je však výhodnejšie pracovať s jednoduchšou reprezentáciou, v ktorej je štruktúrovaná hodnota reprezentovaná objektom typu java.util.List
, ktorého prvky reprezentujú jednotlivé riadky. V jednom zozname sú všetky prvky objektmi tej istej aplikačne definovanej triedy, ktorá je anotáciami mapovaná na bunky štruktúrovanej hodnoty.ktorá je anotáciami mapovaná na bunky štruktúrovanej hodnoty.
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
Na obrázku je uvedená definícia štruktúry SD.Person, ktorá poslúži ako príklad. Nasleduje mapovanie definície štruktúry na triedu Person
.
...
Anotácia @ColumnValue
na metóde getName
indikuje, že metóda slúži ako getter hodnoty v bunke stĺpca Name (podľa atribútu anotácie name = "Name"
) a že sú hodnoty v tomto stĺpci textového typu (podľa atribútu anotácie columnType = ColumnType.text
). JAPI bude pri spracovaní tejto anotácie vyžadovať prítomnosť setter metódy setName
a tiež bude očakávať, že property NameAnotácie JAPI pre pokročilé mapovanie na objekty D20004 je typu String. Obdobným spôsobom funguje anotácia @ColumnValue
na metóde getId
.
Anotácia @ColumnAttribute
na metóde getNameTime
indikuje, že metóda slúži ako getter časovej značky hodnoty (podľa atribútu anotácie attribute = UnivalAttributeType.valueTime
) v bunke stĺpca Name (podľa atribútu anotácie name = "Name"
). JAPI bude pri spracovaní tejto anotácie vyžadovať prítomnosť setter metódy setNameTime
a tiež bude očakávať, že property NameTimeAnotácie JAPI pre pokročilé mapovanie na objekty D20004 je typu Date alebo Long. Pri konverzii na unival by bolo považované za chybu, ak by bola hodnota NameTime rovná null
, preto metóda setNameTime
takúto hodnotu odmietne nastaviť.
...
Všimnite si, že trieda Person
neobsahuje mapovanie buniek stĺpca Active. Pri mapovaní štruktúrovaných unival hodnôt je mapovanie jednotlivých stĺpcov nepovinné. Pri mapovaní z unival u sú hodnoty bez mapovania ignorované. Pri mapovaní do univalu sú hodnoty bez mapovania nahradené neplatnými hodnotami. Chýbajúce časové značky sú doplnené aktuálnym časom.
Kotva | ||||
---|---|---|---|---|
|
So štruktúrovanými hodnotami sa v prostredí JAPI stretávame na dvoch miestach – parametre RPC volaní a hodnoty objektov typu štruktúrovaná premenná. Ak sú pre RPC použité pokročilé anotácie, štruktúrované hodnoty sú konvertované podľa mapovania automaticky. Inak je možné konvertovať medzi typom UnivalRecord a mapovanou triedou ručne, za pomoci objektu triedy UnivalConvertor.
...
Blok kódu | ||||
---|---|---|---|---|
| ||||
List<Convertor> dictionaryConvertors = new ArrayList<>(); for (DictionaryLanguage language : session.getConnector() .getSharedResourcesCache().getDictionaryLanguages()) dictionaryConvertors.add( session.getConnector().createDictionaryConvertor(language.getIndex())); convertor.fillMulticonvertedValues(list, Person.class, dictionaryConvertors); |
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
Podľa rôznych kategórií je možné RPC volania deliť nasledovne.
...
V prostredí ESL a v prostredí internej Javy je synchrónne aj asynchrónne RPC nasmerované do tej istej procedúry (metódy). Spôsob volania vyberá volajúci na základe dohody, lebo volaný kód toto nevie ovplyvniť ani zistiť. V prostredí JAPI je vo volanom kóde RPC vidieť, či bol zavolaný synchrónne alebo asynchrónne. Pokročilými anotáciami sa dVolajúci okonca volaný kód označí tak, aby spracúval iba jeden konkrétny z dvoch typov volania.typov volania.
Kotva | ||||
---|---|---|---|---|
|
Volanie RPC je systémom D2000 prenášané ako správa zložená z viacerých častí:
- adresa volajúceho
- HOBJ procesu (proces typu Event Handler, HI, Session),
- dynamické HOBJ vykonávaného objektu (objekt typu Event, Schéma alebo 0 ak je volajúci Session),
- príznak, či RPC volanie pochádza z prostredia interného Java run-time,
- adresa volaného
- HOBJ procesu (proces typu Event Handler, HI, Session),
- HOBJ vykonávaného objektu (objekt typu Event, Schéma alebo 0 ak je volajúci Session),
- príznak, či RPC volanie smeruje do prostredia interného Java run-time,
- číslo inštancie vykonávaného objektu (ak ide o „inštančne" vytvorený Event alebo Schému a HOBJ objektu bolo bázové, inak 0),
- identifikátor volanej RPC
- meno
- HOBJ objektu ESL Interface, ak ide o implementáciu RPC definovanej v ESL Interface, inak 0,
- hodnoty parametrov volania,
- príznak, či ide o synchrónneAnotácie JAPI pre pokročilé mapovanie na objekty D2000 alebo asynchrónneAnotácie JAPI pre pokročilé mapovanie na objekty D20005 alebo asynchrónne6 volanie.
Klasický spôsob volania RPC prostredníctvom JAPI vyžadoval, aby volajúci pri každom volaní uviedol všetky položky okrem adresy volajúceho (ktorú doplnil D2Connector). Nevýhodou tohto prístupu je predovšetkým chýbajúca typová kontrola hodnôt parametrov volania ako aj ich prácne vytváranie. Nepohodlná je tiež nutnosť ručne získať a ukladať HOBJ objektov a procesov.
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
Blok kódu | ||||
---|---|---|---|---|
| ||||
RPC PROCEDURE Parse(IN TEXT _text, INT _result) _result := %StrToI(_text) END Parse RPC PROCEDURE Square(REAL _value) _value := _value * _value END Square RPC PROCEDURE Redim(IN INT _n, RECORD NOALIAS(SD.Person) _data) REDIM _data[_n] END Redim RPC PROCEDURE SetValue(IN TIME _value) U.Value := _value TIME _value\TIM END SetValue RPC PROCEDURE GetDataAndMetadata(RECORD NOALIAS(SD.Person) _data, RECORD NOALIAS(SD.Metadata) _metadata) ... END Redim BEGIN END |
Uvedený ESL kód predstavuje zdrojový kód server event-u E.Service
, ktorého rodič je proces SELF.EVH
. Väčšina procedúr má pre ilustratívnosť implementované jednoduché telo. RPC GetDataAndMetadata
telo nemá, pretože by bolo príliš zložité. Ilustruje však príklad procedúry, ktorá má viac ako jeden výstupný parameter7 .
V nasledujúcich podkapitolách bude postupne po častiach uvedený zdrojový kód, ktorý by za normálnych okolností tvoril jeden súbor.
4.3.2.1 Jednoduché mapovanie vstupného a výstupného parametra
Blok kódu | ||||
---|---|---|---|---|
| ||||
import java.util.Date; import java.util.List; import sk.ipesoft.d2000.d2japi.annotations.InOut; import sk.ipesoft.d2000.d2japi.annotations.ParameterDirectionType; import sk.ipesoft.d2000.d2japi.annotations.ParameterType; import sk.ipesoft.d2000.d2japi.annotations.UnivalAttributeType; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.Event; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.Parameter; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.ParameterAttribute; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.ParameterValue; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.RPC; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.ReturnValue; @Event(name = "E.Service") public interface Service { @RPC(name = "Parse", asynchronous = false, parameters = { @Parameter(name = "value", type = ParameterType.text, inOut = false), @Parameter(name = "result", type = ParameterType.integer, inOut = true) }) @ReturnValue(name = "result") public Integer parse( @ParameterValue(name = "value") String value); } |
...
Anotácia @ReturnValue
slúži na previazanie návratovej hodnoty metódy s návratovou hodnotou niektorého z parametrov. Parameter anotácie name = "result"
indikuje, že to má byť návratová hodnota 2. parametra zo zoznamu formálnych parametrov kvôli zhode v identifikátoroch. Typ návratovej hodnoty Integer
zodpovedá typu formálneho parametra podľa tabuľky v kapitole 4.1.1. Dôležitou podmienkou je, aby bol formálny parameter označený ako vstupno-výstupný.
Anotácia 1. parametra metódy @ParameterValue
indikuje, že hodnota tohto parametra má byť premenená na vstupnú hodnotu 1. formálneho parametra (podľa parametra anotácie name = "value"
). Typ hodnoty String zodpovedá typu formálneho parametra podľa tabuľky v kapitole 4.1.1.
Zaujímavý je tiež fakt, že pre 2. formálny parameter (result) nie je definované mapovanie vstupnej hodnoty. V takomto prípade je pri volaní RPC procedúry nastavený 2. parameter na neplatnú (invalidnú) hodnotu.
4.3.2.2. Mapovanie vstupno-výstupného parametra
Blok kódu | ||||
---|---|---|---|---|
| ||||
@RPC(name = "Square", parameters = { @Parameter(name = "v", type = ParameterType.real) }) @ReturnValue(name = "v") public Double sqare_1( @ParameterValue(name = "v") Double value); @RPC(name = "Square", parameters = { @Parameter(name = "v", type = ParameterType.real) }) public void sqare_2( @ParameterValue(name = "v") InOut<Double> value); |
...
- formálny parameter RPC procedúry je definovaný ako vstupno-výstupný
- parameter metódy je deklarovaný s typom
InOut<>
. Generický parameter typu musí zodpovedať typu formálneho parametra. - nepovinný parameter anotácie
@ParameterValue.direction
nebol uvedený, čiže automaticky nadobudol hodnotuParameterDirectionType.derived
. (Rovnaké správanie by bolo dosiahnuté, keby bol explicitne nastavený na hodnotuderived
aleboinout
.)
4.3.2.3. Mapovanie synchrónnej procedúry s odloženým vyhodnotením výsledku
Blok kódu | ||||
---|---|---|---|---|
| ||||
RPC(name = "Square", parameters = { @Parameter(name = "v", type = ParameterType.real) }) @ReturnValue(name = "v") public Future<Double> sqare_3( @ParameterValue(name = "v") Double value); |
Metóda square_3
sa od metódy square_1
odlišuje typom návratovej hodnoty. Keď je typ návratovej hodnoty deklarovaný ako Future
, volanie metódy nie je blokujúce, tak ako pri bežnej synchrónnej RPC, ale skončí hneď. Výsledok je uložený vo Future
objekte, ktorého .get()
metóda zabezpečí synchrónnosť volania.
4.3.2.4. Mapovanie parametra so štruktúrovaným typom
Blok kódu | ||||
---|---|---|---|---|
| ||||
@RPC(name = "Redim", parameters = { @Parameter(name = "n", type = ParameterType.integer, inOut = false), @Parameter(name = "r", type = ParameterType.record, recordType = Person.class) }) @ReturnValue(name = "r") public List<Person> redim( @ParameterValue(name = "n") Integer length, @ParameterValue(name = "r") List<Person> data); |
...
Pri použití metódy redim
bude pre účely návratovej hodnoty vytvorená nová inštancia typu List<Person>
a jej prvky budú nové inštancie typu Person
napriek tomu, že majú rovnaký obsah ako inštancie, ktoré boli použité ako parametre..
4.3.2.5. Mapovanie asynchrónneho volania a časovej značky hodnoty
Blok kódu | ||||
---|---|---|---|---|
| ||||
@RPC(name = "SetValue", asynchronous = true, parameters = { @Parameter(name = "v", type = ParameterType.time, inOut = false) }) public void setValue( @ParameterValue(name = "v") Date value, @ParameterAttribute(name = "v", attributeType = UnivalAttributeType.valueTime) Long valueTime); |
...
V príklade je zámerne použitý iný typ parametra value
(java.util.Date
) a parametra valueTime
(java.lang.Long
). Obidva typy je možné rovnako dobre použiť na mapovanie hodnoty vyjadrujúcej „D2000 absolútny čas", ich výber je na tvorcovi mapovania.
4.3.2.6. Mapovanie procedúry s dvomi výstupnými štruktúrovanými parametrami
Blok kódu | ||||
---|---|---|---|---|
| ||||
@RPC(name = "GetDataAndMetadata", asynchronous = false, parameters = { @Parameter( name = "data", inOut = true, type = ParameterType.record, recordType = Person.class), @Parameter( name = "meta", inOut = true, type = ParameterType.record, recordType = Metadata.class)}) public void getDataAndMetadata( @ParameterValue(name = "data") InOut<List<Person>> data, @ParameterValue(name = "meta") InOut<List<Metadata>> meta); |
...
- Typ parametra data je
InOut<List<Person>>
➔ Generickým parametrom kontajneraInOut
je generickýList
, ktorého parametrom je triedaPerson
, ktorej mapovanie naSD.Person
je popísané v kapitole 4.2.1. - Trieda Metadata mapuje definíciu štruktúry
SD.Metadata
. Jej definíciu v príkladoch neuvádzame. - Inštancia objektu typu
List
, ako aj inštancie predstavujúce jeho prvky, ktoré sa nachádzajú v kontajneri typuInOut
po skončení synchrónneho volania sú vždy iné, ako inštancie, ktoré sa v kontajneri nachádzali na začiatku volania. Toto správanie je vlastnosť knižnice JAPI.
Kotva | ||||
---|---|---|---|---|
|
Kotva | ||||
---|---|---|---|---|
|
V nasledujúcej ukážke bude uvedený zdrojový kód triedy ExampleHandler. Je to aplikačne definovaná trieda, ktorej metódy môžu byť volané ako RPC z prostredia ESL .
...
Metóda parseInt
má rovnaké formálne rozhranie a ja tiež funkčne zhodná s RPC PROCEDURE E.Service.Parse
uvedenou v kapitole 4.3.2. Pri jej mapovaní boli použité rovnaké anotácie s rovnakým významom ako na metódu Service.parse
.
Rozdiel medzi RPC Parse
napísanej v ESL a metódou ExampleHandler.parseInt
je v tom, že metódu parseInt nie je možné zavolať asynchrónne. Pre takéto volanie by sa JAPI pokúsilo nájsť druhú metódu s rovnakým formálnym rozhraním, ktoré by malo parameter RPC.asynchronous = true
.
Kotva | ||||
---|---|---|---|---|
|
Blok kódu | ||||
---|---|---|---|---|
| ||||
import sk.ipesoft.d2000.d2japi.annotations.ParameterType; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.Parameter; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.ParameterValue; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.RPC; import sk.ipesoft.d2000.d2japi.annotations.eventBinding.ReturnValue; public class HelloHandler { @RPC(name = "Hello") public void hello( @CallerInformation(type = CallerInformationType.processHobj) Integer processHobj, @CallerInformation(type = CallerInformationType.eventHobj) Integer eventHobj, @CallerInformation(type = CallerInformationType.internalJava) Boolean java) { ... } } |
...
- processHobj – HOBJ procesu (EVH, HIP, DCC), z ktorého bola RPC zavolaná
- eventHobj – HOBJ objektu typu Event, z ktorého bola RPC zavolaná.
- internalJava – nadobúda hodnotu true, ak bola RPC zavolaná z prostredia internej Javy.
Kotva | ||||
---|---|---|---|---|
|
V kapitolách 4.2. a 4.3. a ich podkapitolách boli vytvorené definície mapovania štruktúrovaných hodnôt (SD.Person ⟺ Person
) a definície mapovania volania RPC (Service
➔ E.Service
) a späť (trieda ExampleHandler
). Ich použitie zjednodušuje mechanickú prácu vytvárania a konverzie unival hodnôt ako aj potrebu manažovať a opakovane používať množstvo HOBJ pre volanie RPC.
...
Nasledujúce príklady sa budú odkazovať na triedy vytvorené v príkladoch v kapitolách 4.2.1, 4.3.2. a 4.3.3. Okrem toho budú použité nasledovné objekty:
...
Na konverzie štruktúrovaných hodnôt bude použitý objekt typu UnivalConvertor
prístupný cez connector.getDefaultUnivalConvertor()
.
Kotva | ||||
---|---|---|---|---|
|
V uvedenom príklade je ukážka volania RPC z prostredia JAPI. Príklad sa skladá z inicializačnej časti (kroky 1 a 2), ktorú je potrebné spraviť raz, pri štarte aplikácie, po pripojení sa ku kernelu. Ďalšie kroky (odrážky), sú príklady samotného volania, je možné použiť v ľubovoľnom poradí a opakovať podľa potreby.
...
- Krok 1 stačí spraviť raz, po vytvorení 1.
session
. Vzniknutúfactory
môžete považovať za platnú, pokým je aktívnyconnector
. Pre novýconnector
je potrebné vytvoriť novú factory. - Krok 2 je potrebné raz zopakovať pre každú novú
session
, z ktorej majú byť volané RPC.
Kotva | ||||
---|---|---|---|---|
|
V uvedenom príklade je ukážka volania RPC z prostredia ESL do prostredia JAPI a najmä spôsob spracovania a odpovedania na toto volanie. Príklad sa skladá z inicializačnej časti (kroky 1 a 2), po ktorej bude možné adresovať RPC volania do zvolenej session. Krok 3 je inicializáciou v ESL. Krok 4 je samotné volanie, ktorý možno podľa potreby opakovať s ľubovoľnými parametrami.
...