Přeskočit na hlavní obsah
  1. Tags/

Oracle

2014


2013


Oracle EDN, implementace EDA

·5 min
SOA Suite je zajímavou kompilací technologií, které, poskládány dohromady, stojí na architektonickém principu SCA (Service Component Architecture). Patří sem například implementace BPELu, business rules a human tasků. A jednou z těchto technologií je i Event Delivery Network (EDN), což je implementace paradigmatu Event Driven Architecture (EDA).

Event Driven Architecture

Even Driven Architecture (EDA) může být alternativou, nebo doplňkem k Servisně orientované architektuře (SOA). Ale EDN se netýká pouze SOA - tento architektonický princip najdeme i uvnitř GUI frameworků, jako je Java Swing, nebo Apache (dříve Adobe) Flex.

Jak už napovídá název, vše se v této architektuře motá kolem událostí. Událost je v EDA first-class citizen. Vlastně je to jediný citizen (obyvatel). Ale co to vlastně ta událost je? Událost je v podstatě zpráva, podobně jako zpráva má hlavičku a tělo. V hlavičce jsou samozřejmě meta-data, např. jméno a typ zprávy, timestamp apod. Zásadní rozdíl je v obsahu těla události (payload), ten bývá zpravidla velmi malý a měl by obsahovat pouze popis faktu, který událost instancoval. Někdy payload ani být nemusí - pokud je událost určitého typu, stačí pouze vědět, že nastala.

A jak taková událost zapadá do architektury? Dalším významem akronymu EDA by mohlo být: Extremely Decoupled Architecture. Události, které nejsou nijak svázány s konkrétním producentem, jsou publikovány do nějaké centrální generické infrastruktury. Producenti publikují události stylem fire-and-forget a vůbec se nestarají o to, kdo je jejich konzumentem.

Konzumentem je pak kdokoli, kdo se zajímá o výskyt určitého typu události. Pro konzumenty je původ události neznámý - neví kdo ji publikoval, oni se pouze dozvědí, že nastala. Na konzumentovi pak leží veškerá zodpovědnost za správné business zpracování události. S tím souvisí i to, že příjemce může konzumované události filtrovat.

Event Driven Architecture (barvy představují typy událostí)
Z předešlého komponentového diagramu vyplývá několik věcí. Jednak že v EDA existují v podstatě jen dva základní komponenty - Event Coordinator, který si můžeme představit jako jakýsi "event bus" (podle vzoru service bus) pro události, který se stará o publikování událostí, přihlášení (subscription) konzumentů apod.

A pak jednotlivé uzly (nody). Ty mohou fungovat buď jako producenti událostí (Node 3), nebo jejich konzumenti (Node 2, Node 5), anebo obojí (Node 1, Node 4). Každý node může publikovat nebo přijímat více typů událostí. Že jeden typ události může být konzumovaný více nody asi nikoho nepřekvapí (oranžová událost konzumovaná Nody 1 a 4). Daný typ události ale může taky být publikovaný více producenty (fialová událost publikovaná Nody 3 a 4).

To by, myslím, mohlo stačit, jako takový velmi lehoulilinký úvod do EDA a teď se podíváme na jednu její konkrétní implementaci.

Event Delivery Network

Event Delivery Network (EDN), která je součástí SOA Suite, je infrastruktura (postavená na JMS), která poskytuje deklarativní způsob definice událostí, jejich publikování a registraci jejich konzumace. Tři hlavní entity, se kterými pracuje jsou producent událostí, konzument událostí a události samotné.

Definice události

Události jsou v EDN definované názvem a typem a jsou uloženy v souboru s příponou edl. Tento soubor může být umístěný buď v rootu projektu, nebo v MDS (MetaData Services repository).
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<definitions
xmlns="http://schemas.oracle.com/events/edl"
targetNamespace="http://sw-samuraj.blog/events/SimpleEvent-v1">
<schema-import
namespace="http://sw-samuraj.blog/events/simpleMessage-v1"
location="xsd/simpleMessage-v1.0.xsd"/>
<event-definition name="SimpleEvent">
<content
xmlns:sim="http://sw-samuraj.blog/events/simpleMessage-v1"
element="sim:simpleMessage"/>
</event-definition>
</definitions>
Definice události

Typ je popsán pomocí XSD:
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:sim="http://sw-samuraj.blog/events/simpleMessage-v1"
targetNamespace="http://sw-samuraj.blog/events/simpleMessage-v1"
elementFormDefault="qualified">
<xsd:element name="simpleMessage">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="timestamp" type="xsd:dateTime"/>
<xsd:element name="status">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="ON"/>
<xsd:enumeration value="OFF"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
Typ události definovaný v XSD

Publishers

