Sending and Receiving Binary Data

This section discusses how to:

  • Send binary data.

  • Receive binary data.

PeopleSoft supports the MTOM protocol for sending and receiving binary data using service operations. While you can send and receive binary data using SOAP, doing so requires that you Base64-encode the data, which can increase message size by 33 percent or more. The MTOM protocol enables you to send and receive binary data in its original binary form, without any increase in size due to encoding.

Whether sending or receiving MTOM-encoded binary data, you use message segments to store the data. The SegmentContentType property of the Message object is used to set or read the content type of each message segment.

This section discusses how to send MTOM-encoded binary data and discusses how to:

  • Set target connector properties to send MTOM-encoded binary data.

  • Develop messages to send MTOM-encoded binary data.

Setting Target Connector Properties to Send MTOM-Encoded Binary Data

When sending MTOM-encoded binary data, you must use the HTTP target connector. The HTTP target connector features an MTOM property that you must set to Y for MTOM encoding to occur. When you set the MTOM property to Y, the HTTP target connector attempts to convert all outgoing message to the MTOM wire format.

See Using the HTTP Target Connector.

Developing Messages to Send MTOM-Encoded Binary Data

An outgoing MTOM message is composed of a SOAP message and one or more sets of binary data. Segments are used to add the binary data to the outgoing request.

For each chunk of data, use a single segment as follows:

  1. Create the segment.

  2. Copy the data to the segment.

  3. Add the MIME type that is to appear for the MIME part containing the binary in the outgoing MTOM wire message.

  4. Set the content transfer encoding to binary.

In PeopleCode this appears as:

 &theMessage.CreateNextSegment();

  If (&theMessage.SetContentString(&dataString)) Then
     &theMessage.SegmentContentType = "image/jpeg";
     &theMessage.SegmentContentTransfer = %ContentTransfer_Binary;
  End-If;

The SetContentString method requires character data, and is not capable of passing binary data. For MTOM, pass in a Base64-encoded string that contains the binary data. The File object method GetBase64StringFromBinary allows a binary file to be read in and captured as a string; use this string to set the data for the newly created segment.

See SetContentString, GetBase64StringFromBinary.

When seen on the wire, the SOAP XML in the MIME multipart message contains xop:Include references. These references point to the MIME parts that contain the binary data. In order to be able to construct these references, Integration Broker requires that a specific XML element, PsftXopInclude, is present in the outgoing message.

Each PsftXopInclude element corresponds directly to an xop:include in the outgoing wire message, and therefore each PsftXopInclude element logically corresponds to an instance of binary data. Placement of the PsftXopInclude element in the XML is application-specific; Integration Broker does not require any particular location.

In the following example the first instance of the PsftXopInclude element corresponds to the logical point to include an image and the second PsftXopInclude element corresponds to the logical point to include a binary document:

<?xml version='1.0'?>
<JobApplication>
  <Photo name='JohnSmith'>
    <PsftXopInclude SegmentNumber='1'/>
  </Photo>
  <Resume name='JohnSmithCV'>
    <PsftXopInclude SegmentNumber='2'/>
  </Resume>
</JobApplication>

The value of the SegmentNumber attribute is used by Integration Broker to link the PsftXopInclude entry to a specific segment used to add the data. For the purposes of MTOM, the first segment used to add binary data is considered to be number 1, the second segment, number 2, and so on. Care should be taken when setting these values as Integration Broker does not check to ensure that they are correct; they are used as-is to build the xop:include references in the wire message.

In the previous example, the message data is not SOAP-wrapped. You can choose to build your own SOAP wrapper or elect to have Integration Broker SOAP-wrap the message. If Integration Broker is to SOAP wrap the message, you must set the HTTP target connector property SOAPUpContent to Y.

See Using the HTTP Target Connector.

An example of XML to use this feature is as follows:

<?xml version="1.0"?>
<flt:process xmlns:flt=" http://xmlns.oracle.com/Enterprise/ 
  Tools/schemas/flightdata.v1">
  <PsftXopInclude/>
  <flt:input1>515</flt:input1>
  <PsftXopInclude/>
  <flt:input2>664</flt:input2>
 </flt:process>

You would include the previous XML in the XmlDoc object and add it to the first segment of the message.

The additional segments include the binary data associated with each declaration. For example:

&MSG = CreateMessage(Message.FLIGHTDATA);

&MSG.SetXmlDoc(&xmldoc);

&MSG.CreateNextSegment();
&MSG.SetContentString("your encoded image data");
&MSG.SegmentContentType = "image/gif";
&MSG.SegmentContentTransfer = %ContentTransfer_Binary;

