Release 10.1A: OpenEdge Development:
Messaging and ESB

> ## 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.

> In OpenEdge Release 10.1, 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. The 4GL has built-in functionality to transform `TEMP-TABLE` or `ProDataSet` data into XML. Additionally, 4GL clients read, write, and parse XML using `SAX-READER`, `SAX-WRITER`, and `X-DOCUMENT`.

> For more information on accessing the examples files, see the "Example procedures" section.

> The following example shows how to use the `SAX-WRITER` object:

> Saxwriter message example
>     DEFINE VARIABLE sessionH AS HANDLE no-undo.
>     DEFINE VARIABLE mesgH AS HANDLE no-undo.
>     RUN jms/jmssession.p PERSISTENT SET sessionH ("-SMQConnect").
>     RUN SETBrokerURL IN sessionH ("-H localhost -S 5162 ").
>     RUN beginSession IN sessionH.
>     DEFINE VARIABLE saxWriterH AS HANDLE NO-UNDO.
>     RUN createXMLMessage IN sessionH (OUTPUT mesgH).
>     saxWriterH = DYNAMIC-FUNCTION('getSaxWriter':u IN mesgH, ?).
>     /* Will write an envelope address */
>     saxWriterH:FORMATTED = TRUE.
>     /* Want to format this so it is easy to read */
>     saxWriterH:START-DOCUMENT().
>     /* The ENCODING           attribute defaults to UTF-8 */
>     /* The FRAGMENT           attribute defaults to FALSE */
>     /* The STRICT             attribute defaults to TRUE  */
>     saxWriterH:START-ELEMENT("mailingaddress").
>     RUN xmlData(INPUT "name", INPUT "Joe Perry").
>     saxWriterH:START-ELEMENT("address").
>     /* This node contains an attribute */
>     saxWriterH: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").
>     saxWriterH:END-ELEMENT("address").
>     saxWriterH:START-ELEMENT("address").
>     saxWriterH: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").
>     saxWriterH:END-ELEMENT("address").
>     saxWriterH:WRITE-EMPTY-ELEMENT("default").
>     saxWriterH:INSERT-ATTRIBUTE("type", "personal").
>     saxWriterH:END-ELEMENT("mailingaddress").
>     saxWriterH:END-DOCUMENT().
>     RUN deleteSaxWriter IN mesgH (saxWriterH).
>     RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?).
>     RUN deleteMessage IN mesgH.
>     PROCEDURE xmlData:
>     DEFINE INPUT PARAMETER xmlNode AS CHARACTER.
>     DEFINE INPUT PARAMETER charData AS CHARACTER.
>         saxWriterH:START-ELEMENT(xmlNode).
>         saxWriterH:WRITE-CHARACTERS(charData).
>         saxWriterH:END-ELEMENT(xmlNode).
>     END PROCEDURE.

> The following example shows how to use the setSaxReader procedure:

> setSaxReader example
>     DEFINE VARIABLE saxH AS HANDLE NO-UNDO.
>     CREATE SAX-READER saxH.
>     /* SAX-READER setup as needed */
>     PROCEDURE messageHandler:
>     DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO.
>     DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO.
>     DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE resultH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE mtype AS CHAR NO-UNDO.
>     mtype =  DYNAMIC-FUNCTION('getMessageType':u IN messageH).
>     IF mtype = "TemptableMessage" THEN DO:
>         resultH = DYNAMIC-FUNCTION('GetTempTable':u IN messageH, ?, ?, ? ).
>         /* TempTable actions as needed */
>     END.
>     IF mtype = "DatasetMessage" THEN DO:
>         resultH = DYNAMIC-FUNCTION('GetDataSet':u IN messageH, ?, ?, ? ).
>         /* DataSet actions as needed */
>     END.
>     IF mtype = "XMLMessage" THEN DO:
>         RUN setSaxReader IN messageH (saxH).
>         saxH:SAX-PARSE().
>     END.
>     RUN deleteMessage IN messageH.
>     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 sessionH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE mesgH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO.
>     DEFINE VARIABLE hdl2 AS HANDLE NO-UNDO.
>     /* Start up the session to the SonicMQ broker */
>     RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN sessionH ("localhost:2506").
>     RUN beginSession IN sessionH.
>     /* Create the Sonic XML message */
>     RUN createXMLMessage IN sessionH (OUTPUT mesgH).
>     /*
>        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 mesgH, ?).
>     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 mesgH (hdl2).
>     /* Send the XML message. */
>     RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?).
>     /* Disconnect the session from the SonicMQ broker */
>     RUN deleteMessage IN mesgH.
>     RUN deleteSession IN sessionH.
>     /*****************************************************/
>     /* callbacks for the SAX-READER function SAX-PARSE() */
>     /*****************************************************/
>     /* This procedure is called when the parser finds the start tag for an element.
>     */
>     PROCEDURE StartElement:
>     DEFINE INPUT PARAMETER namespaceURI AS CHARACTER.
>     DEFINE INPUT PARAMETER localName AS CHARACTER.
>     DEFINE INPUT PARAMETER qname AS CHARACTER.
>     DEFINE INPUT PARAMETER attributes AS HANDLE.
>     hdl2:START-ELEMENT(localName, namespaceURI).
>     END.
>     /* This callback gets passed the character data for an element. */
>     PROCEDURE Characters:
>     DEFINE INPUT PARAMETER charData AS MEMPTR.
>     DEFINE INPUT PARAMETER numChars AS INTEGER.
>     DEFINE VARIABLE data AS CHARACTER NO-UNDO.
>     data = GET-STRING(charData, 1, GET-SIZE(charData)).
>     hdl2:WRITE-CHARACTERS(data).
>     END.
>     /* This callback is called when the parser finds the end tag for an Element. */
>     PROCEDURE EndElement:
>     DEFINE INPUT PARAMETER namespaceURI AS CHARACTER.
>     DEFINE INPUT PARAMETER localName AS CHARACTER.
>     DEFINE INPUT PARAMETER qName AS CHARACTER.
>     hdl2:END-ELEMENT(localName, 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 sessionH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE msgConsumer AS HANDLE NO-UNDO.
>     DEFINE VARIABLE mesgH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE hdl2 AS HANDLE NO-UNDO.
>     DEFINE VARIABLE stillWaiting AS LOGICAL INIT yes.
>     DEFINE VARIABLE lch AS LONGCHAR NO-UNDO view-as editor size 70 by 30 large.
>     /* Start up the session to the SonicMQ broker */
>     RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN sessionH ("localhost:2506").
>     RUN beginSession IN sessionH.
>     /* Create the message consumer and start receiving messages. */
>     RUN createMessageConsumer IN sessionH (THIS-PROCEDURE,
>                                            "messageHandler",
>                                            OUTPUT msgConsumer).
>     RUN receiveFromQueue IN sessionH ("SampleQ1", ?, msgConsumer).
>     RUN startReceiveMessages IN sessionH.
>     /* Wait for all messages to be received. */
>     RUN waitForMessages IN sessionH ("inWait", THIS-PROCEDURE, ?).
>     RUN deleteSession IN sessionH.
>     /* Message handler procedure */
>     PROCEDURE messageHandler:
>     DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO.
>     DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO.
>     DEFINE OUTPUT PARAMETER autoReplyH 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 messageH (hdl1).
>     hdl1:SAX-PARSE().
>     DELETE OBJECT hdl1.
>     RUN deleteMessage IN messageH.
>     hdl2:END-DOCUMENT().
>     DISPLAY lch.
>     lch = "".
>     stillWaiting = FALSE.
>     END.
>     FUNCTION inWait RETURNS LOGICAL.
>     RETURN stillWaiting.
>     END.
>     /*****************************************************/
>     /* callbacks for the SAX-READER function SAX-PARSE() */
>     /*****************************************************/
>     /*
>        This procedure is called when the parser finds the start tag for an element.
>     */
>     PROCEDURE StartElement:
>     DEFINE INPUT PARAMETER namespaceURI AS CHARACTER.
>     DEFINE INPUT PARAMETER localName AS CHARACTER.
>     DEFINE INPUT PARAMETER qname AS CHARACTER.
>     DEFINE INPUT PARAMETER attributes AS HANDLE.
>     hdl2:START-ELEMENT(localName, namespaceURI).
>     END.
>     /* This callback gets passed the character data for an element.*/
>     PROCEDURE Characters:
>     DEFINE INPUT PARAMETER charData AS MEMPTR.
>     DEFINE INPUT PARAMETER numChars AS INTEGER.
>     DEFINE VARIABLE data AS CHARACTER NO-UNDO.
>     data = GET-STRING(charData, 1, GET-SIZE(charData)).
>     hdl2:WRITE-CHARACTERS(data).
>     END.
>     /* This callback is called when the parser finds the end tag for an Element.*/
>     PROCEDURE EndElement:
>     DEFINE INPUT PARAMETER namespaceURI AS CHARACTER.
>     DEFINE INPUT PARAMETER localName AS CHARACTER.
>     DEFINE INPUT PARAMETER qName AS CHARACTER.
>     hdl2:END-ELEMENT(localName, namespaceURI).
>     END.

> The following example shows how to use the setX-Document procedure:

> setX-Document example
>     CREATE x-document hdl1.
>     hdl1:LOAD("file", "4k.xml", false).
>     RUN createXMLMessage IN sessionH (OUTPUT mesgH).
>     RUN setX-Document IN mesgH(hdl1).
>     RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?).
>     RUN deleteMessage IN mesgH.

> The following example shows how to use getX-Document function:

> getX-Document example
>     PROCEDURE messageHandler:
>     DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO.
>     DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO.
>     DEFINE OUTPUT PARAMETER autoReplyH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE resultH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE mtype AS CHAR NO-UNDO.
>     mtype = DYNAMIC-FUNCTION('getMessageType':u IN messageH).
>     IF mtype = "TemptableMessage" THEN DO:
>         resultH = DYNAMIC-FUNCTION('GetTempTable':u IN messageH, ?, ?, ? ).
>         /* TempTable actions as needed */
>     END.
>     IF mtype = "DatasetMessage" THEN DO:
>         resultH = DYNAMIC-FUNCTION('GetDataSet':u IN messageH, ?, ?, ? ).
>         /* DataSet actions as needed */
>     END.
>     IF mtype = "XMLMessage" THEN DO:
>         resultH = DYNAMIC-FUNCTION('getX-Document':u IN messageH).
>         /* x-document calls as needed */
>     END.
>     RUN deleteMessage IN messageH.
>     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 sessionH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE mesgH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE hdl1 AS HANDLE NO-UNDO.
>     /* Start up the session to the SonicMQ broker */
>     RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN sessionH ("localhost:2506").
>     RUN beginSession IN sessionH.
>     /* Create the Sonic XML message */
>     RUN createXMLMessage IN sessionH (OUTPUT mesgH).
>     /* 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 mesgH(hdl1).
>     DELETE OBJECT hdl1.
>     /* Send the XML message. */
>     RUN sendToQueue IN sessionH ("SampleQ1", mesgH, ?, ?, ?).
>     /* Disconnect the session from the SonicMQ broker */
>     RUN deleteMessage IN mesgH.
>     RUN deleteSession IN sessionH.

> 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 sessionH AS HANDLE NO-UNDO.
>     DEFINE VARIABLE msgConsumer AS HANDLE NO-UNDO.
>     DEFINE VARIABLE stillWaiting AS LOGICAL INIT yes.
>     DEFINE VARIABLE lch AS LONGCHAR NO-UNDO view-as editor size 70 by 30 large.
>     /* Start up the session to the SonicMQ broker */
>     RUN jms/ptpsession.p PERSISTENT SET sessionH ("-H localhost -S 5162 ").
>     RUN setBrokerURL IN sessionH ("localhost:2506").
>     RUN beginSession IN sessionH.
>     /* Create the message consumer and start receiving messages. */
>     RUN createMessageConsumer
>         IN sessionH ( THIS-PROCEDURE, "messageHandler", OUTPUT msgConsumer).
>     RUN receiveFromQueue IN sessionH ("SampleQ1", ?, msgConsumer).
>     RUN startReceiveMessages IN sessionH.
>     /* Wait for all messages to be received. */
>     RUN waitForMessages IN sessionH ("inWait", THIS-PROCEDURE, ?).
>     RUN deleteSession IN sessionH.
>     /* Message handler procedure */
>     PROCEDURE messageHandler:
>     DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO.
>     DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO.
>     DEFINE OUTPUT PARAMETER autoReplyH 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 messageH).
>     hdl1:SAVE("LONGCHAR",lch).
>     DELETE OBJECT hdl1.
>     RUN deleteMessage IN messageH.
>     DISPLAY lch.
>     lch = "".
>     stillWaiting = FALSE.
>     END.
>     FUNCTION inWait RETURNS LOGICAL.
>     RETURN stillWaiting.
>     END.

Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095