Corporate Info | News | Solutions | Products | Partners | Services | Events | Download | How To Buy
BEA eLink JAM Doc Home | BEA eLink Java Adapter for Mainframe WLS Edition User Guide | Previous Topic | Next Topic | Contents | Index

Programming Scenarios

This section contains three scenarios for developing and deploying BEA eLink Java Adapter for Mainframe WLS Edition (JAM) applications. The scenarios are based on the general procedures presented in Developing Java Applications. They give you practical examples for using JAM tools, presented as tasks with step-by-step procedures. They illustrate typical situations, but do not represent all possible uses of the product.

The scenarios depict the development of a new application and the updating of existing applications. WebLogic Server (WLS) samples are used to illustrate any existing applications. All discussions are from the application developer's point of view, presume a properly installed and configured environment, and presume an appropriate mainframe application is available.

The following scenarios are provided:

- Scenario A: Developing a Multi-Service Data Entry Servlet

- Scenario B: Enhancing an Existing Servlet to Originate a Mainframe Request

- Scenario C: Updating an Existing EJB to Service a Mainframe Request

  Note: Although the sample code in this section represents typical applications, it is intended for example only and is not supported for actual use.

Scenario A: Developing a Multi-Service Data Entry Servlet

In this scenario, you develop a multi-service application, as opposed to the single-service application presented in Generating a Servlet-Only JAM Application. The scenario contains more sophisticated data validation with tips on how to manage states and it includes cosmetic enhancements using static HTML frames to present default forms.

Task 1: Use EgenCobol to Create a Base Application

Prerequisite

You must first identify the mainframe application and obtain its COBOL copybook. This is typically a CICS DFHCOMAREA or the user data portion of an IMS queue record layout. The copybook's name in this discussion is emprec.cbl, as shown in Listing 7-1.

Listing 7-1 Mainframe Application COBOL Copybook emprec.cbl

>     02  emp-record.
>     	05  emp-ssn					pic 9(9) comp-3.
>     	05  emp-name.
>     		10  emp-name-last			pic x(15).
>     		10  emp-name-first			pic x(15).
>     		10  emp-name-mi				pic x.
>     	05  emp-addr.
>     		10  emp-addr-street			pic x(30).
>     		10  emp-addr-st				pic x(2).
>     		10  emp-addr-zip			pic x(9).

Step 1: Prepare EgenCobol Script

In Listing 7-2, the data view emprecData is generated from the copybook named emprec.cbl.

Listing 7-2 Basic EgenCobol script

>     view emprecData from emprec.cbl

Step 2: Add Service Entries

Add the single line service entries in Listing 7-3 for create, read, update, and delete operations. They all use empRecData as input and return emprecData as output. In this example, a single data view is used; however, the input and output data views could be different.

Listing 7-3 Service Names Associated with Input and Output Views

>     service empRecCreate accepts empRecData returns empRecData
>     service empRecRead accepts empRecData returns empRecData
>     service empRecUpdate accepts empRecData returns empRecData
>     service empRecDelete accepts empRecData returns empRecData

Step 3: Add Page Declaration in EgenCobol Script

Multiple pages can be chained together. Any service entries should match services defined elsewhere in the script. The page declarations shown in Listing 7-4 associate buttons on the HTML display with services declared in the previous step.

Listing 7-4 Page Declaration Associating Display Buttons with Services

>     page empRecPage "Employee Record" {
>     view empRecData
>     	buttons {
>     		"Create" service(empRecCreate) shows empRecPage
>     		"Read" service(empRecRead) shows empRecPage
>     		"Update" service(empRecUpdate) shows empRecPage
>     		"Delete" service(empRecDelete) shows empRecPage
>     	}
>     }

Step 4: Add Servlet Name

As shown in Listing 7-5, empRecServlet is the servlet name to be registered as a URL in the WLS properties file. (Every servlet requires a URL to be registered this way. Refer to WLS documentation about deploying servlets for more specific information.) Here, the empRecPage is to be displayed when the empRecServlet is invoked.

Listing 7-5 Add Servlet Name

>     servlet empRecServlet shows empRecPage

The script is then saved as emprec.egen.

Step 5: Generate the Java Source Code

In Listing 7-6, invoke the EgenCobol code generator to create the base application that is then compiled. This makes class files (*.class) available for servlet customizing. The empRecData.java is the data view object for emprec.cbl.

Warning: CLASSPATH should include the WLS subdirectories and the jam.jar file; otherwise, the compile fails.

Note: You can create a script file containing the EgenCobol command line, along with the javac command to make the invocation easier.

Listing 7-6 Generating the Java Source Code

>     java bea.jam.egen.EgenCobol emprec.egen
>     ls  emp*.java
>     	empRecData.java      empRecServlet.java

>     javac emp*.java

Step 6: Review the Java Source Code

It is a good idea to obtain a list of accessors for use later. In general, you should look at the EgenCobol output to become familiar with each of the scenarios presented in this section.

The entire method of customizing the generated output is predicated on derivation from generated code. The base application can be regenerated without destroying the custom code.

Note: Each COBOL group item has its own accessor. This is important because the group name represents a nested inner class that must be accessed in order to retrieve the members.

In the Listing 7-7, the output from the grep command shows the relationships in reverse order, for example:

>     getEmpRecord().getEmpAddr().getEmpAddrSt()

This is illustrated in the actual code example shown subsequently in this scenario.

Listing 7-7 Review the Java Source Code

>     grep get emp*.java
>       empRecData.java:			public BigDecimal			getEmpSsn()
>       empRecData.java:				public String			getEmpNameLast()
>       empRecData.java:				public String			getEmpNameFirst()
>       empRecData.java:				public String			getEmpNameMi()
>       empRecData.java:			public EmpNameV		getEmpName()
>       empRecData.java:				public String			getEmpAddrStreet()
>       empRecData.java:				public String			getEmpAddrSt()
>       empRecData.java:				public String			getEmpAddrZip()
>       empRecData.java:			public EmpAddrV		getEmpAddr()
>       empRecData.java:		   public EmpRecordV		getEmpRecord()

Task 2: Create Your Custom Application from the Base Application

The preferred customizing method is to derive a custom class from the generated base application.

Step 1: Start with Imports

In Listing 7-8, BigDecimal supports COMP-3 packed data. HttpSession is available for saving limited state. DataView is the base for emprecData. The empRecData and empRecServlet were generated from the COBOL copybook.

Listing 7-8 Using Imports to Start Creating the Custom Application

>     import java.math.BigDecimal;
>     import javax.servlet.http.HttpSession;
>     import bea.dmd.dataview.DataView;
>     import empRecData;
>     import empRecServlet;

Step 2: Declare the New Custom Class

Listing 7-9 shows how to extend the generated servlet. This enables regeneration of the base application without destroying customized code. Fields can be added to the copybook without disrupting the customized code.

Listing 7-9 Declaring the New Custom Class

>     public class customCrud
>     	extends empRecServlet
>     {
>     :
>     :

Step 3: Add Implementation for doGetSetup

In Listing 7-10, you can see how to provide a new data view and the http session. The HttpSession (s) can be used to hold a reference to the data view. This ensures you are actually in the first pass rather than a browser back arrow. The data view provided (dv) is a fresh instance of the empRecData data view.

Listing 7-10 Add Implementation for doGetSetup

>     public DataView doGetSetup(DataView dv, HttpSession s){
>     empRecData erd = (empRecData)s.getValue("customCrud");
>     if (erd == null)
>        erd = (empRecData)dv; // use new dataview

Step 4: Continue Implementation for doGetSetup

In Listing 7-11, note the use of group level accessors to obtain fields. This code pre-fills fields with data entry hints as to what fields are required, or how numeric values should be entered. You can fill form data in any manner required prior to displaying.

Listing 7-11 Continue Implementation for doGetSetup

>     if(erd.getEmpRecord().getEmpSsn().compareTo(BigDecimal.valueOf(0L)) == 0)
>     	erd.getEmpRecord().setEmpSsn(BigDecimal.valueOf(123121234L));
>     if (erd.getEmpRecord().getEmpName().getEmpNameLast().length() == 0)
>     	erd.getEmpRecord().getEmpName().setEmpNameLast("Entry Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameFirst().trim().length() == 0)
>     	erd.getEmpRecord().getEmpName().setEmpNameFirst("Entry Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrStreet().trim().length() == 0)
>     	erd.getEmpRecord().getEmpAddr().setEmpAddrStreet("Entry Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrSt().trim().length() == 0)
>     	erd.getEmpRecord().getEmpAddr().setEmpAddrSt("TX");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrZip().trim().length() == 0)
>     	erd.getEmpRecord().getEmpAddr().setEmpAddrZip("123451234");

Step 5: Finish Implementation for doGetSetup

In Listing 7-12, note the use of the http session putValue to save a reference to the data view. The doGet() processing continues on return. This data will be presented in the displayed form.

Listing 7-12 Finish Implementation for doGetSetup

>     s.putValue("customCrud",(Object)erd);
>     	return erd;
>     }

Step 6: Create Implementation for doPostSetup

In Listing 7-13, the data view passed in contains values entered into the form by the application user. (The HttpSession is also available for use at this point, if required.)

Listing 7-13 Create Implementation for doPostSetup

>     public DataView doPostSetup(DataView dv, HttpSession s)
>     {
>     	empRecData erd = (empRecData)dv;

Step 7: Continue Implementation for doPostSetup

In Listing 7-14, note the use of group-level accessors to obtain fields. This code checks for original defaults, as well as missing data. The SocialSecurity is a BigDecimal object. Validation can be simple or complex as necessary.

Listing 7-14 Continue implementation for doPostSetup

>     if(erd.getEmpRecord().getEmpSsn().compareTo(BigDecimal.valueOf(0L)) == 0)
>     	throw new Error("Social Security Number Is Required");
>     if(erd.getEmpRecord().getEmpSsn().compareTo(BigDecimal.valueOf(123121234L)) == 0)
>     	throw new Error("Social Security Number Is Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameLast() == null)
>     	throw new Error("Last Name Is Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameLast().trim().length() == 0)
>     	throw new Error("Last Name Is Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameLast().trim().compareTo("Entry
>     			Required") == 0)
>     	throw new Error("Last Name Is Required");

Step 8: Continue Implementation of doPostSetup

In Listing 7-15, note the use of group-level accessors to obtain fields. This code checks for original defaults, as well as missing data. (Validation routines could have been split out by field.)

Listing 7-15 Continue Implementation of doPostSetup

>     if (erd.getEmpRecord().getEmpName().getEmpNameFirst() == null)
>     	throw new Error("First Name Is Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameFirst().trim().length() == 0)
>     	throw new Error("First Name Is Required");
>     if (erd.getEmpRecord().getEmpName().getEmpNameFirst()
>                                           .trim().compareTo("Entry Required") == 0)
>     	throw new Error("First Name Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrStreet() == null)
>     	throw new Error("Street Address Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrStreet().trim().length() == 0)
>     	throw new Error("Street Address Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrStreet()
>                                          .trim().compareTo("Entry Required") == 0)
>     	throw new Error("Street Address Is Required");

Step 9: Continue Implementation for doPostSetup

In Listing 7-16, notice the use of group-level accessors to obtain fields. This code checks for original defaults, as well as missing data. Depending on the application, it may be more advantageous to develop validations as separate methods. This enables routines to be developed and tested with a servlet and easily re-used in an EJB.

Listing 7-16 Continue Implementation for doPostSetup

>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrSt() == null)
>     	throw new Error("State Abreviation Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrSt().trim().length() == 0)
>     	throw new Error("State Abreviation Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrSt()
>                                          .trim().compareTo("TX") != 0)
>     	throw new Error("Texas Employees ONLY");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrZip() == null)
>     	throw new Error("ZipCode Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrZip().trim().length() == 0)
>     	throw new Error("ZipCode Is Required");
>     if (erd.getEmpRecord().getEmpAddr().getEmpAddrZip()
>                                          .trim().compareTo("123451234") == 0)
>     	throw new Error("ZipCode Is Required");

Step 10: Finish Implementation of doPostSetup

In Listing 7-17, the http session getValue is used to remove a reference to the data view. This prevents re-posting the same data twice. The doPost processing continues on return. This data is now passed to the mainframe.

Listing 7-17 Finish Implementation for doPostSetup

>     else
>     	s.removeValue("customCrud");
>     	return erd;
>     }

Step 11: Create Implementation for doPostFinal

In Listing 7-18, the doPostFinal occurs after mainframe transmission, but prior to re-display in the browser. This example clears entered data after it is sent to the mainframe. This step completes the custom servlet.

Listing 7-18 Create Implementation for doPostFinal

>     public DataView doPostFinal(DataView dv, HttpSession s){
>     empRecData erd = (empRecData)dv;
>     erd.getEmpRecord().setEmpSsn(BigDecimal.valueOf(0L));
>     erd.getEmpRecord().getEmpName().setEmpNameLast("");
>     erd.getEmpRecord().getEmpName().setEmpNameFirst("");
>     erd.getEmpRecord().getEmpName().setEmpNameMi("");
>     erd.getEmpRecord().getEmpAddr().setEmpAddrStreet("");
>     erd.getEmpRecord().getEmpAddr().setEmpAddrSt("");
>     erd.getEmpRecord().getEmpAddr().setEmpAddrZip("");
>     return erd;  }

Step 12: Update the jcrmgw.cfg File with Service Entries

Listing 7-19 defines the entries which are used when the corresponding Create/Read/Update/Delete form buttons are pushed; for example, the Create button triggers empRecCreate which invokes DPLDEMOC. The gateway must be restarted for the new services to take effect.

Listing 7-19 Update jcrmgw.cfg File

>     empRecCreate			RDOM="CICS410"
>     			RNAME="DPLDEMOC"
>     empRecRead			RDOM="CICS410"
>     			RNAME="DPLDEMOR"
>     empRecUpdate			RDOM="CICS410"
>     			RNAME="DPLDEMOU"
>     empRecDelete			RDOM="CICS410"
>     			RNAME="DPLDEMOD"

Step 13: Create Basic Three-Part HTML Frame

In Listing 7-20, the primary frame (identified as "main" in the HTML code) displays the servlet, while an auxiliary frame provides links to HELP pages. The "Built on BEA WebLogic" logo is also displayed. A single line of Java script is used to ensure the window displays in the foreground.

Listing 7-20 Create Basic Three-Part HTML Frame

>     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
>     <html>
>       <head>
>         <title>eGen</title>
>       </head>
>     <script language="javascript">
>     <!--
>     if (window.focus) {self.focus();} // -->
>     </script>
>       <FRAMESET cols="20%, 80%">
>         <FRAMESET rows="20%, 80%">
>           <FRAME src="bea_built_on_wl.gif" name="logo">
>             <FRAME src="panel.html" name="aux">
>         </FRAMESET>
>         <FRAME src="http://machine.domain.com:7001/empRec" name="main">
>       </FRAMESET>
>     </html>

Step 14: Create a Series of Links to HELP Pages

Listing 7-21 shows how the HTML can display as a sidebar frame. The intro.html, emprec.html, and create.html can display inside the "main" frame to provide basic HELP.

Listing 7-21 Creating a Series of HELP Page Links

>     <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
>     <html>
>       <head> <title>eGen help</title>  </head>
>     <script language="javascript">
>     <!--
>     if (window.focus) {self.focus();} // -->
>     </script>
>     <body>
>     <TABLE summary="This table contains links to help pages.">
>     <TR> <TH>empRec Info</TH>
>     <TR> <TD><a href="intro.html" target="help">Introduction </a>
>     <TR> <TD><a href="emprec.html" target="help">EmpRec </a>
>     <TR> <TD><a href="create.html" target="help">Create </a>
>     <TR> <TD><a href="read.html" target="help">Read </a>
>     <TR> <TD><a href="update.html" target="help">Update </a>
>     <TR> <TD><a href="delete.html" target="help">Delete </a>
>     </TABLE>
>     </body>
>     </html>

Task 3: Update the JAM Configurations and Update WLS Properties

Update the jcrmgw.cfg file with the remote service entries shown in Listing 7-22. The Java gateway must be restarted for new services. The entries are used when the corresponding form button is pushed. The Create button triggers empRecCreate, which invokes DPLDEMOC. The service name must match values in the EgenCobol script. In this example, the RNAME must match an actual CICS program name.

Listing 7-22 Remote Service Entries for Create/Read/Update/Delete

>     empRecCreate			RDOM="CICS410"
>     			RNAME="DPLDEMOC"
>     empRecRead			RDOM="CICS410"
>     			RNAME="DPLDEMOR"
>     empRecUpdate			RDOM="CICS410"
>     			RNAME="DPLDEMOU"
>     empRecDelete			RDOM="CICS410"
>     			RNAME="DPLDEMOD"

Update the weblogic.properties file with the entries shown in the Listing 7-23.

Listing 7-23 Update WLS Properties File

>     weblogic.httpd.register.customEmpRec=customCrud

Task 4: Deploy Your Application

At this point, you have a basic form capable of receiving data entry, along with some static HTML code for display. The following are standard WLS servlet deployment steps:

1. If required, compile the *.java files.

2. Copy the class files to the WLS servlet directory.

3. If required, add URL registration lines to the weblogic.properties file.

4. If required, restart WLS.

5. Test the result with your browser pointed at the registered URL.

Task 5: Use the Application

Figure 7-1 shows the default servlet with customized code displayed in an HTML facade. This type of servlet is useful for presentation, proof-of-concept, and as a test bed for development.

Figure 7-1 New Data Entry Servlet Display

Figure 7-2 shows the servlet with the Create HELP page displayed in a new window over the application.

Figure 7-2 Servlet with HELP Page Displayed

Figure 7-3 is an example of the page used for the front end of the new custom servlet.

Figure 7-3 New Data Entry Servlet Front End Page

Scenario A Summary

The following listings show COBOL programs for each of the button and service combinations:

- Create (DPLDEMOC)

- Read (DPLDEMOR)

- Update (DPLDEMOU)

- Delete (DPLDEMOD)

All of these programs make use of a CICS temporary storage queue for data. This is a simple technique that is useful for testing and demonstrations.

Create

The simple program shown in Listing 7-24 writes a temporary storage queue using the first eight characters of the employee name as the QID.

Listing 7-24 COBOL Program for Create (DPLDEMOC)

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.    DPLDEMOC.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  TSQ-DATA-LENGTH				PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-NAME.
>     		05 TSQ-ID			PIC X(8) VALUE SPACES.
>     		05 FILLER			PIC X(30) VALUE SPACES.
>     	LINKAGE SECTION.
>     	01  DFHCOMMAREA.
>     		COPY EMPREC.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE EMP-NAME TO TSQ-NAME
>     		MOVE LENGTH OF EMP-RECORD
>     		TO  TSQ-DATA-LENGTH
>     		EXEC CICS WRITEQ TS
>     			QUEUE(TSQ-ID)
>     			FROM(EMP-RECORD)
>     			LENGTH(TSQ-DATA-LENGTH)
>     		END-EXEC.
>     		EXEC CICS RETURN
>     		END-EXEC.
>     		EXIT.

Read

The simple program shown in Listing 7-25 reads a temporary storage queue using the first eight characters of the employee name as the QID. If the read fails, the COMMAREA is reset in consideration of the client application so residual data does not appear as the result of a read.

Listing 7-25 COBOL Program for Read (DPLDEMOR)

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.		DPLDEMOR.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  TSQ-DATA-LENGTH			PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-RESP				PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-NAME.
>     		05 TSQ-ID			PIC X(8) VALUE SPACES.
>     		05 FILLER			PIC X(30) VALUE SPACES.
>     	LINKAGE SECTION.
>     	01  DFHCOMMAREA.
>     		COPY EMPREC.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE EMP-NAME TO TSQ-NAME
>     		MOVE LENGTH OF EMP-RECORD
>     		TO TSQ-DATA-LENGTH
>     		EXEC CICS READQ  TS
>     			ITEM(1)
>     			INTO(EMP-RECORD)
>     			QUEUE(TSQ-ID)
>     			LENGTH(TSQ-DATA-LENGTH)
>     			RESP(TSQ-RESP)
>     		END-EXEC.
>     		IF TSQ-RESP NOT EQUAL ZERO
>     			MOVE ZEROS  TO EMP-SSN
>     			MOVE SPACES TO EMP-NAME-FIRST
>     			MOVE SPACES TO EMP-NAME-MI
>     			MOVE SPACES TO EMP-ADDR
>     		END-IF
>     		EXEC CICS RETURN
>     		END-EXEC.

Update

The simple program shown in Listing 7-26 deletes a temporary storage queue using the first eight characters of the employee name as the QID. It then creates a new queue with the COMMAREA provided.

Listing 7-26 COBOL Program for Update (DPLDEMOU)

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.		DPLDEMOU.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  TSQ-DATA-LENGTH			PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-NAME.
>     		05 TSQ-ID			PIC X(8) VALUE SPACES.
>     		05 FILLER			PIC X(30) VALUE SPACES.
>     	LINKAGE SECTION.
>     	01  DFHCOMMAREA.
>     		COPY EMPREC.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE EMP-NAME TO TSQ-NAME
>     		MOVE LENGTH OF EMP-RECORD
>     		TO TSQ-DATA-LENGTH
>     		EXEC CICS DELETEQ TS
>     			QUEUE(TSQ-ID)
>     		END-EXEC.
>     		EXEC CICS WRITEQ TS
>     			QUEUE(TSQ-ID)
>     			FROM(EMP-RECORD)
>     			LENGTH(TSQ-DATA-LENGTH)
>     		END-EXEC.
>     		EXEC CICS RETURN
>     		END-EXEC.
>     		EXIT.

Delete

This simple program shown in Listing 7-27 deletes a temporary storage queue using the first eight characters of the employee name as the QID. The COMMAREA is reset in consideration of the client application so residual data does not remain after the delete.

Listing 7-27 COBOL Program for Delete (DPLDEMOD)

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.    DPLDEMOD.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  TSQ-DATA-LENGTH			PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-NAME.
>     		05 TSQ-ID			PIC X(8) VALUE SPACES.
>     		05 FILLER			PIC X(30) VALUE SPACES.
>     	LINKAGE SECTION.
>     	01  DFHCOMMAREA.
>     		COPY EMPREC.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE EMP-NAME TO TSQ-NAME
>     		MOVE LENGTH OF EMP-RECORD
>     		TO  TSQ-DATA-LENGTH
>     		EXEC CICS DELETEQ TS
>     			QUEUE(TSQ-ID)
>     		END-EXEC.
>     		MOVE SPACES
>     		TO DFHCOMMAREA
>     		MOVE ZEROS  TO EMP-SSN
>     		EXEC CICS RETURN
>     		END-EXEC.
>     		EXIT.

Scenario B: Enhancing an Existing Servlet to Originate a Mainframe Request

In this scenario, you take the WebLogic Server (WLS) survey servlet and add a mainframe request to the post routine. You add the code to the postprocessing routine, creating a mainframe buffer and sending it to CICS where an application writes the buffer to a temporary storage queue and returns.

Task 1: Use EgenCobol to Create a Base Class

Prerequisite

You should have successfully created the survey servlet prior to attempting the enhancement discussed in this scenario. You must then identify the mainframe application and obtain its COBOL copybook. This is typically a CICS DFHCOMAREA or the user data portion of an IMS queue record layout. The copybook's name in this discussion is survey.cbl, shown in Listing 7-28.

Listing 7-28 Mainframe Application COBOL Copybook survey.cbl

>     02  survey-record.
>     	05  survey-ide				pic x(12).
>     	05  survey-emp				pic x(12).
>     	05  survey-cmt				pic x(256).

Step 1: Prepare EgenCobol Script

In Listing 7-29, both the data view surveyData and the client class SurveyClient are generated from the copybook survey.cbl.

Listing 7-29 Basic EgenCobol script

>     view surveyData from survey.cbl
>     service doSurvey accepts surveyData returns surveyData
>     client class SurveyClient
>     {
>     	method doSurvey is service doSurvey
>     }

You are now finished creating the survey.egen script file and are ready to generate the source code.

Step 2: Generate the Java Source Code

In Listing 7-30, you invoke the EgenCobol code generator to create the base class that is then compiled. This makes class files (*.class) available for servlet customizing. The surveyData.java is the data view object for survey.cbl.

Warning: CLASSPATH should have both the WLS subdirectories and the jam.jar file; otherwise, the compile fails.

Note: You could create a script file containing the EgenCobol command line, along with the javac command to make the invocation easier.

Listing 7-30 Generating the Java Source Code

>     java bea.jam.egen.EgenCobol survey.egen
>     ls  *.java
>     SurveyServlet.java surveyData.java SurveyClient.java
>     javac *.java

Step 3: Review the Java Source Code

It is a good idea to obtain a list of accessors for use later. In general, you should look at the EgenCobol output to become familiar with each of the scenarios presented in this section.

Note: Each COBOL group item has its own accessor. This is important because the group name represents a nested inner class that must be accessed in order to retrieve the members.

In Listing 7-31, the output from the grep command shows the relationships in reverse order, for example:

>     getSurveyRecord().getSurveyIde()

This is illustrated in the actual code example shown subsequently in this scenario.

Listing 7-31 Review the Java Source Code

>     grep get surveyData.java
>     	public String				getSurveyIde()
>     	public String				getSurveyEmp()
>     	public String				getSurveyCmt()
>     	public SurveyRecordV			getSurveyRecord()
>     grep set surveyData.java
>     	public void				setSurveyIde(String value)
>     	public void				setSurveyEmp(String value)
>     	public void				setSurveyCmt(String value)

Task 2: Update the Survey Servlet Using the Generated Class

The preferred customizing method is to derive a custom class from the generated base application. You are now ready to update the WLS example survey servlet.

Step 1: Start with Imports

In Listing 7-32, bea.jam.egen provides the EgenCobol client and data view base. The surveyData is the specific data view generated from the COBOL copybook. SurveyClient is the generated client class.

Listing 7-32 Using Imports to Start Creating the Custom Application

>     import bea.jam.egen.*;
>     import surveyData;
>     import SurveyClient;

Step 2: Add New Data Members

In Listing 7-33, the code adds a private member for SurveyClient, which can be created in the init() function because there is no state for it. The init() is then updated for a new member. The SurveyClient obtains a connection factory when created. A single instance of SurveyClient can serve all requests.

Listing 7-33 Adding New Data Members

>     //Add private member for SurveyClient
>     private SurveyClient egc = null;
>     //Update init() for new member
>     egc = new SurveyClient();

Step 3: Update doPost with Mainframe Request

In Listing 7-34, add the local variables for form data and data view in doPost. The data view is the minimum requirement. The values entry has been declared previously.

Listing 7-34 Update doPost with Mainframe Request

>     values = req.getParameterNames();
>     surveyData        sd  = new surveyData();

Step 4: Continue Updating doPost by Extracting Form Data

In Listing 7-35, the code loops through the form using data view accessors to set data. The submit field is skipped. The surveyData accessors are used to set values for ide, employee, and comment. The surveyData object represents the mainframe message buffer that ultimately is used to make the request. (The surveyData class was generated using the EgenCobol code generator with the mainframe COBOL copybook.)

Listing 7-35 Continue Updating doPost

>     while(values.hasMoreElements()) {
>     	String name = (String)values.nextElement();
>     	String value = req.getParameterValues(name)[0];
>     		if(name.compareTo("submit") != 0) {
>     		  if(name.compareTo("ide") == 0)
>     			sd.getSurveyRecord().setSurveyIde(value);
>     		  else if(name.compareTo("employee") == 0)
>     			sd.getSurveyRecord().setSurveyEmp(value);
>     		  else if(name.compareTo("comment") == 0)
>     			sd.getSurveyRecord().setSurveyCmt(value);
>     	}
>     }

Step 5: Continue Updating doPost by Calling Mainframe Service

In Listing 7-36, the code shows how to make the mainframe request. The doSurvey command blocks until a response is provided. The call can throw either IOException or snaException. In this listing, doSurvey is in a try block that catches IOException. The doSurvey command returns a data view that contains any response.

Listing 7-36 Continue Updating doPost

>     egc.doSurvey(sd);

The snaException is the base class for several exceptions, shown in Listing 7-37. A time-out is the most likely error an application would get.

Listing 7-37 Mainframe Exceptions

>     snaException
>     	jcrmConfigurationException
>     	snaCallFailureException
>     	snaLinkNotFoundException
>     	snaNoSessionAvailableException
>     	snaRequestTimeoutException
>     	snaServiceNotReadyException

Task 3: Update the JAM Configurations and Update WLS Properties

In Listing 7-38, update the jcrmgw.cfg file with the remote service name doSurvey. The Java gateway must be restarted for new services to take effect. The RNAME DPLSURVY is a CICS program that exists on the mainframe.

Listing 7-38 Update the jcrmgw.cfg File with Service Name

>     doSurvey     		RDOM="CICS410"                                        															 			RNAME="DPLSURVY"

Update the weblogic.properties file with the entries shown in Listing 7-39.

Listing 7-39 Update WLS Properties File

>     weblogic.httpd.register.survey=examples.servlets.SurveyServlet

Task 4: Deploy Your Application

At this point, you have a basic form capable of making a maintenance request. The following are standard WLS servlet deployment steps:

1. If required, compile *.java files.

2. Copy class files to the WLS servlet directory.

3. Copy HTML form to WLS document directory.

4. If required, add URL registration to weblogic.properties file.

5. If required, restart WLS.

6. Test the result with your browser pointed at the registered URL.

Task 5: Use the Application

Figure 7-4 shows the HTML display of the enhanced application.

Figure 7-4 Enhanced Survey Servlet Display

Scenario B Summary

The simple program shown in Listing 7-40 writes the contents of the COMMAREA to a temporary storage queue. This type of servlet is useful for testing, demonstrations, and new application development.

Listing 7-40 COBOL Program for DPLSURVY

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.    DPLSURVY.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  TSQ-DATA-LENGTH				PIC S9(4) COMP VALUE ZERO.
>     	01  TSQ-ID				PIC X(8) VALUE SPACES.
>     	LINKAGE SECTION.
>     	01  DFHCOMMAREA.
>     		COPY SURVEY.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE 'SURVEY' TO TSQ-NAME
>     		MOVE LENGTH OF SURVEY-RECORD
>     		TO  TSQ-DATA-LENGTH
>     		EXEC CICS WRITEQ TS
>     			QUEUE(TSQ-ID)
>     			FROM(SURVEY-RECORD)
>     			LENGTH(TSQ-DATA-LENGTH)
>     		END-EXEC.
>     		EXEC CICS RETURN
>     		END-EXEC.
>     		EXIT.

Note: Some applications have extremely large COMMAREA copybooks. Distributed applications can be very sensitive to large amounts of data being transferred between components. If the Java application requires only a few fields from a large copybook, it would be advantageous to front-end the target application with a simpler program passing only the data required.

Scenario C: Updating an Existing EJB to Service a Mainframe Request

In this scenario, you take the WebLogic Server (WLS) basic statelessSession TraderBean and update the interface to add a dispatch function that is given control upon receipt of an inbound request. The EgenCobol client class code generation model is used. The TraderBean is designed to run from a stand-alone client and output a list of stock trades.

Task 1: Use EgenCobol to Create a Base Class

Prerequisite

You should have successfully run the WLS basic statelessSession TraderBean prior to attempting the updates discussed in this scenario. You must then identify the mainframe application and obtain its COBOL copybook. This is typically a CICS DFHCOMAREA or the user data portion of an IMS queue record layout. The copybook's name in this discussion is trader.cbl, as shown in Listing 7-41.

Listing 7-41 Mainframe Application COBOL Copybook trader.cbl

>     02  TRADER-RECORD.
>     	05  CUSTOMER				PIC X(24).
>     	05  SYMBOL				PIC X(6).
>     	05  SHARES				PIC 9(7) COMP-3.
>     	05  PRICE				PIC 9(7) COMP-3.

Step 1: Prepare EgenCobol Script

The single-line script in Listing 7-42 generates the data view traderData from the copybook named trader.cbl. The script is then saved as inboundEJB.egen.

Listing 7-42 Basic EgenCobol script

>     view traderData from trader.cbl

You are now finished creating the inboundEJB.egen script file and are ready to generate the source code.

Step 2: Generate the Java Source Code

In Listing 7-43, you invoke the EgenCobol code generator to compile trader.cbl copybook and inboundEJB.egen. The traderData.java is the data view object for trader.cbl.

Warning: CLASSPATH should have both the WLS subdirectories and the jam.jar file; otherwise, the compile fails.

Note: You could create a script file containing the EgenCobol command line, along with the javac command to make the invocation easier.

Listing 7-43 Generating the Java Source Code

>     java bea.jam.egen.EgenCobol inboundEJB.egen
>     ls  traderDat*.java
>     traderData.java
>     javac traderData.java

Step 3: Review the Java Source Code

It is a good idea to obtain a list of accessors for use later. Look at the EgenCobol output to become familiar with each of the scenarios presented in this section.

The entire method of customizing the generated output is predicated on deriving the output from generated code. The base application can be regenerated without destroying the custom code.

Note: Each COBOL group item has its own accessor. This is important because the group name represents a nested inner class that must be accessed in order to retrieve the members.

In Listing 7-44, the output from the grep command shows the relationships in reverse order, for example:

>     getTraderRecord().getPrice()

This is illustrated in the actual code example shown subsequently in this scenario.

Listing 7-44 Review the Java Source Code

>     grep get traderData.java
>     	public String			getCustomer()
>     	public String			getSymbol()
>     	public BigDecimal				getShares()
>     	public BigDecimal				getPrice()
>     	public TraderRecordV					getTraderRecord()
>     grep set traderData.java
>     	public void			setCustomer(String value)
>     	public void			setSymbol(String value)
>     	public void			setShares(BigDecimal value)
>     	public void			setPrice(BigDecimal value)

Task 2: Update the Trader Interface Using the Generated Class

You are now ready to update the WLS trader example basic statelessSession bean.

Step 1: Start with Import

In Listing 7-45, the EJB interface is updated. In the Trader interface declaration, the EJBobject is replaced with gwObject. The gwObject extends EJBObject and provides the dispatch method that gets control on receipt of an incoming request.

Listing 7-45 Using Imports to Start Updating the EJB

>     import bea.sna.jcrmgw.gwObject;
>     .
>     .
>     .
>     public interface Trader extends gwObject {
>     .
>     .
>     .

Step 2: Continue with Imports

In Listing 7-46, you perform four imports to update the EJB. The bea.base.io.* import provides the mainframe reader and writer. The traderData import is the specific data view generated from the COBOL copybook. The BigDecimal class handles packed decimal COMP-3 fields. The mainframe reader and writer can generate IOExceptions.

Listing 7-46 Continuing Imports

>     import bea.base.io.*;
>     import traderData;
>     import java.math.BigDecimal;
>     import java.io.IOException;

Step 3: Update EJB with dispatch

In Listing 7-47, the gateway invokes dispatch with a byte array of mainframe EBCDIC data. The code converts the mainframe byte array to a data view using a MainFrameReader. The traderData is the generated data view class.

Listing 7-47 Update EJB with dispatch

>     .
>     .
>     .
>     public byte[] dispatch(byte[] b)
>     	{
>     		traderData td = null;
>     		try {
>     		  td = new traderData(new MainframeReader(b));
>     		} catch(IOException ie) { return b; }
>     				// error protocol required

Step 4: Continue Updating EJB with dispatch

In Listing 7-48, the code uses accessors to get input and set output. The mainframe COMMAREA is updated with the result. Note the use of an accessor to obtain the group level class prior to accessing the member variable. An application level error indicator in the data is used to convey the exception. Updating the data view member results in updates to the mainframe application. Any application exception thrown from the dispatch routine results in an abend returned to the mainframe.

Listing 7-48 Continue Updating EJB with dispatch

>     try {
>     	TradeResult tr = buy(td.getTraderRecord().getCustomer()
>     		,td.getTraderRecord().getSymbol()
>     		,td.getTraderRecord().getShares().intValue());
>     	td.getTraderRecord().setShares(new
>     			BigDecimal((long)tr.numberTraded));
>     	td.getTraderRecord().setPrice(new
>     			BigDecimal((long)tr.priceSoldAt));
>     }catch(ProcessingErrorException pe)
>     	td.getTraderRecord().setSymbol("*ERROR");}

Step 5: Finish Updating EJB with dispatch

In Listing 7-49, the code converts the data view back into a byte array to be returned to the mainframe using a MainframeWriter. The MainframeWriter and data view handle conversions. Note that the dispatch function takes a byte array and returns a byte array. This means when you set up an initial configuration, you can stub dispatch as an echo function.

Listing 7-49 Finish Updating EJB with dispatch

>     try {
>     		return td.toByteArray(new MainframeWriter());
>     	}	catch(IOException ie) {return b; }
>     					// error protocol required
>     }

Task 3: Update the JAM Configurations

Update the jcrmgw.cfg file with the service name shown in Listing 7-50. The Java gateway must be restarted for new services to take effect.

Listing 7-50 Update the jcrmgw.cfg File with Service Name

>     *JC_LOCAL_SERVICES
>     statelessSession.TraderHome			RNAME="DPL1SVR"

Task 4: Deploy Your Application

Use the build function supplied with WLS to build the basic statelessSession example. The EJB is saved in /myserver/ejb_basic_statelessSession.jar. To deploy the EJB, either use the hot deploy feature of the WLS console, or add an entry to deploy the jar file in the weblogic.ejb.deploy property in the weblogic.prperties file.

To run the client, follow the instructions in the WLS documentation.

Warning: Data view classes are not included in the jar file using the default script. You must either add traderData*.class entries to the jar file, or copy the entries to another location on the CLASSPATH. The EJB does not deploy if the traderData classes cannot be found.

Task 5: Use the Application

Listing 7-51 shows the inbound mainframe request for a "buy" transaction executed by the traderBean. If the previous tasks have been performed correctly, the result should look similar to this listing.

Listing 7-51 Inbound Mainframe Request

>     Thu Feb 17 15:31:10 CST 2000:<I> <EJB> EJB home interface: 'examples.ejb.basic.statelessSession.TraderHome' deployed bound to the JNDI name: 'statelessSession.TraderHome'

>     Thu Feb 17 15:31:10 CST 2000:<I> <EJB> 0 EJBs were deployed using .ser files.

>     Thu Feb 17 15:31:10 CST 2000:<I> <EJB> 1 EJBs were deployed using .jar files.
>     .
>     .
>     .

>     **** Inbound Mainframe Request ****

>     buy (JEFF TESTER, WEBL, 150)

>     Executing stmt: insert into tradingorders (account, stockSymbol, shares, price) VALUES ('JEFF TESTER','WEBL',150,10.0)

Scenario C Summary

The simple program shown in Listing 7-52 writes the contents of the COMMAREA to a temporary storage queue. This type of simple mainframe program is useful for testing, demonstrations, and new application development.

Listing 7-52 COBOL Program for DPL1CLT

>     IDENTIFICATION DIVISION.
>     	PROGRAM-ID.    DPL1CLT.
>     	INSTALLATION.
>     	DATE-COMPILED.
>     	ENVIRONMENT DIVISION.
>     	DATA DIVISION.
>     	WORKING-STORAGE SECTION.
>     	01  STUFF.
>     		COPY INBOUND.
>     	PROCEDURE DIVISION.
>     	MAINLINE SECTION.
>     		MOVE 'JEFF TESTER' TO CUSTOMER
>     		MOVE 'WEBL'        TO SYMBOL
>     		MOVE ZEROS         TO PRICE
>     		MOVE +150          TO SHARES
>     		EXEC CICS LINK
>     			PROGRAM('DPL1SVR')
>     			COMMAREA(STUFF)
>     		END-EXEC.
>     		EXEC CICS WRITEQ TS
>     			QUEUE('TRADER')
>     			FROM(STUFF)
>     		END-EXEC.
>     		EXEC CICS RETURN
>     		END-EXEC.

Note: Some applications have extremely large COMMAREA copybooks. Distributed applications can be very sensitive to large amounts of data being transferred between components. If the Java application requires only a few fields from a large copybook, it would be advantageous to preface the target application with a simpler program passing only the data required.

Copyright © 2000 BEA Systems, Inc. All rights reserved. Required browser: Netscape 4.0 or higher, or Microsoft Internet Explorer 4.0 or higher.