Wednesday, April 20, 2011

ebMS Attachment Handling in Oracle B2B 11g

In my last post I showed that how you can send an attachment with RosettaNet message and how you can use B2B adapter’s JMS interface to pass messages from composite to B2B. In this post, I will demonstrate that how attachment should be handled in ebMS and how you can use B2B adapter’s AQ interface to pass messages from Oracle SOA composite to Oracle B2B.


So, in this blog post we will see -

1. How to create attachment XML for ebMS?
2. Configuration required in Oracle B2B?
3. How to pass payload and attachment to Oracle B2B from Oracle SOA composite using AQ interface of B2B Adapter?
4. How to verify whether attchments are being passed correctly using EM console and B2B reports?

So let's start with creating an attachment XML for ebMS.


Section#1 Creating Attachment XML for ebMS :-

This process is same as what you follwed for B2B 10g. The attchment XML must adhere to following XSD -

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="Attachments">
<xs:annotation>
<xs:documentation>This element encapsulates the descriptions of the attachements that need to go out with a payload through Oracle B2B.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="AttachmentPart" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>This element contains the complete description of a single attachment; there can be many such attachments that go out with a payload.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:element name="Attachment" type="xs:base64Binary" minOccurs="0">
<xs:annotation>
<xs:documentation>It is also possible to specify the actual attachment in base64 here. Or, it could be placed in some location, and the URI of the location specified in the location element.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Location" type="xs:anyURI" minOccurs="0">
<xs:annotation>
<xs:documentation>This element contains a URI that points to the location of the attachment.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
<xs:element name="Content-Type">
<xs:annotation>
<xs:documentation>This element specifies the Content-Type of the attachment.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence>
<xs:element name="Top-Level-Type" type="xs:string"/>
<xs:element name="Sub-Type" type="xs:string">
<xs:annotation>
<xs:documentation>Specifies the sub-media type.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Parameter" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>Allows the specification of parameter name and value.</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attribute name="Name"/>
<xs:attribute name="Value"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Content-Transfer-Encoding">
<xs:annotation>
<xs:documentation>This element specifies the transfer encoding format.</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="BASE64"/>
<xs:enumeration value="Quoted-Printable"/>
<xs:enumeration value="8bit"/>
<xs:enumeration value="7bit"/>
<xs:enumeration value="binary"/>
<xs:enumeration value="X-token"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="Content-ID" minOccurs="0">
<xs:annotation>
<xs:documentation>Can be used to specify an optional content ID.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Content-Description" minOccurs="0">
<xs:annotation>
<xs:documentation>Can be used to specify an optional content description.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="boundary"/>
</xs:complexType>
</xs:element>
</xs:schema>


I created a XML based on above XSD which looks like -

<?xml version="1.0" encoding="utf-8"?>
<Attachments xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" boundary="">
<AttachmentPart>
<Attachment>'First Test Attachment'</Attachment>
<Content-Type>
<Top-Level-Type>text</Top-Level-Type>
<Sub-Type>plain</Sub-Type>
</Content-Type>
<Content-Transfer-Encoding>8bit</Content-Transfer-Encoding>
<Content-ID>1234567890123</Content-ID>
<Content-Description/>
</AttachmentPart>
<AttachmentPart>
<Location>file:///C:/b2bfile/OS/attachment/ebMS/outbound/OrderBill.doc</Location>
<Content-Type>
<Top-Level-Type>application</Top-Level-Type>
<Sub-Type>octet-stream</Sub-Type>
</Content-Type>
<Content-Transfer-Encoding>base64</Content-Transfer-Encoding>
<Content-ID>1221</Content-ID>
<Content-Description/>
</AttachmentPart>
<AttachmentPart>
<Location>file:///C:/b2bfile/OS/attachment/ebMS/outbound/OrderBill.pdf</Location>
<Content-Type>
<Top-Level-Type>application</Top-Level-Type>
<Sub-Type>pdf</Sub-Type>
</Content-Type>
<Content-Transfer-Encoding>base64</Content-Transfer-Encoding>
<Content-ID>1221</Content-ID>
<Content-Description/>
</AttachmentPart>
</Attachments>


As you can see, there are three attachments included in this attachment XML -

i) A text attchment with content "Fisrt Test Attachment"
ii) A binary attachment (MSWORD doc) which is stored in file system in file "C:/b2bfile/OS/attachment/ebMS/outbound/OrderBill.doc"
iii) A binary attachment (PDF) which is stored in file system in file "C:/b2bfile/OS/attachment/ebMS/outbound/OrderBill.pdf "

