Thursday, April 21, 2011

Implementing Message Security in Oracle B2B 11g

I have already blogged about how to enable SSL on weblogic and configure keystores on Oracle B2B 11g. In this blog I will show you that how to use message security with Oracle B2B.

First of all let me explain that what comes under message security. As part of message security you may-

1. Encrypt an outgoing message so that no one other than the intended recipient can read that message
2. Sign an outgoing message so that receiver can verify that message is actually sent by a trusted party and it has not been modified/manipulated in between the transmission

Encryption is always done using the public key (or public certificate) of the party to whom the message is being sent. Signing is always done using the private key of the party who is sending the message.

Now after understanding this fact that you need a pair of certificates/keys (private key and public key) for message security, you should also understand that two parties communicating with each-other MUST NOT use the same pair of keys or in other words they CAN NOT use the same pair of keys. Both the parties must have different keystores configured on their servers.

I will use two B2B domains and hence two B2B servers – b2bserver1 and b2bserver2 which are configured with two different keystores. Each server has a keystore which holds it’s private key and other server’s public key. I used below keytool commands to create the keystores and export/import each other’s certificate into the respective keystores –

D:\>keytool -genkeypair -alias serverCert -keyalg RSA -keysize 1024 -validity 365 -keypass welcome1 -keystore keystore.jks -storepass welcome1

What is your first and last name?
[Unknown]: localhost.myCompany.com
What is the name of your organizational unit?
[Unknown]: Support
What is the name of your organization?
[Unknown]: MyCompany
What is the name of your City or Locality?
[Unknown]: Hyderabad
What is the name of your State or Province?
[Unknown]: AndhraPradesh
What is the two-letter country code for this unit?
[Unknown]: IN
Is CN=localhost.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN correct?
[no]: yes

D:\>keytool -list -keystore keystore.jks
Enter keystore password:

Keystore type: JKS
Keystore provider: SUN
Your keystore contains 1 entry
servercert, Apr 21, 2011, PrivateKeyEntry,
Certificate fingerprint (MD5): 02:70:1E:A4:CD:86:3C:F3:6B:88:4F:F0:F6:8F:B2:ED

D:\>keytool -exportcert -alias serverCert -file serverCert.cer -keystore keystore.jks -storepass welcome1
Certificate stored in file


D:\>keytool -genkeypair -alias SOAServerCert -keyalg RSA -keysize 1024 -validity 365 -keypass welcome1 -keystore soakeystore.jks -storepass welcome1
What is your first and last name?
[Unknown]: soaserver.myCompany.com
What is the name of your organizational unit?
[Unknown]: Support
What is the name of your organization?
[Unknown]: MyCompany
 What is the name of your City or Locality?
[Unknown]: Hyderabad
What is the name of your State or Province?
[Unknown]: AndhraPradesh
What is the two-letter country code for this unit?
[Unknown]: IN
Is CN=soaserver.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN correct?
[no]: yes


D:\>keytool -exportcert -alias SOAServerCert -file SOAServerCert.cer -keystore soakeystore.jks -storepass welcome1
Certificate stored in file


D:\>keytool -importcert -trustcacerts -alias SOAServerCert –file SOAServerCert.cer -keystore keystore.jks -storepass welcome1
Owner: CN=soaserver.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN
Issuer: CN=soaserver.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN
Serial number: 4dafd400
Valid from: Thu Apr 21 12:21:44 IST 2011 until: Fri Apr 20 12:21:44 IST 2012
Certificate fingerprints:
MD5: 70:7E:86:6A:03:E8:54:31:04:9D:3B:97:69:50:2E:ED
SHA1: 9C:69:D6:47:27:11:27:BE:72:9E:3A:0C:8E:F0:F0:80:AB:D0:D5:99
Signature algorithm name: SHA1withRSA
Version: 3
Trust this certificate? [no]: yes
Certificate was added to keystore

