Showing posts with label OSB 12c. Show all posts
Showing posts with label OSB 12c. Show all posts

Friday, June 26, 2020

Xquery to remove namespace from XML

xquery version "1.0" encoding "utf-8";

(:: OracleAnnotationVersion "1.0" ::)

declare variable $input as element() external;

declare function local:change-ns($input as element()) as element() {
    
    element {fn:local-name($input) }
    {
    for $child in $input/(@*,node())
      return
      if ($child instance of element())
        then local:change-ns($child)
      else $child
    }
};
local:change-ns($input)

Thursday, May 28, 2020

Xquery to change namespace of xml

Change namespace of XML - 


xquery version "1.0" encoding "utf-8";

 

(:: OracleAnnotationVersion "1.0" ::)

 

declare variable $src as element() external;

declare variable $ns as xs:string external;

 

declare function local:change-element-ns-deep

  ( $nodes as node()* ,

    $newns as xs:string ,

    $prefix as xs:string )  as node()* {

 

  for $node in $nodes

  return if ($node instance of element())

         then (element

               {QName ($newns,

                          concat($prefix,

                                    if ($prefix = '')

                                    then ''

                                    else ':',

                                    local-name($node)))}

               {$node/@*,

                local:change-element-ns-deep($node/node(),

                                           $newns, $prefix)})

         else if ($node instance of document-node())

         then local:change-element-ns-deep($node/node(),

                                           $newns, $prefix)

         else $node

} ;

local:change-element-ns-deep($src, $ns, 'ns')

Thursday, February 20, 2020

Pipeline Alerts in OSB

Alerts in OSB are used to notify members of the team about any issues/abnormalities/factors in the services that need to be notified for immediate or future action.

Two types of alerts can be configured in OSB - Pipeline alerts and Service Level Agreement (SLA) alerts.

This blog will provide basic examples of how to set Pipeline alerts.


Pipeline Alerts:

These are simple alerts setup in the OSB pipeline based on the message context/body/payload. We can consider these alerts to be more for business purpose or error handling. To notify business users about any discrepancies in the data being submitted or any other errors to be reported.

Say, for example, 
a) In an Order processing flow in OSB, if there are any orders being processed with Price more than $1000, an alert notification needs to be raised.
b) If there are specific business errors in the flow, an alert notification need to be raised.

Here, I have created a simple OSB to show on how to work with Pipeline alerts. This blog will not cover the basic OSB creation process.

This OSB will take two int elements and an Operation parameter as input. If the operation is Sum, addition is done on the input parameters and response is returned. If the operation is Sub, subtraction is done. If the operation in anything else, an Alert needs to be raised.

Here's the screenshot of how pipeline looks. SumNode and SubNode are the two valid nodes which would return results. Default node will raise an alert with invalid operation error. The highlighted part is the alert that has been added. I will show in detail on how to go with the creation of pipeline alert.



Right click on the project and Create an alert destination. Give a specific name.


In the next screen, ensure that Alert logging is enabled. This will help to view the alerts in the alerts dashboard.


In the Pipeline, in default operation node, drag and drop an alert activity. You would see the following alert properties.


Lets start filling up each of the above properties.

Content will be the actual data you would want to capture in the alert. In my case, I would want to show the operation that caused the issue.
 

Summary can be some descriptive heading for the alert.

Severity - There are several levels present in the drop down. Select the one which you would want the alert to be notified as.


Finally, for the destination, choose the alert destination you created in the initial steps.


We are done with the alert setting. Now test the OSB with an operation other than Sum and Sub, you would find the alert in the console.

Navigation to check the alert - Go to EM console -> Select the service-bus under SOA -> Click on Alerts History tab.

In the Alert Type -> Choose Pipeline Alerts. You can also filter by Alert Summary name. Click on Search. You can find the alerts as following.


Click on the Alert Summary for any one of the notifications, you can find all the details that have been logged.



Friday, May 26, 2017

Read emails and email attachments through Email protocol in OSB 12c

Reading emails and processing the information within the mail, is a common requirement in today's business processes. 

I have always found OSB to be easier in implementing any functionality compared to SOA. Email protocol proves it right for email reading.Unlike SOA, where email adapters, drivers need to be created to read mails, OSB provides a simple protocol to take care of this feature.

In my example, I am going to read mails from a gmail account and process the details in the mail. Before proceeding on how to create an OSB for email reading, lets get the mailbox details ready. 