&MSG.CreateNextSegment();
&MSG.SetContentString("your encoded video here")
&MSG.SegmentContentType = "video/mp4";
&MSG.SegmentContentTransfer = %ContentTransfer_Binary;

%IntBroker.Publish(&MSG);

The following code example provides another XML example that demonstrates using this feature:

Local File &theFile;
Local XmlDoc &theXmlDoc;
Local Message &theMessage;
Local string &theBase64encodedString;

/* note: this example does not have any error handling, in */
/* order to keep the code relatively short and concise.    */

/* create the message, and add the basic XML message data */
/* ------------------------------------------------------ */

&theMessage = CreateMessage(Operation.QE_FLIGHTPLAN_UNSTRUCT);
Local string &xml;

/* this example requires the SOAPUPContent HTTP Target */
/* connector property to be set to "Y", so that the    */
/* outbound XML will be SOAP wrapped.                  */

&xml = &xml | "<?xml version='1.0'?>";
&xml = &xml | "<JobApplication>";
&xml = &xml | "<Photo name='JohnSmith'>";
&xml = &xml | "<PsftXopInclude SegmentNumber='1'/>";
&xml = &xml | "</Photo>";
&xml = &xml | "<Resume name='JohnSmithCV'>";
&xml = &xml | "<PsftXopInclude SegmentNumber='2'/>";
&xml = &xml | "</Resume>";
&xml = &xml | "</JobApplication>";


&theXmlDoc = CreateXmlDoc(&xml);
&theMessage.SetXmlDoc(&theXmlDoc);

/* add an image to the outgoing message */
/* ------------------------------------ */

&theFile = GetFile("D:\output\smallPicture.jpg", "R", %FilePath_Absolute);
If &theFile.IsOpen Then
   &theBase64encodedString = &theFile.GetBase64StringFromBinary();
   &theFile.Close();
End-If;

&theMessage.CreateNextSegment();
If (&theMessage.SetContentString(&theBase64encodedString)) Then
   &theMessage.SegmentContentType = "image/jpeg";
   &theMessage.SegmentContentTransfer = %ContentTransfer_Binary;
End-If;


/* add a PDF file to the outgoing message */
/* -------------------------------------- */

&theFile = GetFile("D:\output\smallDocument.pdf", "R", %FilePath_Absolute);
If &theFile.IsOpen Then
   &theBase64encodedString = &theFile.GetBase64StringFromBinary();
   &theFile.Close();
End-If;

&theMessage.CreateNextSegment();
If (&theMessage.SetContentString(&theBase64encodedString)) Then
   &theMessage.SegmentContentType = "application/pdf";
   &theMessage.SegmentContentTransfer = %ContentTransfer_Binary;
End-If;


/* send the message */
/* ---------------- */

%IntBroker.Publish(&theMessage);

Note: PeopleSoft currently supports MTOM for asynchronous messaging only.

This section discusses receiving MTOM-encoded binary data requests and discusses how to:

  • Enable listening connectors to receive MTOM-enoded binary data.

  • Use PeopleCode to process inbound MTOM-encoded binary data.

Understanding Receiving MTOM-Encoded Binary Data

To receive MTOM-encoded binary data from integration partners, you must use the PeopleSoft services listening connector or the HTTP listening connector.

When a message is received by an MTOM-enabled connector, the gateway first determines if the message is using MTOM. If it is not, the message is processed normally. If MTOM is detected, the gateway extracts the SOAP message from the MIME and then encodes the binary data in the MIME parts. This is effectively a pre-processing step and is done first, before normal processing can occur. Once complete, the SOAP message is then treated no differently from any other SOAP message received. The binary data is Base64 encoded, and is attached to the message in the form of segments.

Enabling Listening Connectors to Receive MTOM-Encoded Binary Data

The following listening connectors can receive and process MTOM-encoded messages:

  • PeopleSoft services listening connector.

  • HTTP listening connector.

You must enable these connectors for receiving and processing MTOM messages for any MTOM processing to occur. You enable these properties in the integration gateway properties file. The properties appear the MTOM Enable ListeningConnectors section as shown in the following example:

# MTOM Enable ListeningConnectors
#
#ig.MTOM.enablePeopleSoftServiceListeningConnector=true
#ig.MTOM.enableHttpListeningConnector=true

By default the properties are not enabled and are commented out.

