Gebruik van de “Standaard Zaak-en Documentservices 1.1” van Kwaliteitsinstituut Nederlandse Gemeenten (KING), almede MTOM/XOP t.b.v. een koppeling tussen diverse applicaties (gerealiseerd binnen OSB 11g) aangaande het proces van vergunningverlening voor een organisatie in de publieke sector

1
Share this on .. Tweet about this on TwitterShare on LinkedIn2Share on Facebook0Share on Google+1Email this to someoneShare on Tumblr0Buffer this page

Voor een organisatie in de publieke sector werd aan AMIS gevraagd om met behulp van Oracle Service BUS 11g, een koppeling te realiseren tussen diverse applicaties aangaande het proces van vergunningverlening, zodat de daarbij benodigde gegevens eenvoudiger geautomatiseerd verwerkt konden worden.

Belangrijke randvoorwaarden uit het Solution Design waren:

  • het hanteren van landelijk vastgestelde standaarden voor informatie-uitwisseling, waarbij gekozen is voor StuF-ZKN en het gebruik van de “Standaard Zaak-en Documentservices 1.1” van Kwaliteitsinstituut Nederlandse Gemeenten (KING)
  • de keuze om grote bestanden op basis van MTOM/XOP over te zetten
  • het feit dat het gebruikte document managementsysteem (DMS) ten gevolge van een back-up een aantal uren per nacht niet beschikbaar is

Dit artikel zal nader ingaan op de “Standaard Zaak-en Documentservices 1.1” van KING en het gebruik van MTOM/XOP binnen de gerealiseerde oplossing. Verder wordt er ingegaan op het gebruik van Java Callout’s om bestanden weg te schrijven en te laden van de WebLogic applicatie server, alsmede het gebruik van een WebLogic queue om rekening te houden met de genoemde DMS back-up.

De betreffende koppeling is recent met succes in productie genomen.

Zaakgericht werken

Bij de organisatie waar de koppeling is gerealiseerd, is er sprake van zogenaamd zaakgericht werken en rondom het proces van vergunningverlening speelt de Wet algemene bepalingen omgevingsrecht (Wabo) een belangrijke rol. Zaakgericht werken is een procesgeoriënteerde manier van werken. Hierbij spelen onder andere zaken en documenten een rol. Zie voor nadere informatie bijvoorbeeld: http://www.noraonline.nl/wiki/Het_basisconcept_van_Zaakgericht_Werken.

In de Wet algemene bepalingen omgevingsrecht (Wabo) staat voor welke activiteiten een omgevingsvergunning nodig is. De omgevingsvergunning is één geïntegreerde vergunning voor de onderwerpen: bouwen, wonen, monumenten, ruimte, natuur en milieu. De omgevingsvergunning kan nodig zijn als een bedrijf op een bepaalde plek iets wil slopen, (ver-)bouwen, oprichten of gebruiken. Centraal in de Wabo staat de dienstverlening door de overheid aan burgers en het bedrijfsleven.

Bij de betreffende organisatie is de belangrijkste verandering het feit dat de benodigde gegevens deels geautomatiseerd in de zaak en het document kunnen worden gezet en vervolgens het vervolg van het proces kan worden gestart. Dit betekent dat handelingen zoals het aanmaken van de zaak en het toevoegen van de documentgegevens niet meer standaard handmatig wordt uitgevoerd, maar dat alleen als het nodig is, de zaken en documenten gecontroleerd en aangepast worden.

In onderstaande afbeelding is een overzicht te zien van de betreffende applicaties en OSB services waarmee de gewenste koppeling is gerealiseerd.

De volgende applicaties spelen een rol in de koppeling:

  • E-formulieren (IPROX-Forms)

IPROX-Forms is een op IPROX-CMS gebaseerde applicatie die de mogelijkheid biedt om complexe interacties met een bezoeker te definiëren en af te handelen. Anders gezegd: met IPROX-Forms is het mogelijk E-formulieren te maken.

Bron: https://www.infoprojects.nl/iprox/iprox-forms/

  • Landelijke Omgevingsloket online (OLO)

Met Omgevingsloket online (www.omgevingsloket.nl) kan digitaal een aanvraag of melding gedaan worden voor omgevingsvergunningen en watervergunningen. De overheid kan met Omgevingsloket online de aanvragen behandelen. Ook kan met Omgevingsloket online een vergunningcheck worden gedaan om te zien of een vergunning of melding nodig is.

Bron: http://www.infomil.nl/onderwerpen/integrale/omgevingsloket/

  • Squit XO

Squit XO is een veelzijdig softwarepakket voor de uitvoering van allerlei taken op het gebied van vergunningverlening, toezicht en handhaving (VTH). Door de ondersteuning van standaarden en de mogelijkheid om te koppelen met een breed scala aan andere applicaties, is Squit XO uitgegroeid tot dé marktleider in de VTH-softwaremarkt.

Bron: https://www.roxit.nl/media/715771/factsheet_squit-xo_algemeen_03032015.pdf

  • EDO / eBUS

De applicatie EDO bestaat uit een Document Management Systeem (OpenText eDOCS) en een deel maatwerk.

OpenText eDOCS oplossingen bieden ondernemingen een geïntegreerd aanbod speciaal ontwikkeld om bedrijfsprocessen, risicobeheer en naleving van wet- en regelgeving gedurende de hele content levenscyclus te ondersteunen, van content creatie tot archivering, en procesondersteuning en samenwerking te verbeteren, terwijl de content beschermd wordt en risico’s en naleving van wet- en regelgeving beheerd worden.

