Using WS-Addressing in CICS Transaction Server V4.1

This article shows you how to construct a simple SOA application using WS-Addressing techniques to dynamically locate services and route messages between services using IBM CICS Transaction Server V4.1. Using these techniques, you'll be able to build sophisticated SOA applications using message exchange patterns that do not fit the normal request/response paradigm, along with applications that use dynamic location of services.

Ian Hodges (ihodges@uk.ibm.com), Advisory Software Engineer, IBM

Photo of Ian HodgesIan Hodges is an Advisory Software Engineer at the IBM Software Lab in Hursley, United Kingdom, and develops Web technologies for CICS TS. He has developed various products that use Java technologies over the past 10 years, and is a Sun Certified Java Developer. You can contact Ian at ihodges@uk.ibm.com.



Lun Li (lilunbj@cn.ibm.com), Intern, IBM

Photo of Lun LiLun Li is an intern on the CICS and Enterprise Networking Solutions team at the IBM China Development Lab. You can contact Lun at lilunbj@cn.ibm.com.



Guan Jun Liu (liuguanj@cn.ibm.com), Software Engineer, IBM China

Photo of Guan Jun LiuGuan Jun Liu is a Software Engineer on the CICS TS Development Team at the IBM China Development Lab. He tests and develops Java and Web technologies for CICS TS, and has two years experience with Web services and CICS TS. You can contact Guan Jun at liuguanj@cn.ibm.com.



03 November 2010 (First published 03 November 2010)

Introduction

Web Services Addressing (WS-Addressing) is a newly supported standard in IBM® WebSphere® CICS® Transaction Server (TS) V4.1. Web service applications can use this standard to take advantage of new message exchange patterns, transport-neutral addressing, and reference properties. In this article, you'll look at a simple franchise business scenario that illustrates the new WS-Addressing support, and learn how to implement a WS-Addressing SOA application using the CICS WS-Addressing APIs.

Prerequisites

  • Development environment
    • Platform: CICS TS V4.1 on z/OS
    • Programming language: COBOL
  • CICS Web service-related concepts
    • Resources that CICS uses to support Web services, including PIPELINE, URIMAP, WEBSERVICE, and TCPIPSERVICE. With these resources, you can define the process that enables a Web service to run on CICS.
    • Web Service Assistant tool DFHWS2LS, which supports COBOL, PL/I, C, and C++ on CICS TS V4.1. DFHWS2LS is used to create language structures from WSDL and to produce the WSBind file that CICS requires to process service requests and responses.
    • CICS APIs that support Web services, such as INVOKE SERVICE.
    • CICS APIs that support WS-Addressing, including WSACONTEXT BUILD, WSACONTEXT GET, WSACONTEXT DELETE, and WSAEPR CREATE.
    • WS-Addressing Context -- a data area that is used to hold WS-Addressing MAPs constructed via the WSACONTEXT API, or by the DFHWSADH pipeline header handler from the MAPs held in the SOAP header during a request or received response. WSACONTEXTs can be built, interrogated, and deleted via the WSACONTEXT API functions BUILD, GET, and DELETE. During an outbound request or response, the WSACONTEXT is used to populate the SOAP header.

Overview of WS-Addressing

WS-Addressing provides a standard framework for specifying the endpoints of a SOAP message. This framework is transport-neutral and improves interoperability between Web services by defining a standard way to address these services and to provide addressing information in SOAP messages. SOAP messages can be sent over a variety of transport mechanisms, including HTTP and WMQ, each of which stores destination information for the message in a different way. The WS-Addressing specification introduces message addressing properties (MAPs) and endpoint references (EPRs), which are the core concepts of WS-Addressing.

Message addressing properties

Message addressing properties are a set of well-defined WS-Addressing properties that can be represented as elements in SOAP headers. MAPs provide a standard way of conveying a variety of information -- the endpoint to which message replies must be directed, for instance, or information about the relationship that the message has with other messages.

The MAPs are: To, Action, From, ReplyTo, FaultTo, MessageID, and RelatesTo. From, ReplyTo, and FaultTo are EPRs (more on which momentarily), and To is a URI address in the SOAP header and an EPR in the WS-Addressing Context. MessageID and RelatesTo are universally unique identifiers (UUIDs), and Action is a string.

Endpoint references

An endpoint reference is a specific type of MAP that provides a standard mechanism to encapsulate information about specific endpoints. Endpoint references can be sent to other parties and used to target the Web service endpoint that they represent. Thus, EPRs can be used to propagate information between a service and its clients -- an ability that's exploited in this tutorial. An EPR can contain a URI address, reference parameters, and metadata to describe the EPR.

The value of WS-Addressing

WS-Addressing is a core Web service specification that is employed by other specifications, including WS-RM (Reliable Messaging) and WS-AT (Atomic Transactions). It provides a number of advantages to an SOA application:

  • It makes transport-neutral addressing possible, which means that endpoint locations are no longer tied to the transport mechanisms that reach them.
  • Endpoint references encapsulate the address of the endpoint, the parameters required on a request, and the metadata of the endpoint. This allows parameters to be passed to, but not tied to, the transport.
  • New message exchange patterns can be constructed using asynchronous exchanges.
  • Responses can be routed according to response type: normal or fault.
  • Messages can be related to other messages.

WS-Addressing support in CICS TS V4.1

CICS supports the following recommendation specifications:

  • W3C WS-Addressing 1.0 -- Core
  • W3C WS-Addressing 1.0 -- SOAP Binding
  • W3C WS-Addressing 1.0 -- Metadata

These specifications are identified by the http://www.w3.org/2005/08/addressing namespace. For interoperability, CICS also supports the following submission specification:

  • W3C WS-Addressing -- Submission. This specification is identified by the http://schemas.xmlsoap.org/ws/2004/08/addressing namespace.

For more information on all of these specifications. see the Resources section below.

Use the submission specification only if you must interoperate with a client or Web service provider that only implements the submission specification.

CICS provides WS-Addressing support via a new pipeline handler, DFHWSADH, and new CICS APIs, WSACONTEXT and WSAEPR. You will see how these are set up and used in the sample application.

The DFHWS2LS utility recognizes WS-Addressing WSDL extensions and stores any WS-Addressing data in the WS-Bind files.

For more information on these topics, see the CICS TS V4.1 information center.

Overview of sample application

Franchising is a business model in which a company lets other companies use its business model and marketing initiatives. The franchisee company pays an initial fee and monthly fees based on revenues. The parent company also provides the franchisee with training to ensure that the franchisee conforms to the business model.

Our scenario involves a fictitious company called Acme Garden Structures (AGS), a multinational supplier of garden buildings such as sheds, summer houses, and log cabins. The main selling outlet for AGS is the Web, backed by marketing in individual countries. The garden structures that AGS produces are not manufactured in one place. Instead, to reduce transport costs, AGS uses the franchise model, producing the specification of the garden structures that many franchises around the world build and deliver to local customers. All stages of the order process are tracked so that a customer can log in to the AGS Website and view their order status.

Franchisee systems can be implemented on any Web services platform supporting WS-Addressing. In this tutorial, AGS systems are implemented in CICS. The sample franchisee systems are also implemented in CICS, but in a real-world setup the franchisee system implementations would be varied; which is when the power of SOA comes to the fore.

AGS SOA application

The AGS application is implemented as an SOA application, enabling it to interact with many heterogeneous franchisee systems. The AGS application exposes four Web services: AGSOrder, AGSConfig, AGSProblemResolution, and AGSTracking. The franchise applications (AGSFranchise) each expose a single Web service in accordance with AGS WSDL. The overall architecture is illustrated in Figure 1:

Figure 1. System architecture
System architecture of sample application

Here are descriptions of the Web services:

  • AGSOrder: Accepts orders and to queries existing orders. In accepting an order, AGSOrder uses AGSConfig to locate a suitable franchise to satisfy the order. Using the franchise's EPR, the order is placed with the franchise service AGSFranchise.
  • AGSConfig: Accepts and stores franchisee details, including the types of garden structures they produce, and, most importantly, an EPR containing details on how to call the franchise's AGSFranchise service. The service is also used to find franchises that can satisfy an order.
  • AGSTracking: Finds the current status of an order and also accepts status updates. As an order progresses, the franchisee service AGSFranchise sends order update messages.
  • AGSProblemResolution: Accepts faults that can occur in the ordering and production stages and returns an ordered list of faults to be resolved.
  • AGSFranchise: Accepts orders from AGSOrder. The service's responses are directed to the AGSTracking service. The service also calls the AGSTracking service to update the status of an order as the order progresses.
  • Client: The client application is a simple test program that drives AGSOrder.