Producentem události může být buď BPEL proces, nebo Mediator. V případě Mediatoru je publikování události přímočaré - v definici akce se místo invoke zavolá raise s patřičnou události.

Publikování události v Mediatoru
Graficky pak vypadá kompozitní aplikace s publikujícím Mediatorem takto:

Mediator event publisher (kompozitní aplikace)

U BPEL procesu je situace maličko složitější. Vzhledem k tomu, že BPEL je otevřený standard, do kterého události nepatří, řeší to SOA Suita (standardním) BPEL extension. Událost se tak dá publikovat pomocí rozšíření z aktivity Invoke.

Publikování události v BPELu z aktivity Invoke

BPEL event publisher (kompozitní aplikace)
Všimněte si, že jak v případě Mediatoru, tak BPELu končí implementace publikování události na dané komponentě. Kdyby totéž bylo implementováno pomocí messagingu, musel by být v kompozitní aplikaci definován ještě JCA adaptér s pevně uvedenou destinací. Tohle u EDA/EDN není potřeba.

Subscribers

Konzumentem události může být opět buď Mediator nebo BPEL komponent.

Subskripce události v Mediatoru

Mediator event subscriber (kompozitní aplikace)

Podobně jako u publikování i u konzumace událostí si BPEL vypomáhá rozšířením, tentokrát v rámci aktivity Receive.
Subskripce události v BPELu v aktivitě Receive

BPEL event subscriber (kompozitní aplikace)

Monitorování událostí

Asi trochu překvapí, že již publikované, ale ještě nezkonzumované události nelze nikde vidět. Alespoň ne standardními nástroji. V podstatě lze vidět pouze "historický otisk" událostí. Něco jako: tudy kráčely dějiny :-)

Cestu události lze vidět v Enterprise Manageru:

Audit trace události (Enterprise Manager)
V uvedeném logu publikuje Mediator Publisher událost, která je konzumována dvěma konzumenty: Mediator Subscriber a BPEL komponent BpelSubscriber. Zároveň je vidět, že Enterprise Manager loguje celou cestu události - ačkoliv jsou producent a konzumenti události od sebe odděleni a vůbec o sobě nemají povědomí, v audit logu je to zaznamenáno jako jeden souvislý tok události.

BPEL nebo Mediator?

Na základě čeho se rozhodnout, kterou komponentu použít pro konzumaci/publikování události? Jednodušší a přímočařejší je použití Mediatoru. Koneckonců to doporučuje i sám Oracle. BPEL má jedinou výhodu - jako konzument může události korelovat. Čili pokud je reakcí na nějakou událost jiná událost a obě dvě jsou zpracovávány stejnou kompozitní aplikací, tak jejich korelace je možná pouze v BPEL procesu.

Závěr

Event Delivery Network (EDN) je standardní součástí SOA Suity a nabízí out-of-the-box implementaci Event Driven Architecture (EDA). Pokud nepotřebujeme robustní a konfigurovatelné messaging řešení, může být EDN vhodnou, rychle provozovatelnou alternativou.

Rozhodně bych ale EDN nedoporučoval použít pro kritické části systému. Byť je postavena na prověřené JMS platformě, její možnosti z hlediska konfigurace, provozování, monitoringu atd. jsou velmi omezené - berte jak to je, nebo nechejte být.

Související články

Oracle SOA certifikace

·3 min
Půlrok se sešel s půlrokem a já jsem si vystřihnul další certifikaci. Tentokrát jsem chtěl něco, čím bych zakončil své roční působení na projektu a důstojně :-) tak završil trnitý proces získávání znalostí o nové technologii: Oracle SOA Suite.

Okolnosti tomu chtěly, že jsem se zrovna trefil do přelomu, kdy Oracle jednu  SOA certifikaci nahrazuje jinou. Aktuální certifikace, která je k dispozici od letošního ledna, se jmenuje  Oracle SOA Suite 11g Certified Implementation Specialist. Já, protože jsem se ke zkoušce přihlásil již dříve, jsem nyní obdržel certifikaci Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert. Uff! To je titul :-/

Každopádně, co je nám po jménu? Podstatné je, jestli se obě zkoušky od sebe nějak obsahově liší. Liší? Ano, ale pouze drobně - v nové certifikaci přibylo pouze něco málo o governance, deploymentu a monitoringu, ale gró zůstává stejné: jednotlivé komponentní technogie (viz Exam Topics).

Jak dlouho jsem se na certifikaci připravoval? Přípravě přímo na zkoušku jsem věnoval cca 3 týdny - přečetl jsem si guide (viz dále) a prošel testovací otázky. Ale obecně jsem k certifikaci studijně směřoval téměř celý rok. Za jeden z podstatných zdrojů vědomostí totiž považuji přímou zkušenost s technologií - 7 měsíců intenzivního "programování".