To enable a given connector, remove the comment (#) and ensure that the property is set to true.

Note: When these properties are enabled there is a slight performance degradation to all non-MTOM requests sent to the connectors. The degradation is a result of system process that takes place to determine if requests are MTOM-encoded messages.

Using PeopleCode to Process Inbound MTOM–Encoded Binary Data

MTOM messages are processed in the form of message segments. The system processes inbound MTOM requests in two general steps:

  • Process the XML data contained in the first segment.

  • For each subsequent segment, process the binary data.

The first segment contains the XML data. The xop:include references in the XML are replaced with PsftXopInclude elements, and each instance will point to the segment containing the associated binary data.

The structure of this XML is application-specific, and therefore processing of this XML cannot be easily generalized. You may be able to use the location of the PsftXopInclude elements in the XML to derive information about the binary data segments.

Consider the following inbound MTOM request example:

<?xml version='1.0'?>
<JobApplication>
  <Photo name='JohnSmith'>
    <PsftXopInclude SegmentNumber='2'/>
  </Photo>
  <Resume name='JohnSmithCV'>
    <PsftXopInclude SegmentNumber='3'/>
  </Resume>
</JobApplication>

In this example, the XML has been structured such that the parent element contains a name value for the associated binary content. A more complete XML might also contain information such as file type, size, or creation date. Again, the structure of this XML is not necessarily determined by Integration Broker, but rather by the design of the application itself.

All segments after the first contain the Base64–encoded binary data. This data is accessible as a string. Processing of this is also application-specific. Some applications may decide to store the encoded string for later use, while others may wish to decode it immediately.

To process the string immediately, use the PeopleCode File object method WriteBase64StringToBinary to decode the string and to write it out as a byte array to a file. Once the method has completed and the file closed, the file can be accessed as any other file on the file system.

See WriteBase64StringToBinary.

The following code example shows how to use PeopleCode to process and inbound MTOM request:

import PS_PT:Integration:INotificationHandler;

class MTOM_CLASS implements PS_PT:Integration:INotificationHandler
   method MTOM_CLASS();
   method OnNotify(&MSG As Message);
   method getFileExtensionForContentType(&contentType As string) 
   Returns string;
end-class;

/* constructor */
method MTOM_CLASS
end-method;

method getFileExtensionForContentType
   /+ &contentType as String +/
   /+ Returns String +/
   
   Evaluate &contentType
   When = "image/jpeg"
      Return "jpg"
   When = "application/pdf"
      Return "pdf"
   When-Other
      Return "unk"
   End-Evaluate;
   
end-method;


method OnNotify
   /+ &MSG as Message +/
   /+ Extends/implements PS_PT:Integration:INotificationHandler.OnNotify +/
   

   /* note: this example does not have any error handling, in */
   /* order to keep the code relatively short and concise.    */


   /* Variable Declaration */
   Local integer &i, &j;
   Local string &contentSectionData, &contentSectionType;
   Local File &theFile;
   Local XmlDoc &theXml;
   
   
   /* the first section will be XML */
   /* ----------------------------- */
   
   &MSG.GetSegment(1);
   &contentSectionData = &MSG.GetContentString(1);
   
   &theXml = CreateXmlDoc(&contentSectionData);
   
   Local array of XmlNode &nodeList;
   
   /* get all PsftXopInclude nodes, ignore namespaces */
   &nodeList = &theXml.DocumentElement.FindNodes("//*[local-name()=
   'PsftXopInclude']");
   
   
   /* all subsequent sections will be binary data */
   /* ------------------------------------------- */
   
   For &i = 2 To &MSG.SegmentCount
      
      &MSG.GetSegment(&i);
      &contentSectionData = &MSG.GetContentString(&i);
      
      /* get the type information directly from the segment */
      /* we'll use this to determine the file extension */
      &contentSectionType = &MSG.SegmentContentType;
      
      Local string &theFileName = "D:\output\";
      
      For &j = 1 To &nodeList.Len
         If (&nodeList [&j].GetAttributeValue("SegmentNumber") = 
         String(&i)) Then
            
             rem we've found the entry that matches this content section;
             rem use the 'name' attribute from the parent XML element to 
             rem get the file name
             rem NOTE - this assumes a particular XML format that may not
             rem be the same for most applications;

            &theFileName = &theFileName | &nodeList [&j].ParentNode.
            GetAttributeValue("name");
            
         End-If;
      End-For;
      
      rem build the complete filename, including the extension;
      &theFileName = &theFileName | "." | %This.getFileExtensionForContentType
      (&contentSectionType);
      
      
      &theFile = GetFile(&theFileName, "W", %FilePath_Absolute);
      If &theFile.IsOpen Then
         &theFile.WriteBase64StringToBinary(&contentSectionData);
         &theFile.Close();
      End-If;
      
   End-For;
   
end-method;

Note: PeopleSoft currently supports MTOM for asynchronous messaging only.