Bron: http://www.onefox.nl/Producten/Content/OpenTexteDOCS/Paginas/eDOCS.aspx

Uw Document Management Systeem (DMS) vervult een essentiële rol in uw bedrijfsprocessen. Integratie met andere bedrijfsapplicaties conform een open en transparante SOAP interface met uw DMS is daarom cruciaal. One Fox eBUS is dé web service laag bovenop OpenText eDOCS DM/RM die integratie met andere applicaties aanzienlijk vergemakkelijkt. Conform marktstandaarden, met inachtneming van uw bedrijfsregels voor eDOCS.

Bron: http://www.onefox.nl/Producten/Integratie/One%20Fox%20eBUS/Paginas/eBUS.aspx

Standaard Zaak-en Documentservices 1.1

Als uitgangspunt voor de inrichting van de OSB services geldt de “Standaard Zaak-en Documentservices 1.1”, welke uitgaat van vastgestelde standaarden: CMIS 1.0, StUF 3.01, StUF-ZKN 3.10, RGBZ 1.0 en ZTC 2.0 en welke deze (voor het beschreven toepassingsgebied genoemde standaarden) aanscherpt door ze te concretiseren voor de betrokken applicaties en de te ondersteunen functionaliteit. Daardoor verbetert de interoperabiliteit tussen betrokken applicaties.

De “Standaard Zaak-en Documentservices 1.1” is een beperkte uitwerking van de StUF-ZKN standaard met minder verplichte velden.

De services worden daarin gespecificeerd volgens de StUF-standaard (StUF 3.01 / StUF-ZKN 3.10). De volgende berichten worden ondersteund:

  • Synchrone vraag-/antwoordberichten (Lv01/La01)
  • Asynchrone kennisgevingen (Lk01)
  • Foutberichten en bevestigingsberichten(Fo0x en Bv03)(Lk01 en Bv01)
  • Vrije berichten (Di02/Du02)

Ten tijde van de realisatie van de koppeling bij de klant was versie 1.1.0.2 de laatste versie.

Bron: 20150707_Specificatie_Zaak-_en_Documentservices_v1.1.02.pdf, http://gemmaonline.nl/index.php/Documentatie_Zaak-_en_Documentservices#Zaak-_en_Documentservices_1.1

De bij deze standaard behorende WSDL en XML Schema Definitions (zie Zaak_DocumentServices_1_1_02.zip op bovengenoemde url) zijn gebruikt bij de koppeling.