Using WS-Addressing in this scenario allows AGSOrder to dynamically select the franchise system with which it will place an order, and to use a pre-registered EPR to call the franchise Web service, passing an order number as a reference parameter. The transports to the franchise systems can be a mix of HTTP and WMQ. The overall system operates as follows:

  1. A customer browses the AGS online catalog and places an order. (In this tutorial, a simple client is used to simulate this function.)
  2. The order is sent to AGSOrder, which uses the customer's address and requirements to select a suitable franchise from AGSConfig.
  3. Using AGSConfig, the selected franchise's order system EPR is sought. The franchises register their order services' EPR with the config service periodically. This EPR details how to contact the franchisee using the Address element and may include some fixed reference parameters relevant to the franchise.
  4. The AGS system constructs a ReplyTo EPR for its order tracking service.
  5. The To, ReplyTo, and FaultTo EPRs are updated with the AGS order number as a reference parameter. This identifies all messages as pertaining to a particular order.
  6. A WS-Addressed order request is made to the selected franchise with the WS-Addressing MAPs placed in the SOAP header.
  7. The franchise accepts the order and replies using the ReplyTo EPR that the order has been accepted.
  8. At all stages of the order, the ReplyTo EPR is used to send order updates to the AGS order tracking service. As a result, the franchisee system stores the EPR for later use.
  9. Problems may occur with the order as a result of technical difficulties, supply constraints, or other issues. In such a case, an assured message is sent to the problem resolution service (PRS). Customer representatives use the PRS to investigate and resolve the problem with the franchise.
  10. Customers can view their order status through a submit request from the AGS online Website.

Figure 2 illustrates the complete flow of order information within the application:

Figure 2. Order flow
Flowchart showing information flow within the application

Designing Web services interfaces in WSDL

The AGS application consists of five services: AGSOrder, AGSConfig, AGSTracking, AGSFranchise, and AGSProblemResolution. In this tutorial, the implementation of the AGSProblemResolution service is left as an exercise for the reader. To implement the AGS application, you need to determine the interfaces of each service and construct WSDL for each. Here is a chart of the information flow within the application:

Figure 3. Detailed flowchart
Detailed flowchart showing information flow within the application

The application walks through the following steps:

  1. Franchise services (FS) register their own EPRs with AGSConfig.
  2. AGSConfig responds to confirm that the registration was successful.
  3. A customer uses the AGS Website to place an order. The Website calls the AGSOrder service placeOrder, passing along the Name, Address, Structure, and Color.
  4. AGSOrder returns an order number.
  5. AGSOrder uses the customer's Address and Structure to find a franchise using AGSConfig (locateFranchiseEPR).
  6. AGSConfig returns the EPR.
  7. AGSOrder uses the returned EPR to address the FS and call processOrder. The order number is used as a reference parameter.
  8. The FS replies to AGSTracking (trackOrderStatus) with either an order accepted status or a fault status.
  9. If an FS has a system fault, then a fault message is sent to AGSProblemResolution registerProblem via the FaultTo EPR. If an application fault occurs (for example, if a structure cannot be built), FS generates a fault and sends it to AGSProblemResolution via the FaultTo EPR.
  10. The FS stores the FaultTo EPR like the ReplyTo EPR. If at any time a problem occurs with the order, the AGSFranchise service can call AGSProblemResolution with the order problem using the FaultTo EPR as its To destination.
  11. For an accepted order, the order status is checked.
  12. The FS system periodically sends a one-way request to the AGSTracking trackOrderStatus (using the ReplyTo EPR as a To EPR) with a status update at significant times (structure built, structure delivered, etc.). The EPR contains a reference parameter with the order number to identify the order.
  13. The status of the order is returned from AGSTracking to AGSOrder.
  14. The customer requests the status of the order via the Website, which calls AGSOrder trackOrder. trackOrder creates a WS-Addressed call to AGSTracking getOrderTracking. The response is returned to the customer via AGSOrder.

From these steps, you will need the following methods and parameters:

  • AGSConfig:
    • registerFranchise REQ(Franchise, Geography, Structure, EPR)
    • locateFranchiseEPR REQ(Geography, Structure) RESP(Franchise, EPR)
  • AGSOrder, called via the AGS Website:
    • placeOrder REQ(Customer Name, Structure, Color, Geography) RESP(Order number)
    • trackOrder REQ(Order number) RESP(Date, status)
  • AGSFranchise:
    • processOrder REQ(Customer Name, Structure, Color, Geography) RESP(Date, Status) RefParam=OrderNumber ReplyTo=AGSTracking FaultTo=AGSProblemResolution
    • updateOrderStatus REQ(Order number, Date, Status) (called by franchisee systems)
  • AGSTracking:
    • trackOrderStatus REQ(Date, Status) RefParam=OrderNumber
    • getOrderTracking REQ(order number) RESP(Date, Status)
  • AGSProblemResolution:
    • problem REQ(SOAPFault) -- This interface is left for the reader to implement.

WSDL file details

You must use WSDL files to describe the Web services and their interfaces. These files use WS-Addressing metadata extensions to provide WS-Addressing actions to the request messages. The WS-Addressing action MAP is similar to the SOAP action and denotes the action that the Web service must perform. In order to use WS-Addressing metadata, the http://www.w3.org/2005/08/addressing schema must be imported. The WSDL snippet in Listing 1 shows the WS-Addressing WSDL metadata action:

Listing 1. WSDL segment
<input message="ags:registrationMsg" wsam:action=
    "http://ags.example.ibm.com/registerEPR"/>
...
<input  message="ags:locateEPRReqMsg" wsam:action=
    "http://ags.example.ibm.com/locateEPR"/>

Here, wsam:action defines the actions that the service is expecting from the SOAP message header, and the operations that the service will take when it receives an action.

For a complete description of the WSDL, Download WSADEMO.zip at the bottom of the article and unzip it to see the WSDL files AGSOrderService, AGSConfigService, AGSTrackingService, and AGSFranchiseService. In the next few sections, you will create each of the Web services in the sample application.

Creating the AGSOrder service: Overview

To create the ASGOrder service, begin by establishing the service logic. AGSOrder is the core of the whole AGS IT system and accepts the request sent from the client. There are two kinds of request: placeOrder and trackOrder. Here is the program flowchart for the service:

Figure 4. AGSOrder flowchart
Flowchart for the AGSOrder service

AGSOrder uses the WSACONTEXT API to get the Action MAP sent from the client. During the execution of the Web service pipeline, the WS-Addressing header handler, DFHWSADH, processes the MAPs in the SOAP header and places them in a data area called the WS-Addressing Context or WSACONTEXT. The WSACONTEXT API can be used to interrogate the context and return MAPs sent by the caller.

If the Action is placeOrderReq, the program gets the input parameters from the container. There are four parameters: name, structure, color, and geography. AGSOrder sends these parameters to AGSConfig to find a suitable franchise to satisfy the order. Getting the returned EPR of the franchise, AGSOrder uses the EPR to build a To EPR and construct a ReplyTo EPR using the AGSTracking service EPR. The To, ReplyTo, and FaultTo EPRs are updated with the order number.

In the WS-Addressing core specification, the To MAP is of type URI and contains a simple URI address, and reference parameters are held separately in the SOAP header. But in the WSACONTEXT, the To MAP is stored as an EPR containing the address and the reference parameters.

If the Action is trackOrderReq, the program gets the input parameters from the container. There is only one parameter: OrderNumber. AGSOrder passes the order number to AGSTracking and gets the order status.

Creating the AGSOrder service: Detailed steps

Using DFHWS2LS (JCL DFHORDP and DFHORDR), process AGSOrderService.wsdl to create the WSBind files required by CICS to process the requests and responses, along with the COBOL copybooks for the AGSOrder service. This process generates the copybooks in Listings 2 through 5:

Listing 2. AGSORP01
03 placeOrderReq.                              
  06 name                    PIC X(256). 
  06 structure               PIC X(256). 
  06 color                   PIC X(256). 
  06 geography               PIC X(256).
Listing 3. AGSORP02
03 trackOrderReq.            
  06 orderNumber             PIC X(256).
Listing 4. AGSORQ01
03 placeOrderResp.
  06 orderNumber             PIC X(256).
Listing 5. AGSORQ02
03 trackOrderResp.                    
  06 orderDate               PIC X(256). 
  06 orderStatus             PIC X(256).

After the language structures are produced, the AGSOrder service can be written as the program AGSORDER. The key elements of the program are shown in the next few listings.

Listing 6 contains the main line of AGSOrder. AGSOrder can take one of two operations, as determined by the Action parameter in the request WSACONTEXT: one is placeOrder and the other is TrackOrderStatus:

Listing 6. AGSOrder main line
A-MAIN-PROCESSING SECTION. 
* Initialise any variables and information   
  PERFORM B010-INIT-PROC.     
* Get Action from the WSACONTEXT     
  PERFORM C010-GET-REQUEST-ACTION.      
* If the client sends a placeorder request   
  IF ACTION-OPTION(1:40) = ACTION-PLACEORDER 
    THEN                                     
      PERFORM C020-GET-REQUEST-ORDER-DATA    
      PERFORM C030-FORWARD-ORDER-REQUEST     
      PERFORM C040-PUT-ORDER-NUMBER        
  ELSE
* If the client sends a trackorder request  
      IF ACTION-OPTION(1:40) = ACTION-TRACKORDER 
          PERFORM C050-GET-REQUEST-ORDER-STATUS 
          PERFORM C060-GET-ORDER-STATUS          
          PERFORM C070-PUT-ORDER-STATUS
      ELSE PERFORM X-GENERIC-ABEND
      END-IF                      
   END-IF.                        
 A-MAIN-PROCESSING-EXIT.          
      GOBACK.