IMAP or POP3 - 

In order to read any mail box, we would need to connect to the mailbox through one of the two protocols - imap or pop3. imap connects over port 993 where as pop3 connects over port 995. Lets check if the gmail box is imap enabled. Else, we would need to enable it.

1) Login to the gmail box. Click on Settings.
2) Next click on "Forwarding and POP/IMAP".
3) Under IMAP Access section, check if Enable IMAP is checked. If not, select the option.


IMAP Access@prasanna-soa.blogspot.com


Now the gmail box is IMAP enabled and we can use this protocol to OSB to access. 

OSB project -

1. Create a simple service bus project. I have named it as PGEmailProject.
2. Create a Service Account with static mappings. This service account should contain the username and password to the gmail account you would listen to. Let me call mine as testgmail@gmail.com.




3. Next step is to start with the proxy service. Right click on the services section of the composite.xml. From the Transports section, choose Email.




4. A Proxy service popup would open. Provide a name for the proxy service. Transport is defaulted to email. Generate pipeline is ticked by default. Click on next.




5. The next wizard allows you to choose the Service Type. In my example, I can have any type of input coming. It need not be an xml. Hence, I chose Messaging service with Request as Text and Response None. Go to next section.




6. Final section is the Transport section where you need to enter the end point uri. The end point uri in Email protocol is nothing but the host and port of the mailbox from which the mails have to be read. In our case, it is imap.gmail.com:993. If we are connecting through pop, it would be pop.gmail.com:995. Click on Finish and we are done with the proxy service creation.



7. Now to set the transport parameters right. Click on the proxy service and move to Transport Details section. This section would be empty showing lot of errors. Time to fill up each of the applicable parameters.

  1. SSL Required - As gmail is https, check the checkbox.
  2. Service Account - Choose the one we created at the start of the project - PGEmailServiceAccount.sa
  3. Managed Server - All polling services, be it email, FTP, listen through one managed server of a clustered environment. We need to choose one of the managed servers. Mine being machine1.
  4. Polling Interval - Time between each email poll - 10 seconds for me
  5. Email protocol - As mentioned in earlier section, you can choose between imap and pop3. I choose imap. 
  6. Read Limit - The number of mails to be read at a time - I left it as 10
  7. Pass By Reference - When enabled, the body is staged in archive location and the file location is passed as part of header. This is applicable only for Request type xml. As my reference type is Text, I have it disabled.
  8. Pass Attachments by Reference - Attachments are staged in archive location and file location is sent as part of headers. This is not applicable in my case and hence goes disabled.
  9. Post Read Action - What do you want to do with the mail once read? I want it to be deleted and hence my option is delete.
  10. IMAP Move Folder - Empty. As I didnt choose my Post Read Action as Move.
  11. Download, Archive and Error directory - The path to which the mails should be archived, downloaded. I have /test/email/download/ and /test/email/error/ locations in my server and hence have given this location. You can give the location based on your file structure.
  12. Request Encoding - Left to the default ISO-8859-1
Finally the Transport details page looks as follows -


8. Time to fill up the pipeline with some activities to check the mails that are read. For simplicity, I have added two alerts in the pipeline to print the body and the headers once they are read.




9. Deploy the project to your server and now send a mail to testgmail@gmail.com mailbox. This is the mailbox to which the proxy is listening to.
10. I sent a mail with Subject and Body as "Test Mail".

Once OSB reads the mails, alerts will be published with the following information.

PG Email Body:

This will contain the content of the body in the email.
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">Test Email</soapenv:Body>

PG Email Inbound:

All the header information including who sent the mail, subject, etc are returning as part of inbound headers.
<con:endpoint name="ProxyService$PGEmailProject$PGEmailProxyService" xmlns:con="http://www.bea.com/wli/sb/context">
 <con:service/>
 <con:transport>
  <con:uri>mailfrom:imap.gmail.com:993</con:uri>
  <con:mode>request</con:mode>
  <con:qualityOfService>exactly-once</con:qualityOfService>
  <con:request xsi:type="ema:EmailRequestMetaData" xmlns:ema="http://www.bea.com/wli/sb/transports/email" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <tran:headers xsi:type="ema:EmailRequestHeaders" xmlns:tran="http://www.bea.com/wli/sb/transports">
    <tran:user-header name="MIME-Version" value="1.0"/>
    <tran:user-header name="X-MS-Exchange-Organization-MessageDirectionality" value="Incoming"/>
    <tran:user-header name="X-MS-Exchange-Organization-AuthSource" value="BN1AFFO11FD012.protection.gbl"/>
    <tran:user-header name="X-EOPAttributedMessage" value="0"/>
    <tran:user-header name="X-DkimResult-Test" value="Passed"/>
    <tran:user-header name="X-EOPTenantAttributedMessage" value="9274ee3f-9425-4109-a27f-9fb15c10675d:0"/>
    <tran:user-header name="SpamDiagnosticOutput" value="1:99"/>
    <tran:user-header name="SpamDiagnosticMetadata" value="NSPM"/>
    <tran:user-header name="X-MS-Exchange-CrossTenant-Id" value="9274ee3f-9425-4109-a27f-9fb15c10675d"/>
    <tran:user-header name="X-MS-Exchange-Transport-EndToEndLatency" value="00:00:00.9743427"/>
    <tran:user-header name="X-MS-PublicTrafficType" value="Email"/>
    <tran:user-header name="X-MS-Office365-Filtering-HT" value="Tenant"/>
    <tran:user-header name="X-MS-Office365-Filtering-Correlation-Id" value="9948914d-638a-4764-c610-08d4a3f44afd"/>
    <tran:user-header name="Message-ID" value="<CABOwZYhyJ3enfdVQRMXG=3Ha=YFf_fzEeMYFJSat9gVywytRRg@mail.gmail.com>"/> 
    <tran:user-header name="Return-Path" value="prasannarani.g@gmail.com"/>
    <tran:user-header name="X-MS-Exchange-CrossTenant-OriginalArrivalTime" value="26 May 2017 05:01:39.0171 (UTC)"/>
    <ema:To>Prasanna <testgmail@gmail.com></ema:To>
    <ema:From>Prasanna G <testprasanna@gmail.com></ema:From>
    <ema:Date>Fri May 26 01:01:38 EDT 2017</ema:Date>
    <ema:Subject>Test Mail</ema:Subject>
    <ema:Content-Type>multipart/alternative; boundary=94eb2c1499a87e29340550663b14</ema:Content-Type>
    </tran:headers>
    <tran:encoding xmlns:tran="http://www.bea.com/wli/sb/transports">utf-8</tran:encoding>
   </con:request>
  </con:transport>
  <con:security>
   <con:transportClient>
    <con:username><anonymous></con:username>
   </con:transportClient>
  </con:security>
 </con:endpoint>


Reading Attachments in the email :

The way attachments are read using email protocol depends on Pass Attachment by reference option set at the Email Transport Configuration level. 

If the Messaging type is xml, we do get an option to enable Pass Attachment By Reference. In this case, the content in the attachment is staged in archive location and only reference to the location is sent as part of headers.

When the Messaging type is text, Pass By Reference and Pass attachment by Reference options cannot be enabled. In this case, the attachments are sent as part of $attachment variable.

I added two attachments - a png file and an xlsx file as attachments to another mail. The attachment variable looks as follows.
<con:attachments xmlns:con="http://www.bea.com/wli/sb/context">
 <con:attachment>
  <con:Content-Type>image/png; name="Test.png"</con:Content-Type>
  <con:Content-Disposition>attachment; filename="Test.png"</con:Content-Disposition>
  <con:Content-Transfer-Encoding>base64</con:Content-Transfer-Encoding>
  <con:body>
   <con:binary-content ref="cid:-6ed90ee0:15c2ed5f20c:-7b17"/>
  </con:body>
 </con:attachment>
 <con:attachment>
  <con:Content-Type>application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; name="Book1.xlsx"</con:Content-Type>
  <con:Content-Disposition>attachment; filename="Book1.xlsx"</con:Content-Disposition>
  <con:Content-Transfer-Encoding>base64</con:Content-Transfer-Encoding>
  <con:body>
   <con:binary-content ref="cid:2862c084:15c2ed5ba2e:-7a65"/>
  </con:body>
 </con:attachment>
</con:attachments>

Note that for each attachment, the <con:attachment> section is repeated. You can find the Content type, name of the file, etc. But if you notice, the actual attachment is not present in base64 format, it is present as binary-content with reference cid. This is a feature in OSB, where the actual files are returned in binary-content format. 

