Gegevensverrijking in Oracle SOA Suite
November 2010 - Gegevensverrijking behoort tot één van de verantwoordelijkheden van een adapter (verbindingscomponent): Validatie - Gegevensverrijking - Transformatie. Verrijken heeft betrekking op het toevoegen van gegevens aan een bericht zodat deze betekenisvoller is voor een service of doelapplicatie. In de praktijk blijkt het lastig om gegevensverrijking op de juiste manier toe te passen. Dit komt omdat het aanmaken en vullen van mapping tabellen als omslachtig wordt ervaren en de noodzaak ervan niet direct aanwezig is. Dit is met name het geval als de interface is ontworpen met één afnemer in gedachte (rechtstreekse koppeling). Vaak ook is het een kwestie van gemakzucht. Het op de juiste manier toepassen van verrijking is niet moeilijk. Deze Whitebook gaat over gegevensverrijking in Oracle SOA Suite, het nut ervan en hoe het gebruikt dient te worden.
Volgens de SOA-gedachte zijn de service objecten in de integratie laag losgekoppeld van applicaties. Dit betekent onder andere dat deze objecten geen waarden mogen bevatten die specifiek zijn voor een bepaalde applicatie. Deze loskoppeling zorgt ervoor dat een leverende applicatie te vervangen is door een andere applicatie. Alle applicaties dienen hun informatie naar dezelfde objecten te vertalen. Een manier om applicatie-specifieke waarden om te zetten naar applicatie-onafhankelijke waarden is door middel van gegevensverrijking.
Lang niet altijd is het direct duidelijk of een element een waarde bevat die specifiek is voor een bepaalde applicatie. Daar komt men pas naderhand achter. Statussen en sleutels die voor identificatie worden gebruikt zijn vaak overduidelijk applicatie specifiek. Maar ook er zijn ook andere eigenschappen waarvoor gegevensverrijking moet worden toegepast: alle informatie die nodig is om een bericht compleet te maken maar die niet (in eerste instantie) worden geleverd door de bronapplicatie.
Er zijn verschillende technieken om gegevensverrijking te bewerkstelligen:
- Domain Value Maps - statische mapping
- Cross Reference Tables - dynamische mapping
- Services - functies die objecten terug geven aan de hand van invoer parameters
Domain Value Maps
Als in een interface twee applicaties voor een bepaald element dezelfde waarden worden gebruikt lijkt het omslachtig om deze eerst naar een applicatie-onafhankelijke waarde te vertalen. Doordat men bij het ontwerp van een interface al weet welke applicatie afnemer is van de informatie wordt vaak voor de eenvoudige weg gekozen. Het is namelijk veel eenvoudiger om de waarde te kopiëren:
<xsl:value-of select="/serviceObject/value"/>
| App_A | App_B |
| Y | Y |
| N | N |
In dit geval gebruiken beide applicaties toevallig dezelfde waarde voor een bepaald element. Dit blijft goed gaan zolang deze koppeling beperkt blijft tot deze twee applicaties en er niets wijzigt in de applicaties. Echter, een probleem ontstaat op het moment er een derde applicatie bij komt die een andere code nodig heeft.
| App_A | App_B | App_C |
| Y | Y | 1 |
| N | N | 0 |
Welke waarde moet er nu in het service object worden gebruikt? Meestal wordt er gekozen voor een <choose> constructie:
<xsl:choose> <xsl:when test="/inp1:Person/isCustomer = 'Y'">1</xsl:when> <xsl:when test="/inp1:Person/isCustomer = 'N'">0</xsl:when> </xsl:choose>
Dit kan acceptabel zijn zolang het aantal verschillende waarden te overzien is. Als er echter meerdere waarden bijkomen wordt deze constructie onoverzichtelijk en wordt de kans op fouten groter. Een ander bezwaar aan deze constructie is dat de waarden ‘hard’ gecodeerd zijn. Dus als er iets wijzigt, dan moet deze wijziging in alle transformaties worden aangebracht.
Een betere oplossing is om de mapping van deze waarden in een tabel te stoppen. In Oracle SOA Suite is functionaliteit toegevoegd genaamd Domain Value Maps. Middels een web-interface is een dergelijke DVM tabel te creëren en te vullen.
| App_A | App_B | App_C | Common |
| Y | Y | 1 | true |
| N | N | 0 | false |
De kolom Common bevat de waarde zoals deze in het service object terecht komt. Voor de transformatie bestaan er XPath functies. Het ophalen van een waarde ziet er als volgt uit:
<xsl:value-of select="orcl:lookup-dvm ('Status_Code','App_B',/inp1:Person/Status,'Common','')"/>
Een DVM is voornamelijk geschikt voor element- en attribuutwaarden waarop nauwelijks mutaties plaatvinden, zoals statussen, landcodes, afkortingen voor eenheden. Hieronder een voorbeeld van een mapping van status codes:
| App_A | App_B | App_C | Common |
| A | Active | 1 | status_open |
| I | Inactive | 3 | status_inactive |
| R | Deleted | 2 | status_removed |
| T | Discontinued | 4 | status_terminated |
Bij een DVM is niet mogelijk om vanuit een BPEL process of ander component nieuwe waarden toe te voegen aan een mapping. Het is wel mogelijk om via de beheer console waarden toe te voegen aan een tabel. Deze wijzigingen zijn dan direct beschikbaar. Als er voortdurend objecten bijkomen en verdwijnen zijn Cross Reference Tables beter geschikt.
Cross Reference Tables
Cross Reference Tables (XRef) worden voornamelijk gebruikt voor het vertalen van primaire sleutels. Primaire sleutels zijn vaak nodig om een object is te uniek te identificeren. Deze identificatie geldt vaak alleen voor één applicatie; de sleutel van bijvoorbeeld een klant heeft in applicatie A een andere sleutel als in applicatie B.
| App_A | App_B | Common |
| 213 | 4235 | 9b946206-f2f8-45e0-9b2b-c0fb63a7c599 |
| 214 | 4567 | 51eb8a09-d95f-4875-94ad-a0db86cd4e73 |
Net als DVM is XRef geen standaard Java EE functionaliteit, maar een feature die door Oracle is toegevoegd aan SOA Suite. Voor XRef bestaan ook een aantal XPath functies waarmee waarden kunnen worden toegevoegd, opgehaald en verwijderd. Hieronder een fragment voorbeeld code om een waarde op te halen:
<xsl:value-of select="xref:lookupXRef('Customer_ID','App_A',/inp1:Person/Status, 'Common', true())"/>
De common waarde wordt meestal gevuld met een gegenereerde GUID die in geen van de applicaties een betekenis heeft en is daarmee applicatie-onafhankelijk. Deze GUID wordt alleen gebruikt om een relatie tussen de verschillende sleutels aan te geven.
In principe hoeft er voor XRef geen onderhoud plaats te vinden. Een XRef tabel wordt door de componenten in de integratielaag actueel gehouden. In Create-adapters worden rijen in een XRef tabel aangemaakt en in Delete-adapters worden rijen verwijderd. Onderstaand voorbeeld illustreert het gebruik van XRef aan de hand van een aantal Application Integration Architecture (AIA) scenario's:

Vullen van XRef (populate):
1. Bronapplicatie verstuurt details van nieuw aangemaakt object.
2. Primaire sleutel van bronapplicatie wordt opgeslagen in XRef tabel m.b.v. populate functie. De Common waarde wordt gegenereerd. Deze Common waarde wordt doorgegeven aan de business of entitity service.
3. Object wordt aangemaakt in de doelapplicatie.
4. De synchrone service retourneert de primaire sleutel van het object in de doelapplicatie.
5. De primaire sleutel van doelapplicatie wordt toegevoegd aan de XRef tabel en gekoppeld aan de Common waarde.

Verrijken met behulp van XRef (lookup):
6. Bronapplicatie verstuurt de details van een gewijzigd object.
7. Met behulp van de XRef lookup functie wordt de Common waarde opgehaald uit de XRef tabel.
8. In de adapter van de doelapplicatie wordt de primaire sleutel opgehaald van het object in de doelapplicatie.
9. De primaire sleutel van de doelapplicatie wordt meegestuurd naar de doelapplicatie.

Verwijderen uit XRef (mark for delete):
10. Bronapplicatie verstuurt de primaire sleutel van een te verwijderen object.
11. De Common waarde wordt opgehaald en de primaire sleutel van doelapplicatie wordt uit de XRef tabel verwijderd.
12. De primaire sleutel van doelapplicatie wordt uit de XRef tabel opgehaald.
13. Het object wordt uit de doelapplicatie verwijderd.
14. De primaire sleutel van de doelapplicatie wordt uit de XRef tabel verwijderd.
XRef ondersteunt het gebruik van één-op-meer relaties: een waarde in 1 applicatie wordt vertaald naar meerdere waarden in een andere applicatie. De mapping hiervan levert dus in één richting één waarde op maar kan in de andere richting een array met meerdere waarden opleveren. Een waarschuwing bij het toepassen van één-op-meer relaties is hier wel op zijn plaats. In de praktijk levert deze vorm van XRef complexe situaties op. Welke waarde moet je kiezen als er meerdere mogelijkheden zijn? Daarom is het is beter om één-op-meer relaties te vermijden. Hou de vertaling zo simpel en eenduidig mogelijk.
Services
Sommige integratie architecten vinden dat een ESB geen data mag bevatten. Als men dit principe volgt dan moeten gegevens voor verrijking uit een externe bron komen. Aangezien zowel XRef en DVM gegevens opslaan op de ESB server (althans op de database van de ESB server), moet een andere manier gebruikt worden om deze gegevens op te halen en op te slaan. Dit kan middels services. Services zijn componenten die functies aanbieden die gegevens retourneren voor invoer parameters. Een component die een services levert kan uitgevoerd zijn als een BPEL proces, database adapter, etc.
Het nadeel van services is dat ze niet in een (XSL) transformatie gebruikt kunnen worden. Ze moeten als in aparte (BPEL) stappen uitgevoerd worden en de retourwaarde moet in afzonderlijke stappen aan de XML worden toevoegd. Het gevolg is dat de BPEL processen vaak behoorlijk complex kunnen worden. While - Assign - Invoke - Assign. Het zou veel gemakkelijker is om gebruik te maken van specifieke XPath functies (zoals dit het geval is bij XRef en DVM). Hiermee kunnen alle vertalingen in de XSL transformatie plaatsvinden.
Een service kan een wrapper om een SQL query of stored procedure aanroep zijn. Bijvoorbeeld om een straatnaam en/of plaatsnaam te bepalen voor een bepaalde postcode / huisnummer combinatie:
| Postcode | Straat | Huisnummer vanaf | Huisnummer tot | Even | Plaatsnaam |
| 3543GT | Miles Davisstraat | 151 | 295 | false | Utrecht |
| 3439NE | Fultonbaan | 2 | 84 | true | Nieuwegein |
Het contract van de service die gebruik maakt van bovenstaande tabel kan er als volgt uitzien:
<definitions ... >
<types>
<schema ... >
<element name="QueryPostcode">
<complexType>
<sequence>
<element name="postcode" type="string"/>
<element name="huisnummer" type="int"/>
</sequence>
</complexType>
</element>
<element name="QueryPostcodeResponse">
<complexType>
<sequence>
<element name="straat" type="string"/>
<element name="plaatsnaam" type="string"/>
</sequence>
</complexType>
</element>
</schema>
</types>
<message name="QueryPostcodeRequestMsg">
<part name="payload" element="tns:QueryPostcode"/>
</message>
<message name="QueryPostcodeResponseMsg">
<part name="payload" element="tns:QueryPostcodeResponse"/>
</message>
<portType ... >
<operation name="query">
<input message="tns:QueryPostcodeRequestMsg"/>
<output message="tns:QueryPostcodeResponseMsg"/>
</operation>
</portType>
...
</definitions>
Anders dan in BPEL kan in Oracle Service Bus (OSB) wel verrijking met behulp van een service in 1 stap plaatsvinden. OSB biedt verschillende manieren om gegevens te op te halen: middels web services, databases of Java code. Omdat OSB geen tijdelijke variabelen kent is het niet zo geschikt als de gegevens uit verschillende bronnen komen of wanneer er complexe logica nodig is. In deze gevallen biedt BPEL meer mogelijkheden.
Beslissingstabel
Wanneer gebruik je wat? In onderstaande tabel laat zien wanneer welke technologie gebruikt kan worden.
| DVM | XRef | Service | |
| Vertaling van statische waarden (codes, afkortingen)? | Ja | Nee | Nee |
| Vertaling van dynamische waarden (primaire sleutels)? | Nee | Ja | Ja |
| Is het toevoegen van een waarde aan de mapping mogelijk vanuit een BPEL proces? | Nee | Ja | Ja |
| Verrijking van gegevens die afhankelijk zijn van meerdere parameters? | Nee | Nee | Ja |
| Te gebruiken in een SCA Mediator? | Ja | Ja | Nee |
| Te gebruiken in een BPEL proces? | Ja | Ja | Ja |
| Te gebruiken in AIA? | Ja | Ja | Ja |
| Te gebruiken in OSB? | Nee(*) | Nee(*) | Ja |
(*) Volgens de blog van Chris Tomkins komen DVM en XRef beschikbaar in OSB 11gR2, zie referenties.
Conclusie
DVMs en XRefs zijn zeer nuttig voor het verrijken van gegevens en zijn bovendien eenvoudig in gebruik. De broncode blijft netjes. Als er principiële bezwaren bestaan om mapping-gegevens op te slaan op de ESB kan er gebruik worden gemaakt van services. Bij services worden de gegevens in een applicatie ondergebracht. Services dienen ook te worden toegepast wanneer XRefs en DVMs niet toereikend zijn.
Bedenk goed wanneer je welke manier toepast. Misbruik deze technieken niet voor dingen waar ze niet voor bedoeld zijn. Persoonlijk ben ik geen voorstander van het samenvoegen (concateneren) van verschillende waarden om op deze manier een lookup mogelijk te maken. Als een waarde afhankelijk is van meerdere parameters gebruik dan een service en geen DVM of XRef. Het is goed om principieel te zijn bij de keuze van verrijkkingsmethode.
Tenslotte wil ik benadrukken dat DVM en XRef functionaliteit alleen bestaan in Oracle SOA Suite. Als je geen gebruik kunt of wil maken van Oracle SOA Suite en toch DVM en/of XRef functionaliteit zou willen, kun je nog altijd zelf proberen om XPath functie extensies te programmeren (bijvoorbeeld met behulp van de Saxon XSLT libraries). Persoonlijk vind ik het wel zo prettig als deze functionaliteit ’out-of-the-box’ beschikbaar is.

Reacties
Nieuwe reactie inzenden