Use the ASSIGN CHANNEL command shown in Listing 7 to get the name of the current channel the Web service is using for later use:

Listing 7. ASSIGN CHANNEL
B010-INIT-PROC.
* Initialise any variables and information  
EXEC CICS ASSIGN                   
           CHANNEL(CURRENT-CHANNEL)
           RESP(RESP)              
           RESP2(RESP2)            
 END-EXEC.   
*
*   ... COBOL code ...
*

Use the WSACONTEXT GET command shown in Listing 8 in a service provider to get the MAPs sent by the service requester. ACTION specifies an output area to contain the Action MAP of the request. REQCONTEXT specifies that the program is to fetch the MAPs from the addressing context containing the request that is created by the pipeline header handler from MAPs in the SOAP header:

Listing 8. WSACONTEXT GET
C010-GET-REQUEST-ACTION.
* Retrieve the action value from WSACONTEXT with WS-A  API 
     EXEC CICS WSACONTEXT GET REQCONTEXT            
                              ACTION(ACTION-OPTION) 
                              RESP(resp)            
                              RESP2(resp2)          
     END-EXEC. 
*
*   ... COBOL code ...
*

Use the GET CONTAINER command shown in Listing 9 to retrieve data from a named channel container. PI-DFHWS-DATA is the container that holds the top-level data structure that is mapped to and from a SOAP request. WORKING-ROOT-DATA1 is the high-level language data structure:

Listing 9. GET CONTAINER
C020-GET-REQUEST-ORDER-DATA.
* Retrieve the content of root container of the request
     EXEC CICS GET CONTAINER(PI-DFHWS-DATA) 
                   INTO(WORKING-ROOT-DATA1) 
                   RESP(RESP)               
                   RESP2(RESP2)             
     END-EXEC.        
*
*   ... COBOL code ...
*

Use the PUT CONTAINER command shown in Listing 10 to place the structure type and geography in the named channel container, PI-DFHWS-DATA. The CHANNEL parameter is the channel name to which the container belongs. You must use a different channel here to distinguish the inbound channel and the outbound channel, so the inbound and outbound data will not be confused:

Listing 10. PUT CONTAINER
C030-FORWARD-ORDER-REQUEST. 
* Locate a franchise and forward the order request to it    
     MOVE STRUCTURE OF WORKING-ROOT-DATA1    
               TO structure OF locateEPRReq. 
     MOVE GEOGRAPHY OF WORKING-ROOT-DATA1    
               TO geography OF locateEPRReq. 
                                             
     EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)  
                   CHANNEL(OUTBOUND-CHANNEL) 
                   FROM(locateEPRReq)        
                   RESP(RESP)                
                   RESP2(RESP2)              
     END-EXEC.    
*
*   ... COBOL code ...
*

Use the WSACONTEXT BUILD command shown in Listing 11 to insert or replace WS-Addressing MAPs in the addressing context. CHANNEL specifies the name of the channel that is holding the addressing context. TOEPR is the destination EPR to which the SOAP message is sent. The Address field of the endpoint reference is specified as a URI in the EPRFROM option. EPRFROM is an input data value that contains a complete or partial endpoint reference that is to be placed in the addressing context. In this case, you supply the URI of the AGSConfig service:

Listing 11. WSACONTEXT BUILD
* Construct the TO EPR in the WSACONTEXT using WSA API 
    EXEC CICS WSACONTEXT BUILD              
                  CHANNEL(OUTBOUND-CHANNEL) 
                  TOEPR                     
                  ADDRESS                   
                  EPRFROM(AGSCFGURI)        
                  RESP(RESP)                
                  RESP2(RESP2)              
    END-EXEC. 
*
*   ... COBOL code ...
*

Use the INVOKE SERVICE command shown in Listing 12 to call a service from a CICS application. SERVICE specifies the name of the service. CHANNEL specifies the name of the channel that is used to pass the containers that hold the data mapped by the application data structure. On return, the same channel holds the response from the Web service. OPERATION specifies a data area that contains the name of the operation that is to be invoked. The name of the operation is contained in the WSDL for the target Web service:

Listing 12. INVOKE SERVICE
* Invoke AGSCFG Service
     EXEC CICS INVOKE                    
               SERVICE(AGSCFGSERVICE)    
               CHANNEL(OUTBOUND-CHANNEL) 
               OPERATION(AGSCFGOPERATION)
               RESP(RESP)                
               RESP2(RESP2)              
     END-EXEC  
*
*   ... COBOL code ...
*

After invoking the Web service, use the GET CONTAINER command shown in Listing 13 to get the response:

Listing 13. GET CONTAINER
* Get the return value
    EXEC CICS GET CONTAINER(PI-DFHWS-DATA) 
                  CHANNEL(OUTBOUND-CHANNEL)
                  INTO(locateEPRResp)      
                  RESP(RESP)               
                  RESP2(RESP2)             
END-EXEC.                                  
* Get the franchise EPR
   EXEC CICS GET CONTAINER(EPR-xml-cont OF locateEPRResp) 
                 CHANNEL(OUTBOUND-CHANNEL)
                 INTO(EPR-TEMP)           
                 RESP(RESP)               
                 RESP2(RESP2)             
   END-EXEC.                              
*
*   ... COBOL code ...
*

Having located a franchise that can satisfy the order, you use its EPR to call the franchisee service. Use the WSACONTEXT BUILD command shown in Listing 14 to construct the WSACONTEXT. The ReplyTo EPR is the EPR to which the SOAP response message is returned and REFPARMS is the reference parameter entity of the EPR:

Listing 14. WSACONTEXT BUILD
* Construct the TO EPR and put them into WSACONTEXT
     EXEC CICS WSACONTEXT BUILD              
                   CHANNEL(OUTBOUND-CHANNEL) 
                   TOEPR                     
                   ALL                       
                   EPRFROM(EPR-TEMP)         
                   RESP(RESP)                
                   RESP2(RESP2)              
     END-EXEC.  
     EXEC CICS WSACONTEXT BUILD              
                   CHANNEL(OUTBOUND-CHANNEL) 
                   TOEPR                     
                   REFPARMS                  
                   EPRFROM(REFER-ORDER-NUMBER)
                   RESP(RESP)                 
                   RESP2(RESP2)               
     END-EXEC.  
* Construct the REPLYTO EPR and put it into WSACONTEXT
     EXEC CICS WSACONTEXT BUILD                
                   CHANNEL(OUTBOUND-CHANNEL)   
                   REPLYTOEPR                  
                   ADDRESS                     
                   EPRFROM(TRACKING-SERVICE)   
                   RESP(RESP)                  
                   RESP2(RESP2)                
     END-EXEC.  
* Construct the REFERENCE PARAMETER and put it into WSACONTEXT
     EXEC CICS WSACONTEXT BUILD                
                   CHANNEL(OUTBOUND-CHANNEL)   
                   REPLYTOEPR                  
                   REFPARMS                    
                   EPRFROM(REFER-ORDER-NUMBER) 
                   RESP(RESP)                  
                   RESP2(RESP2)                
     END-EXEC.  
* Construct the FAULTTO EPR and put it into WSACONTEXT
     EXEC CICS WSACONTEXT BUILD                        
                   CHANNEL(OUTBOUND-CHANNEL)           
                   FAULTTOEPR                          
                   ADDRESS                             
                   EPRFROM(PROBLEM-RESOLUTION-SERVICE) 
                   RESP(RESP)                   
                   RESP2(RESP2)                 
     END-EXEC.  
     EXEC CICS WSACONTEXT BUILD                 
                   CHANNEL(OUTBOUND-CHANNEL)    
                   FAULTTOEPR                   
                   REFPARMS                     
                   EPRFROM(REFER-ORDER-NUMBER)  
                   RESP(RESP)                   
                   RESP2(RESP2)                 
     END-EXEC.  
*
*   ... COBOL code ...
*

After constructing the WSACONTEXT, you invoke the franchise Web service. The request pipeline is invoked and the WS-Addressing handler transforms the WSACONTEXT into SOAP header elements. Upon return, the addressing pipeline handler puts the response SOAP header MAPS into the response WSACONTEXT. The order number is returned to the caller that completes the processOrder action:

Listing 15. PUT RESPONSE
* Invoke Service AGSFranchise
     EXEC CICS INVOKE                         
               SERVICE(AGSFRANSERVICE1)       
               CHANNEL(OUTBOUND-CHANNEL)      
               OPERATION(AGSCFROPERATION)     
               RESP(RESP)                     
               RESP2(RESP2)                   
     END-EXEC       
*
*    ... COBOL code ...
*                   
* Response order number to client   
      MOVE ORDER-NUMBER-CHARS TO RESP-ORDER-NUMBER.   
      EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)          
                    FROM(RESP-ORDER-NUMBER)           
                    RESP(RESP)                        
                    RESP2(RESP2)                      
      END-EXEC.    
*
*   ... COBOL code ...
*