In order to further use the attachment content, it needs to be explicitly converted into base64 format. I would also quickly show you, on how to do that. I used a Java class to achieve this functionality and passed the binary content from OSB to java callout and got base64 format as response.

Here's the simple java code -
import weblogic.utils.encoders.BASE64Encoder;

public class Base64Converter {
    public Base64Converter() {
        super();
    }
    
    public static String encode(final byte[] bytes) {
        final BASE64Encoder encoder = new BASE64Encoder();
        final String encodedString = encoder.encodeBuffer(bytes);
        return encodedString;
    }
}

1. Create a simple Java class as above. 
2. You need to import webservices-9.2.2.0.jar into the java project in order to make this class work. 
3. Create a java jar of this class and add into OSB project.
4. Now add a Java Callout in the OSB.
5. The encode function of the class takes bytes array as input. From OSB, add the following binary-content as input to the java callout.
$attachments/ctx:attachment/ctx:body/ctx:binary-content

6. String returned as output of java callout will be in encoded base64 format.

Thus, emails and email attachments can be read through OSB email protocol.

Note: If you are using OSB 11g version, make sure that {MsgIdNotFound:READ_TIMEOUT} parameter is set to 0. Changing it any value is throwing a SocketTimeout Exception - Read TImeout exception. Oracle is looking into this issue.







Wednesday, May 10, 2017

Xquery to group elements in OSB

This blog shows an example of how to convert a flat xml into a hierarchy by grouping them based on some element/tag.

Lets consider the following xmls. 

SourceXml - This xml contains list of orders and order lines. OID can be repeated under each OrderList with unique OLineIDs. This xml like Order lineitems for same or different Orders.
<Orders xmlns="http://www.example.org">
 <OrderList>
  <OID>333</OID>
  <OStatus>Active</OStatus>
  <OLineID>3331</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
 <OrderList>
  <OID>222</OID>
  <OStatus>Active</OStatus>
  <OLineID>2222</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
 <OrderList>
  <OID>333</OID>
  <OStatus>Reactivated</OStatus>
  <OLineID>3332</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
 <OrderList>
  <OID>111</OID>
  <OStatus>Inactive</OStatus>
  <OLineID>1112</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
 <OrderList>
  <OID>111</OID>
  <OStatus>Active</OStatus>
  <OLineID>1111</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
 <OrderList>
  <OID>333</OID>
  <OStatus>Reactivated</OStatus>
  <OLineID>3333</OLineID>
  <OLineStatus>Active</OLineStatus>
 </OrderList>
</Orders>


Now our goal is to convert it into a hierarchy, where we group all the OLineIDs under each OID into Parent-Child format. 

Sample TargetXML 
 <ns1:Order  xmlns:ns1="http://www.example.org"> 
 <ns0:OrderList  xmlns:ns0="http://www.example.org"> 
  <ns0:OrderID>333</ns0:OrderID> 
  <ns0:OrderStatus>Active</ns0:OrderStatus> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>3331</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>3332</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>3333</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
 </ns0:OrderList> 
 <ns0:OrderList  xmlns:ns0="http://www.example.org"> 
  <ns0:OrderID>222</ns0:OrderID> 
  <ns0:OrderStatus>Active</ns0:OrderStatus> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>2222</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
 </ns0:OrderList> 
 <ns0:OrderList  xmlns:ns0="http://www.example.org"> 
  <ns0:OrderID>111</ns0:OrderID> 
  <ns0:OrderStatus>Inactive</ns0:OrderStatus> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>1112</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
  <ns0:OrderLineItem> 
   <ns0:LineItemId>1111</ns0:LineItemId> 
   <ns0:LineItemStatus>Active</ns0:LineItemStatus> 
  </ns0:OrderLineItem> 
 </ns0:OrderList> 
</ns1:Order> 


In order to achieve this, we are going to do for loop with distinct values as follows. 

xquery version "1.0" encoding "utf-8";
(:: OracleAnnotationVersion "1.0" ::)

declare namespace ns1="http://www.example.org";
declare namespace ns0 = "http://www.example.org";
(:: import schema at "GroupTarget.xsd", "GroupSource.xsd" ::)

declare variable $wo as element() (:: schema-element(ns1:Orders) ::) external;