D:\>keytool -importcert -trustcacerts -alias serverCert -file serverCert.cer -keystore soakeystore.jks -storepass welcome1
Owner: CN=localhost.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN
Issuer: CN=localhost.myCompany.com, OU=Support, O=MyCompany, L=Hyderabad, ST=AndhraPradesh, C=IN
Serial number: 4dafd232
Valid from: Thu Apr 21 12:14:02 IST 2011 until: Fri Apr 20 12:14:02 IST 2012
Certificate fingerprints:
MD5: 02:70:1E:A4:CD:86:3C:F3:6B:88:4F:F0:F6:8F:B2:ED
SHA1: 6E:49:33:62:BF:76:27:8A:74:44:DB:73:27:69:80:D3:ED:3B:E7:6B
Signature algorithm name: SHA1withRSA
Version: 3
Trust this certificate? [no]: yes
Certificate was added to keystore

Now configure the keystore keystore.jks on b2b server1 and keystore soakeystore.jks on b2bserver2 –



You can now use these keystores for message security on Oracle B2B.


Now configure the MarketInc AS2 channel (Remote TP Channel) with message security on b2bserver1 -


In “Exchange Protocol Parameters” of same channel I also enabled the “Signed and Compressed” setting.


Now configure the OracleServices AS2 channel (Remote TP Channel) with message security on b2bserver2 -


In “Exchange Protocol Parameters” of same channel I also enabled the “Signed and Compressed” setting.


Now configure the agreements on both the servers with respective channels and deploy them.
On B2B server 1-



On B2B server2 –


Now you are ready to test your configuration. Push a message to b2bserver1 from middleware and it must sign and encrypt the message before sending it to b2bserver2 and b2bserver2 must be able to decrypt the message and verify the signature. Similarly, b2bserver2 must sign and encrypt the message before sending it to b2bserver1 and b2bserver1 must be able to decrypt the message and verify the signature. In Business Message reports you can see the status of the messages and in wire message report you can see the “Message Digest” and “Digest Algorithm” which proves that message has been signed and when you will try to see the “Packed Message”, you will get below message –


Data is encrypted and can not be displayed.

This proves that message has been encrypted. Advanced users can also see the logs and verify whether signing and encryption is happening properly. Go ahead and experiment more with it.

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.

Wednesday, April 6, 2011

RosettaNet Attachment Handling in Oracle B2B 11g

I saw few queries on OTN related to RosettaNet attachment handling in Oracle B2B 11g recently. And hence thought to blog about the same.

In this blog post we will see -

1. How to create attachment XML for RosettaNet?
2. Configuration required in Oracle B2B?
3. How to pass payload and attachment to Oracle B2B from SOA composite using JMS 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 RosettaNet.

Section#1 Creating Attachment XML for RosettaNet :-

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

<!ENTITY % common-attributes "id CDATA #IMPLIED" >
<!ELEMENT B2BAttachment (Attachment*)>
<!ELEMENT Attachment (#PCDATA) >
<!ATTLIST Attachment Type CDATA #REQUIRED
ID CDATA #REQUIRED
Encoding CDATA #REQUIRED
Description CDATA #IMPLIED
FileName CDATA #IMPLIED>

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

<?xml version="1.0" encoding="UTF-8"?>
<B2BAttachment>
<Attachment ID="123456" Type="text/plain" Encoding="none" Description="Description">Fisrt Text Attachment</Attachment>
<Attachment ID="123457" Type="text/plain" Encoding="none" Description="Description">Second Test Attachment</Attachment>
<Attachment ID="123457" Type="application/pdf" Encoding="base64" Description="Description"
FileName="OrderBill.pdf">file:///C:/b2bfile/OS/attachment/out/OrderBill.pdf</Attachment>
</B2BAttachment>

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

i) A text attchment with content "Fisrt Text Attachment"
ii) Another text attachment with content "Second Test Attachment"
iii) A binary attachment (PDF) which is stored in file system in file "C:/b2bfile/OS/attachment/out/OrderBill.pdf"