Kniha

Vývoj samotný z učedníka mistra neudělá. Primárním zdrojem informací jsou pro mne knihy, takže od nich jsem začal: hned z počátku práce na projektu jsem si koupil knihu Oracle SOA Suite 11g Handbook.

Jde o 800stránkový opus a pokud to někdo myslí se SOA Suitou vážně, tak rozhodně tuto knihu doporučuji - obsahuje vyčerpávající sumu témat (daleko přesahující rozsah zkoušky), které umožní pochopit principy, které za SOA Suitou stojí a provede návrhem, vývojem, testováním a provozem jednotlivých komponent a technologií. Ještě jednou: vysoce doporučuji!

Školení

Školení obvykle v portfoliu přípravných zdrojů nemám, tentokrát se mi ovšem naskytla příležitost, tak jsem ji využil a absolvoval školení hned tři:
  • Oracle SOA Suite 11g Implementation Bootcamp
  • Oracle Service Bus 11g
  • Oracle BPM Suite 11g Implementation Bootcamp
Školení nebyla špatná. Probíhala formou labů, takže si člověk mohl věci prakticky vyzkoušet. Tematicky školení zkoušku více méně pokrývala (s výjimkou BPM, který v certifikaci není) a umožnila mi trochu jiný pohled na věc, než byl třeba v knize, nebo jsem sám získal praxí. Z pohledu certifikace nejsou školení nutností, ale příjemným bonusem - stejné informace se dají získat i jinde a levněji :-)

Certifikační guide

Krátce před zkouškou jsem pořídil knihu Oracle SOA Infrastructure Implementation Certification Handbook, což je certifikační guide zaměřený na původní zkoušku (1Z0-451). Co se týká obsahu, kniha je slušným, velmi lehkým úvodem do SOA Suite. Jako studijní materiál je nedostačující. Co je na ní cenné, je sada testovacích otázek a odpovědí ke každému tématu, plus závěrečný test (také s řešením).

Závěr

Pokud vezmu v potaz svoji celoroční "přípravu", tak pro mne certifikace splnila (opět) svůj hlavní účel - motivační prostředek pro sebevzdělávání. Tak jako u jiných zkoušek i nyní mě certifikace přinutila podívat se do hloubky i na témata, která nutně (projektově) nepotřebuju a umožnila mi tak lépe pochopit celý kontext dané technologie.

Kecám, nepřinutila - já to dělám rád ;-)

Související články

Odstranění metadat z MDS

·2 min
Dneska to bude jedna praktická. Aneb jak v SOA Suite smazat z MDS (MetaData Store) nějaká metadata, soubory nebo adresář. Práce s MDS není z počátku úplně intuitivní, dokumentace není úplně jednoduše k nalezení a informace aby člověk vyškrabával z různých blogů a fór.

Tak, jak na to. Možnosti jsou dvě. Jednak použít WLST, nebo Ant skript, který je součástí SOA Suite (ten ale umožní pouze smazání adresáře).

WLST

WebLogic Scripting Tool (WLST) je zajímavý, v Jythonu napsaný, nástroj na administraci WebLogic serveru. Lze s ním pracovat dvěma způsoby: offline a online. Bohužel, s ohledem na MDS, je potřeba pro mazání souborů použít online způsob a pro smazání adresáře naopak offline (a také se používají dvě různé funkce). WLST zpravidla najdeme v adresáři <ORACLE_HOME>/oracle_common/common/bin.

Smazání souboru

Pro smazání jednoho a více souborů lze použít příkaz deleteMetadata. Vzhledem k tomu, že se tento příkaz používá online, je potřeba se prvně připojit k WebLogic administračnímu serveru. A po zadání mazacího příkazu se zase odpojit.
connect('weblogic', '<password>', 't3://<AdminServer>:7001')
deleteMetadata(
application='soa-infra',
server='soa_server1',
docs='/apps/<pathToFile>/DeadLetterQueue-v1.0.wsdl')
disconnect()
exit()


Smazání adresáře

Pro smazání adresáře slouží offline příkaz sca_removeSharedData. Problém s tímhle příkazem je, že není součástí standardních WLST modulů, ale je součástí instalace SOA Suite. Proto aby fungoval, je potřeba spustiti WLST z odpovídajícího adresáře: <ORACLE_HOME>/Oracle_SOA1/common/bin.

Dalším rozdílem je, že se nezadává cesta k administrativnímu serveru, ale ke spravovanému (managed) serveru, na kterém MDS běží.
sca_removeSharedData(
'http://<ManagedServer>:8001',
'public/evm/iface/DeadLetterQueue-v1',
'weblogic', '<password>')



