Featured Posts

books, osb

Oracle Service Bus 11g Development Cookbook has been published!

Good news today from the publisher!
The book of which i’m coauthor of has been published! After months of hard work it’s finally there.

Oracle Service Bus 11g Development Cookbook : http://www.packtpub.com/oracle-service-bus-11g-development-cookbook/book

I hope you will all like it.

Thanks to the other authors (Guido, Edwin, Jan and Mischa) for all their hard work and for the great few months of working together to establish this great piece of work.
Special thanks go out to Guido for guiding the whole process of making this book. All the hours of hard work and organizing everything, i hope it was worth it!

The book

Something about the book (which i nicely copy/pasted from Guido his blog)

The book contains more than 80 practical recipes to develop service- and message-oriented solutions on the Oracle Service Bus 11g.

This cookbook is full of immediately usable recipes showing how to efficiently develop on the Oracle Service Bus. In addition to its cookbook style, which ensures the solutions are presented in a clear step-by-step manner, the explanations go into great detail, which makes it good learning material for everyone who has experience with the OSB and wants to improve. Most of the recipes are designed in such a way that each recipe is presented as a separate, standalone entity and reading of prior recipes is not required. The finished solution of each recipe is also made available electronically.

The 80+ recipes are organized into the following chapters (the digit behind the title showing the number of recipes in that chapter):

  • Creating a basic OSB service (13)
  • Working efficiently with OSB artifacts in Eclipse OEPE (7)
  • Messaging with JMS transport (9)
  • Using EJB and JEJB transport (5)
  • Using HTTP transport (5)
  • Using File and Mail transports (5)
  • Using JCA adapter to communicate to the database (6)
  • Using SOA Direct transport to communicate with SOA Suite (4)
  • Communication, Flow Control and Message Processing (10)
  • Reliable communication with OSB (5)
  • Handling Message-Level Security requirements (9)
  • Handling Transport-Level Security requirements (4)

Happy reading!

Reviews

AMIS blog : Review of Oracle Service Bus 11g Development Cookbook (Packt Publishing) by Edwin Biemond, Guido Schmutz, Eric Elzinga et. al.
SOA@Oracle SCA, BPEL, BPM & Service Bus blog

Popularity: 2% [?]

osb

Oracle Service Bus : Using custom xpath functions in xslt

One of the readers of my blog post ‘Oracle Service Bus 11g, Using Custom Xpath Functions asked we can reuse the custom xpath functions in a xsl transformation.

It’s possibel to reuse the jar and calll the custom functions from within a xsl transformation.

Starting with creating the resources needed for the custom xpath function :

  1. XML Configuration file (osb-custom.xml)
  2. Property file (optional, osb-custom.properties)
  3. Custom Function Class (jar package)

Restart the osb service so the new jar will get loaded.

- Create a new osb project
- Create a new xslt

	<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:cust="xalan://nl.xenta.osb.custom.functions.OsbUtils">
		<xsl:variable name="param1" select="string('the beginning')"/>
		<xsl:variable name="param2" select="string('the end')"/>
		<xsl:template match="/">
			<xsl:variable name="my_custom_concat" select="cust:customConcat($param1,$param2)" />
			<the_result><xsl:value-of select="$my_custom_concat"/></the_result>
		</xsl:template>
	</xsl:stylesheet>

To be able to call a custom xpath function with the Xalan engine we need to add a new namespace_prefix + definition the the xsl

xmlns:cust="xalan://tests.pipeline.CustomXQFunctions"

- Start with xalan://
- Then the java package + classname, nl.xenta.osb.custom.functions.OsbUtils
- In the select of the value-of we eventually use the namespace-prefix + java method interface to call the java method, cust:customConcat($param1,$param2)

Create a new proxy service and use the xsl in for example an assing activity.
Deploy the service and use the testconsole to test it.

Popularity: 2% [?]

soasuite

Oracle SOA Suite : import in xsl from mds location

In one of my xsl transformations i needed to import a generic xsl from the mds store.
For this i created a new jdeveloper application with a soa sar deployment descriptor and jar descriptor in it.

Contents of the jar :

	SharedMDSResources/generic.xsl

When i browse the mds repository i see the SharedMDSResources folder in the root of the tree (instead of in the apps folder).

For testing i deployed the jar manually in the EM.


In my xsl i use the next import :

  <xsl:import href="oramds:/SharedMDSResources/generic.xsl"/>

Resulting in the next stacktrace :

The following exception occurred while attempting to execute operation copy at line 389
<exception class="com.collaxa.cube.xml.xpath.XPathException">
<parsererror style="display: block; white-space: pre; border: 2px solid #c77; padding: 0 1em 0 1em; margin: 1em; background-color: #fdd; color: black">
<h3>This page contains the following errors:</h3>
<div style="font-family:monospace;font-size:12px">
error on line 7 at column 1: Extra content at the end of the document
</div>
<h3>Below is a rendering of the page up to the first error.</h3>
</parsererror>
XPath expression failed to execute.
An error occurs while processing the XPath expression; the expression is ora:doXSLTransformForDoc('xsl/format_dates.xsl', $csvXml).
The XPath expression failed to execute; the reason was: XML-22000: (Fatal Error) Error while parsing XSL file (oramds:/deployed-composites/default/mycomposite_rev1.0/xsl/my_process.xsl<Line 3, Column 46>: XML-22002: (Fatal Error) Error while processing include XSL file (oramds:/SharedMDSResources/generic.xsl).)..
Check the detailed root cause described in the exception message text and verify that the XPath query is correct.
<stack>
<f>com.collaxa.cube.xml.xpath.BPELXPathUtil.evaluate#262</f>
<f>com.collaxa.cube.engine.ext.bpel.common.BPELWMPHelper.evalFromValue#339</f>
<f>com.collaxa.cube.engine.ext.bpel.v1.wmp.BPEL1AssignWMP.__executeStatements#137</f>
<f>com.collaxa.cube.engine.ext.bpel.common.wmp.BaseBPELActivityWMP.perform#158</f>
<f>com.collaxa.cube.engine.CubeEngine._performActivity#2463</f>
<f>com.collaxa.cube.engine.CubeEngine.performActivity#2334</f>
<f>com.collaxa.cube.engine.CubeEngine.handleWorkItem#1115</f>
<f>com.collaxa.cube.engine.dispatch.message.instance.PerformMessageHandler.handleLocal#73</f>
<f>com.collaxa.cube.engine.dispatch.DispatchHelper.handleLocalMessage#220</f>
<f>com.collaxa.cube.engine.dispatch.DispatchHelper.sendMemory#328</f>
<f>com.collaxa.cube.engine.CubeEngine.endRequest#4350</f>
<f>com.collaxa.cube.engine.CubeEngine.endRequest#4281</f>
<f>com.collaxa.cube.engine.CubeEngine.createAndInvoke#679</f>
<f>com.collaxa.cube.engine.delivery.DeliveryService.handleInvoke#654</f>
<f>com.collaxa.cube.engine.ejb.impl.CubeDeliveryBean.handleInvoke#293</f>
<f>sun.reflect.GeneratedMethodAccessor944.invoke</f>
<f>...</f>
</stack>
</exception>

Problem

Since i deployed the jar manually from within the EM the SharedMDSResources folder will not be created in the apps-dir but in the root of the tree.
The oramds imports can only import from within the apps folder structure.

Solution

When manually creating the jar archive make sure the contributor has the apps-directory already in the path

Path : d:\SharedMDS\apps\SharedMDSResources\

After the import the mds repository will contain the path ‘oramds:/apps/SharedMDSResources/generic.xsl’