Listing 16 shows how to process the trackingOrder action. Extract the client input order number using the GET CONTAINER command, then put the order number into the outbound channel and construct WSACONTEXT using the tracking service URI. Invoke the trackingOrder service to get the status of the order and return it to the client:

Listing 16. TRACKINGORDER ACTION
C050-GET-REQUEST-ORDER-STATUS.
* Get the OrderNumber sent by the client
     EXEC CICS GET CONTAINER(PI-DFHWS-DATA)       
                   INTO(WORKING-ROOT-DATA2)       
                   RESP(RESP)                     
                   RESP2(RESP2)                   
     END-EXEC.                                    
* Put the Order Number into OUTBOUND-CHANNEL
     EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)       
                   CHANNEL(OUTBOUND-CHANNEL)      
                   FROM(WORKING-ROOT-DATA2)       
                   RESP(RESP)                     
                   RESP2(RESP2)                   
     END-EXEC.       
* Construct the TO EPR and put it into WSACONTEXT
     EXEC CICS WSACONTEXT BUILD                   
                   CHANNEL(OUTBOUND-CHANNEL)      
                   TOEPR                          
                   ADDRESS                        
                   EPRFROM(TRACKING-SERVICE)      
                   RESP(RESP)                     
                   RESP2(RESP2)                   
     END-EXEC.    
     MOVE orderNumber OF WORKING-ROOT-DATA2(1:18)
                        TO ORDER-NUMBER-CHARS.
     EXEC CICS WSACONTEXT BUILD
                CHANNEL(OUTBOUND-CHANNEL) 
                TOEPR
                REFPARMS
                EPRFROM(REFER-ORDER-NUMBER)
                RESP(RESP)
                RESP2(RESP2)
     END-EXEC. 
* Invoke Service AGSTracking
     EXEC CICS INVOKE                      
               SERVICE(AGSTRACKINGSERV)    
               CHANNEL(OUTBOUND-CHANNEL)   
               OPERATION(AGSTRACKOPERATION)
               RESP(RESP)                  
               RESP2(RESP2)                
     END-EXEC 

C060-GET-ORDER-STATUS.
* Get order status
     MOVE SPACES TO ORDER-STATUS-VALUE.      
     EXEC CICS GET CONTAINER(PI-DFHWS-DATA)  
              INTO(ORDER-STATUS-VALUE)  
              RESP(RESP)                
              RESP2(RESP2)              
     END-EXEC. 

C070-PUT-ORDER-STATUS.
* Construct the output
* Send to status back to client                     
     MOVE ORDER-STATUS-VALUE TO RESP-ORDER-STATUS.  
     EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)         
              FROM(RESP-ORDER-STATUS)             
              RESP(RESP)                          
              RESP2(RESP2)                        
     END-EXEC.                                      
*
*   ... COBOL code ...
*

Creating the AGSConfig service: Overview

AGSConfig is the configuration service for AGS. It holds details about the franchises and the products that the franchises build. It accepts the register request sent from each franchise and records the necessary information, including franchise name and location, product type, and Web service EPR in the AGM corporate VSAM file. AGSOrder uses AGSConfig to find a suitable franchise for each order. AGSConfig returns the EPR of the franchise that is found for each search request; this EPR is then used to call the franchise's AGSFranchise service. Here is the program flowchart for the service:

Figure 5. AGSConfig flowchart
Flowchart for the AGSConfig service

AGSConfig uses the WS-Addressing API to get the Action parameter from the request WSACONTEXT. If the Action is LocateEPR, the program gets two input parameters from the container: structure and geography. AGSConfig uses these parameters to find a suitable franchise and return its EPR.

If the Action is RegisterEPR, the program gets five input parameters from the container: franchise, geography, structure-num, structure-cont, and EPR. AGSConfig gets the structure information and records what kind of product this franchise can produce in the VSAM file. Using name, geography, structure-num, structure-cont, and EPR, AGSConfig constructs a record of the newly joined franchise and writes the record into the VSAM file.

Creating the AGSConfig service: Detailed steps

Using DFHWS2LS (JCL AGSCFGP and AGSCFGR), you must first process AGSConfigService.wsdl to create the WSBind files required by CICS to process the requests and responses, along with the COBOL copybooks for the AGSConfig service. This process generates the copybooks shown in Listings 17 through 19:

Listing 17. AGSCFP01
  03 registrationReq.                          
    06 franchise             PIC X(256).            
    06 geography             PIC X(256).            
                                                 
    06 structure-num         PIC S9(9) COMP-5 SYNC. 
    06 structure-cont        PIC X(16).             
                                                 
    06 EPR.                                      
      09 EPR-xml-cont        PIC X(16).           
      09 EPR-xmlns-cont      PIC X(16).           
                                                 
01 AGSCFP01-structure.                           
  03 structure               PIC X(256).
Listing 18. AGSCFP02
03 locateEPRReq.                    
  06 geography               PIC X(256). 
  06 structure               PIC X(256).
Listing 19. AGSCFQ02
03 locateEPRResp.                   
  06 franchise               PIC X(256). 
  06 EPR.                           
    09 EPR-xml-cont          PIC X(16).
    09 EPR-xmlns-cont        PIC X(16).

You also need to construct the data structure of the VSAM file record for franchise information, as shown in Listing 20:

Listing 20. AGSCFGCP
03  FRAN-NAME                PIC   X(30).        
03  FRAN-STRUCT-TYPE         PIC   X(8).         
03  FRAN-GEOGRAPHY           PIC   X(2).         
03  FRAN-EPR                 PIC   X(2048).

After the language structures are produced, the AGSConfig service can be written as the program AGSCFG. The key elements of the program are illustrated in the next few listings.

Listing 21 contains the main line of AGSConfig, which can take one of two operations, as determined by the Action in the request message WSACONTEXT: locateEPR and registerEPR:

Listing 21. AGSConfig main line
A-MAIN-PROCESSING SECTION. 
* Initialise any variables and information         
  PERFORM B010-INIT-PROC.  
* get Action from the WSACONTEXT                   
  PERFORM C010-GET-HEADER-ACTION.  
* find suitable franchise request from AGSOrder    
      IF ACTION-OPTION(1:36) = ACTION-LOCATE       
        THEN                                       
          PERFORM C020-GET-LOCATEEPR-DATA          
          PERFORM C030-BROWSE-READ-VSAM-FILE       
          PERFORM C040-PUT-CONTAINER-REPLY-EPR     
        ELSE 
 * register franchise request from franchise       
           IF ACTION-OPTION(1:38) = ACTION-REGISTER
              PERFORM C050-GET-REGISTEREPR-DATA    
              PERFORM C060-GET-STRUCT-EPR-DATA     
              PERFORM C070-FILL-NEW-RECORD   
              PERFORM C080-WRITE-VSAM-FILE
           ELSE PERFORM X-GENERIC-ABEND      
           END-IF                            
       END-IF.                               
 A-MAIN-PROCESSING-EXIT.                     
      GOBACK.

Next, initialize variables and information using the ASSIGN CHANNEL API:

Listing 22. ASSIGN CHANNEL
B010-INIT-PROC.
* Initialise any variables and information
      EXEC CICS ASSIGN                    
                 CHANNEL(CURRENT-CHANNEL) 
                 RESP(RESP)               
                 RESP2(RESP2)             
      END-EXEC.   
*
*   ... COBOL code ...
*

Listing 23 shows how to use the WSACONTEXT GET command in a service provider to get the MAPs sent by the service requester:

Listing 23. WSACONTEXT GET
C010-GET-HEADER-ACTION.
* Retrieve the action value from WSACONTEXT with WS-A API 
      EXEC CICS WSACONTEXT GET REQCONTEXT                
                                ACTION(ACTION-OPTION)     
                                RESP(resp)                
                                RESP2(resp2)              
      END-EXEC. 
*
*   ... COBOL code ...
*

For the Action registerEPR, use the GET CONTAINER command shown in Listing 24 to retrieve data from the named channel container PI-DFHWS-DATA, which holds the top-level data structure that is mapped to and from a SOAP request. WORKING-ROOT-DATA1 is AGSCFP01, which represents the register information:

Listing 24. GET CONTAINER
C050-GET-REGISTEREPR-DATA.
* Retrieve the content of root container of the request
       EXEC CICS GET CONTAINER(PI-DFHWS-DATA)  
                       INTO(WORKING-ROOT-DATA1)
                       RESP(RESP)              
                       RESP2(RESP2)            
       END-EXEC.        
*
*   ... COBOL code ...
*

STRUCTURE-CONT is the container that contains the types of products that the franchise can provide. EPR-XML-CONT contains the EPR of the service that the franchise provides. The loop in the code is used to mark the kind of product the franchise can provide. The types of products are represented with a flag byte 8 bits long, with each bit representing a product type. If the franchise can provide a product, the appropriate bit is set to 1; otherwise, it is set to 0, as shown in the logic in Listing 25:

Listing 25. AGSConfig logic
C060-GET-STRUCT-EPR-DATA.
* Get structure types when franchise registering      
     EXEC CICS GET CONTAINER(STRUCTURE-CONT)          
                   INTO(STRUCT-TYPE)                  
                   RESP(RESP)                         
                   RESP2(RESP2)                       
     END-EXEC.                                        
     IF RESP NOT = DFHRESP(NORMAL)                    
     THEN                                             
        PERFORM X-GENERIC-ABEND                       
     END-IF.                                          