Aangaande StUF-ZKN 3.10 was er nog een patch beschikbaar, genaamd Zkn0310_20151126_patch23 (zie http://gemmaonline.nl/index.php/Sectormodellen_Zaken:_StUF-ZKN), welke is gebruikt in de koppeling.

Aangaande StUF-BG 3.10 was er nog een patch beschikbaar, genaamd Bg0310_20151126_patch23 (zie http://gemmaonline.nl/index.php/Sectormodel_Basisgegevens:_StUF-BG), welke is gebruikt in de koppeling.

In de “Standaard Zaak-en Documentservices 1.1” wordt uitgegaan van een referentiearchitectuur. Deze is hieronder weergegeven. In de referentiearchitectuur is voor elke referentiecomponent aangegeven welke groep van services deze moet leveren dan wel gebruiken.

In onderstaande tabel is aangegeven welke services tot welke groep behoren:

Alle benodigde informatie en sources behorend bij de “Standaard Zaak-en Documentservices 1.1” kan worden gevonden op de webpagina van Gemeentelijke Model Architectuur (GEMMA) (http://gemmaonline.nl/index.php/Documentatie_Zaak-_en_Documentservices), de publicatie- en co-creatieomgeving van Kwaliteitsinstituut Nederlandse Gemeenten (KING).

OSB Services ZKN ZaakService-2.0 en ZKN ZaakDocumentService-2.0

Bij de klant zijn de bovengenoemde applicatieservices (alleen degene die functioneel nodig waren) als operaties opgenomen in een tweetal OSB services: ZKN ZaakService-2.0 en ZKN ZaakDocumentService-2.0. De algemene afhandeling van de berichten wordt gevormd door proxy service ZaakService_PS, respectievelijk ZaakDocumentService_PS. Elke proxy service bevat een “Operational Branch” waarbij de gekozen operatie wordt gebruikt om het binnenkomende bericht te routeren naar het juiste, bericht specifieke, afhandelingsdeel (geïmplementeerd door een local proxy service).

De operaties van de ZKN ZaakService-2.0, zijn ook toegevoegd aan de ZKN ZaakDocumentService-2.0, dit omdat vanuit Squit XO (via systeeminstellingen) maar naar één service gekoppeld kan worden.

Zo is voor bijvoorbeeld applicatieservice “Creëer Zaak” een operatie “creeerZaak_Lk01” aanwezig in proxy service ZaakService_PS met de volgende specificaties:

<operation name="creeerZaak_Lk01">
  <input message="ZKN:zakLk01"/>
  <output message="StUF:Bv03"/>
  <fault name="fout" message="StUF:Fo03"/>
</operation>

Zo is voor bijvoorbeeld applicatieservice “Voeg Zaakdocument toe” een operatie “voegZaakdocumentToe_Lk01” aanwezig in proxy service ZaakDocumentService_PS met de volgende specificaties:

<operation name="voegZaakdocumentToe_Lk01">
  <input message="ZKN:edcLk01"/>
  <output message="StUF:Bv03"/>
  <fault name="fout" message="StUF:Fo03"/>
</operation>

T.b.v. het gebruik van speciale karakters is bij de proxy services op tabblad HTTP Transport het volgende ingesteld:

Berichten, WSDL’s en XSD’s

De berichten die binnen de OSB service ZKN ZaakDocumentService-2.0 gebruikt worden zijn:

BerichtWSDL
zakLv01…\zkn0310\zs-dms\zkn0310_beantwoordVraag_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\vraagAntwoord\zkn0310_msg_vraagAntwoord.xsd

zakLa01…\zkn0310\zs-dms\zkn0310_beantwoordVraag_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\vraagAntwoord\zkn0310_msg_vraagAntwoord.xsd

Fo02…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

edcLv01…\zkn0310\zs-dms\zkn0310_beantwoordVraag_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\vraagAntwoord\zkn0310_msg_vraagAntwoord.xsd

edcLa01…\zkn0310\zs-dms\zkn0310_beantwoordVraag_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\vraagAntwoord\zkn0310_msg_vraagAntwoord.xsd

edcLk01…\zkn0310\zs-dms\zkn0310_ontvangAsynchroon_mutatie_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\mutatie\zkn0310_msg_mutatie.xsd

Bv02…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

Bv03…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

Fo03…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

genereerDocumentIdentificatie_Di02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

genereerDocumentIdentificatie_Du02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

geefZaakdocumentbewerken_Di02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

geefZaakdocumentbewerken_Du02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

updateZaakdocument_Di02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

cancelCheckout_Di02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

Omdat verderop in dit blog artikel het vaak gaat over een bestand (in het kader van de operatie “voegZaakdocumentToe_Lk01”) is dit het moment om aan te geven dat in het edcLk01 bericht de verwijzing naar het bestand (oftewel het fysieke document) te vinden is in element edcLk01/object[1]/inhoud (met attributen contentType en bestandsnaam).

Bijvoorbeeld:

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf">
  <con:binary-content ref="cid:-15258baa:15451665d79:-7bc5"/>
</inhoud>

De berichten die binnen de OSB service ZKN ZaakService-2.0 gebruikt worden zijn:

BerichtWSDL

 

zakLk01…\zkn0310\zs-dms\zkn0310_ontvangAsynchroon_mutatie_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\mutatie\zkn0310_msg_mutatie.xsd

Bv03…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

Fo03…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

genereerZaakIdentificatie_Di02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

genereerZaakIdentificatie_Du02…\zkn0310\zs-dms\zkn0310_vrijeBerichten_zs-dms.wsdl

Met daarbij de volgende XSD:

…\zkn0310\zs-dms\zkn0310_msg_zs-dms.xsd

Fo02…\0301\stuf0301_types.wsdl

Met daarbij de volgende XSD:

…\0301\stuf0301.xsd

Aangezien zowel het Solution Design, aangaande beveiliging, als de “Standaard Zaak-en Documentservices 1.1” voorstelt dat bij een WSDL niet ondersteunde berichten uit de binding en portType worden verwijderd, zijn de benodigde WSDL’s uit de standaard (lees het CDM project) als basis gebruikt voor de uiteindelijke WSDL (behorend bij de proxy service). Deze WSDL staat in de proxy directory van de OSB service ZKN ZaakDocumentService-2.0 en is samengesteld uit WSDL’s uit de standaard.

Omdat er binnen de WSDL meerdere operaties zijn die hetzelfde input bericht gebruiken, moest bij de instellingen van de proxy services aangegeven worden bij “Selection Algorithm” dat er gebruik moest worden gemaakt van “SOAPAction Header” (Select this algorithm to specify that operation mapping be done automatically from the WSDL associated with this proxy service).

ExtraElementen

Binnen de standaard kunnen extra elementen worden toegevoegd aan de berichten, zonder dat je het schema hoeft aan te passen. De StUF 3.01 standaard, in het bijzonder het stuf0301.xsd schema, bevat hiervoor het element “extraElementen”. Hiermee worden extra elementen gedefinieerd, die niet gevalideerd worden. De afstemming en validatie moeten dus tussen de applicaties worden geregeld. Door gebruik te maken van de extra elementen kan er dus toch binnen de standaard een stukje “maatwerk” worden gerealiseerd.

<element name="extraElementen" type="StUF:ExtraElementen"/>

<complexType name="ExtraElementen">
  <sequence>
    <element name="extraElement" nillable="true" maxOccurs="unbounded">
      <complexType>
        <simpleContent>
          <extension base="string">
            <attributeGroup ref="StUF:element"/>
            <attribute name="naam" type="string" use="required"/>
            <attribute ref="StUF:indOnvolledigeDatum"/>
          </extension>
        </simpleContent>
      </complexType>
    </element>
  </sequence>
</complexType>

Issues tijdens het deployen van de wsdl’s en xsd’s behorend bij de “Standaard Zaak-en Documentservices 1.1”

Aangezien de WSDL’s en XSD’s als onderdeel van de te realiseren koppeling als een canoniek data model worden beschouwd, zijn deze als onderdeel van een apart OSB Project gedeployed naar de Oracle Service Bus versie 11.1.1.7. Tijdens het deployen hiervan liep ik tegen een aantal issues aan. Door aanpassingen te doen aan de bestanden bleek het uiteindelijke mogelijk om ze succesvol te deployen.

Bijvoorbeeld tijdens het deployen van .\zkn0310\mutatie\zkn0310_ontvangAsynchroon_mutatie.wsdl trad de volgende fout op:

Attribute not allowed: version in element definitions@http://schame.xmlsoap.org.wsdl/

In dit bestand is regel 2 veranderd van:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:StUF="http://www.egem.nl/StUF/StUF0301" xmlns:ZKN="http://www.egem.nl/StUF/sector/zkn/0310" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="StUF-ZKN0310" targetNamespace="http://www.egem.nl/StUF/sector/zkn/0310" version="031003">

naar:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:StUF="http://www.egem.nl/StUF/StUF0301" xmlns:ZKN="http://www.egem.nl/StUF/sector/zkn/0310" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsi="http://ws-i.org/schemas/conformanceClaim/" xmlns:xs="http://www.w3.org/2001/XMLSchema" name="StUF-ZKN0310" targetNamespace="http://www.egem.nl/StUF/sector/zkn/0310">

Deze aanpassing was inmiddels ook al als issue ERR0429 in de onderhoudsverzoeken voor de standaard opgenomen (zie http://www.gemmaonline.nl/index.php/Onderhoudsverzoeken.xls).

Het is dus goed je bewust te zijn dat een dergelijk lijst met “problemen” en bijbehorende oplossingen bestaat.

MTOM/XOP

Een van de randvoorwaarden uit het Solution Design was de keuze om grote bestanden op basis van MTOM/XOP te verzenden.

SOAP Message Transmission Optimization Mechanism (MTOM) is een manier om binaire data van en naar Web services te sturen. MTOM gebruikt XML-binary Optimized Packaging (XOP) om de binaire data over te zetten.

Binaire data, zoals een afbeelding in JPEG formaat, kunnen uitgewisseld worden tussen een client en de service. Meestal wordt de binaire data hierbij als een xsd:base64Binary string in een XML document opgenomen. Het versturen van de binaire data in dit formaat zorgt echter voor een enorme toename van de omvang van het bericht en is duur in termen van de benodigde processing ruimte en tijd.

Door MTOM te gebruiken, kan binaire data verzonden worden als een MIME bijlage, waardoor de transmissie ruimte op de lijn beperkt wordt. De binaire data is semantisch onderdeel van het XML document. Dit is een voordeel ten opzichte van SWA (SOAP Messages with Attachments), omdat dit het mogelijk maakt om bijvoorbeeld berichtbeveiliging op basis van WS-Security te gebruiken.

Het gebruik van MTOM om binaire data als een bijlage over te zetten verbeterd de prestaties van de Web services stack. De prestaties worden niet beïnvloed als een MTOM-encoded bericht geen binaire data bevat. Voor betere interoperabiliteit zouden berichten die geen binaire data bevatten niet MTOM-encoded moeten worden.
Bron: Oracle Fusion Middleware Online Documentation Library, 11g Release 1 (11.1.1.7), Using MTOM Encoded Message Attachments

Alle applicaties die betrokken waren bij de koppeling (zoals bijvoorbeeld SquitXO) zijn MTOM enabled.

Het gebruik van MTOM/XOP kan bij een proxy service (ook bij gebruik van het local protocol) ingesteld worden via de Message Handling page.

Door bij de proxy service Message Handling page te kiezen voor “Include Binary Data by Reference” (Default) worden in de inbound request message alle xop:Include elementen vervangen door ctx:binary-content elementen bij het vullen van de header en body message-related context variabelen.

Zie voor nadere informatie over de configuratie “Fusion Middleware Administrator’s Guide for Oracle Service Bus”.
Bron: Oracle Fusion Middleware Online Documentation Library, 11g Release 1 (11.1.1.7), Configuring Proxy Services

Voorbeeld zonder MTOM/XOP, verkregen door het uitvragen van de body context variabele:

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf">e1xydGY…</inhoud>

Voorbeeld met MTOM/XOP, verkregen door het uitvragen van de body context variabele:

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf">
  <con:binary-content ref="cid:-15258baa:15451665d79:-7bc5"/>
</inhoud>

Toelichting op gebruik MTOM/XOP

Hieronder volgt een voorbeeld van een bericht (SoapUI http log) zoals dat wordt aangeboden aan de OSB service ZKN ZaakDocumentService-2.0, operatie voegZaakdocumentToe_Lk01.

Te zien is dat er een multipart bericht wordt gebruikt, met enerzijds een gedeelte (Part) met Content-Type “application/xop+xml” en Content-ID “<rootpart@soapui.org>” en anderzijds een gedeelte (Part) met Content-Type “application/rtf” en Content-ID van “<http://www.soapui.org/9637768303968>”. Vanuit het eerste gedeelte wordt via “href=cid:http://www.soapui.org/9637768303968” verwezen naar het tweede gedeelte.

POST /ZaakDocumentService-2.0/ZaakDocumentService-2.0 HTTP/1.1[\r][\n]"
Accept-Encoding: gzip,deflate[\r][\n]"
Content-Type: multipart/related; type="application/xop+xml"; start="<rootpart@soapui.org>"; start-info="text/xml"; boundary="----=_Part_5_132570683.1461663503405"[\r][\n]"
SOAPAction: "http://www.egem.nl/StUF/sector/zkn/0310/voegZaakdocumentToe_Lk01"[\r][\n]"
MIME-Version: 1.0[\r][\n]"
Content-Length: 104249[\r][\n]"
Host: localhost:7001[\r][\n]"
Connection: Keep-Alive[\r][\n]"
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)[\r][\n]"
[\r][\n]"
[\r][\n]"
------=_Part_5_132570683.1461663503405"
[\r][\n]"
Content-Type: application/xop+xml; charset=UTF-8; type="text/xml""
[\r][\n]"
Content-Transfer-Encoding: 8bit"
[\r][\n]"
Content-ID: <rootpart@soapui.org>"
[\r][\n]"
[\r][\n]"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">[\n]"
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">[\n]"
<edcLk01 xmlns="http://www.egem.nl/StUF/sector/zkn/0310">[\n]"
..
<object a:entiteittype="EDC" a:sleutelVerzendend="123" a:sleutelGegevensbeheer="2016/0000221" a:verwerkingssoort="T" xmlns:a="http://www.egem.nl/StUF/StUF0301">[\n]"
<identificatie>2016/0000221</identificatie>[\n]"
<dct.omschrijving>Een omschrijving</dct.omschrijving>[\n]"
<creatiedatum>20160406</creatiedatum>[\n]"
<ontvangstdatum>20160406</ontvangstdatum>[\n]"
<titel>xyz</titel>[\n]"
<beschrijving>Een beschrijving</beschrijving>[\n]"
<formaat>.rtf</formaat>[\n]"
<taal>NL</taal>[\n]"
<verzenddatum>20160406</verzenddatum>[\n]"
<vertrouwelijkAanduiding>OPENBAAR</vertrouwelijkAanduiding>[\n]"
<auteur>Een auteur</auteur>[\n]"
<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf" xmlns:b="http://www.w3.org/2005/05/xmlmime"><inc:Include href="cid:http://www.soapui.org/9637768303968" xmlns:inc="http://www.w3.org/2004/08/xop/include"/></inhoud>[\n]"
..
</object>[\n]"
</edcLk01>[\n]"
</s:Body>[\n]"
</s:Envelope>"
[\r][\n]"
------=_Part_5_132570683.1461663503405"
[\r][\n]"
Content-Type: application/rtf"
[\r][\n]"
Content-Transfer-Encoding: binary"
[\r][\n]"
Content-ID:<http://www.soapui.org/9637768303968>"
[\r][\n]"
[\r][\n]"
{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff38\deff0\stshfdbch0...05000000000000}}"
[\r][\n]"
------=_Part_5_132570683.1461663503405--"

Door bij de proxy service Message Handling page te kiezen voor “Include Binary Data by Reference” worden in de inbound request message alle xop:Include elementen vervangen door ctx:binary-content elementen bij het vullen van de header en body message-related context variabelen.

Daarmee wordt iets als:

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf" xmlns:b="http://www.w3.org/2005/05/xmlmime">
  <inc:Include href="cid:http://www.soapui.org/9637768303968" xmlns:inc="http://www.w3.org/2004/08/xop/include"/>
</inhoud>

vervangen door iets als (verkregen door het uitvragen van de body context variabele):

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf">
  <con:binary-content ref="cid:-15258baa:15451665d79:-7bc5"/>
</inhoud>

Let op:

Het edcLk01-bericht ondersteund standaard geen MTOM. D.w.z. dat het bericht niet zal valideren tegen de XSD i.v.m. de aanwezigheid van element binary-content binnen element inhoud. Hieronder volgt een voorbeeld van de soap fault (variabele $fault) die dan optreedt in de Service Error Handler:

<con:fault xmlns:con="http://www.bea.com/wli/sb/context">
  <con:errorCode>BEA-382505</con:errorCode>
  <con:reason>OSB Validate action failed validation</con:reason>
  <con:details>
    <con1:ValidationFailureDetail xmlns:con1="http://www.bea.com/wli/sb/stages/transform/config">
      <con1:message>Element not allowed: Include@http://www.w3.org/2004/08/xop/include in element inhoud@http://www.egem.nl/StUF/sector/zkn/0310</con1:message>
      <con1:xmlLocation>
        <xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F635977930478048534" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
      </con1:xmlLocation>
    </con1:ValidationFailureDetail>
  </con:details>
  <con:location>
    <con:node>VoegZaakdocumentToe_Lk01PipelinePairNode</con:node>
    <con:pipeline>VoegZaakdocumentToe_Lk01PipelinePairNode_request</con:pipeline>
    <con:stage>ValidationStage</con:stage>
    <con:path>request-pipeline</con:path>
  </con:location>
</con:fault>

Rekening houden met de EDO back-up

Bij gebruik van de koppeling worden uiteindelijk gegevens in EDO geplaatst. In dit kader diende er rekening mee te worden gehouden dat EDO in verband met een back-up een aantal uren niet beschikbaar is. Omdat het in die uren wel mogelijk moet zijn om nieuwe aanvragen en aanvullende documenten in te dienen, moest er een voorziening worden getroffen om deze gegevens tijdelijk op te slaan, zodat deze na de back-up in EDO konden worden opgeslagen.

De berichten worden daarom in een queue op de OSB opgeslagen en de documenten op een fileshare.

OSB services JMSProducerStuFZKNMessageService-1.0 en JMSConsumerStuFZKNMessageService-1.0

De OSB service JMSProducerStuFZKNMessageService-1.0 bevat de business service JMSProducerStuFZKNMessageService_BS. Deze business service dient er voor om een bericht op de queue StuFZKNMessageQueue te plaatsen. De business service accepteert willekeurige SOAP-berichten. Bij bovenstaande queue is ook een error queue geconfigureerd.

De OSB service JMSConsumerStuFZKNMessageService-1.0 bevat de proxy service JMSConsumerStuFZKNMessageService_PS. Deze proxy service dient er voor om berichten van de queue StuFZKNMessageQueue op te halen (dequeue).

OSB service eFormulierenService-1.0

De OSB service eFormulierenService-1.0 bevat de proxy service eFormulierenService_PS. Deze bevat een “Operational Branch” waarbij de gekozen operatie wordt gebruikt om het binnenkomende bericht te routeren naar het juiste, bericht specifieke, afhandelingsdeel (geïmplementeerd door een local proxy service). Vanuit het bericht specifieke, afhandelingsdeel wordt de bijbehorende operatie aangeroepen in de OSB service ZKN ZaakDocumentService-2.0.

Wegschrijven bestand naar WebLogic applicatie server

Voordat een edcLk01 bericht op een queue wordt geplaatst (i.v.m. EDO back-up), wordt de document content weggeschreven naar een directory op de WebLogic applicatie server.

Dit wordt via een “Java Callout” gedaan. Deze “Java Callout” roept een java functie aan welke de volgende parameters ontvangt:

  • Lokatie en naam van een te gebruiken property-bestand
  • Attribuut bestandsnaam van element inhoud in het edcLk01 bericht
  • DataSource referentie naar de “binary-content” van de MTOM attachment
  • Context
  • Logging aan of uit

De java functie zorgt er vervolgens voor dat de inhoud van de MTOM attachment naar een, in het property-bestand opgegeven, lokatie wordt geschreven. De bestandsnaam wordt gevormd door een UUID en de meegegeven bestandsnaam. De UUID wordt gebruikt om de bestandsnaam gegarandeerd uniek te maken.

De, voor opslag, gebruikte bestandsnaam, incl. lokatie, wordt door java functie teruggegeven aan de proxy. De proxy plaatst deze naam in het attribuut bestandsnaam van element inhoud in het edcLk01 bericht zodat daar later aan gerefereerd kan worden. Tevens wordt het element binary-content verwijderd omdat deze niet meer nodig is.

Het element inhoud ziet er dan uiteindelijk bijvoorbeeld als volgt uit:

<inhoud b:contentType="application/rtf" a:bestandsnaam="/home/oracle/osb/attachments/squitXO/3690a3d0-6b7d-4d61-aa77-d1727d9c02ab#10_xyz.rtf" xmlns:b="http://www.w3.org/2005/05/xmlmime"/>

Java Callout AttachmentProcessor.processAttachment en Actions welke gebruikt zijn in de Proxy Service Message Flow

Java CalloutTypeNameExpression
Method = AttachmentProcessor. processAttachment
Parameterjava.lang.StringpropertyFileLocation$attachmentProcessorPropertyFileLocation
Parameterjava.lang.Stringbestandsnaam$body/zkn:edcLk01/zkn:object[1]/zkn:inhoud/@stuf:bestandsnaam
Parameterjavax.activiation.DataSourcedatasource$body/zkn:edcLk01/zkn:object[1]/zkn:inhoud/ctx:binary-content
Parameterjava.lang.Stringcontext$attachmentProcessorContext
ParameterbooleanenableLogging$attachmentProcessorEnableLogging
Resultjava.lang.Stringbestandsnaam

Als context (variabele attachmentProcessorContext) wordt het bericht nummer binnen de KING Standaard Zaak-en Documentservices 1.1 gebruikt: #10

Hieronder staat de specificatie van de gebruikte class en method:

class AttachmentProcessor {

        public static String processAttachment(final String propertyFileLocation,
                                               final String bestandsnaam,
                                               final String context,
                                               final boolean enableLogging,
                                               final DataSource datasource) throws IOException 
}

Passing Streaming Content to a Java Callout:

You can pass binary-content as an input argument to a Java callout method in a streaming fashion. Oracle Service Bus handles this by checking the Java type of the input argument. If the argument is of type javax.activation.DataSource, the system creates a wrapper DataSource object and gets the InputStream from the corresponding source by invoking the Source.getInputStream() method. You can call this method as many times as you need in your Java callout code.

Bron: Oracle Fusion Middleware Online Documentation Library, 11g Release 1 (11.1.1.7), Fusion Middleware Administrator’s Guide for Oracle Service Bus

Replace Action:

Replace node contents of In Variabele body and XPath ./zkn:edcLk01/zkn:object[1]/zkn:inhoud/@stuf:bestandsnaam with outcome of Expression $bestandsnaam.

Hiermee wordt de bestandsnaam vervangen door:

<128 bit UUID><context>_<oorspronkelijke bestandsnaam>

Delete Action:

In Variabele body and XPath ./zkn:edcLk01/zkn:object[1]/zkn:inhoud/ctx:binary-content

Door bovenstaande actions wordt iets als:

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf">
  <con:binary-content ref="cid:-15258baa:15451665d79:-7bc5"/>
</inhoud>

vervangen door iets als (verkregen door het uitvragen van de body context variabele):

<inhoud b:contentType="application/rtf" a:bestandsnaam="/home/oracle/osb/attachments/squitXO/3690a3d0-6b7d-4d61-aa77-d1727d9c02ab#10_xyz.rtf"/>

Laden bestand van WebLogic applicatie server

Voordat een edcLk01 bericht inclusief document content in EDO wordt geplaatst, wordt de document content eerst geladen vanuit een directory op de WebLogic applicatie server. Pas als het laden van het bestand en het opslaan ervan in EDO succesvol is wordt het bestand verwijderd van de directory op de WebLogic applicatie server.

Dit wordt via een “Java Callout” gedaan.

Java Callout AttachmentProcessor.loadAttachment en Actions welke gebruikt zijn in de Proxy Service Message Flow

Java CalloutTypeNameExpression
Method = AttachmentProcessor. loadAttachment
Parameterjava.lang.Stringbestandsnaam$body/zkn:edcLk01/zkn:object[1]/zkn:inhoud/@stuf:bestandsnaam
Parameterjava.lang.Stringcontext$attachmentProcessorContext
ParameterbooleanenableLogging$attachmentProcessorEnableLogging
Resultjavax.activiation.DataSourcedatasource

Als context (variabele attachmentProcessorContext) wordt het bericht nummer binnen de KING Standaard Zaak-en Documentservices 1.1 gebruikt: #10

Hieronder staat de specificatie van de gebruikte class en method:

class AttachmentProcessor {

    public static DataSource loadAttachment(final String bestandsnaam,
                                            final String context,
                                            final boolean enableLogging) throws IOException
}

Streaming Content Results from a Java Callout:

You can get streaming content results from a Java callout method. Oracle Service Bus handles this by checking the Java type of the result and then adding the new source to the source repository, setting the appropriate context variable value to the corresponding ctx:binary-content XML element.

Note:

To return the contents of a file from a Java callout method, you can use an instance of javax.activation.FileDataSource.

Whenever the Oracle Service Bus pipeline needs the binary contents of the source, it looks up the DataSource object corresponding to the ctx:binary-content element in the repository and invokes the DataSource.getInputStream() method to retrieve the binary octets.

The getInputStream() method might be called multiple times during message processing, for example to accommodate outbound message retries in the transport layer.

Bron: Oracle Fusion Middleware Online Documentation Library, 11g Release 1 (11.1.1.7), Fusion Middleware Administrator’s Guide for Oracle Service Bus

Replace Action:

Replace node contents of In Variabele body and XPath ./zkn:edcLk01/zkn:object[1]/zkn:inhoud with outcome of Expression $datasource.

Assign Action:

Assign outcome of Expression $body/zkn:edcLk01/zkn:object[1]/zkn:inhoud/@stuf:bestandsnaam to variable processAttachmentBestandsnaam.

Replace Action:

Replace node contents of In Variabele body and XPath ./zkn:edcLk01/zkn:object[1]/zkn:inhoud/@stuf:bestandsnaam with outcome of Expression fn:substring-after($processAttachmentBestandsnaam,’_’).

Door bovenstaande actions wordt iets als:

<inhoud b:contentType="application/rtf" a:bestandsnaam="/home/oracle/osb/attachments/squitXO/3690a3d0-6b7d-4d61-aa77-d1727d9c02ab#10_xyz.rtf"/>

vervangen door iets als (verkregen door het uitvragen van de body context variabele):

<inhoud b:contentType="application/rtf" a:bestandsnaam="xyz.rtf"/>
  <con:binary-content ref="cid:2265ab65:1549eee2602:-7bbf" xmlns:con="http://www.bea.com/wli/sb/context"/>
</inhoud>

Java Callout AttachmentProcessor.deleteAttachment welke gebruikt is in de Proxy Service Message Flow

Java CalloutTypeNameExpression
Method = AttachmentProcessor. deleteAttachment
Parameterjava.lang.Stringbestandsnaam$processAttachmentBestandsnaam
Parameterjava.lang.Stringcontext$attachmentProcessorContext
ParameterbooleanenableLogging$attachmentProcessorEnableLogging
ResultbooleandeleteAttachmentSuccessfull

Als context (variabele attachmentProcessorContext) wordt het bericht nummer binnen de KING Standaard Zaak-en Documentservices 1.1 gebruikt: #10

Hieronder staat de specificatie van de gebruikte class en method:

class AttachmentProcessor {

    public static boolean deleteAttachment(final String bestandsnaam,
                                           final String context,
                                           final boolean enableLogging) throws IOException
}

AttachmentProcessor.java:

package nl.xyz.osb;


import com.sun.xml.internal.ws.util.ByteArrayDataSource;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Properties;
import java.util.UUID;

import javax.activation.DataSource;


public class AttachmentProcessor {

    /**
     * Processes an attachment by saving the binary content (param datasource) to a file with a filename based on param bestandnaam.
     * @param propertyFileLocation the filename and directory of the property file
     * @param bestandsnaam         the original filename of the attachment
     * @param datasource           the binary content of the attachment
     * @param context              the context for which the attachment is processed
     * @param enableLogging        indicator if logging should be enabled
     * @return                     the filename of the saved attachment
     * @throws IOException
     */
    public static String processAttachment(final String propertyFileLocation,
                                           final String bestandsnaam,
                                           final DataSource datasource,
                                           final String context,
                                           final boolean enableLogging) throws IOException {
        final Properties properties = readProperties(propertyFileLocation);
        final String targetPath = properties.getProperty("target_path");
        if ((targetPath == null) || targetPath.isEmpty()) {
            throw new IOException("Property [target_path]niet gevonden of leeg!");
        }

        final String filename =
            targetPath + UUID.randomUUID().toString() + context + "_" +
            bestandsnaam;
        FileOutputStream fileOutputStream = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date startDate = new Date();
        try {
            println("Begin of AttachmentProcessor.processAttachment",
                    enableLogging);
            println(sdf.format(startDate), enableLogging);
            println("AttachmentProcessor.processAttachment: bestandsnaam = " +
                    bestandsnaam, enableLogging);
            println("AttachmentProcessor.processAttachment: context = " +
                    context, enableLogging);
            if (datasource != null) {
                final InputStream inputStream = datasource.getInputStream();

                if (inputStream != null) {
                    fileOutputStream = new FileOutputStream(filename);

                    int total = 0;
                    int len = 0;
                    byte[] bytes = new byte[1024];

                    while ((len = inputStream.read(bytes)) != -1) {
                        fileOutputStream.write(bytes, 0, len);
                        total = total + len;
                    }
                    println("AttachmentProcessor.processAttachment: written file length = " +
                            total + " bytes", enableLogging);
                    println("AttachmentProcessor.processAttachment: filename = " +
                            filename, enableLogging);
                } else {
                    throw new IOException("InputStream/binary-content is leeg!");
                }

            } else {
                throw new IOException("Datasource/binary-content is leeg!");
            }
            println("End of AttachmentProcessor.processAttachment",
                    enableLogging);
        } catch (Exception e) {
            println("Error in AttachmentProcessor.processAttachment",
                    enableLogging);
            e.printStackTrace();
            throw new IOException(e);
        } finally {
            fileOutputStream.close();
        }

        return filename;
    }

    /**
     * Returns binary content (as datasource) of a saved attachment with a filename equal to param bestandnaam.
     * @param bestandsnaam  the filename of the attachment
     * @param context       the context for which the attachment is loaded
     * @param enableLogging indicator if logging should be enabled
     * @return              the binary content of the attachment
     * @throws IOException
     */
    public static DataSource loadAttachment(final String bestandsnaam,
                                            final String context,
                                            final boolean enableLogging) throws IOException {
        DataSource datasource = null;
        java.io.FileInputStream fileInputStream = null;
        java.io.ByteArrayOutputStream byteArrayOutputStream = null;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date startDate = new Date();
        try {
            println("Begin of AttachmentProcessor.loadAttachment",
                    enableLogging);
            println(sdf.format(startDate), enableLogging);
            println("AttachmentProcessor.loadAttachment: bestandsnaam = " +
                    bestandsnaam, enableLogging);
            println("AttachmentProcessor.loadAttachment: context = " + context,
                    enableLogging);
            fileInputStream = new java.io.FileInputStream(bestandsnaam);
            byteArrayOutputStream = new java.io.ByteArrayOutputStream();

            int total = 0;
            int len = 0;
            byte[] bytes = new byte[1024];
            while ((len = fileInputStream.read(bytes)) != -1) {
                byteArrayOutputStream.write(bytes, 0, len);
                total = total + len;
            }

            byte[] data = byteArrayOutputStream.toByteArray();

            datasource =
                    new ByteArrayDataSource(data, "application/octet-stream");
            println("AttachmentProcessor.loadAttachment: read file length = " +
                    total + " bytes", enableLogging);
            println("End of AttachmentProcessor.loadAttachment",
                    enableLogging);
        } catch (Exception e) {
            println("Error in AttachmentProcessor.loadAttachment",
                    enableLogging);
            e.printStackTrace();
            throw new IOException(e);
        } finally {
            fileInputStream.close();
        }

        return datasource;
    }

    /**
     * Returns binary content (as datasource) of a saved attachment with a filename equal to param bestandnaam.
     * @param bestandsnaam  the filename of the attachment
     * @param context       the context for which the attachment is deleted
     * @param enableLogging indicator if logging should be enabled
     * @return              indicator showing if deleting the file was successfull
     * @throws IOException
     */
    public static boolean deleteAttachment(final String bestandsnaam,
                                           final String context,
                                           final boolean enableLogging) throws IOException {
        boolean success;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date startDate = new Date();
        try {
            println("Begin of AttachmentProcessor.deleteAttachment",
                    enableLogging);
            println(sdf.format(startDate), enableLogging);
            println("AttachmentProcessor.deleteAttachment: bestandsnaam = " +
                    bestandsnaam, enableLogging);
            println("AttachmentProcessor.deleteAttachment: context = " +
                    context, enableLogging);
            success = (new File(bestandsnaam)).delete();
            println("End of AttachmentProcessor.deleteAttachment",
                    enableLogging);

        } catch (Exception e) {
            println("Error in AttachmentProcessor.deleteAttachment",
                    enableLogging);
            e.printStackTrace();
            throw new IOException(e);
        }

        return success;
    }

    /**
     * Returns properties of a property file
     * @param propertyFileLocation the filename and directory of the property file
     * @return properties
     * @throws IOException
     */
    private static Properties readProperties(final String propertyFileLocation) throws IOException {
        Properties properties = null;
        FileInputStream fileInputStream = null;

        try {
            File file = new File(propertyFileLocation);
            fileInputStream = new FileInputStream(file);
            properties = new Properties();
            properties.load(fileInputStream);
        } catch (Exception e) {
            e.printStackTrace();
            throw new IOException(e);
        } finally {
            if (fileInputStream != null) {
                fileInputStream.close();
            }
        }

        return properties;
    }

    /**
     * Print a text if enableLogging is true
     * @param s             the text to print
     * @param enableLogging indicator if logging should be enabled
     */
    private static void println(final String s, final boolean enableLogging) {
        if (enableLogging) {
            System.out.println(s);
        }
    }
}
Share this on .. Tweet about this on TwitterShare on LinkedIn2Share on Facebook0Share on Google+1Email this to someoneShare on Tumblr0Buffer this page

About Author

Marc, active in IT (and with Oracle) since 1995, is a Senior Oracle SOA Consultant with focus on Oracle Service Bus, Oracle SOA Suite, Java and Oracle Database (SQL & PL/SQL). Over the past 20 years he has worked for several customers in the Netherlands. Marc likes to share his knowledge through publications, blog’s and presentations.

1 Comment

  1. All of these tips are great, that’s very interesting. I’m so tempted to try that myself, but you would think if it were effective, more people would do it.

Leave A Reply