| Obsah |
|---|
Vo verzii 10.1.39-build4 pribudla do knižnice JAPI možnosť aplikačne definovať objekty, ktoré výrazným spôsobom prispievajú k typovo bezpečnej komunikácii pri RPC volaniach. Balíček sk.ipesoft.d2000.d2japi.annotations obsahuje triedy a anotácie pre definovanie mapovania.
...
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); |
Metóda redim mapuje RPC, ktorej druhým formálnym parametrom je štruktúrovaná hodnota. Pre správne mapovanie je typ parametra v anotácii nastavený na @Parameter.type = ParameterType.record a nepovinný parameter anotácie @Parameter.recordType = Person.class. Použitá definícia štruktúry SD.Person a jej mapovanie triedou Person pochádza z kapitoly 5.2.1.
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); |
Metóda setValue sa od predošlých príkladov odlišuje tým, že mapuje asynchrónne volanie (RPC.asynchronous = true). To znamená, že z pohľadu používateľa skončí jej volanie okamžite (po odoslaní správy) a nečaká sa na doručenie odpovede o výsledku. Preto tiež asynchrónna metóda nemôže pristupovať ku výstupnej časti parametrov volania a teda nemôže použiť anotáciu @ReturnValue alebo @ReturnAttribute a takisto nemôže nastaviť parametre anotácií ParameterValue.direction a ParameterAttribute a ParameterAttribute.direction na hodnoty inout alebo out.
Nová anotácia @ParameterAttribute mapuje vybraný unival atribút – v tomto prípade časovú značku hodnoty (attributeType = UnivalAttributeType.valueTime) . Pozor, nie je dovolené zavolať metódu s null hodnotou null hodnotou tohto parametra – mapovanie null na atribút univalu nie je možné.
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); |
Metóda getDataAndMetadata mapuje procedúru s dvomi vstupno-výstupnými parametrami (2 parametre s inOut = true). V porovnaní s predošlými metódami stojí za povšimnutie:
- Typ parametra data je
InOut<List<Person>> Generickým ➔ Generickým parametrom kontajneraInOutje generickýList, ktorého parametrom je triedaPerson, ktorej mapovanie naSD.Personje popísané v kapitole 5 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 typuInOutpo 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 Môžu byť volané aj z prostredia internej Javy a tiež z prostredia JAPI..
import ako RPC z prostredia ESL .
| 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 ExampleHandler |
...
{ |
...
@RPC(name = "Parse", |
...
parameters = |
...
{ @Parameter(name = "text", type = ParameterType.text, inOut = false), |
...
@Parameter(name = "result", type = ParameterType.integer) |
...
}) |
...
@ReturnValue(name = "result") |
...
public Integer parseInt( |
...
@ParameterValue(name = "text") String text) |
...
{ try { return Integer.parseInt(text); |
...
} catch (NumberFormatException ex) |
...
{ return null; } } } |
Metóda parseInt má rovnaké formálne rozhranie a ja tiež funkčne zhodná s RPC s RPC PROCEDURE E.Service.Parse uvedenou v kapitole 5 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.
...
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) |
...
{ ... |
...
} |
...
} |
Anotácia parametra metódy @CallerInformation indikuje, že za hodnotu parametra má byť dosadená informácia o volajúcom. Hodnota parametra type určuje, aká informácia bude dosadená:
- 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 5 4.2. a 5 4.3. a ich podkapitolách boli vytvorené definície mapovania štruktúrovaných hodnôt (SD.Person Person ⟺ Person) a definície mapovania volania RPC (Service E➔ 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.
Pri používaní anotácií v jazyku Java je dôležité si uvedomiť, že označenie nejakého objektu anotáciou nemá žiadne priame funkčné dôsledky. Napríklad, ak vytvoríme inštanciu triedy ExampleHandler a následne zavoláme jeho metódu parseInt, jej vykonanie prebehne vždy rovnako, bez ohľadu na prítomnosť alebo neprítomnosť anotácie @RPC. Anotácie slúžia iba na to, aby sa kód, ktorý skúma iné časti kódu, vedel lepšie orientovať.
Nasledujúce príklady sa budú odkazovať na triedy vytvorené v príkladoch v kapitolách 5 4.2.1, 5 4.3.2. a 5 4.3.3. Okrem toho budú použité nasledovné objekty:
| Blok kódu | ||||
|---|---|---|---|---|
| ||||
D2Connector connector = ... // aktivne spojenie |
...
D2Session session = connector.createSession(... // aktivna session |
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.
- Vytvorenie tzv. Event Proxy Factory objektu. V tomto kroku je trieda
Serviceanalyzovaná. Nový objekt (factory) v sebe implementuje mapovanie RPC volaní podľa nájdených anotácií. Parametre volania majú nasledujúci význam:Service.class referencia ➔ referencia na triedu, ktorá definuje mapovanie
získaniesession➔ získanie HOBJ a parent HOBJ
objektu E.Serviceobjektu
E.ServiceBlok kódu language java theme Eclipse EventProxyFactory<Service> factory =EventProxyFactory.createFactory(Service.class, session);
- Vytvorenie tzv. Event Proxy objektu s využitím
factoryz predošlého kroku. V tomto kroku vznikne inštancia anonymnej triedy (odvodenej odjava.lang.reflect.Proxy), ktorá implementuje rozhranieService, aby bolo možné volať anotované metódy. Implementáciu tejto triedy generuje JAPI. Parameter volania má nasledovný význam:
asociujesession➔ asociuje vytvorený objekt proxy s touto inštanciou Session – v jej mene budú RPC volané. Môže to byť iná inštancia, ako v kroku 1.
Blok kódu language java theme Eclipse Service proxy = factory.createDefault(session);
Nasledujú príklady samotného volania:
Jednoduché volanie RPC Parse:
Blok kódu language java theme Eclipse Integer result;
...
result = proxy.parse("12"); // Integer.valueOf(12)
...
result = proxy.parse("ab"); // null
Použitie kontajnera InOut<> vo volaní RPC Square:
Blok kódu language java theme Eclipse Double value = 5.0;
...
InOut<Double> valueContainer = new InOut<>(value);
...
proxy.sqare_2(valueContainer);
...
Double result = valueContainer.getValue();
V aplikáciách, kde dochádza k viacnásobnému pripájaniu a odpájaniu počas životného cyklu aplikácie:
- Krok 1 stačí spraviť raz, po vytvorení 1.
session. Vzniknutúfactorymôžete považovať za platnú, pokým je aktívnyconnector. Pre novýconnectorje potrebné vytvoriť novú factory. - Krok 2 je potrebné raz zopakovať pre každú novú
session, z ktorej majú byť volané RPC.
| Kotva | ||||
|---|---|---|---|---|
|
...
4.4.2. Príklad volania z ESL do JAPI
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.
- Vytvorenie tzv. Event Wrapper Factory objektu. V tomto kroku je trieda
ExampleHandleranalyzovaná. Nový objektfactoryv sebe implementuje spracovanie prichádzajúcich RPC volaní a ich mapovanie na volania metód triedyExampleHandler. Význam použitých parametrov je nasledovný:ExampleHandler.class referencia ➔ referencia na triedu, ktorá definuje mapovanie
preklad miensession➔ preklad mien
Blok kódu language java theme Eclipse EventWrapperFactory<ExampleHandler> factory = EventWrapperFactory.createFactory(ExampleHandler.class, session);
Registrácia inštancie triedy
ExampleHandlerpre prijímanie RPC volaní do konkrétnej session. Po tomto kroku bude možné adresovať volanie RPCParseaj do použitejsession.Blok kódu language java theme Eclipse ExampleHandler handler = new ExampleHandler();
...
factory.registerNewHandler(session, handler);
Uloženie HOBJ dynamického objektu
session, aby bolo možné neskôr volať späť. V tele ľubovoľnej RPC v ESL je možné zistiť adresu (HOBJ procesu a objektu) volajúceho nasledovným spôsobom:Blok kódu language esl theme RDark INT _sessionHobj
...
RPC PROCEDURE Register
...
_sessionHobj := %GetRPCCallerProcess()
...
END Register
Značky Wiki Volanie
RPC
z prostrediaz prostredia ESL.
Namiesto
mena
objektu
je
použité
\
\[(0)]pretože
v
_JAPI
_neexistuje
ekvivalent
objektu
typ
Event.
Namiesto
mena
procesu
je
použité
(
_sessionHobj)pretože
sessionje
v D2000v D2000 DODM
dynamický
objekt
typu
proces
a naa na jeho
meno
sa
nedá
použiť
ako
identifikátor
v zdrojovomv zdrojovom kóde.
...
Blok kódu language esl theme RDark INT _r CALL
...
[(0)
...
] Parse("12", _r) ON (_sessionHobj)
...
...
1 D2000 logická hodnota je štandardne mapovaná vymenovaným typom sk.ipesoft.d2000.base.VBool. Pre zjednodušenie použitia je umožnené mapovať typom java.lang.Boolean, pričom je hodnota vOscillate mapovaná ako false.Kotva 1 1
...
7 Rovnako v dokumente neuvádzame definíciu a mapovanie pre SD.Metadata, lebo nie je potrebné.Kotva 7 7
8 Môžu byť volané aj z prostredia internej Javy a tiež z prostredia JAPI.Kotva 8 8