Ant

Součástí instalace vývojového prostředí pro SOA Suite (JDeveloper) je i sada Ant skriptů mmj. pro buildování, (unit) testování a deployment. A také pro smazání adresáře z MDS. Tímto způsobem nejde mazat jednotlivé soubory.

Soubory se dají najít v adresáři <ORACLE_HOME>/jdeveloper/bin.
ant -f ant-sca-deploy.xml removeSharedData
-DserverURL=<ManagedServer>
-DfolderName=<pathToFolder>
-Duser=<user>
-Dpassword=<password>

Související články

2012


Java a fault handling policies v Oracle SOA Suite

·6 min
Jednou ze součástí Oracle SOA Suite je tzv. Fault Management Framework, který se mmj. stará o zpracování výjimek v BPELu. Pokud během invoke aktivity nastane výjimka, framework ji odchytí a předá ji ke zpracování akci, která je definovaná ve fault policy.

Tyto politiky jsou zajímavou alternativou k odchytávání výjimek v samotném BPELu  pomocí fault handleru <catch>. Dá se na ně pohlížet jako na aspekt (ve smyslu AOP), který je deklarativně navěšený na procesu (nebo i celé kompozitní aplikaci).

No, pokud jsem řekl aspekt, pravděpodobně jsem vzbudil velká očekávání. Tak to bohužel není - sám jsem musel pohřbít některé své designové představy - má to spoustu omezení, resp. možnosti nejsou rozsáhlé. Takže co to vlastně umí?

V rámci politiky se dají definovat následující zotavné akce:
  • Retry. Nepovedený invoke se dá zopakovat. Dá se nastavit počet opakování, prodleva, exponenciální prodleva a následující zřetězená akce, pokud retry nezafunguje.
  • Human Intervention. Proces se zastaví a je možné ho manuálně obnovit z management konzole.
  • Terminate Process. Proces je ukončen. Totéž jako aktivita.exit.
  • Rethrow Fault. Chyba je vyhozena zpátky do BPEL procesu.
  • Replay Scope. Vyhodí reply fault, což způsobí znovu vykonání aktivit ve scope.
  • Java Code. Zavolá externí Java třídu. To je to, na co se budeme dále soustředit.

Problém

Mám pro klienty vystavenou službu SOAPFault, která má ve svém kontraktu definovaný SOAP Fault:
<xsd:element name="fault">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="resultCode"
type="xsd:string"/>
<xsd:element name="error">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="errorCode"
type="xsd:string"/>
<xsd:element name="errorDescription"
type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

Pro graficky orientované to vypadá takhle:


Tento fault je pak použit ve WSDL:
<wsdl:message name="faultMessage">
<wsdl:part name="payload" element="inp1:fault"/>
</wsdl:message>

<wsdl:portType name="SOAPFaultPort">
<wsdl:operation name="test">
<wsdl:input message="tns:requestMessage"/>
<wsdl:output message="tns:replyMessage"/>
<wsdl:fault name="testfault"
message="tns:faultMessage"/>
</wsdl:operation>
</wsdl:portType>
Služba je implementovaná pomocí BPEL procesu, který v rámci orchestrace volá další službu, nazvanou BPELFault:


Tak, to byla expozice. Teď přijde kolize. V BPELu mám definovanou invoke aktivitu, která volá externí službu BPELFault. Chtěl bych použít politiku tak, aby když externí služba vrátí chybu, aby mi politika nastavila můj definovaný SOAP fault a proces ho vrátil klientovi.

Než se pustíme do implementace politiky, musíme v BPEL procesu ještě splnit dvě podmínky. Jednak v procesu definovat proměnnou, která bude mít nastavený typ zprávy jako daný fault:
<variable name="soapFault"
messageType="ns1:faultMessage"/>
A druhak, proces musí náš fault vyhodit ven pomocí aktivity throw:
<catchAll>
<throw name="ThrowFault"
faultName="ns1:testfault"
faultVariable="soapFault"/>
</catchAll>

Jak to celé funguje?

Obrázek je za tisíc slov, takže tady je BPMN diagram. Swimliny jsou trochu nečitelný :-/ takže odshora: BPEL, External WS, Fault Management Framework a Java Class.


Java

Java třída, která bude z politiky volaná musí implementovat rohraní IFaultRecoveryJavaClass. To má dvě metody, nás bude zajímat pouze handleFault, která má jako parametr IFaultRecoveryContext. Pomocí tohoto kontextu lze přistupovat k objektům v BPEL procesu, odkud vyletěla výjimka.

Z kontextu si tak vytáhneme výše uvedenou BPEL proměnnou soapFault a pomocí XPath, nebo DOMu ji naplníme. Na závěr vrátíme z metody string RETHROW, aby politika vrátila řízení zpátky do BPEL procesu, odkud je pak už vrácena SOAP fault klientovi.