* Record franchise products types                     
     PERFORM WITH TEST BEFORE UNTIL STRUCTURE-NUM = 0 
       MOVE CURRENT-POS TO START-POS                  
       MULTIPLY 256 BY START-POS                      
       ADD 1 TO START-POS                             
       EVALUATE STRUCT-TYPE(START-POS:5)              
         WHEN STRUCT-SHEDS                            
              MOVE '1' TO STRUCT-TEMP(1:1)            
         WHEN STRUCT-HOUSE                            
              MOVE '1' TO STRUCT-TEMP(2:1)            
         WHEN STRUCT-CABIN                            
              MOVE '1' TO STRUCT-TEMP(3:1)            
       END-EVALUATE                                   
       SUBTRACT 1 FROM STRUCTURE-NUM                  
       ADD 1 TO CURRENT-POS                           
     END-PERFORM.                                     
* Get EPR of the franchise service                    
     MOVE STRUCT-TEMP TO FRAN-STRUCT-TYPE OF NEW-RECORD.      
     EXEC CICS GET CONTAINER(EPR-XML-CONT OF registrationReq) 
                   INTO(EPR-TEMP)                             
                   RESP(RESP)                                 
                   RESP2(RESP2)                               
     END-EXEC.                                                
*
*   ... COBOL code ...
*

Next, create a new franchise record:

Listing 26. Create a franchise record
C070-FILL-NEW-RECORD.
* Construct data according to the structure of the VSAM file   
      MOVE FRANCHISE OF WORKING-ROOT-DATA1           
               TO FRANCHISE-TEMP.                    
      MOVE FRANCHISE-TEMP(1:30)                      
               TO FRAN-NAME OF NEW-RECORD.           
      MOVE GEOGRAPHY OF WORKING-ROOT-DATA1           
               TO GEOGRAPHY-TEMP.                    
      MOVE GEOGRAPHY-TEMP(1:2)                       
               TO FRAN-GEOGRAPHY OF NEW-RECORD.      
      MOVE EPR-TEMP                                  
               TO FRAN-EPR OF NEW-RECORD.            
  
*
*   ... COBOL code ...
*

Write the newly created record into the VSAM file using the WRITE FILE command, as shown in Listing 27, to complete the registerEPR action:

Listing 27. WRITE FILE
C080-WRITE-VSAM-FILE.
* Write file  
      MOVE FRAN-NAME OF NEW-RECORD TO PRIID. 
      EXEC CICS WRITE                        
                FILE(FILE-NAME)              
                FROM(NEW-RECORD)             
                RIDFLD(PRIID)                
                RESP(WR-RESP-CODE)           
      END-EXEC.                              
  
*
*   ... COBOL code ...
*

For the locateEPR Action, use the GET CONTAINER command shown in Listing 28 to retrieve data from the named channel container PI-DFHWS-DATA, which holds the top-level data structure that is mapped to and from a SOAP request. WORKING-ROOT-DATA2 is AGSCFP02, which represents the search information:

Listing 28. GET CONTAINER
C020-GET-LOCATEEPR-DATA. 
* Retrieve the content of root container of the request
       EXEC CICS GET CONTAINER(PI-DFHWS-DATA)   
                       INTO(WORKING-ROOT-DATA2) 
                       RESP(RESP)               
                       RESP2(RESP2)             
       END-EXEC.        
*
*   ... COBOL code ...
*

WORKING-ROOT-DATA2 holds the search condition from AGSOrder. The VSAM file is opened, and then you start reading it to search for a suitable franchise:

Listing 29. READ VSAM FILE
C030-BROWSE-READ-VSAM-FILE.
* Initialize search condition
MOVE STRUCTURE OF WORKING-ROOT-DATA2 TO STRUCT-VALUE. 
MOVE GEOGRAPHY OF WORKING-ROOT-DATA2                  
                          TO GEOGRAPHY-VALUE.         
                                                      
* STRUCT-VALUE IS THE STRUCTURE REQUIRED BY USER      
      EVALUATE STRUCT-VALUE(1:5)                      
         WHEN STRUCT-SHEDS                            
              MOVE 1 TO STRUCT-POS                    
         WHEN STRUCT-HOUSE                            
              MOVE 2 TO STRUCT-POS                    
         WHEN STRUCT-CABIN                            
              MOVE 3 TO STRUCT-POS                    
      END-EVALUATE.    
* Open VSAM file and search for a suitable franchise
      PERFORM C035-BROWSE-VSAM-FILE.                  
      IF BR-RESP-CODE = 0 THEN                        
         PERFORM C037-READ-VSAM-FILE                  
      ELSE                                            
         MOVE 'BROWSE FILE ERROR' TO FILE-RECORD      
         EXEC CICS SEND FROM(FILE-RECORD)             
                        LENGTH(120)                   
                        ERASE                         
         END-EXEC                                     
      END-IF.                                         
      EXIT.

Next, as shown in Listing 30, start browsing the VSAM file for a franchise that can satisfy the customer's requirements:

Listing 30. STARTBR
C035-BROWSE-VSAM-FILE.  
* Browse VSAM file        
      EXEC CICS STARTBR          
                FILE(FILE-NAME)  
                RIDFLD(PRIID)    
                RESP(BR-RESP-CODE)
      END-EXEC.      
*
*   ... COBOL code ...
*

Use the READNEXT FILE command shown in Listing 31 to get the next record in the VSAM file. Each record is a whole description of a franchise, including its product types and EPR. Next, compare the record you got with the search condition. If they match, the right franchise has been selected and its EPR returned. If they don't match, the next record in the VSAM file is selected and compared with the search condition. This continues until end of file -- not a particularly efficient search mechanism, but it sufficient for the purposes of this article:

Listing 31. Loop for finding a record
C037-READ-VSAM-FILE.
* Get a new record                            
      EXEC CICS READNEXT FILE(FILE-NAME)      
                         INTO(FILE-RECORD)    
                         RIDFLD(PRIID)        
                         RESP(RE-RESP-CODE)   
      END-EXEC.                               
* find the suitable franchise and get its EPR 
      IF RE-RESP-CODE = 0                     
         THEN                                 
           MOVE FRAN-STRUCT-TYPE OF FILE-RECORD TO STRUCT-TEMP    
           IF FRAN-GEOGRAPHY OF FILE-RECORD = GEOGRAPHY-VALUE(1:2)
              AND                                                 
              STRUCT-TEMP(STRUCT-POS:1) = '1'                     
              THEN                                                
                 MOVE FRAN-NAME OF FILE-RECORD   
                          TO  FRANCHISE OF RESP-FRANCHISE-EPR 
                 MOVE FRAN-EPR  OF FILE-RECORD   
                             TO  EPR-TEMP        
           ELSE                                  
              GO TO C037-READ-VSAM-FILE          
           END-IF                                
      ELSE                                       
         IF RE-RESP-CODE = DFHRESP(ENDFILE)      
            PERFORM C038-BROWSE-END-BR           
         ELSE                                    
            MOVE 'READ FILE ERROR' TO FILE-RECORD
            EXEC CICS SEND FROM(FILE-RECORD)     
                           LENGTH(120)           
                           ERASE                 
            END-EXEC                             
         END-IF                                  
      END-IF                                     
      EXIT.

When you have finished browsing the file, end the browse using ENDBR:

Listing 32. ENDBR
C038-BROWSE-END-BR.
       EXEC CICS ENDBR
             FILE(FILE-NAME)
       END-EXEC.

Use the PUT CONTAINER command shown in Listing 33 to put the located franchise EPR and the name of the franchise into containers. This code completes the locateEPR action:

Listing 33. PUT RESPONSE IN CONTAINER
C040-PUT-CONTAINER-REPLY-EPR. 
* Response franchise and its EPR to requester  
 MOVE 'FRAN-CONTAINER ' TO EPR-XML-CONT OF LOCATEEPRRESP.  
 EXEC CICS PUT CONTAINER(EPR-XML-CONT OF LOCATEEPRRESP)   
                    FROM(EPR-TEMP)
                    CHAR          
                    RESP(RESP)    
                    RESP2(RESP2)  
 END-EXEC.                        
*
*   ... COBOL code ...
*  
 EXEC CICS PUT CONTAINER(PI-DFHWS-DATA) 
              FROM(RESP-FRANCHISE-EPR)  
              RESP(RESP)                
              RESP2(RESP2)              
 END-EXEC.  
*
*   ... COBOL code ...
*

Creating the AGSTracking service: Overview

AGSTracking is used to record order information and track order status. It accepts requests sent from franchises and from AGSOrder. The franchise can accept an order and transmit the order information to AGSTracking for recording. AGSOrder accepts a tracking order status request from a client and forwards it to AGSTracking. AGSTracking uses the order number to find relevant information relating to the order, and returns that information to AGSOrder. The program flowchart for the service is illustrated in Figure 6:

Figure 6. AGSTracking flowchart
Flowchart for AGSTracking service