declare function local:func($wo as element() (:: schema-element(ns1:Orders) ::)) as element() (:: schema-element(ns1:Order) ::) {
    
     {
 for $woId in distinct-values($wo/ns0:OrderList/ns0:OID)
 let $woList := $wo/ns0:OrderList[ns0:OID=$woId]
 return
            { data($woId) }
            { data($woList[1]/ns0:OStatus) }
            {
            for $woline in $woList return
                    { data($woline/ns0:OLineID) }
                    { data($woline/ns0:OLineStatus) }
                
               }            
        }    
};

local:func($wo)

Note that there is another way of achieving this functionality by using group by.
But group by does not work with XQuery 1.0. Hence, for XQuery 1.0, we need to use distinct-values.

Hope this blog helps.

Wednesday, December 21, 2016

SOAP, REST XML and JSON Custom Faults in OSB 12c

One of the amazing and useful feature in 12c is the automatic JSON exposure of REST based services. In 11g, we always had to write custom codes to convert JSON to XML and XML to JSON and pass to requested systems. But 12c makes it easy.

Most of the times, we get requirements to expose a service as SOAP and REST (including JSON), which is easy in 12c world. But how does a single service handle custom errors for all types of protocols.


In this blogpost, we will see how custom errors are returned in 12c for SOAP, REST XML and JSON. 


We will begin with WSDL and XSDs for the OSB service - PGRaiseErrorProject.


The request and response schemas have pretty simple elements. Request takes 2 double fields as input and Response gives a status as output.
































Following Custom Fault xsd will be used.





















The abstract and concrete wsdls looks as follows:

Abstract wsdl - ErrorServiceV1Abstract.wsdl


<?xml version= '1.0' encoding= 'UTF-8' ?>

<wsdl:definitions
     name="ErrorService"
     targetNamespace="http://pgservice.com/services/ErrorService/V1"
     xmlns:tns="http://pgservice.com/services/ErrorService/V1"
     xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     xmlns:fault="http://pgservice.com/errortest/customfault/V1"
     xmlns:ser="http://pgservice.com/errortest/V1"
    >
    <wsdl:types>
        <xsd:schema targetNamespace="http://pgservice.com/errortest/V1">
            <xsd:include schemaLocation="../xsd/RequestSchema.xsd"/>
            <xsd:include schemaLocation="../xsd/ResponseSchema.xsd"/>
        </xsd:schema>
        <xsd:schema targetNamespace="http://pgservice.com/errortest/customfault/V1">
            <xsd:include schemaLocation="../xsd/CustomFault.xsd"/>
        </xsd:schema>
    </wsdl:types>
    <wsdl:message name="ErrorServiceRequestMsg">
        <wsdl:part name="parameters" element="ser:testRequest"/>
    </wsdl:message>
    <wsdl:message name="CustFaultMsg">
        <wsdl:part name="parameters" element="fault:custFault"/>
    </wsdl:message>
    <wsdl:message name="ErrorServiceResponseMsg">
        <wsdl:part name="parameters" element="ser:testResponse"/>
    </wsdl:message>
    <wsdl:portType name="ErrorServicePortType">
        <wsdl:operation name="checkStatus">
            <wsdl:input message="tns:ErrorServiceRequestMsg"/>
            <wsdl:output message="tns:ErrorServiceRequestMsg"/>
            <wsdl:fault name="custFault" message="tns:CustFaultMsg"/>
        </wsdl:operation>
    </wsdl:portType>

</wsdl:definitions>

Concrete wsdl - ErrorServiceV1SOAP.wsdl


<wsdl:definitions name="ErrorService" targetNamespace="http://pgservice.com/services/ErrorService/V1"

                  xmlns:tns="http://pgservice.com/services/ErrorService/V1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               >
  <wsdl:import location="ErrorServiceV1Abstract.wsdl" namespace="http://pgservice.com/services/ErrorService/V1"/>
  <wsdl:binding name="ErrorServiceSOAP" type="tns:ErrorServicePortType">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="checkStatus">
      <soap:operation soapAction="http://pgservice.com/services/ErrorService/V1/Test"/>
      <wsdl:input>
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal"/>
      </wsdl:output>
      <wsdl:fault name="custFault">
        <soap:fault use="literal" name="custFault"/>
      </wsdl:fault>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="ErrorService">
    <wsdl:port name="ErrorServicePort" binding="tns:ErrorServiceSOAP">
      <soap:address location="http://pgservice.com/services/ErrorServiceV1"/>
    </wsdl:port>
  </wsdl:service>

</wsdl:definitions>