(Omlouvám se, že ten kód uvádím celý. Ale kdyby náhodou to někdo (v Česku) řešil, tak ať to má trochu jednodušší :-)
package cz.swsamuraj.soa.fault;

import com.collaxa.cube.engine.fp.BPELFaultRecoveryContextImpl;

import
oracle.integration.platform.faultpolicy.IFaultRecoveryContext;
import
oracle.integration.platform.faultpolicy.IFaultRecoveryJavaClass;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

/**
* This class is called by fault policy. Its purpose is to set up
* a variable which is then throwed as a SOAP fault.
*
* @author Guido
*/
public class SOAPFaultHandler implements IFaultRecoveryJavaClass {

private static final String VARIABLE = "soapFault";
private static final String PART = "payload";
private static final String RESULT_CODE_NAME = "resultCode";
private static final String RESULT_CODE_VALUE = "255";
private static final String ERROR_NAME = "error";
private static final String ERROR_CODE_NAME = "errorCode";
private static final String ERROR_CODE_VALUE =
"EXTERNAL_SERVICE_ERROR";
private static final String ERROR_DESCRIPTION_NAME =
"errorDescription";
private static final String RESULT = "RETHROW";

@Override
public void handleRetrySuccess(
IFaultRecoveryContext iFaultRecoveryContext) {
}

/**
* Method for set up a BPEL variable for SOAP fault.
*
* @param recoveryContext
* @return
*/
@Override
public String handleFault(IFaultRecoveryContext recoveryContext) {
if (recoveryContext instanceof BPELFaultRecoveryContextImpl) {
BPELFaultRecoveryContextImpl bpelContext =
(BPELFaultRecoveryContextImpl) recoveryContext;

Element root =(Element)
bpelContext.getVariableData(VARIABLE,
PART, "/");
Node soapFault = root.getFirstChild();
String namespaceURI = soapFault.getNamespaceURI();

bpelContext.addAuditTrailEntry(String.format(
"Obtained a root element: {%s}%s.", namespaceURI,
soapFault.getLocalName()));

// removes all child nodes
if (soapFault.hasChildNodes()) {
int count = soapFault.getChildNodes().getLength();

for (int i = 0; i < count; i++) {
Node child = soapFault.getFirstChild();
soapFault.removeChild(child);
}
}

Document document = soapFault.getOwnerDocument();
Node resultCode = createNode(document, namespaceURI,
RESULT_CODE_NAME, RESULT_CODE_VALUE);
soapFault.appendChild(resultCode);

Node error = createNode(document, namespaceURI,
ERROR_NAME, null);
soapFault.appendChild(error);

Node errorCode = createNode(document, namespaceURI,
ERROR_CODE_NAME,
ERROR_CODE_VALUE);
error.appendChild(errorCode);

Node errorDescription = createNode(document, namespaceURI,
ERROR_DESCRIPTION_NAME,
bpelContext.getFault()
.toString());
error.appendChild(errorDescription);

bpelContext.addAuditTrailEntry(String.format(
"SOAP fault response has been set"
+ " by fault policy '%s'.",
bpelContext.getPolicyId()));
}

return RESULT;
}

/**
* Method creates a new {@link Node} with given parameters.
*
* @param document {@link Document}
* @param qualifiedName name of the element
* @param namespaceURI namespace of the element
* @return {@link Node}
*/
private Node createNode(Document document, String namespaceURI,
String qualifiedName, String textContent) {
Node node = document.createElementNS(namespaceURI,
qualifiedName);

if (textContent != null) {
node.setTextContent(textContent);
}

return node;
}
}

Zajímavá je zde asi pouze metoda kontextu addAuditTrailEntry, která propisuje informace do auditního záznamu procesu, což je pak vidět v konzoli Enterprise Managera:


Definice politiky

Už máme ruce, teď mozek. Aby politika byla funkční, je potřeba vytvořit dva soubory. Jednak samotnou definici, soubor fault-policies.xml a potom navázání politiky na konkrétní kompozitiní aplikaci (nebo komponent), soubor fault-bindings.xml. Toto jsou defaultní názvy souborů. Pokud chceme jiné názvy, např. protože chceme politiky verzovat, je potřeba tuto odlišnost uvést v definici kompozitní aplikace.
<property name="oracle.composite.faultPolicyFile">
fault-policies-v1.0.xml</property>
<property name="oracle.composite.faultBindingFile">
fault-bindings-v1.0.xml</property>
Nebo graficky:


V definičním souboru fault-policies-v1.0.xml říkáme, že chceme odchytávat výjimku remoteFault (není to standardní chyba definovaná BPELem, ale Oracle BPEL Extension) a chceme, aby byla zpracovaná naší Java třídou:
<?xml version='1.0' encoding='UTF-8'?>
<faultPolicies xmlns="http://schemas.oracle.com/bpel/faultpolicy">
<faultPolicy version="2.0.1" id="BpelInvokeActivityFaults-v1.0">
<Conditions>
<faultName
xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
name="bpelx:remoteFault">
<condition>
<action ref="ora-java"/>
</condition>
</faultName>
</Conditions>
<Actions>
<Action id="ora-java">
<javaAction
className="cz.swsamuraj.soa.fault.SOAPFaultHandler"
defaultAction="ora-rethrow">
<returnValue value="RETRHOW" ref="ora-rethrow"/>
</javaAction>
</Action>
<Action id="ora-rethrow">
<rethrowFault/>
</Action>
</Actions>
</faultPolicy>
</faultPolicies>
Ve vazebním souboru fault-bindings-v1.0.xml jenom říkáme, že naše politika BpelInvokeActivityFaults-v1.0 je svázaná s celou kompozitní aplikací:
<?xml version='1.0' encoding='UTF-8'?>
<faultPolicyBindings
version="2.0.1"
xmlns="http://schemas.oracle.com/bpel/faultpolicy">
<composite faultPolicy="BpelInvokeActivityFaults-v1.0"/>
</faultPolicyBindings>

Deployment do runtime

Pokud máme třídu i politické :-) soubory přímo v kompozitní aplikaci, nemusíme deployment nijak řešit - prostě kompozitní aplikaci standardně nasadíme. Pokud však chceme politiky externalizovat (protože je chceme přepoužít pro více kompozitek), je vhodné umístit XML soubory do MDS (Metadata Services repository) a Java třídu nasadit do runtimu SOA Suity:
  1. Zkompilovanou třídu zabalíme do JAR souboru.
  2. JAR soubor nakopírujeme do adresáře <ORACLE_HOME>/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1
  3. V tomto adresáři spustíme příkaz ant.
  4. Restartujeme WebLogic.

Související články


Odkazy

Custom XSLT funkce v Oracle SOA Suite

·3 min
Už jste se s tím určitě setkali - nejednoznačnost globální definice boolean. (Globální myslím v rámci SOA napříč všemi systémy.) V každém jazyku je to definované trochu jinak. A proto pokud překládám hodnotu z jednoho systému (nebo rozhraní) na jiný, musím použít nějakou konverzi.

Obecně v tomto problému hodně pomůže kanonický datový model (Cannonical Data Model, CDM), ale pořád se nevyhneme tomu překladu (jenom jich bude méně).

Co jsem teď aktuálně řešil (a že nás to na projektu už nějakou chvilku občas drobně trápí), byl překlad boolean typu z XSD na typ v Oracle databázi. Jak asi víte, Oracle DB nemá typ boolean a nejčastěji se to řeší jako integer 0/1, nebo char Y/N apod. Když tak mě v komentářích opravte - nejsem Oraclista (= databázista).

V XSD je to sice jednoznačnější (viz specifikace boolean), ale záleží, jestli pracujeme s kanonickou (true, false), nebo lexikální (true, false, 1, 0) reprezentací.

Protože se tenhle problém čas od času opakoval, rozhodl jsem se napsat uživatelsky definovanou XSLT funkci pro překlad boolean na integer. Platforma, na které se pohybuji je Oracle SOA Suite.

Definice funkce

Protože celá(?) implementace Oracle SOA Suite je v Javě, tak nepřekvapí, že uživatelská XSLT funkce je taky v Javě:
public class CustomFunctions {

public static int booleanToInt(String bool) {
int result = 0;

if ("true".equals(bool) || "1".equals(bool)) {
result = 1;
}

return result;
}

}
Jsou tam dvě drobná omezení. (A) Metoda musí být definovaná jako statická. (B) Jak návratová hodnota, tak parametry metody musí být pouze následujících typů:
  • java.lang.String
  • int
  • float
  • double
  • boolean
  • oracle.xml.parser.v2.XMLNodeList
  • oracle.xml.parser.v2.XMLDocumentFragment

Ve výčtu je sice uvedný boolean, ale jak jsem zjistil, v rámci XSLT transformace vstupuje do metody String. Proto je v uvedené metodě v parametru String a ne boolean.