Note that I have used content type "application/octet-stream" for MSWORD doc however you can also use content type "application/msword" for MSWORD docs. To know that which content type should be used with which doc, you may refer this W3Schools article.

I saved this attachment XML to directory " C:\b2bfile\OS\attachment\ebMS\outbound ". From this directory, composite will read the attachment XML and populate the attachment header.

 


Section#2 Configuring Oracle B2B :-

First of all create ebMS agreement between the trading partners and deploy the agreement. I won't show the steps to create ebMS agreements. You may use ebMS sample from samples site. So the agreement which I deployed, looks like -

 

As you can see the agreement "ebMS_O_M_Custom_10_PO_Agr" has two participants – OracleServices (Host TP) and MarketInc (Remote TP). OracleServices is sending a ebMS PurchaseOrder to MarketInc using this agreement.

Now we need to configure Oracle B2B for attachments.

By default Oracle B2B supports following MIME types -

text/plain : image/jpeg: text/xml : application/xml : application/octet-stream : application/EDIFACT : application/EDI-X12 : application/jpg : application/gzip : application/x-gzip : application/pkcs7-signature

If you need support for any additional MIME type then you have to add it in Oracle B2B configuration using B2B Web Console. As we need support for "application/pdf" to send PDF as attachment, we will add it in Oracle B2B configuration. Login to Oracle B2B console, navigate to Administration-->Configuration and in "Miscellaneous" section add "application/pdf" in "Additional MIME Types" -





On same page, set the "Use JMS Queue as default" to "false" (if it is not already set to false) so that B2B start polling default AQ queue (IP_OUT_QUEUE) instaed of default JMS (B2B_OUT_QUEUE) for outbound messages.


If Oracle B2B is receiving the ebMS (or AS1 or eMail or HTTP) message with attchment then you need to add a property "b2b.attachments.dir" as described in user guide. This property will hold the absolute directory name where incoming attach-ments will be stored. Make sure to restart the B2B server(s) after adding this property.


Section#3 Creating SOA composite for passing attachment and payload to Oracle B2B :-

Now create a SOA composite to pass the message to Oracle B2B. Open Jdeveloper and first of all create a SOA application and inside that create a SOA project with empty composite.

Drag the File Adapter into "Exposed Services" section of composite and configure it for picking up ebMS PurchaseOrder from the local file system. Drag the B2B Adapter into "External Reference" section of composite and configure it by following below steps -

1. On Welcome screen click on "Next"
2. On Service Name screen provide the service name as "SendToB2BAQ" and click "Next"



3. On "B2B Integration Type" screen, select "AQ"


4. On "Application Server Connection" screen select the Application Server connection you have created or create a new one. This connection should be created to AdminServer of B2B domain.


5. On "Operation" screen, select send



6. On "Document Definition Handling" screen, just click on "Next"
7. On "Document Definition" screen, select the ebMS PurchaseOrder Document Definition

 


8. On "Service Connection" screen select the SOAINFRA database connection. If you have not created it yet, create a database connection to soainfra schema and select that. In "JNDI Name" field, provide a desired JNDI name and make sure to create a outbound connection pool in AQAdapter with SAME JNDI name (it is case sensitive)


9. On "Queue Name" screen accept the defaults (Queue name must be shown as IP_OUT_QUEUE)


10. On "Queue Parameters" screen, accept the defaults (Recipients must be shown as b2buser)

   
11. Click on "Finish" to generate the adapter configuration files

Now drag a BPEL process to Components section of composite and configure it as below -

Name – ebMSAttachmentBPEL
Namespace – Accept the default
Template – Define Service Later

 

Now connect this BPEL process with File Adapter and B2B Adapter by dragging wires appropriately and your composite should look like below-


Now double-click on BPEL Process ebMSAttachmentBPEL to configure it. Add a receive activity in main scope to receive the ebMS PurchaseOrder payload from File Adapter and add an invoke activity to invoke B2B adapter to send message to B2B. In between receive and invoke activity add a Assign activity to assign values to B2B required headers and attchment, after that add a Java Embedding activity to encode content of Attachment header into BASE64Content and after that add another assign activity to create the content for AQ header "jca.aq.HeaderDocument" which is required to submit a payload to IP_OUT_QUEUE AQ.

Your BPEL process should look like -






In main scope add below variables of xsd:string type -