Or keep the jar as it was (folder/file structure = SharedMDSResources/generic.xsl) and use the scripts from for example Edwin and setup the ‘mds.reposistory’ correctly (ending with the apps-directory in it).

Popularity: 2% [?]

oracle

Invitation to Fusion Middleware Partner Community Forum

INVITATION TO


FUSION MIDDLEWARE PARTNER COMMUNITY FORUM 
SOA & WebCenter & BPM & WebLogic Partner Communities

Do you want to learn about how to sell the value of Fusion Middleware by combining SOA, BPM and WebCenter Solutions?

We would like to invite you to become updated and trained at our Fusion Middleware Partner Community Forum on February 7th and 8th 2011 at the NH Hotel in Malaga, Spain.



The event is a wonderful opportunity to:
  • learn how to sell the value of Fusion Middleware by combining SOA and WebCenter solutions
  • meet with Oracle SOA, BPM and WebCenter Product management
  • exchange knowledge and have access to competitive intelligence
  • learn from successful SOA, BPM, WebCenter and ADF implementations
  • learn about WebCenter Sites
  • network within the Oracle SOA Partner Community and the Oracle WebCenter Partner Community
During this highly informative event you can learn about partner success stories, participate in an array of break out sessions and exchange information with other partners.

Popularity: 2% [?]

osb

Oracle Service Bus, Request Entity Too Large

In the osb we use business services (http transport + wsdl) to call our composites on the soa suite.
In a few situations the routing in the osb fail with the next error

<con:fault xmlns:con="http://www.bea.com/wli/sb/context">
	<con:errorCode>BEA-380000</con:errorCode>
	<con:reason>Request Entity Too Large</con:reason>
	<con:location>
		<con:node>RouteNodeLeesDeclaratieCompleet</con:node>
		<con:path>response-pipeline</con:path>
	</con:location>
</con:fault>

Looking in the list of instances in the soa suite we see the instances over there just complete in a valid way but still the routing in the osb fails.

Solution

  • Go to the configuration of the business service
  • Go to the HTTP Transport tab
  • Disable “Use Chunked Streaming Mode”

See also this blog for some extra explanation

Popularity: 2% [?]

osb

Oracle Service Bus, Generic fault handling

For a usecase i needed a construction which would give me the option to implemenent generic service error handling in which i could conditionally execute activities like alerts, reports, logging, etc
One place which will contain all the error handling logic and which could be easily extended both in implementation of the logic for handling errors and being able to easily add new errors to be handle which the metadata for this error.

In case third party applications decide to trigger new type of exceptions/faults i don’t want to change the fault handling logic of all the process which do a call to this service. I want to be able to add the to be executed logic for this new specific error to some sort of error repository together with some setup-settings.

Definition of the error repository
In our case the error repository is nothing more then a xml metadata storage which stores settings for the errors to be handled.
The definition of the metadata can be extended with other settings which can be retrieved at one central place again and logic for handling the settings will also be centrally defined.

Definition of the error handling service
In our case the error handling service will be the central point in which we retrieve instance data from the process in which the occured fault.
Based on this data we will retrieve metadata for the fault and decide in the message flow handling what the logic will be to execute.

Error Repository

Schema definition

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://nl.xenta/services/errorRepository" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://nl.xenta/services/errorRepository">
	<xs:element name="service_error_handling">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="error" maxOccurs="unbounded"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="indReporting">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="Y"/>
				<xs:enumeration value="N"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="description">
		<xs:simpleType>
			<xs:restriction base="xs:string"/>
		</xs:simpleType>
	</xs:element>
	<xs:element name="sourceSystem">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="SYSTEM-X"/>
				<xs:enumeration value="OSB"/>
				<xs:enumeration value="NA"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="indLogging">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="Y"/>
				<xs:enumeration value="N"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="faultTransformer">
		<xs:simpleType>
			<xs:restriction base="xs:string"/>
		</xs:simpleType>
	</xs:element>
	<xs:element name="externalCode">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="XXX_DEFAULT_ERROR"/>
				<xs:enumeration value="GENERIC-1234"/>
				<xs:enumeration value="VALIDATE-9999"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="error">
		<xs:complexType>
			<xs:sequence>
				<xs:element ref="code"/>
				<xs:element ref="externalCode"/>
				<xs:element ref="description"/>
				<xs:element ref="sourceSystem"/>
				<xs:element ref="faultTransformer"/>
				<xs:element ref="indAlert"/>
				<xs:element ref="indAlertOverwriteDestionation"/>
				<xs:element ref="alertDestination"/>
				<xs:element ref="indLogging"/>
				<xs:element ref="indReporting"/>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
	<xs:element name="code">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="BEA-382505"/>
				<xs:enumeration value="DEFAULT"/>
				<xs:enumeration value="BEA-380000"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="indAlertOverwriteDestionation">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="Y"/>
				<xs:enumeration value="N"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="indAlert">
		<xs:simpleType>
			<xs:restriction base="xs:string">
				<xs:enumeration value="Y"/>
				<xs:enumeration value="N"/>
			</xs:restriction>
		</xs:simpleType>
	</xs:element>
	<xs:element name="alertDestination">
		<xs:complexType/>
	</xs:element>
</xs:schema>

Modeling the error handling proxy service