Dále potřebujeme mapovací konfigurační soubor. Musí mít následující jméno a umístění:
META-INF/ext-mapper-xpath-functions-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<soa-xpath-functions version="11.1.1"
xmlns="http://xmlns.oracle.com/soa/config/xpath"
xmlns:sws="http://www.oracle.com/XSL/Transform/java/cz.swsamuraj.xslt.CustomFunctions">
<function name="sws:booleanToInt">
<className>
cz.swsamuraj.xslt.CustomFunctions
</className>
<return type="number"/>
<params>
<param name="boolean" type="string"/>
</params>
<desc>Method transforms a boolean value to
integer. True is converted to 1 and false
to 0.
</desc>
<detail>Method transforms a boolean value to
integer. True is converted to 1 and false
to 0.
</detail>
<icon>cz/swsamuraj/xslt/Boolean.png</icon>
</function>
</soa-xpath-functions>
Tady je důležité, aby konfigurační soubor obsahoval namespace, který splňuje následující podmínky. Začíná:
http://www.oracle.com/XSL/Transform/java/

a končí plně kvalifikováným názvem Java třídy, tj.:
cz.swsamuraj.xslt.CustomFunctions

Zbytek je předpokládám zřejmý. Pak už stačí zkompilovat třídu, mapovací soubor a ev. resources (ikona) do JAR souboru.



Nastavení IDE

Aby se dala nová funkce používat v IDE (povinný JDeveloper) je potřeba ji tam zaregistrovat:
  1. Tools -> Preferences -> SOA
  2. Tlačítkem Add přidat připravený JAR soubor.
  3. Restartovat JDeveloper.
Pak již stačí otevřít nějaký XSLT soubor a naši novou funkci najdeme v Component Palette pod položkou User Defined:



Deployment do runtime

Nyní již můžeme novou funkci v IDE vyzkoušet (a otestovat), ale aby fungovala také ve službách je potřeba výše vytvořený JAR soubor dostat také na server (SOA Suita běží na WebLogicu):
  1. JAR soubor nakopírujeme do adresáře <ORACLE_HOME>/Oracle_SOA1/soa/modules/oracle.soa.ext_11.1.1
  2. V tomto adresáři spustíme příkaz ant.
  3. Restartujeme WebLogic.

Odkazy

Certifikace Java EE 6 Web Services Developer

Tak nějak jsem si poslední dobou zvykl, dělat do roka dvě certifikace (asi mi chybí školní dril :-) Takže co to bylo tentokrát? Honosný název, který se nyní skví v mém CV zní: Oracle Certified Expert, Java Platform, Enterprise Edition 6 Web Services Developer, zkráceně (ve stylu někdejších Sunovských certifikací) OCWSD.

Certifikace občas budí (zbytečné) vášně, takže základní otázka asi je: je to vůbec k něčemu? Pro mne je tím největším benefitem, že jsem se něco nového (do hloubky) naučil. A musím říct, že OSWSD je tomto směru opravdu hodnotná. Byť web servisy mastím cca poslední tři roky, ať už v Javě (JAX-WS, Spring WS nebo Axis), nebo v rámci SOA (WebSphere Message Broker, Oracle SOA Suite), tak během přípravy na certifikaci jsem dozvěděl spoustu nových věcí (třeba SOAP Message Handlers) a "dopochopil" lecos již známého.

Témata, která zkouška obsahovala jsou následující:
  • Create an SOAP web service in a servlet container
  • Create a RESTful web service in a servlet container
  • Create a SOAP based web service implemented by an EJB component
  • Create a RESTful web service implemented by an EJB component
  • Configure JavaEE security for a SOAP web service
  • Create a web service client for a SOAP based web service
  • Create a web service client for a RESTful web service
  • Create a SOAP based web service using Java SE platform
  • Create handlers for SOAP web services
  • Create low-level SOAP web services
  • Use MTOM and MIME in a SOAP web service
  • Use WS-Addressing with a SOAP web service
  • Configure Message Level security for a SOAP web service
  • Apply best practices to design and implement web services

Protože na zkoušku není žádný oficiální certifikační guide, prošel jsem trošku širší okruh materiálů. V praxi jsem zatím neměl nikdy možnost dostat se k RESTovým technologiím, takže jsem s předstihem začal s knížkou Billa Burkeho RESTful Java with JAX-RS, kterou vřele doporučuji - pokud chcete začít s RESTem v Javě (tj. libovolnou implementací JAX-RS), je to ta správná volba. Autor sice popisuje (a je tvůrcem) RESTEasy, ale je objektivní i vůči dalším implementacím.

Další knihou jsem si chtěl oživit druhou Javovskou web servisovou větev - JAX-WS. Tady je knižní situace docela slabá. V podstatě jediná aktuální kniha, která je věnována JAX-WS je Java 7 JAX-WS Web Services. Vzhledem k názvu a rozsahu (64 str.) jsem nečekal nic světoborného, ale zklamání bylo obrovské. Pokud nejste úplně nejzelenější začátečník a nevyhovují vám knížky, tvořené ze 2/3 screenshoty (NetBeansů), není to kniha pro vás. Škoda peněz, škoda času.