AGSTracking first uses the WS-Addressing API to get the Action parameter, which exists in the request WSACONTEXT. If the Action is processOrderResp, the program gets two input parameters from the container: orderDate and orderStatus. Then AGSTracking uses the WS-Addressing API to get the order number stored in the reference parameter. AGSTracking uses these parameters to construct a record and writes it into the VSAM file that holds the order status.

If the Action is getOrderTrackingReq, the program gets the lone input parameter, OrderNumber, from the container. AGSTracking reads the VSAM file, finds the order tracking records, and returns the order status to AGSOrder.

Creating the AGSTracking service: Detailed steps

Using DFHWS2LS (JCL AGPTRKP and AGPTRKR), process AGSTrackingService.wsdl to create the WSBind files required by CICS to process the requests and responses, along with the COBOL copybooks for the AGSTracking Service. This process generates the copybooks shown in Listings 34 to 36:

Listing 34. AGSTKP01
03 processOrderResp.               
  06 orderDate               PIC X(256).
  06 orderStatus             PIC X(256).
Listing 35. AGSTKP02
03 orderTrackingReq.                 
  06 orderNumber             PIC X(256).
Listing 36. AGSTKQ02
03 processOrderResp.               
  06 orderDate               PIC X(256).
  06 orderStatus             PIC X(256).

You also need to construct the data structure of the VSAM file that is used to hold order information and status, as shown in Listing 37:

Listing 37. ORDERSTA
03  ORDERNUMBER              PIC   X(30).   
03  ORDERDATE                PIC   X(30).   
03  ORDERSTATUS              PIC   X(2048).

After the language structures are produced, the AGSTracking service can be written as the program AGSTRACK. The key elements of the program are illustrated in the next few listings.

Listing 38 contains main line of AGSTracking. AGSTracking can take one of two operations, as determined by the Action in the SOAP header: processOrderReq and getOrderTrackingReq:

Listing 38. AGSTracking main line
A-MAIN-PROCESSING SECTION.    
* Initialise any variables and information  
PERFORM B010-INIT-PROC.  
* get Action from the WSACONTEXT            
PERFORM C010-GET-HEADER-ACTION.             
* If the process order request is sent      
IF ACTION-OPTION(1:67) = ACTION-PROCESSORDER
  THEN                                      
     PERFORM C020-GET-REQUEST-ORDER-DATA    
     PERFORM C030-FILL-NEW-RECORD           
     PERFORM C040-WRITE-VSAM-FILE   
  ELSE    
* If the get order status request is sent   
     IF ACTION-OPTION(1:46) = ACTION-GETORDSTATUS 
       PERFORM C050-GET-ORDER-NUMBER            
       PERFORM C060-GET-STATUS-FROM-VSAM          
       PERFORM C070-PUT-RESPONSE-STATUS
     ELSE PERFORM X-GENERIC-ABEND      
     END-IF                                       
  END-IF.                                         
A-MAIN-PROCESSING-EXIT.                           
  GOBACK.

Initialize variables and information using the ASSIGN CHANNEL API:

Listing 39. ASSIGN CHANNEL
B010-INIT-PROC.
* Initialise any variables and information  
EXEC CICS ASSIGN                    
           CHANNEL(CURRENT-CHANNEL) 
           RESP(RESP)               
           RESP2(RESP2)             
 END-EXEC.   
*
*   ... COBOL code ...
*

Use the WSACONTEXT GET command shown in Listing 40 in a service provider to get the MAPs sent by the service requester:

Listing 40. WSACONTEXT GET
C010-GET-HEADER-ACTION.
* Retrieve the action value from WSACONTEXT with WS-A API 
     EXEC CICS WSACONTEXT GET REQCONTEXT                
                              ACTION(ACTION-OPTION)     
                              RESP(resp)                
                              RESP2(resp2)              
     END-EXEC. 
*
*   ... COBOL code ...
*

For the processOrderReq action, use the GET CONTAINER command shown in Listing 41 to retrieve data from the container PI-DFHWS-DATA. WORKING-ROOT-DATA1 is the high-level language data structure of AGSTKP01:

Listing 41. GET CONTAINER
C020-GET-REQUEST-ORDER-DATA.
* Retrieve the content of root container of the request
     EXEC CICS GET CONTAINER(PI-DFHWS-DATA)
                   INTO(WORKING-ROOT-DATA1)
                   RESP(RESP)              
                   RESP2(RESP2)            
     END-EXEC.        
*
*   ... COBOL code ...
*

Construct the record that will be written to the VSAM file:

Listing 42. Construct record
C030-FILL-NEW-RECORD. 
* get the ordernumber in reference parameters    
     EXEC CICS WSACONTEXT GET REQCONTEXT         
                              TOEPR              
                              REFPARMS           
                              EPRINTO(REFERPARM) 
                              RESP(resp)         
                              RESP2(resp2)       
     END-EXEC.                                   
     IF RESP NOT = DFHRESP(NORMAL)               
     THEN                                        
        PERFORM X-GENERIC-ABEND                  
     ELSE                                        
       XML PARSE REFERPARM PROCESSING PROCEDURE PARSE-ORDERNUMBER 
     END-IF.
* File in the order number                              
     MOVE ORDERNUM TO ORDERNUMBER OF NEW-RECORD.        
* File in the order date                                
     MOVE ORDERDATE OF WORKING-ROOT-DATA1 TO TEMP-DATA. 
     MOVE TEMP-DATA(1:30) TO ORDERDATE OF NEW-RECORD.   
     MOVE SPACES TO TEMP-DATA.                          
* Fill in the Order Status                              
     MOVE ORDERSTATUS OF WORKING-ROOT-DATA1             
                 TO ORDERSTATUS OF NEW-RECORD.

Use the WRITE FILE command shown in Listing 43 to write the record into the VSAM file. This code completes the processOrderReq action:

Listing 43. WRITE FILE
C040-WRITE-VSAM-FILE 
* Read Update record from VSAM file 
      MOVE ORDERNUMBER OF NEW-RECORD TO PRIID.
      EXEC CICS READ               
                FILE(FILE-NAME)    
                INTO(TEMP-RECORD)  
                RIDFLD(PRIID)  
                UPDATE  
                RESP(WR-RESP-CODE) 
      END-EXEC. 
* If record exists, then perform update    
      IF WR-RESP-CODE = 0
            EXEC CICS REWRITE
                        FILE(FILE-NAME)
                        FROM(NEW-RECORD)
                        RESP(WR-RESP-CODE)
            END-EXEC
* if record does not exist, perform write
      ELSE IF WR-RESP-CODE = DFHRESP(NOTFND)
              MOVE ORDERNUMBER OF NEW-RECORD TO PRIID
              EXEC CICS WRITE
                          FILE(FILE-NAME)
                          FROM(NEW-RECORD)
                          RIDFLD(PRIID)
                          RESP(WR-RESP-CODE)
              END-EXEC
            ELSE PERFORM X-GENERIC-ABEND
            END-IF
      END-IF.
*
*   ... COBOL code ...
*

For the getOrderTrackingReq action, use the GET CONTAINER command to retrieve data from the container PI-DFHWS-DATA, as shown in Listing 44. WORKING-ROOT-DATA2 is the high-level language data structure of AGSTKP02:

Listing 44. Retrieve data
C050-GET-ORDER-NUMBER. 
* Retrieve the content of root container of the request 
 EXEC CICS GET CONTAINER(PI-DFHWS-DATA) 
               INTO(WORKING-ROOT-DATA2) 
               RESP(RESP)               
               RESP2(RESP2)             
 END-EXEC.                              
*
*   ... COBOL code ...
*                                       
 MOVE ORDERNUMBER OF WORKING-ROOT-DATA2 TO TARGET-DATA.
 MOVE TARGET-DATA(1:18) TO PRIID. 
*
*   ... COBOL code ...
*

Read the KSDS file using the order number that was input by the client as a key to get the detailed content, as shown in Listing 45. Then construct the response data structure and return it to the client:

Listing 45. Read file
C060-GET-STATUS-FROM-VSAM. 
* Get order status from VSAM file
       EXEC CICS READ FILE(FILE-NAME)
                  INTO(FILE-RECORD)  
                  RIDFLD(PRIID)     
                  RESP(RE-RESP-CODE)
       END-EXEC.                     
*
*   ... COBOL code ...
*

Finally, as shown in Listing 46, use the PUT CONTAINER command to pass the order status back to the caller. This code completes the getOrderTrackingReq action:

Listing 46. Return order status
C070-PUT-RESPONSE-STATUS. 
* Construct the response data 
      MOVE ORDERDATE OF FILE-RECORD TO                
                    orderDate OF RESP-ORDER-STATUS.   
      MOVE ORDERSTATUS OF FILE-RECORD TO              
                    orderStatus OF RESP-ORDER-STATUS. 
* Response order status to AGSOrder
      EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)     
               FROM(RESP-ORDER-STATUS)
               RESP(RESP)             
               RESP2(RESP2)           
      END-EXEC.                       
*
*   ... COBOL code ...
*

Creating the AGSFranchise service: Overview

In this section, you'll create a sample implementation of a franchisee AGSFranchise service. AGSFranchise has two operations: one to accept an order and process it, and the other to send an updated order status to AGSTracking. Here is the program flowchart for the service:

Figure 7. AGSFranchise flowchart
Flowchart for AGSFranchise service

AGSFranchise first uses the WS-Addressing API to get the Action parameter, which is located in the request WSACONTEXT. If the Action is ProcessOrder, AGSFranchise uses the WS-Addressing API to get the EPR of AGSTracking (stored in the ReplyTo EPR) and writes the EPR into the VSAM file in the AGSFranchise system. Then AGSFranchise gets four input parameters from the container: name, structure, color, and geography. AGSFranchise extracts the order number from the reference parameters of the To EPR using the WS-Addressing API. If the order is accepted, the order status is sent to AGSTracking for recording; if not, an error message is sent to the AGSProblemResolution service.

If the Action is updateOrderStatus, the service gets three input parameters from the container: OrderNumber, OrderDate, and OrderStatus. AGSFranchise uses the order number to locate the EPR of AGSTracking from the VSAM file and uses it as the To EPR. AGSFranchise then invokes the AGSTracking service to update the order status.

Creating the AGSFranchise service: Detailed steps

Using DFHWS2LS (JCL AGSFANP and AGSFANR), process AGSFranchiseService.wsdl to create the WSBind files required by CICS to process the requests and responses, along with the COBOL copybooks for the AGSFranchise service. This process generates the copybooks shown in Listings 47 through 49:

Listing 47. AGSFAP01
03 processOrderReq.                            
  06 name                    PIC X(256). 
  06 structure               PIC X(256). 
  06 color                   PIC X(256). 
  06 geography               PIC X(256).
Listing 48. AGSFAP02
03 updateOrderStatusReq.            
  06 orderNumber             PIC X(256). 
  06 orderDate               PIC X(256). 
  06 orderStatus             PIC X(256).
Listing 49. AGSFAQ01
03 processOrderResp.               
  06 orderDate               PIC X(256).
  06 orderStatus             PIC X(256).

You also need to construct the data structure of the VSAM file that is used to hold the order number and its ReplyTo EPR, as shown in Listing 50:

Listing 50. AGSFRANF
03  ORDERNUMBER              PIC   X(30).  
03  AGSTRACKING-EPR          PIC   X(2048).

After the language structures are produced, the AGSFranchise service can be written as the program AGSFAN1. The key elements of the program are illustrated in the next few listings.

Listing 51 contains the main line of AGSFranchise, which can take one of two operations, as determined by the Action in the request WSACONTEXT: processOrderReq and updateOrderReq:

Listing 51. AGSFranchise main line
A-MAIN-PROCESSING SECTION. 
* Initialise any variables and information             
  PERFORM B010-INIT-PROC.  
* get Action from the WSACONTEXT                       
  PERFORM C010-GET-HEADER-ACTION.      
* Accept an order                                      
      IF ACTION-OPTION(1:39) = ACTION-PROCESS-ORDER    
        THEN                                           
          PERFORM C020-GET-REQUEST-ORDER-DATA          
          PERFORM C030-PUT-FIRST-ORDER-STATUS          
      ELSE                                             
* Update order status                                  
         IF ACTION-OPTION(1:46) = ACTION-REGISTER-ORDER
            PERFORM C040-GET-REQUEST-ORDER-STATUS      
            PERFORM C050-PUT-UPDATED-ORDER-STATUS
         ELSE PERFORM X-GENERIC-ABEND                  
         END-IF                           
      END-IF.                                          
 A-MAIN-PROCESSING-EXIT.                               
      GOBACK.

Initialize variables and information using the ASSIGN CHANNEL API:

Listing 52. ASSIGN CHANNEL
B010-INIT-PROC.
* Initialise any variables and information  
EXEC CICS ASSIGN                                  
           CHANNEL(CURRENT-CHANNEL)                
           RESP(RESP)                              
           RESP2(RESP2)                            
 END-EXEC.   
*
*   ... COBOL code ...
*

Use the WSACONTEXT GET command shown in Listing 53 in a service provider to get the MAPs sent by the service requester:

Listing 53. WSACONTEXT GET
C010-GET-HEADER-ACTION.
* Retrieve the action value from WSACONTEXT with WS-A API 
     EXEC CICS WSACONTEXT GET REQCONTEXT                
                              ACTION(ACTION-OPTION)     
                              RESP(resp)                
                              RESP2(resp2)              
     END-EXEC. 
*
*   ... COBOL code ...
*

For the processOrderReq action, interrogate the WSACONTEXT and retrieve the To EPR reference parameters. Then, using the XML PARSE command, extract the order number. The details of the order are extracted from the PI-DFHWS-DATA container. WORKING-ROOT-DATA1 is AGSFAP01, which represents the order information. The ReplyTo EPR is also extracted from the WSACONTEXT and is stored for later use as a To EPR to send order update messages to AGSTracking. You should also extract and store the FaultTo EPR so that it can be used to send application fault messages to the AGSProblemResolution service, but for simplicity's sake we have not done that.

At this point, the AGSFranchise service returns to the caller. The service is unaware that the response is sent to another service and not its caller via the ReplyTo EPR. When the pipeline response leg is executed, the WS-Addressing header handler processes the ReplyTo EPR and causes a new one-way request to be sent to the AGSTracking service. All of these actions are handled by the code in Listing 54:

Listing 54. processOrderReq Action
C020-GET-REQUEST-ORDER-DATA.
* get the replytoepr in reference parameters           
     EXEC CICS WSACONTEXT GET REQCONTEXT               
                              CHANNEL(CURRENT-CHANNEL) 
                              TOEPR                    
                              REFPARMS                 
                              EPRINTO(REFERPARM)       
                              RESP(resp)               
                              RESP2(resp2)             
     END-EXEC.                                         
     IF RESP NOT = DFHRESP(NORMAL)                     
     THEN                                              
        PERFORM X-GENERIC-ABEND                        
     ELSE                                              
       XML PARSE REFERPARM PROCESSING PROCEDURE C027-PARSE-ORDERNUMBER 
     END-IF.        
* Retrieve the content of root container of the request
     EXEC CICS GET CONTAINER(PI-DFHWS-DATA)             
                   INTO(WORKING-ROOT-DATA1)             
                   RESP(RESP)                           
                   RESP2(RESP2)                         
     END-EXEC. 
* get the ReplyToEPR and store the EPR into VSAM file
     MOVE ORDERNUM TO ORDERNUMBER OF FILE-RECORD.
     EXEC CICS WSACONTEXT GET REQCONTEXT 
                         CHANNEL(CURRENT-CHANNEL)
                         REPLYTOEPR
                         ALL
                         EPRINTO(AGSTRACKING-EPR OF FILE-RECORD)
                         RESP(resp) 
                         RESP2(resp2)
     END-EXEC.  
     IF RESP NOT = DFHRESP(NORMAL)
     THEN PERFORM X-GENERIC-ABEND
     ELSE
          PERFORM C025-WRITE-RECORD-FILE
     END-IF. 
*
*   ... COBOL code ...
*

Write the ReplyTo EPR to a VSAM file for later use:

Listing 55. Write ReplyTo EPR
C025-WRITE-RECORD-FILE.
* Record the ReplyToEPR to the File
      MOVE ORDERNUM TO PRIID.
      EXEC CICS WRITE         
           FILE(FILE-NAME)    
           FROM(FILE-RECORD)  
           RIDFLD(PRIID)      
           RESP(WR-RESP-CODE) 
      END-EXEC                
*
*   ... COBOL code ...
*

Then construct the initial status of an order and put it into a container, as shown in Listing 56. WS-Addressing transfers it to the AGSTracking service using the ReplyTo EPR. This code completes the processOrderReq action:

Listing 56. Put order initial status
C030-PUT-FIRST-ORDER-STATUS.
* Response the initial order status to AGSTrackingService 
    MOVE FUNCTION CURRENT-DATE(1:14) 
               TO ORDERDATE OF RESP-ORDER-STATUS.         
    MOVE ORDER-INITIAL-STATUS                   
               TO ORDERSTATUS OF RESP-ORDER-STATUS.      
* put the order status into container 
      EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)
                     FROM(RESP-ORDER-STATUS)
                     RESP(RESP)  
                     RESP2(RESP2) 
      END-EXEC.
*
*   ... COBOL code ...
*

The updateOrderReq action is used by the franchisee system to send order status updates to AGSTracking. The initial order's ReplyTo EPR, which was stored in a VSAM file, is retrieved from the file, as shown in Listing 57. This EPR is used as a To EPR to send an order update to the AGSTracking service:

Listing 57. Get ReplyTo EPR
C040-GET-REQUEST-ORDER-STATUS. 
* put the order status into container       
      EXEC CICS GET CONTAINER(PI-DFHWS-DATA)
                    INTO(WORKING-ROOT-DATA2)
                    RESP(RESP)              
                    RESP2(RESP2)            
      END-EXEC.     
      MOVE orderNumber OF WORKING-ROOT-DATA2 TO PRIID.
      EXEC CICS READ
                 FILE(FILE-NAME)
                 INTO(TEMP-RECORD)
                 RIDFLD(PRIID)
                 RESP(WR-RESP-CODE)
      END-EXEC.    
*
*   ... COBOL code ...
*

Use the PUT CONTAINER command to put the updated order status into the container. Use the WSACONTEXT BUILD command to create a To EPR. Use the INVOKE SERVICE command shown in Listing 58 to call the AGSTracking service using the To EPR:

Listing 58. INVOKE SERVICE
C050-PUT-UPDATED-ORDER-STATUS.
            MOVE orderNumber OF WORKING-ROOT-DATA2 TO            
                                ORDER-NUMBER-CHARS.              
            MOVE orderDate   OF WORKING-ROOT-DATA2 TO            
                                orderDate OF RESP-ORDER-STATUS.  
            MOVE orderStatus OF WORKING-ROOT-DATA2 TO            
                                orderStatus OF RESP-ORDER-STATUS.
* put the order status into container         
      EXEC CICS PUT CONTAINER(PI-DFHWS-DATA)  
                    CHANNEL(OUTBOUND-CHANNEL) 
                    FROM(RESP-ORDER-STATUS)   
                    RESP(RESP)                
                    RESP2(RESP2)              
      END-EXEC.   
* build WSACONTEXT                                  
      EXEC CICS WSACONTEXT BUILD                    
                           CHANNEL(OUTBOUND-CHANNEL)
                           TOEPR                    
                           ALL                      
                           EPRFROM(TEMP-RECORD)    
                           RESP(RESP)               
                           RESP2(RESP2)             
      END-EXEC. 
* invoke tracking service using track operation   
      EXEC CICS INVOKE                            
                SERVICE(TRACKINGSERVICE)          
                CHANNEL(OUTBOUND-CHANNEL)         
                OPERATION(AGSTRACKOPERATION)      
                RESP(RESP)                        
                RESP2(RESP2)                      
      END-EXEC 
*
*   ... COBOL code ...
*

Deploying Web services on CICS

Now that you have developed the core services for AGS and for a franchise, you can deploy them to CICS:

  1. Define and install all the programs in the CICS region:
    CEDA DEF PROG(AGSOrder) G(WSA1)
    CEDA DEF PROG(AGSCFG) G(WSA1)
    CEDA DEF PROG(AGSTrack) G(WSA1)
    CEDA DEF PROG(AGSFan1) G(WSA1)
  2. Create three KSDS files. The first file is used by AGSConfigService to store franchisee details. The second is used by AGSTrackingService to store order information using an index. The third is used by AGSFranchise to store the ReplyTo EPR of AGSTracking, using orderNumber as the key. Update and run the sample JCL CRVSAMS to create these files.
  3. Define and install the files in CICS, ensuring that the Add, Browse, Delete, Read, and Update operations are set to YES:
    CEDA DEF FILE(FILEAS) G(WSA1) 
    CEDA DEF FILE(FILEBS) G(WSA1)
    CEDA DEF FILE(ADDRFL) G(WSA1)
  4. Define the provider PIPELINE resource. Use the sample providerforWSAddressing.xml for the ConfigFile, and suitable Shelf and WSDir directories:
    CEDA DEF PIPELINE(WSAPROPL) G(WSA1)
  5. Define the TCPIPSERVICE resource:
    CEDA DEF TCPIPSERVICE(WSAPORT) G(WSA1)
  6. Deploy the WebService provider:
    CEDA INSTALL G(WSA1)

Check that all the resources for a Web service provider have been installed successfully:

  • PIPELINE: A single PIPELINE definition defines an infrastructure that can be used by many applications. The information about the message handlers is supplied indirectly; the PIPELINE resource specifies the name of an HFS file that contains an XML description of the nodes and their configuration.
  • WEBSERVICE: Web services are typically created automatically from a Web service binding file when the PIPELINE's pickup directory is scanned. This action happens when the PIPELINE resource is installed, or as a result of a PERFORM PIPELINE SCAN command.
  • URIMAP: For service providers deployed using the CICS Web services assistant, the URIMAP resources are typically created automatically from a Web service binding file when the PIPELINE's pickup directory is scanned. This action happens when the PIPELINE resource is installed, or as a result of a PERFORM PIPELINE SCAN command.
  • TCPIPSERVICE: A TCPIPSERVICE definition is required in a service provider that uses the HTTP transport, and contains information about the port on which inbound requests are received.

Use CEMT INQUIRE WEBSERVICE to view the status of the Web service; the results should look like Figure 8. The resource is created with a name matching the WSBIND file name, and that the WEBSERVICE is associated with the PIPELINE resource that scanned it in:

Figure 8. CEMT INQUIRE WEBSERVICE PROVIDER
Results of CEMT INQUIRE WEBSERVICE PROVIDER

Use CEMT INQUIRE URIMAP to list the installed URIMAPs; the results should look like Figure 9. Ensure that the path for the URIMAP matches that entered into the JCL for the job that ran the DFHWS2LS utility earlier:

Figure 9. CEMT INQUIRE URIMAP
Results of CEMT CEMT INQUIRE URIMAP

Deploying the Web service requester on the CICS region

Now that you have deployed the Web service provider on the CICS region, you need to deploy a requester as well:

  1. Create the PIPELINE resource for the Web service requester:
    CEDA DEF PIPELINE(WSAREQPL) G(WSA1)
  2. Install the requester PIPELINE resource on the CICS region:
    CEDA Inquire PIPELINE(WSAREQPL) G(WSA1)

A corresponding Web service CICS resource is created and installed automatically, as you can see in Figure 10:

Figure 10. CEMT INQUIRE WEBSERVICE REQUESTER
Results of CEMT INQUIRE WEBSERVICE REQUESTER

Now that you have deployed a service requester on the CICS region, you can start to write the client program and test the business logic.

Creating the client

You have now deployed the AGS application and a sample franchisee AGSFranchise service to CICS. To test the services, you need a simple client program to drive the AGSOrder service. Use the JCICS test client program supplied in the code package AGSClientJCics.java to test the services. Create the PIPELINE resource for the Web service requester:

   CEDA DEF PROG(AGSClint) G(WSA1)

The results should look like Figure 11:

Figure 11. CEDA DEF PROGRAM
Results of CEDA DEF PROGRAM

Next, define and install a transaction to run the program:

   CEDA DEF TRANS(JCLT) PROG(AGSClint) G(WSA1)

Then run the transaction, and input the necessary parameters to invoke AGSOrderService. The result is displayed in the output file for Java on the USS file system. Input parameters include the AgsOrderService URI and the Action, among others. The parameters for the PutOrder action are Name, Structure, Color, and Location. For the TrackOrder action, the parameter is OrderNumber.

Examples of the command are shown in Listing 59:

Listing 59. Sample commands
jclt http://ags.example.ibm.com:80/AgsOrder PutOrder LION HOUSE BLUE 01

jclt http://ags.example.ibm.com:80/AgsOrder TrackOrder LION20100101010101

The result is shown in Figure 12:

Figure 12. Result
Results of the commands in Listing 59

The sample AGSClientJCics program is shown in Listing 60:

Listing 60. AGSClientJCICS
public class AGSClientJCics { 
	/*
	 * Get input parameters, construct the WSAContext and invoke AGSOrderService
	 */	
	public void invokeWebService()
	{
		... Application Code ...
		webService.setName("agsord.req");
		String result;
		//Create channel
		if(channel == null)
		{
			channel = task.createChannel("OUTBOUND-CHANNEL");
			container = channel.createContainer("DFHWS-DATA      ");
		}
		//Build ToEPR address
		WSAContext wsaContext = new WSAContext();
		wsaContext.setChannel(channel.getName());
		wsaContext.setEprAddress(WSAContext.TOEPR, URI);
		//Different logic
		if(Action.equals(putOrder))
		{
		... Application Code ...
			//Put container and invoke AGSOrderService
			container.put(orderReq);
			webService.invoke(channel, "placeOrder");
		... Application Code ...
		}
		else if(Action.equals(trackOrder))
		{
		... Application Code ...
			//Put container and invoke AGSOrderService
			container.put(trackReq);
			webService.invoke(channel, "trackOrder");
		... Application Code ...
			}
		... Application Code ...
	}
}

A Java client is also supplied with the code download. It was developed using IBM Rational Developer for System Z (Rational Application Developer could have also be used). The project uses the com.ibm.jaxws.thinclient_7.0.0.jar. package, which is provided by those two products and must be imported into the workspace. AGSOrderClient.zip contains the client as an exported Eclipse Java project.

Conclusion

This article has shown you how to construct a simple SOA application using WS-Addressing techniques to dynamically locate services and route messages between services using CICS TS V4.1. Using these techniques, you can construct sophisticated SOA applications that enable use of message exchange patterns that do not fit the normal request/response paradigm, along with applications that make use of dynamic location of services. The business uses are many and varied; this article has shown how a franchise business could operate with each franchisee registering their own service to work as part of the overall franchise application.


Download

DescriptionNameSize
Code sampleWSADEMO.zip84 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into WebSphere on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=572601
ArticleTitle=Using WS-Addressing in CICS Transaction Server V4.1
publish-date=11032010