Try OpenEdge Now
skip to main content
Messaging and ESB
Programming for the OpenEdge Adapter for SonicMQ with the ABL - JMS API : Programming scenarios : Enhanced XML support
 

Enhanced XML support

Prior to OpenEdge Release 10.1, the OpenEdge Adapter for SonicMQ supported using the XMLMessage type if the client created the message as text in a well-formed XML document.
Currently, OpenEdge clients can send additional types of data, such as temp-tables and ProDatasets, as XMLMessage. The TempTableMessage and DataSetMessage transport data to the SonicMQ Broker using XML. ABL has built-in functionality to transform TEMP-TABLE or ProDataSet data into XML. Additionally, OpenEdge clients read, write, and parse XML using SAX-READER, SAX-WRITER, and X-DOCUMENT.
For more information on accessing the examples files, see OpenEdge messages.
The following example shows how to use the SAX-WRITER object.

Saxwriter message

DEFINE VARIABLE hSaxWriter AS HANDLE NO-UNDO.
DEFINE VARIABLE hSession   AS HANDLE NO-UNDO.
DEFINE VARIABLE hMesg      AS HANDLE NO-UNDO.
RUN jms/jmssession.p PERSISTENT SET hSession ("-SMQConnect").
RUN SetBrokerURL IN hSession ("-H localhost -S 5162 ").
RUN beginSession IN hSession.
RUN createXMLMessage IN hSession (OUTPUT hMesg).
/* Will write an envelope address */
hSaxWriter = DYNAMIC-FUNCTION('getSaxWriter':u IN hMesg, ?).
/* Want to format this so it is easy to read */
hSaxWriter:FORMATTED = TRUE.
hSaxWriter:START-DOCUMENT().
/* The ENCODING attribute defaults to UTF-8 */
/* The FRAGMENT attribute defaults to FALSE */
/* The STRICT attribute defaults to TRUE */
hSaxWriter:START-ELEMENT("mailingaddress").
RUN xmlData(INPUT "name", INPUT "Joe Perry").
hSaxWriter:START-ELEMENT("address").
/* This node contains an attribute */
hSaxWriter:INSERT-ATTRIBUTE("type", "personal").
RUN xmlData(INPUT "street", INPUT "11 Sugerland St.").
RUN xmlData(INPUT "city", INPUT "Somerville").
RUN xmlData(INPUT "state", INPUT "MA").
RUN xmlData(INPUT "zipcode", INPUT "02143").
hSaxWriter:END-ELEMENT("address").
hSaxWriter:START-ELEMENT("address").
hSaxWriter:INSERT-ATTRIBUTE("type", "business").
RUN xmlData(INPUT "name", INPUT "Progress Software").
RUN xmlData(INPUT "street", INPUT "14 Oak Park").
RUN xmlData(INPUT "city", INPUT "Bedford").
RUN xmlData(INPUT "state", INPUT "MA").
RUN xmlData(INPUT "zip", INPUT "01730").
hSaxWriter:END-ELEMENT("address").
hSaxWriter:WRITE-EMPTY-ELEMENT("default").
hSaxWriter:INSERT-ATTRIBUTE("type", "personal").
hSaxWriter:END-ELEMENT("mailingaddress").
hSaxWriter:END-DOCUMENT().
RUN deleteSaxWriter IN hMesg (saxWriterH).
RUN sendToQueue IN hSession ("SampleQ1", hMesg, ?, ?, ?).
RUN deleteMessage IN hMesg.
PROCEDURE xmlData:
  DEFINE INPUT PARAMETER xmlNode  AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER charData AS CHARACTER NO-UNDO.
  hSaxWriter:START-ELEMENT(xmlNode).
  hSaxWriter:WRITE-CHARACTERS(charData).
  hSaxWriter:END-ELEMENT(xmlNode).
END PROCEDURE.
The following code sample shows how to use the setSaxReader procedure :

setSaxReader example