Jakou určitý druh přípravy můžu zmínit (celkem nudný) letošní Oracle Java Developer Day, kde jsem se šel podívat na jednu přednášku o JAX-WS a na dvě o JAX-RS. Samozřejmě, že to byly naprosté základy, ale člověk si aspoň udržuje povědomí o tématu.

Pak už začalo jít do tuhého, protože jsem potřeboval něco, co by mě připravilo na certifikaci. Nechal jsem tedy firmu zakoupit zkušební testy. Tentokrát jsem zvolil ještě nevyzkoušené řešení - kit od EPractize Labs. Jejich OCEJWSD Training Lab není úplně špatný. Sice je uživatelsky dost nepohodlný a rozložení témat mi přijde dost nevyvážené, ale myslím, že ho můžu označit jako přínosný. V dnešní době bych spíš volil kit od uCertify, s jejichž přípravnými testy mám dobrou zkušenost, který ale v té době ještě nebyl k dispozici.

Posledním materiálem, který jsem na přípravu použil je OCWSD Study Guide od Mikalaie Zaikina, který pokrývá témata zkoušky velmi pěkně. Linkovaná webová verze je zdarma, za $15 je možné si přikoupit sadu 160 otázek s odpověďmi, plus jednotlivé guidy v PDF podobě. Těch patnáct dolarů jsem investoval a můžu říct, že to stálo za to (aneb jak jsme se učili v angličtině it bang for the buck).

Pokud mám certifikaci OCWSD nějak celkově zhodnotit, musím říct, že je to určitě jedna z těch nejpřínosnějších, co dnes Oracle v oblasti Javy nabízí. Všechna témata byla víceméně ryze praktická, žádná nudná (korporátní) teorie, či dokonce ideologie. Zároveň je to taky jedna z těch, kde je těch Oraclovských technologií jen určité minimum - hodně se tam probírají věci z W3C, jako je SOAP, WSDL, XSD, WS-Addressing, nebo věci, které jsou dílem různých jiných organizací, jsou je WS-I (WS-Interoperability (Basic Profile)), nebo WS-Security.

Oracle, vyhodnocení časových podmínek

·2 min
Dneska jsem řešil (pro mne) zajímavý případ - potřeboval jsem v Oracle databázi postavit dotaz s následujícími parametry:

  • zkontrolovat, že dva určité záznamy mají hodnotu DATE mezi 17:00 včerejšího dne a 7:00 dnešního dne,
  • jako výstup dotazu mít hodnotu true nebo false (v Oraclu 1 a 0).
Dejme tomu, že máme následující tabulku
CREATE TABLE result_log (
code VARCHAR2(20),
logged DATE
);
do které vložíme  dva záznamy odpovídající našemu intervalu (17:00-7:00):
INSERT INTO result_log VALUES
('codeA', TRUNC(sysdate - 1) + 22 / 24);
INSERT INTO result_log VALUES
('codeB', TRUNC(sysdate) + 5 / 24);
Výsledek by měl vypadat nějak takto:
SELECT code, TO_CHAR(logged,
'YYYY-MM-DD HH24:MM:SS')
AS logged
FROM result_log;
CODE                 LOGGED
-------------------- -------------------
codeA 2012-04-05 22:04:00
codeB 2012-04-06 05:04:00
Požadované záznamy (codeA, codeB) vybereme následujícím dotazem a zároveň je ohodnotíme, že jsou/nejsou z daného časového intervalu (1 = jsou, 0 = nejsou):
SELECT
CASE
WHEN (logged BETWEEN
(TRUNC(sysdate - 1) + 17 / 24) AND
(TRUNC(sysdate) + 7 / 24))
THEN 1
ELSE 0
END AS eveluation
FROM result_log
WHERE code IN ('codeA', 'codeB');
EVELUATION
----------
1
1
Jelikož nad výsledky potřebujeme v podstatě provést logickou konjunkci (AND) můžeme k tomuto účelu použít funkci DECODE. Výsledný dotaz pak vypadá následovně:
SELECT DECODE(SUM(eveluation), COUNT(*), 1, 0)
AS evaluation
FROM
(SELECT
CASE
WHEN (logged BETWEEN
(TRUNC(sysdate - 1) + 17 / 24) AND
(TRUNC(sysdate) + 7 / 24))
THEN 1
ELSE 0
END AS eveluation
FROM result_log
WHERE code IN ('codeA', 'codeB')
);
EVALUATION
----------
1
Elegantní na tomto řešení je, že stačí pouze přidat do klauzule WHERE další kód (codeC) a vše ostatní bez problémů dál funguje.