i) ToParty
ii) FromParty
iii) DocType
iv) DocTypeRevision
v) MsgType
vi) MsgId
vii) Attachment
viii) JCA_AQ_Header_Variable




Now edit the Assign activity AssignHeaders of BPEL process and perform following copy operations to assign values to above variables -

1. Copy the input variable (ReceiveMessage_Read_InputVariable) body content of BPEL process to output variable (InvokeB2BSend_Enqueue _InputVariable) body content. This will assign the ebMS PurchaseOrder payload read by file adapter to B2B adapter payload.
2. Copy the expression oraext:generate-guid() to variable MsgId
3. Copy the expression 'MarketInc' to variable ToParty
4. Copy the expression 'OracleServices' to variable FromParty
5. Copy the expression 'PurchaseOrder' to variable DocType
6. Copy the expression '1.0' to variable DocTypeRevision
7. Copy the expression '1' to variable MsgType
8. Copy the expression ora:getContentAsString(ora:doc('file:///C:/b2bfile/OS/attachment/ebMS/outbound/attachment.xml')) to variable Attachment

In 8th copy operation, we are reading the content of attachment XML using ora:doc() function and then converting the XML to string using ora:getContentAsString() function




Now edit the Java Embedding activity "AttachmentEncoder_Java" and provide below Java Code there –

try{
String encodedData = oracle.soa.common.util.Base64Encoder.encode((String)getVariableData("Attachment"));
setVariableData("Attachment",encodedData);
}catch(Exception e){
System.out.println("Exception in Embedded Java:" + e.toString());
}



As you can see, in the Java Embedding, we are encoding the "Attachment" variables content into BASE64Content and then re-assigning the encoded content into "Attachment" variable itself.


Now edit the assign activity "AssignPayloadHeader" and copy the below expression into variable JCA_AQ_Header_Variable

concat('<?xml version = "1.0" standalone = "yes"?><tns:Header xmlns:tns="http://www.w3.org/2001/XMLSchema"><tns:PayloadHeader><MSG_ID>',$MsgId,'</MSG_ID><INREPLYTO_MSG_ID></INREPLYTO_MSG_ID><FROM_PARTY>',$FromParty,'</FROM_PARTY><TO_PARTY>',$ToParty,'</TO_PARTY><ACTION_NAME></ACTION_NAME><DOCTYPE_NAME>',$DocType,'</DOCTYPE_NAME><DOCTYPE_REVISION>',$DocTypeRevision,'</DOCTYPE_REVISION><MSG_TYPE>',$MsgType,'</MSG_TYPE><PAYLOAD></PAYLOAD><ATTACHMENT>',$Attachment,'</ATTACHMENT></tns:PayloadHeader></tns:Header>')


As the last step, we need to populate the AQ header jca.aq.HeaderDocument with the value of variable JCA_AQ_Header_Variable, we assigned above. Go to invoke activity "InvokeB2BSend", doube click on it and go to "Properties" tab. Select the AQ header jca.aq.HeaderDocument and provide it’s value as variable "JCA_AQ_Header_Variable" –

Save your project and deploy it to the SOA server.


Section#4 Running a test and verifying configuration :-

Drop a ebMS PurchaseOrder XML into the directory where File Adapter is polling. Wait until the files gets deleted from that directory.

Now login to EM console and navigate to your composite. You must see a instance under "Recent Instances" section. Click on Instance ID and it should open up the Flow Trace. Click on "ebMSAttachmentBPEL" component on Flow Trace to view it's Audit Trail. See the Assign Action "AssignHeaders"Audit Trail and expand the payload under "Updated variable "Attachment"" (You will only able to see payload if Audit level is set to Development). It should show you the exact content as our attachment XML. Even you can see under InvokeB2BSend audit trail that header jca.aq.HeaderDocument is being populated with exact values. Make sure that content of header "jca.aq.HeaderDocument" has base64 encoded attachment. jca.aq.HeaderDocument should have value like –