Next we would start with the OSB project. All the above schemas and wsdls have been placed in xsd and wsdl folders under Resources in the project as follows - 


















In the xsd folder, you would have observed that there are two more schemas. SOAPEnvelope.xsd is the regular SOAP schema and MessageContext.xsd has the structure of the $fault variable in OSB. In order to create xqueries, these can be used.

The next step is to create SOAP proxy service. Based on ErrorServiceV1SOAP wsdl, create a SOAP proxy and pipeline.  Provide the Proxy service name and pipeline name.




















Once the proxy and pipeline are created. Right click on the pipeline. You will find an option to expose the service as Rest. Click on it.













You will now get a new window to enter the resource path and operation details. By default, the operation from the wsdl will be populated  in the operation bindings sections.  

Click on the first + symbol and create a new resource path - /checkStatus - here.

Then select the operation from Operation bindings and select the pencil symbol to edit.
Rest Binding


This will show the Request payload section. Only XML is selected by default. Select the JSON check box as well. 
JSON Option















Similarly in the response as well, select the JSON checkbox. 
In the response you would see that the custFault variable from the wsdl has got auto-populated in the fault bindings, which means REST proxy will allow faults of custFault type to be returned. 


Select the fault and click on edit, it will allow you to select JSON output for fault as well.


















Once the above changes are done, the project looks as follows.
SOAP and REST Proxy














Now, lets write the logic in the pipeline. Double click the pipeline.
Logic goes as follows - 
If the difference between totalAmount and paidAmount is less than 1000, a success response with message is returned.
If the difference is greater than 1000, a raise error is done.
The pipeline looks as follows after implementing the above logic.
Pipeline


The following code and message will be returned for the business error.
Raise Error
















The next step is to handle the error in a way that it abides by the SOAP wsdl contract and also follows REST XML and JSON convention in the same way.

For error handling, we will add an error handler for the Pipeline pair. 


1. First step would be to add a Reply activity and check the option as "With Failure". This will allow error response to be sent.













2. Second step is to populate the Custom Fault that we have in the wsdl. I added an assign activity in the error handler and populated the custFault var using $fault as follows.




















3. CustFaultVar now has the Custom Fault populated. How do we return it in a way that the consuming system gets appropriate message for SOAP, REST XML and JSON?


As we all know any fault for a SOAP service should be returned in SOAP Fault format. Else, it is not considered to be valid. So, here as well, we are supposed to populate the SOAPFault and return as response body.

Any custom fault mentioned in the wsdl should be placed under detail tag of the SOAPFault.

4. I have added a replace activity and replaced the body with SOAP fault as below. The faultcode has been hardcoded. You can populate any other code.

The detail tag has the CustFaultVar embedded.























Rest adapter is smarter than http adapter. When the above fault response is returned from Pipeline to the Rest adapter, the adapter does multiple validations.


1. It checks if the Fault received from pipeline is SOAP fault or not ?


2. Then it checks if the fault structure mentioned in the wsdl (here custFault) and the fault structure in the detail tag of SOAPFault are same. 


3. If yes, Rest adapter will internal extract the structure present in the detail tag and return as response in XML/JSON formats.


4. It checks if the Custom Fault populated in the detail section of response is adhering to the Custom Fault XSD like mandatory fields, field types, etc.

  
If any of the above mentioned items fail, Rest adapter will throw the following error.
<err:RestError xmlns:err="http://www.bea.com/wli/sb/errors"/>

Note that, they http adapter will still show SOAPFault if the above validations fail. But Rest will not work.


The above highlighted part is very important for custom faults to work.


Now I will show how the response looks like when an error occurs. I am going to provide totalAmount as 34325 and paidAmount as 123. The result is going to be >1000. Hence, "Remaining amount is more than allowed limit" error should be returned.  



SOAP proxy - 


SOAP Proxy returns a SOAP Fault, where the Custom Fault is embedded in the detail tag. This is exactly what the pipeline returns to any proxy.






















Rest proxy with application/xml as Media and Accept type - 

The error response contains just the custFault that we saw in the detail section of SOAP Fault. 
As mentioned earlier, Rest adapter just reads and validates the detail tag structure.

Rest proxy with application/json as Media and Accept type -

The error response here is the JSON format of above Rest xml error response.













Thus, custom errors are handled in OSB 12c for SOAP and REST. 

I hope you find this blog useful.