Make sure to add "Type" and "Encoding" attributes correctly for all the attachments. Here "Type" attribute refers to MIME type and "Encoding" attribute refers to Content-Transfer-Encoding. I saved this attachment XML to directory "C:/b2bfile/OS/attachment/out". From this directory, composite will read the attachment XML and populate the attachment header.



Section#2 Configuring Oracle B2B :-


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



As you can see the agreement "RNIF_O_M_3A4_0200_PO_Agr" has two participants – OracleServices (Host TP) and MarketInc (Remote TP). OracleServices is sending a PIP 3A4 PurchaseOrderRequest 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 "true" so that B2B starts polling default JMS queue (B2B_OUT_QUEUE) instaed of default AQ (IP_OUT_QUEUE) for messages.


If Oracle B2B is receiving the RN document with attchment then you need to add a property "b2b.AttachmentInboundDirectory" as desrcibed in user guide. This property will hold the absolute directory name where incoming attachments 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 3A4 PurchaseOrderRequest 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 "SendB2B" and click "Next"



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


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 3A4 PurchaseOrderRequest's Document Definition




8.  On "JMS Provider" screen select the "Oracle Weblogic JMS" from the drop-down against Oracle Enterprise Messaging Service (OEMS) option




9.  On "Service Connection" screen again select the Application Server Connection



10.  On "Produce Operation Parameters" screen, click on the browse button against "Destination Name" and select "B2B_OUT_QUEUE (queue)" under "SOAJMSModule" and click ok. Accept the deafult for other settings and click on "Next"





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 – SendToB2B
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 SendToB2B to configure it. Add a receive activity in main scope to receive the 3A4 PurchaseOrderRequest 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. 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




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


1. Copy the input variable (ReceiveFile_Read_InputVariable) body content of BPEL process to output variable (InvokeSendB2B_Produce_Message_InputVariable) body content. This will assign the 3A4 PurchaseOrderRequest 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 'Pip3A4PurchaseOrderRequest' to variable DocType
6. Copy the expression 'V02.00' to variable DocTypeRevision
7. Copy the expression '1' to variable MsgType
8. Copy the expression ora:getContentAsString(ora:doc('file:///C:/b2bfile/OS/attachment/out/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



As the last step, we need to populate the JMS headers with the value of variables, we assigned above. Go to source of BPEL process and modify the invoke node as below -

<invoke name="InvokeSendB2B"
inputVariable="InvokeSendB2B_Produce_Message_InputVariable"
partnerLink="SendB2B" portType="ns2:Produce_Message_ptt"
operation="Produce_Message" bpelx:invokeAsDetail="no">
<bpelx:inputProperty name="jca.jms.JMSProperty.FROM_PARTY" variable="FromParty"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.TO_PARTY" variable="ToParty"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.DOCTYPE_NAME" variable="DocType"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.DOCTYPE_REVISION" variable="DocTypeRevision"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.MSG_TYPE" variable="MsgType"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.MSG_ID" variable="MsgId"/>
<bpelx:inputProperty name="jca.jms.JMSProperty.ATTACHMENT" variable="Attachment"/>
</invoke>

You can see here that invoke node is populating the JMS properties required for processing in Oracle B2B with the values of the variables we declared.

Save your project and deploy it to the SOA server.


Section#4 Running a test and verifying configuration :-

Drop a 3A4 PurchaseOrderRequest 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 "SendToB2B" component on Flow Trace to view it's Audit Trail. See the Assign Action 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 InvokeSendB2B audit trail that headers are being populated with exact values. Make sure that content of header "jca.jms.JMSProperty.ATTACHMENT" is same as our attachment XML.




Now login to B2B console and go to Reports section. In Business Message Reports, expand the details of 3A4 PurchaseOrderRequest 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 out 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 3A4 PurchaseOrderRequest 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 RosettaNet message using Oracle B2B and composite with JMS interface.