<?xml version = "1.0" standalone = "yes"?><tns:Header xmlns:tns="http://www.w3.org/2001/XMLSchema"><tns:PayloadHeader><MSG_ID>2d353231343433383932313933363537</MSG_ID><INREPLYTO_MSG_ID></INREPLYTO_MSG_ID><FROM_PARTY>OracleServices</FROM_PARTY><TO_PARTY>MarketInc</TO_PARTY><ACTION_NAME></ACTION_NAME><DOCTYPE_NAME>PurchaseOrder</DOCTYPE_NAME><DOCTYPE_REVISION>1.0</DOCTYPE_REVISION><MSG_TYPE>1</MSG_TYPE><PAYLOAD></PAYLOAD><ATTACHMENT>PEF0dGFjaG1lbnRzIHhtbG5zOnhzaT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEtaW5zdGFuY2UiIGJvdW5kYXJ5PSIiPgogIDxBdHRhY2htZW50UGFydD4KICAgIDxBdHRhY2htZW50PidGaXJzdCBUZXN0IEF0dGFjaG1lbnQnPC9BdHRhY2htZW50PgogICAgPENvbnRlbnQtVHlwZT4KICAgICAgPFRvcC1MZXZlbC1UeXBlPnRleHQ8L1RvcC1MZXZlbC1UeXBlPgogICAgICA8U3ViLVR5cGU+cGxhaW48L1N1Yi1UeXBlPgogICAgPC9Db250ZW50LVR5cGU+CiAgICA8Q29udGVudC1UcmFuc2Zlci1FbmNvZGluZz44Yml0PC9Db250ZW50LVRyYW5zZmVyLUVuY29kaW5nPgogICAgPENvbnRlbnQtSUQ+MTIzNDU2Nzg5MDEyMzwvQ29udGVudC1JRD4KICAgIDxDb250ZW50LURlc2NyaXB0aW9uLz4KICA8L0F0dGFjaG1lbnRQYXJ0PgogIDxBdHRhY2htZW50UGFydD4KICAgIDxMb2NhdGlvbj5maWxlOi8vL0M6L2IyYmZpbGUvT1MvYXR0YWNobWVudC9lYk1TL291dGJvdW5kL09yZGVyQmlsbC5kb2M8L0xvY2F0aW9uPgogICAgPENvbnRlbnQtVHlwZT4KICAgICAgPFRvcC1MZXZlbC1UeXBlPmFwcGxpY2F0aW9uPC9Ub3AtTGV2ZWwtVHlwZT4KICAgICAgPFN1Yi1UeXBlPm9jdGV0LXN0cmVhbTwvU3ViLVR5cGU+CiAgICA8L0NvbnRlbnQtVHlwZT4KICAgIDxDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nPmJhc2U2NDwvQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZz4KICAgIDxDb250ZW50LUlEPjEyMjE8L0NvbnRlbnQtSUQ+CiAgICA8Q29udGVudC1EZXNjcmlwdGlvbi8+CiAgPC9BdHRhY2htZW50UGFydD4KICA8QXR0YWNobWVudFBhcnQ+CiAgICA8TG9jYXRpb24+ZmlsZTovLy9DOi9iMmJmaWxlL09TL2F0dGFjaG1lbnQvZWJNUy9vdXRib3VuZC9PcmRlckJpbGwucGRmPC9Mb2NhdGlvbj4KICAgIDxDb250ZW50LVR5cGU+CiAgICAgIDxUb3AtTGV2ZWwtVHlwZT5hcHBsaWNhdGlvbjwvVG9wLUxldmVsLVR5cGU+CiAgICAgIDxTdWItVHlwZT5wZGY8L1N1Yi1UeXBlPgogICAgPC9Db250ZW50LVR5cGU+CiAgICA8Q29udGVudC1UcmFuc2Zlci1FbmNvZGluZz5iYXNlNjQ8L0NvbnRlbnQtVHJhbnNmZXItRW5jb2Rpbmc+CiAgICA8Q29udGVudC1JRD4xMjIxPC9Db250ZW50LUlEPgogICAgPENvbnRlbnQtRGVzY3JpcHRpb24vPgogIDwvQXR0YWNobWVudFBhcnQ+CjwvQXR0YWNobWVudHM+</ATTACHMENT></tns:PayloadHeader></tns:Header>




Now login to B2B console and go to Reports section. In Business Message Reports, expand the details of ebMS PurchaseOrder which has been sent to TP. Scroll down and click on the link against "Attachment" in Business Message Report details. It must show you exactly same content as our attachment XML -



Now to check whether attchments have been included in the message sent to TP, go to Wire Message Report and expand the details of ebMS PurchaseOrder which has been sent to TP. In details, click on the "Packed Message" link and scroll down. At the bottom, you must be able to see the attachments -
 
You are done with sending Text and Binary attachments with ebMS exchange using Oracle B2B and composite with AQ interface.

2 comments:

  1. Its a great work by Anuj. The above mentioned program is quite informational and elaborate to make it understandable.The visual display makes it more clear.
    sap upgrade

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete