Progress
External Program
Interfaces


Gateway Sample Application

The gateway sample application demonstrates a framework for integrating the native 4GL publish and subscribe mechanism (named events) with the 4GL–JMS API. (See the "Integrating With the Native 4GL Publish-and-Subscribe Mechanism" section in Accessing SonicMQ Messaging From the Progress 4GL.")

Application Files

The sample application manages a set of customer records loaded from the sports.customer table. For each country, there is one instance of the application that manages the subset of customers from that country. The country is specified as an application startup parameter.

The gateway sample application files are in:

<Progress_install_dir>\src\samples\sonicmq\adapter\gateway_examples 

The gateway sample application consists of these three files:

The main loop of the application is in appDriver.p:

  1. The user specifies the Customer.Cust–num value.
  2. The application finds the customer and allows the user to update the record if the Customer.Country field matches the startup country.
  3. If the Customer.Country field does not match the startup country, the user can only view the customer record.
  4. Several applications, each managing one country, run concurrently. Each application is connected to a JMS server through a local JMSgateway object. The goal is to keep the records identical across the different locations.

  5. When an application modifies a customer record, it publishes the new record through a 4GL PUBLISH CustUpdate call.
  6. The local JMSgateway object subscribes to the CustUpdate event. It packs the published parameters in a JMS MapMessage and publishes it to the JMS CustUpdate topic.

  7. The other JMSgateway objects subscribe to the JMS CustUpdate topic. They receive the JMS MapMessage, unpack the parameters, and publish the updated record locally through a 4GL PUBLISH CustUpdate call.
  8. The application picks up the updated record and updates the local copy.

The file, appDriver.p, drives the publish and subscribe gateway example.

appDriver.p
/* appDriver.p: Drives the Pub/Sub gateway example. */ 
DEFINE INPUT PARAM country AS CHAR. 
DEFINE VAR customersH AS HANDLE. 
DEFINE VAR gatewayH AS HANDLE. 
DEFINE VAR custNum AS int. 
/* Initialization */ 
RUN customers.p PERSISTENT SET customersH. 
RUN loadCustomers IN customersH. 
RUN JMSgateway.p PERSISTENT SET gatewayH ("-H localhost -S 5162 "). 
/* Main loop. */ 
REPEAT: 
 custNum = ?. 
 UPDATE custNum label "cust-num" WITH FRAME ff CENTERED TITLE "Find Customer". 
 RUN updateCustInteractive IN customersH (custNum, country). 
END. 
RUN deleteGateway IN gatewayH. 

The file, JMSgateway.p (1 of 2), establishes a gateway between local and remote publish and subscribe events.

JMSgateway.p
/* JMSgateway.p: A gateway between local and remote Pub/Sub events. */ 
DEFINE INPUT PARAM connectionParams AS CHAR. 
/* JMS objects */ 
DEFINE VARIABLE pubsubsession AS HANDLE. 
DEFINE VARIABLE outMessage AS HANDLE. 
DEFINE VARIABLE consumer AS HANDLE. 
/* Raw Transfer Declarations */ 
DEFINE TEMP-TABLE rawtt FIELD val AS RAW. 
CREATE rawtt. 
FUNCTION bufferToRaw RETURNS RAW (bufferH AS HANDLE) FORWARD. 
/* Initializes the JMS server and subscribes to the CustUpdate topic */ 
RUN jms/pubsubsession.p PERSISTENT SET pubsubsession (connectionParams). 
RUN setBrokerURL IN pubsubsession ("localhost:2506"). 
RUN beginSession IN pubsubsession. 
RUN createMapMessage IN pubsubsession (OUTPUT outMessage). 
RUN createMessageConsumer IN pubsubsession (THIS-PROCEDURE, 
                                "handleRemoteEvent", 
                                OUTPUT consumer). 
RUN subscribe IN pubsubsession (
            "CustUpdate", /* Topic name */ 
            ?,            /* Not durable. */ 
            ?,            /* No message selector */ 
            true,         /* No local events please */ 
            consumer). 
RUN startReceiveMessages IN pubsubsession. 
/* Subscribes to local CustUpdate events */ 
SUBSCRIBE TO "CustUpdate" ANYWHERE RUN-PROCEDURE "handleLocalEvent". 
/* Publish locally a remote message from the CustUpdate topic. */ 
PROCEDURE handleRemoteEvent: 
DEFINE INPUT PARAMETER messageH AS HANDLE NO-UNDO. 
DEFINE INPUT PARAMETER messageConsumerH AS HANDLE NO-UNDO. 
DEFINE OUTPUT PARAMETER replyH AS HANDLE NO-UNDO. 
  PUBLISH "CustUpdate" 
          (DATE (DYNAMIC-FUNCTION('getChar':U IN messageH, "updateDate")), 
          DYNAMIC-FUNCTION('getInt':U IN messageH, "custNum"), 
          DYNAMIC-FUNCTION('getBytesToRaw':U IN messageH, "rawCust")). 
  RUN deleteMessage IN messageH. 
END. 
/* Publish remotely a local CustUpdate event. */ 
PROCEDURE handleLocalEvent: 
DEFINE INPUT PARAMETER dt AS DATE. 
DEFINE INPUT PARAMETER custNum AS INT. 
DEFINE INPUT PARAMETER custBuffer AS HANDLE. 
RUN setString IN outMessage ("updateDate", STRING(dt)). 
RUN setInt IN outMessage ("custNum", custNum). 
RUN setBytesFromRaw IN outMessage ("rawCust", bufferToRaw(custBuffer)). 
RUN publish IN pubsubsession ("CustUpdate", outMessage,  ?,  ?,  ?). 
END. 
PROCEDURE deleteGateway: 
RUN deleteMessage IN outMessage. 
RUN deleteSession IN pubsubsession. 
DELETE OBJECT THIS-PROCEDURE. 
END. 
FUNCTION bufferToRaw RETURNS RAW (bufferH AS HANDLE): 
/* Raw Transfer Variables */ 
DEFINE VAR rawbuf AS HANDLE. 
DEFINE VAR rawCust AS HANDLE. 
rawbuf = BUFFER rawtt:HANDLE. 
rawCust = rawbuf:buffer-field(1). 
bufferH:raw-transfer(true, rawCust). 
RETURN rawCust:BUFFER-VALUE. 
END. 

The file, customers.p, updates customer records from a specified country while keeping the other records identical to the master copy.

customers.p 
/* customers.p: Manages customer records of a specified country and keeps the 
other records identical to the master copy. */ 
DEFINE TEMP-TABLE custt LIKE customer. 
DEFINE BUFFER custtUpd FOR custt. 
DEFINE VAR custtH AS HANDLE. 
DEFINE VAR bufferH AS HANDLE. 
/* Getting a handle to a dynamic buffer. */ 
custtH = TEMP-TABLE custt:HANDLE. 
bufferH = custtH:DEFAULT-BUFFER-HANDLE. 
/* Subscribes to CustUpdate events. */ 
SUBSCRIBE TO "CustUpdate" ANYWHERE RUN-PROCEDURE "updateCustFromRaw". 
PROCEDURE loadCustomers: 
  FOR EACH customer: 
      CREATE custt. 
      buffer-copy customer to custt. 
  END. 
END. 
/* Updates a customer from the "correct" country, displays customers from 
other countries. */ 
PROCEDURE updateCustInteractive. 
  DEFINE INPUT PARAM custNum AS INT. 
  DEFINE INPUT PARAM custCountry AS CHAR. 
  FIND custt WHERE custt.cust-num = custNum. 
IF custt.country = custCountry THEN 
  DO: 
    UPDATE custt WITH 2 COL. 
    PUBLISH "CustUpdate" (TODAY, custNum, bufferH).  
  END. 
  ELSE 
    DISPLAY custt WITH 2 COL. 
END. 
/* Updates a customer record from a RAW value. */ 
PROCEDURE updateCustFromRaw: 
  DEFINE INPUT PARAM dt AS DATE. 
  DEFINE INPUT PARAM custNum AS INT. 
  DEFINE INPUT PARAM rawCust AS RAW. 
FIND custtUpd WHERE custtUpd.cust-num = custNum. 
  RAW-TRANSFER rawCust TO custtUpd. 
  MESSAGE custNum VIEW-AS ALERT-BOX TITLE "customer updated". 
END. 

Running the Sample Application

Follow these steps to run the sample application:

  1. Start the JMS server and the SonicMQ Adapter.
  2. Start two or more 4GL clients. Each 4GL client calls:
  3. RUN appDriver.p (country–name) 
    

      Each instance should be connected to the Sports database and should start up with a different country.
  4. Update a customer record with one client and watch the others display an ALERT–BOX with the cust–num of the modified customer.
  5. Display the modified customer record at each application instance. All the copies are identical.

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