Creating an integration logic application
In this chapter, you learn how to use IBM WebSphere Liberty Profile (Liberty) within CICS Transaction Server (TS) for IBM z/OS V5.3 (CICS) to develop a new service-based interface into an existing CICS application. We use the general insurance application for all of our coding examples. Although there are many options available when choosing to expose applications, we use the representational state transfer (RESTful) and JavaScript Object Notation (JSON) technologies within Liberty.
This chapter covers only the process of constructing and exposing a RESTful web service with JSON data formats. It assumes the existence of a ready-made Java application programming interface (API) to service the requests. In this case, the Java API that we use is an interface to the CICS GenApp insurance application. This interface, referred to as the GenApp Java business logic interface (BLI), encapsulates access to the underlying CICS GenApp programs and resources.
The GenApp Java BLI is implemented by using Java EE Connector Architecture with external call interface (JCA ECI) requests to invoke the GenApp COBOL programs, and uses JZOS toolkit-record generated Java classes internally to marshal Java data into record structures, to transmit to and from CICS. The details of the implementation of the BLI are not described here. We treat BLI implementation as a black box, which provides the business methods required to fulfill the web service requests.
This chapter describes the following topics:
10.1 JSON and the json-1.0 feature
JavaScript Object Notation (JSON) is an open standard format for data interchange. Although originally used in the JavaScript scripting language, JSON is now language-independent, with many parsers available in many languages.
Compared to Extensible Markup Language (XML), JSON has many advantages. Most predominantly, JSON is well-suited to easy integration for client-side software. It is based on the JavaScript syntax, however it is distinct from it. Suitable for any data exchange, JSON is often used within RESTful web services because of its easy consumption. XML is an extremely verbose language. Every element in the tree has a name, and the element must be enclosed in a matching pair of tags. Alternatively, JSON expresses trees in a nested array format, similar to JavaScript. This enables the same data to be transferred in a far smaller data package with JSON than with XML.
The Java API for JSON (json-1.0) feature provides a standardized method for constructing and manipulating data to be rendered in JSON.
10.2 RESTful and the jax-rs-1.1 feature
Representational State Transfer (REST) is a defined set of architectural principles by which you can design web services that focus on service resources. The REST architectural pattern takes advantage of the technologies and protocols of the World Wide Web to describe how data objects can be defined and modified.
In contrast to a request-response model, such as the SOAP protocol specification, which focuses on procedures made available by the system, REST is modeled around the resources in the system. Each resource is globally identifiable through its uniform resource identifier (URI). Because REST does not focus on the procedures and services provided by a system, a few actions are defined based on existing HTTP methods: GET, POST, PUT, DELETE, HEAD.
The <jaxrs-1.1> feature provides technologies that simplify the creation of RESTful-like web services. This is achieved by the use of Java annotations. For example, Table 10-1 shows annotation declarations before a Java method, in a jax-rs application, can be called directly when the respective HTTP method is received.
Table 10-1 A mapping of Java annotations to HTTP methods and their expected behaviors
Annotation
HTTP method
RESTful behavior expected
@GET
GET
Retrieve a resource representation
@PUT
PUT
Modify a resource representation
@POST
POST
Create a new resource representation
@DELETE
DELETE
Delete a resource representation
@HEAD
HEAD
Retrieve a resource’s metadata
10.3 Exposing GENAPP through a RESTful JSON interface
We now outline the steps that are needed to expose services from the GENAPP application through a RESTful JSON interface using the <jax-rs-1.1> and <json-1.0> features.
To expose a CICS application through a RESTful service, you need to follow a number of steps. At a high level, follow these steps:
Mapping a URI to your application in the Liberty RESTful servlet
Writing the application logic that handles the RESTful requests
Packaging and deploying the application to Liberty running inside CICS
Testing the RESTful service
We now review those steps in detail, using the sample application ported in Chapter 9, “Porting a web application” on page 161 as a starting point.
You now need to create the local project that we will use to build your application. Perform the following steps in your Eclipse environment to create a new Dynamic Web project:
1. Switch to the Java EE perspective by selecting Window → Open Perspective → Other → Java EE. Click OK.
2. Select File → New → Other → Dynamic Web Project.
3. Give the project a name and ensure that Dynamic web mobile version has the value of 3.0.
4. Clear Add project to an EAR in the EAR membership section.
5. Click Next and Next again.
6. Select Generate web.xml deployment descriptor.
7. Click Finish.
Before you start to configure and write your RESTful application, you need to configure the build path of the project. We know that we will use the libraries supplied by Liberty and the GenApp Java business logic interface, which provides access to the underlying CICS GenApp application. Add these libraries to the project by following these steps:
1. Right-click your Integration logic application package and select Build Path → Configure Build Path.
2. On the Projects tab, click Add.
3. Select the Business logic application project and click OK.
4. On the Libraries tab, ensure that Liberty JVM server libraries are present. If they are not, click Add Library. Select Liberty JVM server libraries. Click Next and select CICS TS 5.3 in the Version drop-down box. Click Finish.
5. Open web.xml and click Manage Utility Jars on the Design tab.
6. Click Add.
7. Select Project and click Next.
8. Select the Business logic application project GenAppBli and click Finish.
We have now extended our project build path to include the business logic project that we imported earlier, in addition to the Liberty JVM server libraries. We have also configured Eclipse to ensure that when we build and package our Integration logic application, the business logic package is built and deployed with our project as a utility JAR.
10.3.1 Mapping a URI to your application
We will map a URI pattern to the application that we will write to handle incoming RESTful requests. We do this by configuring the IBM JAX-RS REST servlet, which is provided by the Liberty web container. This mapping is created with the steps shown in Example 10-1. Add the following to WebContent/WEB-INF/web.xml.
Example 10-1 Excerpt of web.xml
<servlet>
<description>RESTful JSON service for the GENAPP application</description>
<servlet-name>GenAppService</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.ibm.cics.genapp.services.ServiceConfig</param-value>
</init-param>
/servlet>
Example 10-1 defines our servlet to the Liberty web container. Each individual field is explained in Table 10-2.
Table 10-2 Description of the parameters when creating a servlet in the web.xml configuration file
Field name
Example value
Field description
servlet
Not applicable
The root node. All fields encapsulated within this XML node define the servlet that we are creating.
servlet-name
GenAppService
The name used for internal reference to this servlet.
servlet-class
com.ibm.websphere.jaxrs.server.IBMRestServlet
The type of servlet we want to create. In this instance, we are extending the IBM JAX-RS REST servlet.
init-param
Not applicable
The initialization parameters required for this type of servlet. All parameters must be encapsulated inside this node.
param-name j
javax.ws.rs.Application
The name of an initialization parameter. In this case, we are describing where the IBM JAX-RS REST servlet will look for the configuration class of our service.
param-value
com.ibm.cics.genapp.services.ServiceConfig
The value of the initialization parameter. In this case, we are defining a class that we will create, which will define to the IBM JAX-RS REST servlet which entry point Java classes are used in our RESTful application.
When deployed, this will define the existence of our servlet to the Liberty web container. Before we begin to write the code for our service, it is important to map the invocation of our service to an inbound URI request. To do this, insert the XML shown in Example 10-2 on page 183 into the web.xml file.
Example 10-2 Excerpt of web.xml
<servlet-mapping>
<servlet-name>GenAppService</servlet-name>
<url-pattern>/service/*</url-pattern>
</servlet-mapping>
The fields in Example 10-2 are described in Table 10-3.
Table 10-3 Description of the parameters required to map a servlet to an inbound URL
Field name
Example value
Field description
servlet-mapping
Not applicable
The root node used for mapping a servlet to an inbound URL.
servlet-name
GenAppService+
The name of the servlet we want to map to a URI. It is important that this value matches the value of servlet-name that was used when defining the servlet to the IBM JAX-RS REST servlet.
url-mapping
/services/*
The URL pattern to map to the servlet. This maps our servlet to a URI that matches this URI pattern suffixed to the domain address of our Liberty application.
With this XML, we defined a servlet mapping between our GenAppServlet servlet and the URI mapping of <domain & port>/GenAppService/services/*. Where GenAppService is the URI of our Liberty application and /services/* maps all requests to our RESTful service.
10.3.2 Writing the application logic that handles the RESTful requests
At this point, we have only defined the existence of one Java class to the IBM JAX-RS REST servlet. The value that we entered for <param-value> in the servlet definition is the subclass that will be used when configuring which classes are available as entry points to our REST service. It is important that we create this class exactly as named. Create com.ibm.cics.genapp.services.ServiceConfig with the Java code that is shown in Example 10-3 on page 184.
Example 10-3 ServiceConfig class
package com.ibm.cics.genapp.services;
 
import java.util.Set;
import java.util.HashSet;
 
public class ServiceConfig extends javax.ws.rs.core.Application {
 
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(com.ibm.cics.genapp.services.CustomerService.class);
return classes;
}
}
This subclass extending javax.ws.rs.core.Application returns a set of classes that the IBM JAX-RS REST servlet will use when attempting to match incoming URI and HTTP method combinations for your RESTful service. In our example, we defined one class: com.ibm.cics.genapp.services.CustomerService.class. You can provide more classes here if you require multiple classes to handle your RESTful service requests. We demonstrate how this is useful when creating a service that interacts with multiple resources. Follow these steps to create your first service:
1. Create the class com.ibm.cics.genapp.services.CustomerService.
2. Above the class declaration, add, @javax.ws.rs.Path("/customer"). This defines a further URI mapping to this class. In our example, with the configuration in web.xml, all URIs with the mapping <domain & port>/GenAppWeb/services/customer will use this class to resolve the request. It is at this point that you can define a different @javax.ws.rs.Path annotation and add a new class to ServiceConfig if you want to create multiple classes to handle different resources. For example, you can create a class with annotation @jvax.ws.rs.Path(“/policy”) to handle requests against policies in the GENAPP application.
3. Create a new method in CustomerService named FetchCustomerById with the definition shown in Example 10-4.
Example 10-4 FetchCustomerById method
@javax.ws.rs.GET
@javax.ws.rs.Produces("application/json")
@javax.ws.rs.Path("/{customerNumber : \d+}}")
public JSONObject FetchCustomerById(
@javax.ws.rs.PathParam("customerNumber")String customerNum)
{
This defines to the IBM JAX-RS REST servlet that this method is driven when the following statements are true:
The URI <domain & port>/GenAppWeb/services/customer/<data> was received, where data matches the regular expression of \d+, digits only.
An HTTP GET request was received.
The request produces a MIME media type of application/json as a response.
This definition also defines that the method driven will produce a response of JSONObject, which is the Java JSON object provided by the Liberty feature <json-1.0> for parsing and serializing JSON data. In Example 10-4 on page 184, we used a variable value in the javax.ws.rs.Path annotation for the first time. This allows you to define URI mappings that will extract data from the URI and input those as path parameters for use in your Java code. In this example, we used the {customerNumber} variable as input data for the FetchCustomerById method, usable with the Java variable customerNum within the method. This means that a request that looks like the following, results in the method FetchCustomerById being driven with the input variable customerNumber defined as the value “1”. :
GET .../GenAppWeb/services/customer/1
The annotation @javax.ws.rs.Path supports regular expressions. The annotation @javax.ws.rs.Consumes is also available. This annotation defines which Content-Type the method receives. This can be useful if you want to create services that handle multiple different types, such as application/json and application/xml.
We are now in a position to create the logic for our interface. For our sample application, create a new class named CustomerService in the com.ibm.cics.genapp.services package.
Use the following package declaration for the application.
package com.ibm.cics.genapp.service;
The following imports are for the classes needed to use the GenApp Java Platform, Enterprise Edition business logic interface. These classes must also be available at run time, by importing the classes into your project, and including the GenAppBli.jar as a utility JAR as described earlier in 10.3, “Exposing GENAPP through a RESTful JSON interface” on page 181.
The source code for the GenApp Java BLI is provided with the additional materials for this book at the following URL:
The interface is specified by com.ibm.cics.genapp.bli.GenAppInterface, and is self-documenting, though Javadoc comments are also included.
The interface uses some auxiliary holder classes for customer and policy data passed to and from the interface methods. You need to import the following holder classes. These classes have getters and setters for the individual data items that they encapsulate.
Example 10-5 Import statements for auxiliary classes
import com.ibm.cics.genapp.GenAppException;
import com.ibm.cics.genapp.bli.Customer;
import com.ibm.cics.genapp.bli.CustomerData;
import com.ibm.cics.genapp.bli.GenAppInterface;
import com.ibm.cics.genapp.bli.GenAppJCAImpl;
import com.ibm.cics.genapp.bli.PolicyData;
import com.ibm.cics.genapp.bli.PolicyType;
Import the following IBM JSON support classes, which are used to build the object model for JSON. These are provided by the json-1.0 feature, which must be included in server.xml for your Liberty server. See Example 10-6.
Example 10-6 Import statements for IBM JSON support classes
import com.ibm.json.java.JSONArray;
import com.ibm.json.java.JSONObject;
The example application that we create uses variables and static strings, among other things that the labels used for individual data items within the JSON. They are shown in Example 10-7.
Example 10-7 Declaration of variables and static strings
private boolean error = false;
private static final String ERROR_MSG_LABEL = "errorMsg";
private static final String ERROR_CODE_LABEL = "errorCode";
private static String errorMsg = "";
private static int errorCode = 0;
private static final String ERROR_NOT_INTEGER = "Customer number must contain only numerical characters";
private static final String ERROR_GENAPP_ERROR = "Error retrieving response from the GenApp application.";
 
private static final int ERROR_NOT_INTEGER_CODE = 1;
private static final int ERROR_GENAPP_ERROR_CODE = 2;
private static final String CUSTOMER_NO_LABEL = "customerNumber";
private static final String FIRST_NAME_LABEL = "firstName";
private static final String LAST_NAME_LABEL = "lastName";
private static final String BIRTH_YEAR_LABEL = "birthYear";
private static final String BIRTH_MONTH_LABEL = "birthMonth";
private static final String BIRTH_DAY_LABEL = "birthDay";
private static final String HOUSE_NAME_LABEL = "houseName";
private static final String HOUSE_NUMBER_LABEL = "houseNumber";
private static final String POST_CODE_LABEL = "postCode";
private static final String MOBILE_PHONE_LABEL = "mobilePhone";
private static final String EMAIL_ADDRESS_LABEL = "emailAddress";
 
private static final String POLICY_NO_LABEL = "policyNumber";
private static final String POLICY_TYPE_LABEL = "policyType";
private static final String POLICY_ISSUE_DATE = "issueDate";
private static final String POLICY_EXPIRY_DATE = "expiryDate";
private static final String HTTP_CODE_LABEL = "httpCode";
private static int httpResponseCode = 0;
private static final int HTTP_OK = 200;
private static final int HTTP_BAD_REQUEST = 400;
private static final int HTTP_NOT_FOUND = 404;
private static final int HTTP_INTERNAL_ERROR = 500;
private static final String DATA_LABEL = "data";
private static final String RECORD_COUNT_LABEL = "recordCount";
Now that the infrastructure for our application is in place, we can focus on the logic and configuration of the RESTful service. The Java code shown below uses the Genapp Business logic interface to fetch a single customer record from Genapp running inside a CICS region. It then returns that customer record as a JSON response to an HTTP client that made the request:
JSONObject cJson = new JSONObject();
try {
Access to CICS data is by means of JCA to the GenApp COBOL programs. In this case, the JCA communications, and marshalling of the required record structures for the commareas and containers, have been encapsulated within the GenApp Java BLI component.
To access the underlying CICS GenApp programs, first instantiate an instance of the GenAppJCAImpl class, which is the live JCA implementation of the GenAppInterface Java interface:
GenAppInterface genAppJcaImpl = new GenAppJCAImpl();
To look up a specific GenApp customer record and obtain the customer details, invoke the getCustomer() method, passing the required customer number. This method builds a commarea in the appropriate format, invokes the LGICUS01 GenApp COBOL program using JCA, and extracts the customer details returned in the commarea.
getCustomer() shown in the following example returns a CustomerData object, which is a holder for the customer details extracted from the customer record returned from the JCA call:
CustomerData cdata = genAppJcaImpl.getCustomer(customerNumber);
If the call was successful and the customer was found (meaning, no GenAppException has been thrown (this is guaranteed by reaching this point in the code)), we can obtain the individual customer attributes by using getter methods on the returned CustomerData object, cdata. We extract each required attribute in turn, adding to the JSONObject Map with an appropriate label for each attribute. See Example 10-8.
Example 10-8 Sample of getter methods to retrieve customer attributes
cJson.put(CUSTOMER_NO_LABEL, cdata.getCustomerNumber());
cJson.put(FIRST_NAME_LABEL, cdata.getFirstName());
cJson.put(LAST_NAME_LABEL, cdata.getLastName());
if(cdata.getBirthDay() > 0)
{
cJson.put(BIRTH_DAY_LABEL, cdata.getBirthDay());
cJson.put(BIRTH_MONTH_LABEL, cdata.getBirthMonth());
cJson.put(BIRTH_YEAR_LABEL, cdata.getBirthYear());
}
cJson.put(HOUSE_NAME_LABEL, cdata.getHouseName());
cJson.put(HOUSE_NUMBER_LABEL, cdata.getHouseNumber());
cJson.put(POST_CODE_LABEL, cdata.getPostCode());
cJson.put(MOBILE_PHONE_LABEL, cdata.getMobilePhone());
cJson.put(EMAIL_ADDRESS_LABEL, cdata.getEmailAddress());
If an exception is thrown by the mainline processing, we catch it here and set an appropriate error message and HTTP response code, depending on the type of exception that is caught. See Example 10-9.
Example 10-9 Sample code for catching exceptions
} catch (NumberFormatException e) {
errorMsg = ERROR_NOT_INTEGER;
errorCode = ERROR_NOT_INTEGER_CODE;
httpResponseCode = HTTP_BAD_REQUEST;
error = true;
} catch (GenAppException e) {
error = true;
errorMsg = ERROR_GENAPP_ERROR;
httpResponseCode = HTTP_NOT_FOUND;
e.printStackTrace();
}
Instantiate a top-level JSONObject to return to the caller. This will be a holder for the response, representing either the customer data or an error message. See Example 10-10.
Example 10-10 Instantiating a new JSON object
JSONObject jsonResponse = new JSONObject();
If the method has been successful and we have valid customer data to return, add this code to the response object. See Example 10-11.
Example 10-11 Adding to response object if return is successful
if(!error)
{
jsonResponse.put(DATA_LABEL, cJson);
}
Otherwise, add the error code and message to the response object. See Example 10-12.
Example 10-12 Adding to response object if an error is returned
else
{
 
jsonResponse.put(ERROR_CODE_LABEL, errorCode);
jsonResponse.put(ERROR_MSG_LABEL, errorMsg);
}
Add the appropriate HTTP code to the response object. See Example 10-13.
Example 10-13 Set the HTTP code to the response object
jsonResponse.put(HTTP_CODE_LABEL, httpResponseCode);
Finally, return the top-level JSONObject response to our caller, the Liberty JAX-RS framework, which marshals the JSON into an HTTP response to the web service client. See Example 10-14.
Example 10-14 Return the JSON response
return jsonResponse;
10.4 Package and deploy the application
We have shown you the steps that are needed to create and configure a JAXRS application. Follow the steps in 5.3.2, “Deploying to CICS as an EBA” on page 94 to create a bundle project with our application and deploy that to CICS. Ensure that you select the Dynamic Web Project Include instead of OSGi Application Project described in step 4 on page 95.
10.4.1 Testing the RESTful service
Our JAXRS application has been configured and deployed to CICS. The next step is to test that our service is available and works correctly. Our application so far has only created a simple GET method for fetching one customer. This takes no HTTP body input from the client and can therefore be tested by using a standard web browser. If you want to test an application that uses an HTTP body, such as the POST methods that are available in the full Genapp sample, you might need to download a RESTful client. The Chrome web browser has one such client named “Simple REST Client.”
To test our application, we can send an HTTP GET request to the domain and path of our application. In this example, that is <domain port>/<application_root>/service/customers/8. This attempts to find a customer with customerNumber 8. Figure 10-1 on page 190 shows an HTTP GET request being made to the application and running a successful retrieval of customer 8 in JSON format.
Figure 10-1 The Simple REST Client Chrome add-on making a successful GET request to the Genapp JSON application
 
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.4.174