The error handling proxy service will be the central point of executing location based on the incoming occured fault.

  • Create a new proxy service called ErrorHandler of Service Type ‘Any XML Service’

    The input we will send to this service will be in the format of

    <errorData>
    	<body>{$body}</body>
    	<inbound>{$inbound}</inbound>
    	<fault>{$fault}</fault>
    </errorData>
    

    The flow will eventually look something like this

    Let’s look at the individual steps

    1. retrieveErrorMetadata

    The first step will contain 2 assigns.

    The first assign will assign the ErrorRepository.xq to variable errorList

    The content of the ErrorRepository.xq is the next

    xquery version "1.0" encoding "Cp1252";
    (:: pragma  type="xs:anyType" ::)
    
    declare namespace xf = "http://nl.xenta/services/errorRepository";
    
    declare function xf:service_error_handling()
        as element(*) {
    		<service_error_handling xmlns="http://nl.xenta/services/errorRepository" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    			<error>
    				<code>BEA-382505</code>
    				<externalCode>VALIDATE-9999</externalCode>
    				<description>Validation of the XML payload failed</description>
    				<sourceSystem>OSB</sourceSystem>
    				<faultTransformer>ErrorHandling/errorRepository/GenericFault_To_SOAPFault</faultTransformer>
    				<indAlert>Y</indAlert>
    				<indAlertOverwriteDestionation>N</indAlertOverwriteDestionation>
    				<alertDestination/>
    				<indLogging>Y</indLogging>
    				<indReporting>Y</indReporting>
    			</error>
    			<error>
    				<code>BEA-380000</code>
    				<externalCode>GENERIC-1234</externalCode>
    				<description>General transport error occured</description>
    				<sourceSystem>SYSTEM-X</sourceSystem>
    				<faultTransformer>ErrorHandling/errorRepository/GenericFault_To_SOAPFault2</faultTransformer>
    				<indAlert>Y</indAlert>
    				<indAlertOverwriteDestionation>N</indAlertOverwriteDestionation>
    				<alertDestination/>
    				<indLogging>Y</indLogging>
    				<indReporting>Y</indReporting>
    			</error>
    			<error>
    				<code>DEFAULT</code>
    				<externalCode>XXX_DEFAULT_ERROR</externalCode>
    				<description>Something went wrong!</description>
    				<sourceSystem>NA</sourceSystem>
    				<faultTransformer>ErrorHandling/errorRepository/GenericFault_To_SOAPFault</faultTransformer>
    				<indAlert>Y</indAlert>
    				<indAlertOverwriteDestionation>N</indAlertOverwriteDestionation>
    				<alertDestination/>
    				<indLogging>Y</indLogging>
    				<indReporting>Y</indReporting>
    			</error>
    		</service_error_handling>
    };
    
    xf:service_error_handling()
    

    At this point we have the list of faults together with metadata about what to execute when they occure available in the Message Flow.

    In the second assign we retrieve only the the metadata from our occured fault, so we just retrieve 1 error-element from the list.

    For this we execute the lookupError xquery which receives the errorList content and the errorCode and will return the error-element.
    If we can’t retrieve any metadata based on the errorCode we will return a default set of metadata (the error-element of which the code = DEFAULT).
    The result we will assign to the errorMetadataDetails variable.

    Content of lookupError xquery

    (:: pragma bea:global-element-parameter parameter="$errorList" element="err:service_error_handling" location="ErrorRepository.xsd" ::)
    (:: pragma bea:global-element-return element="ns0:error" location="ErrorRepository.xsd" ::)
    
    declare namespace err = "http://nl.xenta/services/errorRepository";
    declare namespace xf = "http://nl.xenta/services/faults/lookupError/";
    
    declare function xf:lookupError2($errorCode as xs:string,
        $errorList as element(err:service_error_handling))
        as element(err:error) {
    
    		if(string-length($errorList/err:error[err:code=$errorCode]) > 0)
       		then (
    			let $resolvedError := $errorList/err:error[err:code=$errorCode]
    	   		return $resolvedError
       		) else (
       			let $resolvedError := $errorList/err:error[err:code='DEFAULT']
       			return $resolvedError
       		)
    };
    
    declare variable $errorCode as xs:string external;
    declare variable $errorList as element(err:service_error_handling) external;
    
    xf:lookupError2($errorCode,$errorList)
    

    2. conditionalReporting

    In all the conditional stages we will now re-use the errorMetadataDetails variable to verify if we want to execute certain login.

    If we configurated the indReporting=Y in the error repository xquery file then the if-then loginc will evaluate to the if-tree and the Report-activty will be executed.
    In the same way all the other condition stages (conditionalAlert, conditionalSomethingElse) will work. We re-use the errorMetadataDetails-variable and just do a simple if-then check to see if certain logic needs to be executed.

    3. constructResponse

    The last step of the message flow is the step in which we construct the response of the errorHandler process back to the client process.
    In this step we will be using Dynamic Xquery to be able the construct response messages based on the incoming fault.
    The example of our ErrorReposity defines 2 faults and 1 default.
    In case for example error BEA-380000 occures, we will use the xquery located at ErrorHandling/errorRepository/GenericFault_To_SOAPFault2 to be executed. This xquery will construct our soap fault.

    To be able to use Dynamic Xquery all the to be used xquery transformations need to have the same interface. Depending on the backend system and the returning faults from it we will use different tranformation files.
    But all of them will be using the input paramters ‘body, inbound and fault’. In the expression field we will use the faultTransformer-element from the errorMetadataDetails. So for every fault for which we want to create a
    different fault response we do need to define a faultTransformer-value in the errorRepository.

    And that’s all what is needed to implement in the errorHandler process to receive the metadata, handle the fault and construct the response.

    Testcase

    For this testcase we created a simple EmployeeService. Create a new proxy service based on the next wsdl/xsd content.

    <?xml version="1.0" encoding="UTF-8"?>
    <wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://new.webservice.namespace" xmlns:ns="http://nl.xenta/services/employee" targetNamespace="http://new.webservice.namespace">
    	<wsdl:import namespace="http://nl.xenta/services/employee" location="EmployeeService.xsd"/>
    	<wsdl:message name="NewMessageRequest">
    		<wsdl:part name="parameter" element="ns:employee_request"/>
    	</wsdl:message>
    	<wsdl:message name="NewMessageResponse">
    		<wsdl:part name="parameter" element="ns:employee_response"/>
    	</wsdl:message>
    	<wsdl:portType name="EmployeeServicePort">
    		<wsdl:operation name="getEmployee">
    			<wsdl:input message="tns:NewMessageRequest"/>
    			<wsdl:output message="tns:NewMessageResponse"/>
    		</wsdl:operation>
    	</wsdl:portType>
    	<wsdl:binding name="EmployeeServiceBinding" type="tns:EmployeeServicePort">
    		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    		<wsdl:operation name="getEmployee">
    			<soap:operation soapAction="urn:#NewOperation"/>
    			<wsdl:input>
    				<soap:body use="literal"/>
    			</wsdl:input>
    			<wsdl:output>
    				<soap:body use="literal"/>
    			</wsdl:output>
    		</wsdl:operation>
    	</wsdl:binding>
    	<wsdl:service name="EmployeeService">
    		<wsdl:port name="EmployeeServiceSOAPPort" binding="tns:EmployeeServiceBinding">
    			<soap:address location="No Target Adress"/>
    		</wsdl:port>
    	</wsdl:service>
    </wsdl:definitions>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://nl.xenta/services/employee" attributeFormDefault="unqualified">
    	<xs:element name="employee_request">
    		<xs:annotation>
    			<xs:documentation>Comment describing your root element</xs:documentation>
    		</xs:annotation>
    		<xs:complexType>
    			<xs:sequence>
    				<xs:element name="emp_id" type="xs:int"/>
    			</xs:sequence>
    		</xs:complexType>
    	</xs:element>
    	<xs:element name="employee_response">
    		<xs:complexType>
    			<xs:sequence>
    				<xs:element name="employee">
    					<xs:complexType>
    						<xs:sequence>
    							<xs:element name="firstname"/>
    							<xs:element name="lastname"/>
    							<xs:element name="birthdate" type="xs:date"/>
    						</xs:sequence>
    					</xs:complexType>
    				</xs:element>
    			</xs:sequence>
    		</xs:complexType>
    	</xs:element>
    </xs:schema>
    

    And the message flow will eventually look like this

    The first assign will assign the body to body_temp so in case of an error situation we still have the original body content stored

    The second activity is the validation activity. This one we will be using lateron to trigger a fault which will be processed by the errorHandler process.
    Based on the same wsdl as the proxy service i defined a new business service. In the EmployeeService proxy we will be routing to this business service.
    Since we won’t be implementing any logic on this side we just update the endpoint of the business service to something useless so the route will fail on this one.

    This part is used to the second fault triggering moment in our process. Also this situation will fail and the occured fault will get processed by the errorHandler.

    The ‘normal’ message flow of our proxy service is now done.
    Let’s have a look at the service error handler.

    The first assign will use the next xquery and assign the result to errorhandler_request

    xquery version "1.0" encoding "Cp1252";
    (:: pragma  parameter="$body" type="xs:anyType" ::)
    (:: pragma  parameter="$fault" type="xs:anyType" ::)
    (:: pragma  parameter="$inbound" type="xs:anyType" ::)
    (:: pragma  type="xs:anyType" ::)
    
    declare namespace xf = "http://tempuri.org/ErrorHandling/proxy/constructErrorHandlingInput/";
    
    declare function xf:constructErrorHandlingInput($body as element(*),
        $fault as element(*),
        $inbound as element(*))
        as element(*) {
            <errorData>
    			<body>{$body}</body>
    			<inbound>{$inbound}</inbound>
    			<fault>{$fault}</fault>
    		</errorData>
    };
    
    declare variable $body as element(*) external;
    declare variable $fault as element(*) external;
    declare variable $inbound as element(*) external;
    
    xf:constructErrorHandlingInput($body, $fault, $inbound)
    

    In the binding we will use the body_temp variable so we have the original body content of the process.

    The next activity is the service callout to the errorHandler process

    The third activity is an assign which will assign the constructed body from the errorHandler process to the body variable

    And the last activity will be a ‘Reply with Failure’

    Testrun

    In the ErrorRepository we defined 2 faults, BEA-382505 and BEA-380000.
    For both faults we defined a different faultTransformer.

    BEA-382505 = ErrorHandling/errorRepository/GenericFault_To_SOAPFault
    BEA-380000 = ErrorHandling/errorRepository/GenericFault_To_SOAPFault2

    GenericFault_To_SOAPFault will return

    		<soapenv:Fault>
    		<faultcode>soapenv:Server</faultcode>
    		(:<faultstring>{data($errorMetadataDetails/err:omschrijving)}</faultstring>:)
    		<faultstring>some resource path</faultstring>
    		<faultactor>{fn:concat($inbound/ctx:transport/ctx:request/tp:headers/http:Host/text(),"/",$inbound/ctx:transport/ctx:uri/text())}</faultactor>
    		   <detail>
    				<custom_details>
    					<payload>{$body, $fault, $inbound}</payload>
    				</custom_details>
    		   </detail>
    		</soapenv:Fault>
    

    GenericFault_To_SOAPFault2 will return

    		<soapenv:Fault>
    		<faultcode>soapenv:Server</faultcode>
    		(:<faultstring>{data($errorMetadataDetails/err:omschrijving)}</faultstring>:)
    		<faultstring>some resource path</faultstring>
    		<faultactor>{fn:concat($inbound/ctx:transport/ctx:request/tp:headers/http:Host/text(),"/",$inbound/ctx:transport/ctx:uri/text())}</faultactor>
    		   <detail>
    				<custom_details2>
    				  <payload>{$body, $fault, $inbound}</payload>
    				</custom_details2>
    		   </detail>
    		</soapenv:Fault>
    

    Deploy the process.

    Now test the process either by using the testconsole of some testclient.

    The first testcase will have a valid input message. So the process will pass the Validation activity and will fail when routing to the business service.
    Since we used a non-existing host in here the process will trigger a BEA-380000 fault. As we defined in the errorRepository this errorCode will have the next set of metadata configured

    			<error>
    				<code>BEA-380000</code>
    				<externalCode>GENERIC-1234</externalCode>
    				<description>General transport error occured</description>
    				<sourceSystem>SYSTEM-X</sourceSystem>
    				<faultTransformer>ErrorHandling/errorRepository/GenericFault_To_SOAPFault2</faultTransformer>
    				<indAlert>Y</indAlert>
    				<indAlertOverwriteDestionation>N</indAlertOverwriteDestionation>
    				<alertDestination/>
    				<indLogging>Y</indLogging>
    				<indReporting>Y</indReporting>
    			</error>
    

    The generated soap fault is correct. It contains the custom_details2-element, which is generated by the GenericFault_To_SOAPFault2 transformer.
    Next check the sbconsole to see if there is also a report triggered for this error (indReporting=Y).

    Next check the weblogic console to see if the alert got executed (indAlert=Y). For this one i created an alert with JMS Destionation.

    For the second testcase we will use an invalid input message. The validation will throw an error (BEA-382505).
    Check the generated soap fault (custom_details-element should get generated now).

    And verify the alert and report too, to see if they got handled correctly.

    Extensibility

    In our xsd definition of the errorRepository we only defined a few settings just to show how it could work.
    Eventually this model can be extend with every setting you need in your error handling processes. Since all the logic of reading those settings and decide what logic to execute is defined on only
    one place, the errorHandler proxy service itself, it’s little work to extend the current logic for handlin the errors with new functionality. Just a new if-then activities for new settings and you’re ready to go.

    Conclusion

    The functionality as defined in the blog for handling the errors and creating a single point of error processing was enough for my testcase.
    I needed all the logic on one place and not in every process. I needed a single place in which i could define all the errors i wanted to handle and what actions to execute when such an error occurs.
    Besides that i needed a way in which other persons could easily add new defined errors to the file and the process would just ‘handle’ them without adding extra logic to processes.
    In case you don’t want someone else to manipulate the errorRepository file directly from within the sbconsole itself we could also just read the content of this file from some other external location by use of the doc() function, see this blog.

    I hope the solution described will help you a bit on implementation error handling in the Oracle Service Bus.
    As i’m always keen on learning from others, please leave comments on how to make the implementation better, or if the solution is totally useless please say so too :)

    download : OracleServiceBusGenericErrorHandling.zip

    Popularity: 8% [?]

  • osb

    Oracle Service Bus, The number of parameters for registered XQuery resource System1_To_Fault does not match that given to it at runtime

    To be able to make use of Dynamic Xquery the xqueries itself all need to have the same defined interface.

    So after defining the different xqueries and test them one by one in Eclipse all seem to work.
    On runtime i get the next error :

    The number of parameters for registered XQuery resource System1_To_Fault does not match that given to it at runtime
    

    I was pretty sure after logging all the binded input variables they were all containing data.

    Lesson learned : Make sure you both bind all the variables but also ‘use’ them in the xquery itself.
    OSB will return this fault either when you don’t bind all the variables but also if you don’t use all of them in the xquery

    xquery1 fragment (will work):

    xquery version "1.0" encoding "Cp1252";
    
    declare function xf:System1_To_Fault(
        $metadata1		      as xs:string,
        $metadata2		      as xs:string,
    	$metadata3		      as xs:string)
        as element(soapenv:Fault) {
    		<soapenv:Fault>
    		<faultcode>soapenv:Server</faultcode>
    		<faultstring>some description</faultstring>
    		<faultactor>some string to the resource</faultactor>
    		   <detail>
    				<info1>{$metadata1}</info1>
    				<info2>{$metadata2}</info3>
    				<info3>{$metadata1}</info3>
    		   </detail>
    		</soapenv:Fault>
    };
    
    declare variable $metadata1 as xs:string external;
    declare variable $metadata2 as xs:string external;
    declare variable $metadata3 as xs:string external;
    
    xf:System1_To_Fault($metadata1, $metadata2, $metadata3)
    

    xquery2 fragment (will fail):

    		<soapenv:Fault>
    		<faultcode>soapenv:Server</faultcode>
    		<faultstring>some description</faultstring>
    		<faultactor>some string to the resource</faultactor>
    		   <detail>
    				<info1>{$metadata1}</info1>
    				<info2>{$metadata2}</info2>
    				<info3/>
    		   </detail>
    		</soapenv:Fault>
    

    inputvariable ‘metadata3′ isn’t used in the xquery itself, so the dynamix xquery will fail on runtime
    either make sure you always use all the input variables in the xquery (or do an expression on it, for example assign it to an temp variable but don’t use it for generating your target xml)
    something like this

        	let $temp := $metadata3
        	return
       			<soapenv:Fault>
    			<faultcode>soapenv:Server</faultcode>
    			<faultstring>some description</faultstring>
    			<faultactor>some string to the resource</faultactor>
    		   	<detail>
    				<info1>{$metadata1}</info1>
    				<info2>{$metadata2}</info2>
    				<info3/>
    		   	</detail>
    			</soapenv:Fault>
    

    I’m not sure what this assign will do (performance-wise) when you assign a big dom-tree variable, in that case you could just assign the deepest childnode to the temp variable.
    Eventually it’s just a dirty fix to be able to use the xqueries in combination with dynamic xquery and still be able to not use all of the incoming parameters.

    Popularity: 2% [?]

    osb

    Oracle Service Bus, processing Java Object Messages with JMS transport

    A few releases back Oracle enhanced to JMS transport to be able to handle Java Objects in queues and topic. The JMS transport now has the option to either receive Java Objects in the OSB processes by retrieving them from a topic or queue, or storing the plain Java Objects.

    First we need to create a new queue in Weblogic, in my case QueueuIn.

    1. Create the java entity object

    Create the next entity object

    package nl.xenta.entities;
    
    import java.io.Serializable;
    
    public class Employee  implements Serializable {
    
    	private static final long serialVersionUID = -5802550970297576366L;
    	public String firstname;
    	public String lastname;
    	public Integer age;
    
    	public String getFirstname() {
    		return firstname;
    	}
    	public void setFirstname(String firstname) {
    		this.firstname = firstname;
    	}
    	public String getLastname() {
    		return lastname;
    	}
    	public void setLastname(String lastname) {
    		this.lastname = lastname;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    }
    

    Build it and generate a jar file from it.

    2. Client to send Java Object Message

    package nl.xenta.utilities;
    
    import java.util.Hashtable;
    
    import javax.jms.Message;
    import javax.jms.ObjectMessage;
    import javax.jms.Queue;
    import javax.jms.QueueConnection;
    import javax.jms.QueueConnectionFactory;
    import javax.jms.QueueReceiver;
    import javax.jms.QueueSender;
    import javax.jms.QueueSession;
    import javax.jms.Session;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    
    import nl.xenta.entities.Employee;
    import nl.xenta.entities.Person;
    import nl.xenta.services.EmployeeService;
    
    public class JmsHelper {
    
    	public final static String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
    	public final static String JMS_FACTORY = "javax.jms.QueueConnectionFactory";
    	public final static String QUEUE = "QueueIn";
    
    	static QueueConnectionFactory factory;
    	static QueueConnection qconnection;
    	static QueueSession qsession;
    	static QueueReceiver qreceiver;
    	static Queue queue;
    	static Context ctx;
    	private boolean quit = false;
    
    	/**
    	 * @param args
    	 * @throws Exception
    	 */
    	public static void sendMessage() throws Exception {
    		QueueConnection queueCon = null;
    		try {
    			// get the initial context, refer to your app server docs for this
    			Hashtable<String, String> ht = new Hashtable<String, String>();
    			ht.put(Context.INITIAL_CONTEXT_FACTORY,
    					"weblogic.jndi.WLInitialContextFactory");
    			ht.put(Context.PROVIDER_URL, "t3://localhost:7001");
    			Context ctx = new InitialContext(ht);
    
    			// get the connection factory, and open a connection
    			QueueConnectionFactory qcf = (QueueConnectionFactory) ctx
    					.lookup("weblogic/jms/XAConnectionFactory");
    			queueCon = qcf.createQueueConnection();
    
    			// create queue session off the connection
    			QueueSession queueSession = queueCon.createQueueSession(false,
    					Session.AUTO_ACKNOWLEDGE);
    
    			// get handle on queue, create a sender and send the message
    			Queue queue = (Queue) ctx.lookup(QUEUE);
    			QueueSender sender = queueSession.createSender(queue);
    
    			// create employee object
    			Employee emp = new Employee();
    			emp.setAge(32);
    			emp.setFirstname("Eric");
    			emp.setLastname("Elzinga");
    
    			// send java object to queue
    			Message msg = queueSession.createObjectMessage(emp);
    			sender.send(msg);
    
    			System.out.println("Send Java Object Message");
    		} finally {
    			// close the queue connection
    			if (queueCon != null) {
    				queueCon.close();
    			}
    		}
    	}
    }
    

    Execute the jms java client to create Employee object and store it on the QueueIn queue.
    Go to the Weblogic Console to see if the message arrived in the QueueIn queue.

    When we now click on the message it will give the next message

    	Unable to view message, reason = java.lang.ClassNotFoundException: nl.xenta.entities.Employee
    

    Copy the builded jar from step1 (the jar with the compiled Employee class in it) to the next location

    	YOUR_MIDDLEWARE_HOME/user_projects/domains/osb_domain/lib
    

    Restart Weblogic and try viewing the message in the console again.

    Great, it worked. Now we can see a Employee object is stored in the queue.
    Let’s go on with the OSB part.

    3. Oracle Service Bus Proxy Service

    1. First copy the jar created in step 2 to our OSB project.
    2. Create a new Messaging Proxy Service
    3. Select ‘Java’ for Request Message Type
    4. Use jms protocol and configure the endpoint (use the just created queue)

      Select Queue for Destination Type

      Configure the Client Jar and browse to the jar file generated in step 2.

      If we skip this settings the proxyservice won’t be able to deserialize the java objects retrieved from the queue. Resulting in stacktraces like this

      ####<Aug 28, 2011 10:23:56 AM CEST> <Error> <OSB Kernel> <multimedia> <AdminServer> <[ACTIVE] ExecuteThread: '26' for queue: 'weblogic.kernel.Default (self-tuning)'> <<anonymous>> <BEA1-03E7A5A49D452A912D4B> <1bf9ba3a756c6ce8:6b05e983:1320f4d10ed:-8000-00000000000000bb> <1314519836078> <BEA-380003> <Exception on TransportManagerImpl.receiveMessage, com.bea.wli.sb.context.BindingLayerException: General runtime error: [JMSClientExceptions:055115]Error deserializing an object
      com.bea.wli.sb.context.BindingLayerException: General runtime error: [JMSClientExceptions:055115]Error deserializing an object
      
      Caused By: java.lang.ClassNotFoundException: nl.xenta.entities.Employee
      	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
      
    5. Create the Message Flow as defined in the picture and only add a log activity, which logs the body.

    Deploy the process and use the JmsHelper client to create an Employee object and send it to the queue.
    The proxy service will poll, get it out of the queue and basically does nothing with it except logging the body.
    After the message is send, check the osb domain log file to see what’s in the $body variable.

    <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### debug logging $body ###: <soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
      <con:java-content ref="jcid:4c741db6:131dd1e4544:-7fc5" xmlns:con="http://www.bea.com/wli/sb/context"/>
    </soapenv:Body>>
    

    The java object is retrieved from the queue and processed by the proxy service.
    But when we look in the body we don’t see any ‘actual’ payload, only a java ref to the java object itself.

    Let’s use a few java callouts to see how we can use the content of the java object.

    4. Proxyservice, java callout, java (object) in, string out

    Extend the java project from step1.
    Create a new class (EmployeeService) with the next method (convertEmployeeToString) in it

    package nl.xenta.services;
    
    import java.io.File;
    import java.io.IOException;
    
    import org.apache.xmlbeans.XmlException;
    import org.apache.xmlbeans.XmlObject;
    import org.apache.xmlbeans.XmlOptions;
    
    import nl.xenta.crm.employee.EmployeeDocument;
    import nl.xenta.crm.employee.EmployeeType;
    import nl.xenta.entities.Employee;
    import nl.xenta.entities.Person;
    
    public class EmployeeService {
    
    	public static String convertEmployeeToString(Employee employee) {
    		return employee.toString();
    	}
    }
    

    The input Employee object will be the data from the queue and as response we just return the string value of the object.
    Generate a jar archive from it and store it in your OSB project.

    Add the java callout to your proxy service message flow and after it add the log activity.
    The log activity will just log the value of $my_string_response.

    Now trigger the process again by sending a message with the JmsHelper client and check the osb log file.

    <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging string response after the java callout ###: Employee [firstname=Eric, lastname=Elzinga, age=32]>
    

    Read this for some extra information about the java callouts and their input and return types.
    “The input and return types for Java callouts are not restricted. However, any return types other than primitives, Strings, or XmlObjects can only be passed (unmodified) to other Java callouts.”
    In this example we get a String returned, so we can just retrieve the value of it in the message flow without sending it to another java callout.

    5. Proxyservice, java (object) in, java (object) out

    For this example i made a copy of the Employee object and named it Person. We will use the same Employee object as example1 for the input and return a Person object back to OSB and log this.

    	public static Person convertEmployeeToPerson(Employee employee) {
    		Person person = new Person();
    
    		person.setFirstname(employee.firstname);
    		person.setLastname(employee.lastname);
    		person.setAge(employee.age);
    
    		return person;
    	}
    

    <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging person response after the java callout ###: <con:java-content ref="jcid:4cd600ef:131e1eeb1b1:-7fca" xmlns:con="http://www.bea.com/wli/sb/context"/>>
    

    And again we get a java ref back, only this time a new ref id to a new object.
    To be able to ‘use’ this object we can either send it to a new java callout or publish it to another queue.

    6. Proxyservice, java (object) in, XmlObject out

    See this blog on how to send the java object to a java callout and return a XmlObject back.
    I added the XMLBeans resources (build.xml and libs) to the same project as mentioned in step1.

    For this testcase we used the next method. It will receive the Employee object from the queue and return the xml(object) representation of it back to the OSB.

    	public static XmlObject convertJavaToXml(Employee employee) throws Exception {
    		EmployeeDocument empDoc = EmployeeDocument.Factory.newInstance();
    		EmployeeType myEmp = empDoc.addNewEmployee();
    		myEmp.setAge(32);
    		myEmp.setFirstName("Eric");
    		myEmp.setLastName("Elzinga");
    
    		return myEmp;
    	}
    

    Run the ant build script again and copy the jar to our OSB project.
    In this jar we will find the Employee and Person entities, the generated XMLBeans artifacts and the static methods used for the java callout. I guess we could have splitted some of those in other archives, but for the simplicity of this article it’s fine like this.
    The jar we used in the other cases won’t be needed anymore since all we need is in this new one.

    Don’t forget to edit the proxyservice and change the Client Jar to the new jar.

    And the java callout

    <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### JMSObject_ps, logging my_employee_xml response after the java callout ###: <emp:employee xmlns:emp="http://xenta.nl/crm/employee">
      <emp:FirstName>Eric</emp:FirstName>
      <emp:LastName>Elzinga</emp:LastName>
      <emp:Age>32</emp:Age>
    </emp:employee>>
    

    With this final testcase we’re able to retrieve the java object from the queue, convert it to a xml representation and send it back to the proxy service.
    In the message flow we’re now able to retrieve data from it by use of some xpath expression.

    Popularity: 7% [?]

    osb

    Oracle Service Bus, java callouts with XmlObjects

    In the Oracle Service Bus we can make use of java callouts to invoke plain java.
    Basically there aren’t any restrictions on the the input and output parameters of the static methods.

    There are 2 situations which will differ in the way we get the data returned back from the java callout, see this

    Return primitives, Strings or XmlObjects from the java callout.
    In this case we can just retrieve the data from the $body variable and execute xpath expressions on it to immediately get the value of the payload.

    Return anything else
    In this case we will get back a java ref identifier back from the java callout.
    Executing xpath expressions on the $body will only give use a reference to the java object

    <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, stage2, REQUEST] ### debug logging $body ###: <soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
      <con:java-content ref="jcid:4c741db6:131dd1e4544:-7fc5" xmlns:con="http://www.bea.com/wli/sb/context"/>
    </soapenv:Body>>
    

    To be able to use the data in the java object we can only pass it to other java callouts.

    In this blog i will show an example of how to generate a XmlObject, mentioned as one of the return types in case 1.
    If we’re able to generate this kind of object from the java callout, OSB will just be able to retrieve this in the $body variable and let us execute xpath expression on it.

    1. Create a Java project in Eclipse

    We will be using XML Beans to generate the java artifacts based on a Employee schema definition.
    These artificats we will be using in our static method to generate the Employee java objects which represents our Employee entity definition from the xsd schema.
    Read this and this to get a quickstart on XML Beans.

    1. In Eclipse we will create a new java project with a dependency on the Apache XML Beans library.
      I copied the ORACLE_MIDDLEWARE_HOME\modules\com.bea.core.xml.xmlbeans_2.1.0.0_2-5-1.jar to my lib folder in the project.
      Add the same file as build dependency (libraries) in the project properties.

    2. Create a schemas folder in the root and add the Employee.xsd to it

      <?xml version="1.0" encoding="UTF-8"?>
      <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:emp="http://xenta.nl/crm/employee" targetNamespace="http://xenta.nl/crm/employee" elementFormDefault="qualified" attributeFormDefault="unqualified">
      	<xs:element name="employee" type="emp:EmployeeType">
      		<xs:annotation>
      			<xs:documentation>Employee entity</xs:documentation>
      		</xs:annotation>
      	</xs:element>
      	<xs:complexType name="EmployeeType">
      		<xs:sequence>
      			<xs:element name="FirstName" type="xs:string"/>
      			<xs:element name="LastName" type="xs:string"/>
      			<xs:element name="Age" type="xs:int"/>
      		</xs:sequence>
      	</xs:complexType>
      </xs:schema>
      
    3. Create a build.xml in the root of the project. I used the one mentioned in the quickstart articles and edited it a bit.

      	<?xml version="1.0" encoding="UTF-8"?>
      	<project name="XMLBeansDemo" default="build">
      		<property environment="env"/>
      
      		<path id="Any.path">
      			<path refid="xmlbeans.path"/>
      			<fileset dir="build/lib" includes="*.jar"/>
      			<pathelement path="build/classes"/>
      		</path>
      
      		<target name="init">
      			<property name="xmlbeans.home" value="e:\osb_workspace\EmployeeXmlBeans\"/>    	
      
      			<echo message="xmlbeans.home: ${xmlbeans.home}"/>
      
      			<!-- check for xbean.jar from binary distribution -->
      
      			<available
      				property="xmlbeans.lib"
      				value="${xmlbeans.home}/lib"
      				file="${xmlbeans.home}/lib/com.bea.core.xml.xmlbeans_2.1.0.0_2-5-1.jar" />
      
      			<fail message="Set XMLBEANS_HOME in your environment."
      				unless="xmlbeans.lib"/>
      
      			<echo message="xmlbeans.lib: ${xmlbeans.lib}"/>
      
      			<path id="xmlbeans.path">
      				<fileset dir="${xmlbeans.lib}" includes="*.jar"/>
      			</path>
      
      			<taskdef name="xmlbean"
      				classname="org.apache.xmlbeans.impl.tool.XMLBean"
      				classpathref="xmlbeans.path"/>
      		</target>
      
      		<!-- ========================== clean ==== -->
      
      		<target name="clean">
      			<delete dir="build"/>
      		</target>
      
      		<!-- ========================== build ==== -->
      
      		<target name="build" depends="init,schemas.jar,Any.classes">
      		</target>
      
      		<target name="schemas.check">
      			<uptodate property="schemas.notRequired"
      				targetfile="build/lib/EmployeeXmlBeans.jar">
      				<srcfiles dir="schemas" includes="**/*.xsd"/>
      			</uptodate>
      		</target>
      
      		<target name="schemas.jar" depends="init,schemas.check"
      			unless="schemas.notRequired">
      			<mkdir dir="build/lib"/>
      			<xmlbean schema="schemas"
      				destfile="build/lib/EmployeeXmlBeans.jar"
      				srcgendir="src"
      				classpathref="xmlbeans.path"
      				source="1.5"
      				javasource="1.5"
      				debug="on"
      				/>
      		</target>
      
      		<target name="Any.classes" depends="init">
      			<mkdir dir="build/classes"/>
      
      			<javac srcdir="src"
      				destdir="build/classes"
      				classpathref="Any.path"
      				debug="on"
      				source="1.5"
      				/>
      		</target>
      
      		<!-- ========================== run ==== -->
      
      		<target name="run" depends="init,build">
      			<echo message="============================== running Any"/>
      			<java
      				classname="org.apache.xmlbeans.samples.anytype.Any"
      				classpathref="Any.path"
      				fork="true">
      				<arg line="xml/any.xml"/>
      			</java>
      		</target>
      
      		<!-- ========================== test ==== -->
      
      		<target name="test" depends="init,build">
      			<echo message="============================== testing Any"/>
      			<java
      				classname="org.apache.xmlbeans.samples.anytype.AnyTest"
      				classpathref="Any.path"
      				fork="true">
      				<arg line="xml/any.xml"/>
      			</java>
      		</target>
      
      	</project>
      

      Run the ant build script. Based on the xml namespace of the Employee xsd object it will generate the same package structure for the java objects.
      Verify if it generated the next list of objects

      • nl.xenta.crm.employee.EmployeeDocument
      • nl.xenta.crm.employee.EmployeeType
      • nl.xenta.crm.employee.impl.EmployeeDocumentImpl
      • nl.xenta.crm.employee.impl.EmployeeDocumentImpl

      And if it also generated the file EmployeeXmlBeans.jar in the lib folder.

    4. Next we need to create a static method which will make use of the generated classes.
      Create the next class in the same project

      package nl.xenta.services;
      
      import org.apache.xmlbeans.XmlObject;
      
      import nl.xenta.crm.employee.EmployeeDocument;
      import nl.xenta.crm.employee.EmployeeType;
      import nl.xenta.entities.Employee;
      import nl.xenta.entities.Person;
      
      public class EmployeeService {
      
      	/**
      	 * Retrieve an employee record based on an employee id and return a XmlObject
      	 *
      	 * @param empId
      	 *
      	 * @return Employee XmlObject
      	 */
      	public static XmlObject retrieveEmployee(String empId) {
      		EmployeeDocument empDoc = EmployeeDocument.Factory.newInstance();
      		EmployeeType myEmp = empDoc.addNewEmployee();
      		myEmp.setAge(32);
      		myEmp.setFirstName("Eric");
      		myEmp.setLastName("Elzinga");
      
      		return myEmp;
      	}
      }
      
    5. Run the ant build again and this time copy the EmployeeXmlBeans.jar file to your OSB project and refresh the project in Eclipse.
    6. Add the java callout to your proxy service message flow and see the response
    7. Test the proxyservice and see the response in the logging.

      <BEA-000000> < [PipelinePairNode1, PipelinePairNode1_request, RetrieveEmployee, REQUEST] ### debug, logging my_employee_xml_object ###: <emp:employee xmlns:emp="http://xenta.nl/crm/employee">
        <emp:FirstName>Eric</emp:FirstName>
        <emp:LastName>Elzinga</emp:LastName>
        <emp:Age>32</emp:Age>
      </emp:employee>>
      
      1. Now we’re able to retrieve data from the variable just by using the xpath expressions and re-use it in the rest of the message flow.

        Popularity: 7% [?]

    osb

    Oracle Service Bus, Implementing Aggregator pattern by use of Split-Join

    One of the patterns mentioned on the eai patterns site is the so called Aggregator pattern.

    “Use a stateful filter, an Aggregator, to collect and store individual messages until a complete set of related messages has been received. Then, the Aggregator publishes a single message distilled from the individual messages”

    We will be using this pattern in our next use case.

    Use case

    On the Oracle Service Bus we will implement the EmployeeService with an operation called ‘getEmployee’.
    When we call this operation and supply an input parameters of the EmployeeNumber, we want to receive the next set of information

    • EmployeeDetails
    • AddressDetails
    • ContactDetails

    In a real life scenario we could have the next situation

    On the Oracle Service Bus we want to supply our clients 1 interface to be able to retrieve Employee information. The interface definition will define Employee details, addresses and contact details.

    The process will receive the Employee Number, and by use of parallel invocation it will :

    • send a request to system1 which will supply us the Employee details
    • send a request to system2 which will suppy us the Employee addresses
    • send a request to system3 which will supply us the Employee contact details

    Every system invocation will be a synchronous call and will get a response back from every one of them.
    After having received the last of the 3 responses the parallel invocation is done. In the process flow we now need to aggregate the responses and transform these into one response which will get routed back to the client caller.

    The client caller will not know what backend systems will get invoked to retrieve data. It will only receive one message response according to our defined interface on the service bus.

    Enough talk, let’s see what we need in the Oracle Service Bus to implement this.

    Backend systems

    In a real world situation we could have 3 different backend systems which will all supply diffent parts of the Employee data object. For our case we will use just 1 webservice with different operations which will get invoked as different services.
    Create a new Webservice project in Eclipse and add a new webservice to see.

    package nl.xenta.services;
    
    import nl.xenta.entities.Address;
    import nl.xenta.entities.ContactDetail;
    import nl.xenta.entities.Employee;
    
    public interface EmployeeService {
    
    	public Employee getEmployeeDetails(String employeeNumber);
    
    	public Address getEmployeeAddress(String employeeNumber);
    
    	public ContactDetail getContactDetail(String employeeNumber);
    
    }
    
    package nl.xenta.services;
    
    import javax.jws.*;
    
    import nl.xenta.entities.Address;
    import nl.xenta.entities.Employee;
    import nl.xenta.entities.ContactDetail;
    
    @WebService
    public class EmployeeServiceImpl implements EmployeeService {
    
    	/* (non-Javadoc)
    	 * @see nl.xenta.services.EmployeeService#getEmployeeDetails(java.lang.String)
    	 */
    	@WebMethod
    	public Employee getEmployeeDetails(@WebParam(name="employeeNumber") String employeeNumber) {
    		Employee emp = new Employee();
    		emp.setFirstname("Eric");
    		emp.setLastname("Elzinga");
    		emp.setId(100);
    
    		return emp;
    	}
    
    	/* (non-Javadoc)
    	 * @see nl.xenta.services.EmployeeService#getEmployeeAddress(java.lang.String)
    	 */
    	@WebMethod
    	public Address getEmployeeAddress(@WebParam(name="employeeNumber") String employeeNumber) {
    		Address address = new Address();
    		address.setCity("Utrecht");
    		address.setCountry("The Netherlands");
    		address.setPostalCode("1413JK");
    
    		return address;
    	}
    
    	/* (non-Javadoc)
    	 * @see nl.xenta.services.EmployeeService#getContactDetail(java.lang.String)
    	 */
    	@WebMethod
    	public ContactDetail getContactDetail(@WebParam(name="employeeNumber") String employeeNumber) {
    		ContactDetail contact = new ContactDetail();
    		contact.setType("mobile");
    		contact.setValue("+31(6)24562772");		
    
    		return contact;
    	}
    }
    
    package nl.xenta.entities;
    
    public class Address {
    
    	private String street;
    	private String postalCode;
    	private String city;
    	private String country;
    
    	public String getStreet() {
    		return street;
    	}
    	public void setStreet(String street) {
    		this.street = street;
    	}
    	public String getPostalCode() {
    		return postalCode;
    	}
    	public void setPostalCode(String postalCode) {
    		this.postalCode = postalCode;
    	}
    	public String getCity() {
    		return city;
    	}
    	public void setCity(String city) {
    		this.city = city;
    	}
    	public String getCountry() {
    		return country;
    	}
    	public void setCountry(String country) {
    		this.country = country;
    	}
    }
    
    package nl.xenta.entities;
    
    public class ContactDetail {
    
    	String type;
    	String value;
    	public String getType() {
    		return type;
    	}
    	public void setType(String type) {
    		this.type = type;
    	}
    	public String getValue() {
    		return value;
    	}
    	public void setValue(String value) {
    		this.value = value;
    	}
    }
    
    package nl.xenta.entities;
    
    public class Employee {
    
    	private int id;
    	private String firstname;
    	private String lastname;
    
    	public int getId() {
    		return id;
    	}
    	public void setId(int id) {
    		this.id = id;
    	}
    	public String getFirstname() {
    		return firstname;
    	}
    	public void setFirstname(String firstname) {
    		this.firstname = firstname;
    	}
    	public String getLastname() {
    		return lastname;
    	}
    	public void setLastname(String lastname) {
    		this.lastname = lastname;
    	}
    }
    

    Deploy the service
    The simulated backend systems are ready to supply data.

    Oracle Service Bus resources

    We need to next list of resources in the Oracle Service Bus to be able to implement the process.

    • wsdl + xsd of the deployed EmployeeService java webservice
    • business services for every third party service
    • split-join for the aggregation
    • business service representing the split-join
    • proxy service which routes to the split-join business service

    Wsdl and xsd

    Import the wsdl from the wsdl endpoint shown in the Weblogic Console

    Business services for every third party service

    Since we have just 1 webservice representing all the third parties we don’t really need to create separate business services for every party. To simulate the real scenario we still create 3 separate business services, all based on the same wsdl, but in the routing we will just use different operations.
    So create the next set of business services all based on the same EmployeeService wsdl (which we imported in the step before).

    • AddressDetails.biz
    • ContactDetails.biz
    • EmployeeDetails.biz

    Split-join

    Create a new wsdl for the interface of the split-join. This wsdl will only represent the getEmployee operation. Name the wsdl CRM_EmployeeService.wsdl.

    <!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is Oracle JAX-WS 2.1.5. --><!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is Oracle JAX-WS 2.1.5. --><definitions name="EmployeeServiceService" targetNamespace="http://services.xenta.nl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://services.xenta.nl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/">
    	<types>
    		<xsd:schema>
    			<xsd:import namespace="http://services.xenta.nl/" schemaLocation="EmployeeService.xsd"/>
    		</xsd:schema>
    	</types>
    	<message name="getEmployee">
    		<part name="parameters" element="tns:getEmployee"/>
    	</message>
    	<message name="getEmployeeResponse">
    		<part name="parameters" element="tns:getEmployeeResponse"/>
    	</message>
    	<portType name="CRM_EmployeeService">
    		<operation name="getEmployee">
    			<input message="tns:getEmployee"/>
    			<output message="tns:getEmployeeResponse"/>
    		</operation>
    	</portType>
    	<binding name="EmployeeServicePortBinding" type="tns:CRM_EmployeeService">
    		<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    		<operation name="getEmployee">
    			<soap:operation soapAction=""/>
    			<input>
    				<soap:body use="literal"/>
    			</input>
    			<output>
    				<soap:body use="literal"/>
    			</output>
    		</operation>
    	</binding>
    	<service name="EmployeeServiceService">
    		<port name="EmployeeServicePort" binding="tns:EmployeeServicePortBinding">
    			<soap:address location="http://192.168.178.28:7001/EmployeeService/EmployeeServiceService"/>
    		</port>
    	</service>
    </definitions>
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is Oracle JAX-WS 2.1.5. -->
    <xs:schema xmlns:tns="http://services.xenta.nl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://services.xenta.nl/" version="1.0">
    	<xs:element name="getEmployee" type="tns:getEmployee"/>
    	<xs:element name="getEmployeeResponse" type="tns:getEmployeeResponse"/>
    	<xs:complexType name="getEmployee">
    		<xs:sequence>
    			<xs:element name="employeeNumber" type="xs:string" minOccurs="0"/>
    		</xs:sequence>
    	</xs:complexType>
    	<xs:complexType name="getEmployeeResponse">
    		<xs:sequence>
    			<xs:element name="EmployeeDetails" type="tns:employeeDetailType" minOccurs="0"/>
    			<xs:element name="AddressDetails" type="tns:contactDetailType" minOccurs="0"/>
    			<xs:element name="ContactDetails" type="tns:addressDetailType" minOccurs="0"/>
    		</xs:sequence>
    	</xs:complexType>
    	<xs:complexType name="contactDetailType">
    		<xs:sequence>
    			<xs:element name="type" type="xs:string" minOccurs="0"/>
    			<xs:element name="value" type="xs:string" minOccurs="0"/>
    		</xs:sequence>
    	</xs:complexType>
    	<xs:complexType name="employeeDetailType">
    		<xs:sequence>
    			<xs:element name="firstname" type="xs:string" minOccurs="0"/>
    			<xs:element name="id" type="xs:int"/>
    			<xs:element name="lastname" type="xs:string" minOccurs="0"/>
    		</xs:sequence>
    	</xs:complexType>
    	<xs:complexType name="addressDetailType">
    		<xs:sequence>
    			<xs:element name="city" type="xs:string" minOccurs="0"/>
    			<xs:element name="country" type="xs:string" minOccurs="0"/>
    			<xs:element name="postalCode" type="xs:string" minOccurs="0"/>
    			<xs:element name="street" type="xs:string" minOccurs="0"/>
    		</xs:sequence>
    	</xs:complexType>
    </xs:schema>
    

    Create a new split join (File | New | Split-Join) and name it EmployeeSplitJoin.

    By default it will generate for us the variables request and response.

    Add a Parallel activity between Receive and Reply.
    Add an extra Branch to the Parallel activity.
    In every Scope and a Invoke Service activity.
    Select the first Invoke Service in the first Scope and configure it.
    On the Operation tab, browse to the first business service, AddressDetails.

    On the Input Variable tab, select for Message Variable the option Create Message Variable.

    Name the variable EmployeeAddressRequest and define it as Global Variable

    Do the same for the Output Variable tab and name the variable EmployeeAddressResponse.

    In every Scope add an assign before every Invoke Service activity.

    With these assigns we’re mapping the inputparameter of our process (employeeNumber) to the input of our business service (backend service).

    Repeat these steps (add scope, add assign, add invoke service, configure input/output of invoke service) for every invocation of our business services.
    We should end up with the next set of branches.

    The parallel invocation of our backend services is ready. Now we need to aggregate the responses of all the services. Create a new xquery transformation which will receive 3 inputparameters, one for every response of our backend service. The result of the transformation will be a message according to our proxy service interface (getEmployee).


    After the Parallel activity add an Assign. Click the expression and go to the XQuery Resources tab and browse to the ServicesToAggregatedResponse xquery. Bind all the input parameters as defined in the image below.

    For the Variable select response.parameters.

    Our split-join part of the process is done. The process flow should look a bit like this :

    To be able the call the split-join flow we need to generate a business out of it. Right click on the EmployeeSplitJoin.flow and go to File | Oracle Service Bus | Generate Business Service, name it EmployeeSplitJoin.

    ProxyService

    Create a new http soap proxy service based on the CRM_EmployeeService wsdl. In the proxyservice route to the ‘EmployeeSplitJoin’ business service. Since the interface of our split-join is the same as our proxy service (same wsdl) we can just use the passthrough, no transformation is needed.
    Deploy the project and and test the service

    Conclusion

    Instead of using the split-join we can also use several service call outs in our process. Downside on this approach is all the invokes will be waiting on each other to come back with response (sequential). With the split-join approach we can parallel invoke all the services an aggregate the results. In case of services which need to give a low response time and still need to retrieve data from multiple backend systems we can’t model the flow with sequential invocations, split-join would then be an approach to take.

    Besides that static split-join i used for my case we can also use the dynamic apporach in which we loop over reoccuring elements in the payload, process them parallel an aggregate the results.
    Edwin showed this approach in his blog.

    Popularity: 6% [?]

    Page 1 of 1012345...10...Last »