DEFINE VARIABLE hSax AS HANDLE NO-UNDO.
CREATE SAX-READER hSax.
/* SAX-READER setup as needed */
PROCEDURE messageHandler:
  DEFINE INPUT  PARAMETER hMessage         AS HANDLE NO-UNDO.
  DEFINE INPUT  PARAMETER hMessageConsumer AS HANDLE NO-UNDO.
  DEFINE OUTPUT PARAMETER hAutoReply       AS HANDLE NO-UNDO.
  DEFINE VARIABLE hResult AS HANDLE    NO-UNDO.
  DEFINE VARIABLE mType   AS CHARACTER NO-UNDO.
  mtype = DYNAMIC-FUNCTION('getMessageType':u IN hMessage).
  CASE mType:
    WHEN "TempTableMessage" THEN DO:
      hResult = DYNAMIC-FUNCTION('GetTempTable':u IN hMessage, ?, ?, ? ).
      /* TempTable actions as needed */
    END.
    WHEN "DatasetMessage" THEN DO:
      hResult = DYNAMIC-FUNCTION('GetDataSet':u IN hMessage, ?, ?, ? ).
      /* DataSet actions as needed */
    END.
    WHEN "XMLMessage" THEN DO:
      RUN setSaxReader IN hMessage (hSax).
      hSax:SAX-PARSE().
    END.
  END CASE.
  RUN deleteMessage IN hMessage.
END.
The SAX-WRITER object reads XML from a file using the SAX-READER object and send it to a queue using an XMLMessage. The following example shows how to use the SAX-WRITER object.

saxSender.p

DEFINE VARIABLE hdl1     AS HANDLE NO-UNDO.
DEFINE VARIABLE hdl2     AS HANDLE NO-UNDO.
DEFINE VARIABLE hMesg    AS HANDLE NO-UNDO.
DEFINE VARIABLE hSession AS HANDLE NO-UNDO.
/* Start up the session to the SonicMQ broker */
RUN jms/ptpsession.p PERSISTENT SET hSession ("-H localhost -S 5162 ").
RUN setBrokerURL IN hSession ("localhost:2506").
RUN beginSession IN hSession.
/* Create the Sonic XML message */
RUN createXMLMessage IN hSession (OUTPUT hMesg).
/* The Adapter function GetSaxWriter will return a handle to a newly created
   SAX-WRITER and set its output to a destination local to the Adapter. The
   application may then make normal SAX-WRITER calls using this handle.*/
hdl2 = DYNAMIC-FUNCTION('GetSaxWriter':u IN hMesg, ?).
hdl2:START-DOCUMENT().
/* Create a SAX-READER to read in the xml file to be sent in a SonicMQ XML
   message. The SAX-READER callback procedures will use the handle to the
   SAX-WRITER just created to copy the XML. */
CREATE SAX-READER hdl1.
hdl1:SET-INPUT-SOURCE("FILE", "personal.xml").
hdl1:SAX-PARSE().
DELETE OBJECT hdl1.
hdl2:END-DOCUMENT().
/* The Adapter procedure DeleteSaxWriter will copy the XML written with the
   SAX-WRITER calls into the SonicMQ XML message. It will then delete the
   SAX-WRITER specified by the handle. */
RUN DeleteSaxWriter IN hMesg (hdl2).
/* Send the XML message. */
RUN sendToQueue IN hSession ("SampleQ1", hMesg, ?, ?, ?).
/* Disconnect the session from the SonicMQ broker */
RUN deleteMessage IN hMesg.
RUN deleteSession IN hSession.
/*****************************************************/
/* callbacks for the SAX-READER function SAX-PARSE() */
/*****************************************************/
/* Procedure is called when the parser finds a start tag for an element. */
PROCEDURE StartElement:
  DEFINE INPUT PARAMETER namespaceURI AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER cLocalName   AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qname        AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER attributes   AS HANDLE    NO-UNDO.
  hdl2:START-ELEMENT(cLocalName, namespaceURI).
END PROCEDURE.
/* This callback gets passed the character data for an element. */
PROCEDURE Characters:
  DEFINE INPUT PARAMETER mCharData AS MEMPTR    NO-UNDO.
  DEFINE INPUT PARAMETER iNumChars AS INTEGER   NO-UNDO.
  DEFINE VARIABLE cData AS CHARACTER NO-UNDO.
  cData = GET-STRING(mCharData, 1, GET-SIZE(mCharData)).
  hdl2:WRITE-CHARACTERS(cData).
END PROCEDURE.
/* This callback is called when the parser finds the end tag for an Element. */
PROCEDURE EndElement:
  DEFINE INPUT PARAMETER namespaceURI AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER cLocalName   AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qName        AS CHARACTER NO-UNDO.
  hdl2:END-ELEMENT(cLocalName, namespaceURI).
END.
The SAX-READER object reads an XMLMessage from a queue and writes it to a LONGCHAR. The following example shows how to use the SAX-READER object.

saxReceiver.p

DEFINE VARIABLE hdl2         AS HANDLE   NO-UNDO.
DEFINE VARIABLE hSession     AS HANDLE   NO-UNDO.
DEFINE VARIABLE lch          AS LONGCHAR NO-UNDO
  VIEW-AS EDITOR SIZE 70 BY 30 LARGE.
DEFINE VARIABLE hMsgConsumer AS HANDLE   NO-UNDO.
DEFINE VARIABLE hMesg        AS HANDLE   NO-UNDO.
DEFINE VARIABLE stillWaiting AS LOGICAL  NO-UNDO INITIAL TRUE.
/* Start up the session to the SonicMQ broker */
RUN jms/ptpsession.p PERSISTENT SET hSession ("-H localhost -S 5162 ").
RUN setBrokerURL IN hSession ("localhost:2506").
RUN beginSession IN hSession.
/* Create the message consumer and start receiving messages. */
RUN createMessageConsumer IN hSession
  (THIS-PROCEDURE, "messagehandler", OUTPUT hMsgConsumer).
RUN receiveFromQueue IN hSession ("SampleQ1", ?, hMsgConsumer).
RUN startReceiveMessages IN hSession.
/* Wait for all messages to be received. */
RUN waitForMessages IN hSession ("inWait", THIS-PROCEDURE, ?).
RUN deleteSession IN hSession.
/* Message handler procedure */
PROCEDURE messageHandler:
  DEFINE INPUT  PARAMETER hMessage         AS HANDLE NO-UNDO.
  DEFINE INPUT  PARAMETER hMessageConsumer AS HANDLE NO-UNDO.
  DEFINE OUTPUT PARAMETER hAutoReply       AS HANDLE NO-UNDO.
  DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO.
  CREATE SAX-WRITER hdl2.
  hdl2:SET-OUTPUT-DESTINATION("LONGCHAR",lch).
  hdl2:START-DOCUMENT().
  CREATE SAX-READER hdl1.
  /* The Adapter procedure SetSaxReader will set the input source for a
     SAX-READER to the XML message that has been received. The application may
     then use normal SAX-READER calls to access the XML from the message. */
  RUN SetSaxReader IN hMessage (hdl1).
  hdl1:SAX-PARSE().
  DELETE OBJECT hdl1.
  RUN deleteMessage IN hMessage.
  hdl2:END-DOCUMENT().
  DISPLAY lch.
  ASSIGN
    lch          = ""
    stillWaiting = FALSE.
END PROCEDURE.
FUNCTION inWait RETURNS LOGICAL:
  RETURN stillWaiting.
END.
/*****************************************************/
/* callbacks for the SAX-READER function SAX-PARSE() */
/*****************************************************/
/* Procedure is called when the parser finds the start tag for an element. */
PROCEDURE StartElement:
  DEFINE INPUT PARAMETER namespaceURI AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER cLocalName   AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qname        AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER attributes   AS HANDLE    NO-UNDO.
  hdl2:START-ELEMENT(cLocalName, namespaceURI).
END.
/* This callback gets passed the character data for an element.*/
PROCEDURE Characters:
  DEFINE INPUT PARAMETER charData  AS MEMPTR  NO-UNDO.
  DEFINE INPUT PARAMETER iNumChars AS INTEGER NO-UNDO.
  DEFINE VARIABLE data AS CHARACTER NO-UNDO.
  data = GET-STRING(charData, 1, GET-SIZE(charData)).
  hdl2:WRITE-CHARACTERS(data).
END PROCEDURE.
/* This callback is called when the parser finds the end tag for an Element. */
PROCEDURE EndElement:
  DEFINE INPUT PARAMETER namespaceURI AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER cLocalName   AS CHARACTER NO-UNDO.
  DEFINE INPUT PARAMETER qName        AS CHARACTER NO-UNDO.
  hdl2:END-ELEMENT(cLocalName, namespaceURI).
END.
The following code sample shows how to use the setX-Document procedure.

setX-Document example

CREATE X-DOCUMENT hdl1.
hdl1:LOAD("file", "4k.xml", false).
RUN createXMLMessage IN hSession (OUTPUT hMesg).
RUN setX-Document IN hMesg(hdl1).
RUN sendToQueue IN hSession ("SampleQ1", hMesg, ?, ?, ?).
RUN deleteMessage IN hMesg.
The following sample code shows how to use getX-Document function.

getX-Document example

PROCEDURE messageHandler:
  DEFINE INPUT  PARAMETER hMessage         AS HANDLE NO-UNDO.
  DEFINE INPUT  PARAMETER hMessageConsumer AS HANDLE NO-UNDO.
  DEFINE OUTPUT PARAMETER hAutoReply       AS HANDLE NO-UNDO.
  DEFINE VARIABLE mtype   AS CHARACTER NO-UNDO.
  DEFINE VARIABLE hResult AS HANDLE    NO-UNDO.
  mtype = DYNAMIC-FUNCTION('getMessageType':u IN hMessage).
  CASE mtype:
    WHEN "TemptableMessage" THEN DO:
      hResult = DYNAMIC-FUNCTION('GetTempTable':u IN hMessage, ?, ?, ? ).
      /* TempTable actions as needed */
    END.
    WHEN "DatasetMessage" THEN DO:
      hResult = DYNAMIC-FUNCTION('GetDataSet':u IN hMessage, ?, ?, ? ).
      /* DataSet actions as needed */
    END.
    WHEN "XMLMessage" THEN DO:
      hResult = DYNAMIC-FUNCTION('getX-Document':u IN hMessage).
      /* X-DOCUMENTcalls as needed */
    END.
  END CASE.
  RUN deleteMessage IN hMessage.
END.
The X-DOCUMENT object reads XML from a file and sends it to a queue using an XMLMessage. The following example shows how to use X-DOCUMENT object to send a message.

domSender.p

DEFINE VARIABLE hdl1     AS HANDLE NO-UNDO.
DEFINE VARIABLE hMesg    AS HANDLE NO-UNDO.
DEFINE VARIABLE hSession AS HANDLE NO-UNDO.
/* Start up the session to the SonicMQ broker */
RUN jms/ptpsession.p PERSISTENT SET hSession ("-H localhost -S 5162 ").
RUN setBrokerURL IN hSession ("localhost:2506").
RUN beginSession IN hSession.
/* Create the Sonic XML message */
RUN createXMLMessage IN hSession (OUTPUT hMesg).
/* Load the XML file. */
CREATE X-DOCUMENT hdl1.
hdl1:LOAD("file", "personal.xml", FALSE).
/* The Adapter function SetX-Document will copy the XML from the X-DOCUMENT
   into the XML message. */
RUN setX-Document IN hMesg(hdl1).
DELETE OBJECT hdl1.
/* Send the XML message. */
RUN sendToQueue IN hSession ("SampleQ1", hMesg, ?, ?, ?).
/* Disconnect the session from the SonicMQ broker */
RUN deleteMessage IN hMesg.
RUN deleteSession IN hSession.
The X-DOCUMENT object reads an XMLMessage from a queue and writes it to a LONGCHAR. The following example shows how to use X-DOCUMENT object to receive a message.

domReceiver.p

DEFINE VARIABLE hSession     AS HANDLE   NO-UNDO.
DEFINE VARIABLE lch          AS LONGCHAR NO-UNDO
  VIEW-AS EDITOR SIZE 70 BY 30 LARGE.
DEFINE VARIABLE hMsgConsumer AS HANDLE   NO-UNDO.
DEFINE VARIABLE stillWaiting AS LOGICAL  NO-UNDO INITIAL TRUE.
/* Start up the session to the SonicMQ broker */
RUN jms/ptpsession.p PERSISTENT SET hSession ("-H localhost -S 5162 ").
RUN setBrokerURL IN hSession ("localhost:2506").
RUN beginSession IN hSession.
/* Create the message consumer and start receiving messages. */
RUN createMessageConsumer IN hSession
  (THIS-PROCEDURE, "messageHandler", OUTPUT hMsgConsumer).
RUN receiveFromQueue IN hSession ("SampleQ1", ?, hMsgConsumer).
RUN startReceiveMessages IN hSession.
/* Wait for all messages to be received. */
RUN waitForMessages IN hSession ("inWait", THIS-PROCEDURE, ?).
RUN deleteSession IN hSession.
/* Message handler procedure */
PROCEDURE messageHandler:
  DEFINE INPUT PARAMETER hMessage         AS HANDLE NO-UNDO.
  DEFINE INPUT PARAMETER hMessageConsumer AS HANDLE NO-UNDO.
  DEFINE OUTPUT PARAMETER hAutoReply      AS HANDLE NO-UNDO.
  DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO.
  /* The Adapter function GetX-Document will return a handle to a newly
     created X-DOCUMENT and load it with the XML message that has been
     received. The application may then use normal X-DOCUMENT calls to access
     the XML from the message. */
  hdl1 = DYNAMIC-FUNCTION('GetX-Document':u IN hMessage).
  hdl1:SAVE("LONGCHAR",lch).
  DELETE OBJECT hdl1.
  RUN deleteMessage IN hMessage.
  DISPLAY lch.
  ASSIGN
    lch          = ""
    stillWaiting = FALSE.
END PROCEDURE.
FUNCTION inWait RETURNS LOGICAL:
  RETURN stillWaiting.
END.