Chapter 2: Mapping a Java Interface and Using Resource Adapters

This chapter describes mapping a Java interface onto a COBOL program and using the Micro Focus resource adapters.

This functionality is not yet supported in Eclipse.

Overview of Mapping and Deploying a Java Interface

You can expose procedural COBOL as EJBs or Java beans, by using the Interface Mapping Toolkit to map an interface onto your COBOL program. The Interface Mapping Toolkit generates a COBOL service and an EJB or Java bean, and optionally a client for the EJB.

In brief, the Interface Mapping Toolkit enables you to select the COBOL entry points or program IDs and the parameters to use in the new interface. It records all the mapping information, so that the EJB or Java bean can call the COBOL service. You use the Interface Mapping Toolkit to generate the EJB or Java bean and the COBOL service. See the chapter Interface Mapper for full details.

The COBOL service then needs to be deployed to a COBOL enterprise server. The COBOL service comprises the mapping information and the original COBOL. You can use the Deploy tool in the Interface Mapping Toolkit to do this, or you can do it manually. See the section Deploy Tool in the chapter Interface Mapper

You deploy or run the Java in one of the following ways:

At run time, your client application makes Java requests and invokes the generated EJB or Java bean. The EJB uses the resource adapter to pass the requests to an enterprise server, which in turn runs the exposed COBOL. Tha Java bean pass the requests to the enterprise server directly.

The mapping information is used at run time to pass data to and from the exposed COBOL. The enterprise server returns the response to the EJB through the resource adapter or directly to the Java bean. The EJB or bean passes the response on to the client.

See Third Party Software for details of the supported J2EE versions, J2EE application servers and J2SE run-time environments.

Deployment Descriptors

Deployment descriptors are xml files containing deployment information, such as the settings you specify in the Interface Mapping Toolkit. J2EE application servers require deployment descriptors for the archive files (.jar, .war and .ear) to be deployed. At run time, the J2EE application server reads the descriptors and acts accordingly. Deployment descriptors are not required for the generated Java beans.

When you generate an EJB or client, the following generic deployment descriptors are created and packaged into the relevant archive files:

Some J2EE application servers require additional deployment descriptors in the archive files. These descriptors are generated automatically for the supported application servers. See the Third Party Software for details of the supported J2EE application servers.

If your application server requires additional deployment descriptors and these are not generated, you need to create them manually and add them to the archive files. In many cases, you can do this using the administration console for your application server. You need to specify the following information in the relevant deployment descriptors:

How to

Manifest Files

When you generate an EJB, a manifest file manifest.mf is included in each archive file that is generated. The manifest file specifies the information needed by the files in the archive. For example:

Notice that the manifest file mandates that mfejblib.jar is in the root of the deployed archive file by specifying the classpath as follows:

Class-path: mfejblib.jar

You must ensure that the mfejblib.jar is in that location. Alternatively, if you require mfejblib.jar to be elsewhere, you can change the classpath accordingly. For more details, see the next section CustomRecord and Other EJB Support.

CustomRecord and Other Java Support

If your EJB or Java bean uses custom records you need to make sure that support for them is available. Custom records are created if you map COBOL group items onto Java data types. You map group items in the Interface Mapper whenever you set up Reusable Mappings for group items and you then make those group items into complex interface fields.

For Java beans, support for the CustomRecord and the RuntimeProperties interfaces is provided in mfj2se.jar, which is supplied in the ...\base\bin directory of your installation. This support must be available at run time, and you can ensure this by putting mfj2se.jar on the classpath. For example, you could run your application, with the command:.

java –classpath class-directory\mfj2se.jar myProgram.class

For EJBs, support for the CustomRecord and the RuntimeProperties interfaces is provided in mfejblib.jar. This support is automatically included in the application .ear file when you generate a client for the EJB. When the Deploy tool creates the EJB, it adds a manifest file manifest.mf to the .jar file, and in that manifest file it sets the classpath to mfejblib.jar.

If you create a client manually, you need to add the mfejblib.jar to your .ear file, manually. There are two versions of the file: one for J2EE 1.3 and one for J2EE 1.4, and these are available in the base\bin\j2ee13 and base\bin\j2ee14 directories. By default, the mfejblib.jar file belongs in the root of the .ear file, because the classpath to mfejblib.jar is set to the root in the manifest.mf file of the EJB's .jar file.

You can view this manifest file by extracting it from the EJB's archive file, myservice.jar, which is in myproject\Repos\myservice.deploy. Notice that the classpath is set as follows:

Class-path: mfejblib.jar

If you require mfejblib.jar to be elsewhere, you need to change the classpath in manifest.mf in the EJB's jar file accordingly.

How to ...

Introduction to Resource Adapters

Your COBOL development system provides several resource adapters, also known as J2EE connectors. These resource adapters enable EJBs deployed on J2EE to communicate with COBOL deployed on an enterprise server. Resource adapters are not used by the generated Java beans.

Before an EJB can communicate with the COBOL running on an enterprise server, you need to deploy a resource adapter on the J2EE application server. For details see the section EJBs and Resource Adapters in the chapter Deploying Interfaces in your Enterprise Server Configuration and Administration Guide..

The Micro Focus resource adapters conform to the Java Connector Architecture (JCA). Each one provides an implementation of the Common Client Interface (CCI) as its API. Both JCA and CCI are defined by Sun and both are standards to which EJBs and other J2EE components must conform.

Essentially requests are passed through the resource adapter as follows:

  1. The client sends a request to the generated EJB.
  2. The generated EJB passes the request to the resource adapter using the CCI implementation.
  3. The resource adapter builds the request into a binary request using the Micro Focus binary protocol, and sends the binary request to the enterprise server.
  4. The enterprise server listens for requests from the resource adapter, and handles them accordingly. See your Enterprise Server Configuration and Administration Guide for information on listeners and configuring them.

Because the Micro Focus resource adapters use CCI for their APIs, you can call a resource adapter directly without using the generated EJBs. See the section Using an Unmanaged Connection under J2SE in this chapter.

Calling the Generated EJB or Java Bean

You need to write some Java client software to call the generated EJB or Java bean and to pass it the parameters required for the COBOL service. This client software might be a JSP or a servlet or some other module.

The EJB or Java bean interface is defined in the Interface Mapping Toolkit. Typically, you find out the interface by importing the EJB or Java bean into a Java development tool and investigating the interface there. One point to note is with regard to output parameters. If the mapped interface passes multiple output parameters (rather than using a group item and its corresponding custom record), the output parameters are returned through a container object in the EJB or Java bean interface. You can see this in your Java development tool.

At run time, the Java client software calls the EJB or Java bean. The EJB passes the request to the resource adapter, which communicates with the enterprise server to execute the COBOL service. The Java bean communicates with the enterprise server directly.

Using Java Beans under J2SE

You can bypass the J2EE application server and the resource adapter, by generating a Java bean that accesses the COBOL enterprise server directly. Although this avoids the overhead of administering a J2EE application server, you lose its advantages such as transaction support.

The Java bean generated is stateless. One class is generated for the bean and other classes are generated for any data classes representing the records that are mapped.

The Java bean runs in a J2SE environment with the libraries from the J2EE server. The Java bean accesses the COBOL enterprise server directly, in an out-of-process manner. The J2SE and enterprise server run in two separate processes and they communicate through sockets.

You need to write your client software to call the Java bean.

Support for the Java bean is supplied in mfj2se.jar, which is available in the base\bin directory.

To trace the behavior of the Java bean, use the –Dmfdebug=true switch. For example run the program myBean as follows:

java –Dmfdebug=true myBean

Using an Unmanaged Connection under J2SE

However you can bypass the J2EE application server, by writing your own code to call the resource adapter and send the request to an enterprise server. In this case, the connection is unmanaged. Your code runs in a J2SE environment with the libraries from the J2EE server. Although this avoids the overhead of administering a J2EE application server, you lose its advantages such as transaction support.

To deploy an unmanaged connection, all you need to do is to update your classpath to include the classes that provide support for the Micro Focus resource adapters. These classes are packaged in mfcobolpure.jar and mfconnector.jar. There are two versions of these files: one for J2EE 1.3 and one for J2EE 1.4, and these are available in the base\bin\j2ee13 and base\bin\j2ee14 directories.

How to

Writing a Simple CCI Program

The code you write needs to use CCI. The CCI defines an API for resource adapters connecting to Enterprise Information Servers (EISs), such as Enterprise Server. Micro Focus also supplies some extension classes specific to using the Micro Focus resource adapters.

In summary the code:

  1. Imports the Java and Micro Focus classes
  2. Gets a connection
  3. Gets an interaction
  4. Sets the InteractionSpecs for the interaction
  5. Executes the interaction
  6. Gets the results
  7. Closes the connection

The CCI classes and some of their methods include:

The Micro Focus extensions are supplied in the com.microfocus.cobol.connector.cci package and are documented in the J2EE 1.3 Connector Class Library Reference and J2EE 1.4 Connector Class Library Reference . The com.microfocus.cobol.connector.cci package provides classes like:

Sample Program to Connect to a Resource Adapter

The sample code in the next few sections demonstrates Java code requesting a COBOL service. The Java code uses CCI code to interact with a resource adapter which passes the request to the COBOL service. It demonstrates the use of a CCI custom record to represent a COBOL group item. In this sample, the Add service is mapped from the Calculate COBOL program through the entry point ADD using the reusable record Calculator.

You need to map the COBOL program onto a Java interface using the Interface Mapper. You drag the Calculator parameter into the Reusable Mappings pane and then drag it up into the Interface Fields pane for the Add operation. You can do the same for the subtract, divide and multiply operations. You need to map the interface this way, in this example, because the sample unmanaged class is demonstrating the use of a CCI custom record.

The sample program uses classes from these Java packages:

javax.resource.cci A collection of CCI interfaces defined in the J2EE Connector Architecture specification
com.microfocus.cobol.connector.spi Classes specific to the Micro Focus resource adapters that implement the Service Provider Interface (SPI) interfaces
com.microfocus.cobol.connector.cci Classes specific to the Micro Focus resource adapters that implement the CCI interfaces

To use the classes from these packages, we recommend that you import them into your code. For example, use statements such as:

import com.microfocus.cobol.connector.spi.*;
import com.microfocus.cobol.connector.cci.*;
import javax.resource.cci.*;

Sample Service

Here is code for the sample service followed by an explanation of the significant lines of code.

1      try {
2       // Get a Connection Factory instance
3       mcf = new CobolNoTxManagedConnectionFactory();
4       // set the appropriate fields.
5       mcf.setServerHost("localhost");
6       mcf.setServerPort("9003");

7       // Get a connection Factory (without using JNDI)
8       cxf = (javax.resource.cci.ConnectionFactory) 
               mcf.createConnectionFactory();

9       // Get a Cobol Connection Handle
10      connection = cxf.getConnection();
11      initialize(connection, cxf, true);

12      // Set up an interaction
13      interaction = connection.createInteraction();

14      // create a new interaction spec
15      CobolInteractionSpec iSpec = 
             new CobolInteractionSpec();
16      iSpec.setFunctionName("myservice.add");

17      javax.resource.cci.RecordFactory rf = 
             cxf.getRecordFactory();
18      Calculator calc = new Calculator();
19      calc.setArg1(new java.math.BigDecimal(10));
20      calc.setArg2(new java.math.BigDecimal(20));
21      iSpec.setArgument(0, com.microfocus.cobol.
             RuntimeProperties.BY_REFERENCE);

22      interaction.execute(iSpec, calc, calc);
23      System.out.println(
             "Input - Arg 1 was" + calc.getArg1());
24      System.out.println(
             "Input - Arg 2 was" + calc.getArg2());
25      System.out.println(
             "Result was" + calc.getResult());
26      System.out.println(
             "Memory was" + calc.getStorage());

28      interaction.close();
29      connection.close();
30      } catch( javax.resource.ResourceException re) 
        {
31        re.printStackTrace();
32        Exception le = re.getLinkedException();
33      }

Lines 3-6:

mcf = new CobolNoTxManagedConnectionFactory();

Instantiate the above ConnectionFactory class. The class then configures the following attributes of the unmanaged connection between the Java code and the resource adapter:

Line 8:

cxf = (javax.resource.cci.ConnectionFactory) 
           mcf.createConnectionFactory();

Instantiate the javax.resource.cci.ConnectionFactory object, by using the CobolNoTxManagedConnectionFactory that you created in line 1.

Line 10:

connection = cxf.getConnection();

Instantiate the javax.resource.cci.Connection class. Invoke the getConnection method on your Connection Factory object to obtain an instance of Connection, configured as stated by the configuration of your CobolNoTxManagedConnectionFactory. This connection handle maps to a ManagedConnection at any time.

Line 11:

initialize(connection, cxf, true);

Initialize the connection. This is a necessary step. The true parameter denotes the state of the COBOL program on the enterprise server. If the program requires the same initial state each time, then set the boolean (parameter three) to true. Otherwise if you want to preserve the state between service calls then set the value to false.

Line 13:

interaction = connection.createInteraction();

Instantiate the javax.resource.cci.Interaction object, by invoking createInteraction() on your Connection object. The Connection object is responsible for the creation of the Interaction object, which will execute interactions with the enterprise server.

Line 15:

CobolInteractionSpec iSpec = 
    new CobolInteractionSpec();

Instantiate and configure the specific object for the kind of interaction that is required. In this case, use the com.microfocus.cobol.connector.cci.CobolInteractionSpec class. This class builds the request and method of passing the parameters. The class is used to hold the function name and the direction (In, Out or I/O) of each of the arguments in an indexed record or the direction argument if it is a custom record.

Line 16:

iSpec.setFunctionName("myservice.add");

Set the name of the program to be run on the enterprise server, through the setFunctionName method.

Lines 18-21:

Calculator calc = new Calculator();
calc.setArg1(new java.math.BigDecimal(10));
calc.setArg2(new java.math.BigDecimal(20));
iSpec.setArgument(0, 
      com.microfocus.cobol.
      RuntimeProperties.BY_REFERENCE);

Create a new object of custom record class. If only a custom record is being sent as an argument, the steps above are sufficient. The custom record is generated automatically when you generate the EJB. The source files generated for the custom record are available in myproject\repos\myService.deploy\packageName.

If more than one custom record or a mixture of custom records and basic Java types need to be passed as an argument, you need to use an indexed record. For example, if an integer and a custom record need to be passed as an argument, use the following code:

    javax.resource.cci.RecordFactory rf = 
          cxf.getRecordFactory();
    javax.resource.cci.IndexedRecord iRec = 
          rf.createIndexedRecord("IndexedIn");
    javax.resource.cci.IndexedRecord oRec = 
          rf.createIndexedRecord("IndexedOut");
    iRec.add(new Integer(5));
    iRec.add(calc);
    iSpec.setArgument(0, 
          com.microfocus.cobol.
          RuntimeProperties.BY_REFERENCE);

This sets the direction of the argument. The arguments are numbered from 0 and this is the first value passed to setArgument. The valid values for direction are:

    com.microfocus.cobol.RuntimeProperties.BY_REFERENCE
    com.microfocus.cobol.RuntimeProperties.BY_VALUE
    com.microfocus.cobol.RuntimeProperties.OUTPUT_ONLY

Line 22:

interaction.execute(iSpec, calc, calc);

Execute the Interaction. The execute() method invoked on the Interaction object causes the request to be flowed to the enterprise server.

Lines 28-29:

interaction.close();

Finally, close the Interaction and the Connection. The close() method on the Connection object is the final flow, and closes the underlying connection to the resource adapter. It must be executed after the close() method on the Interaction.

Sample Initialize Method

The code for the initialize method is as follows:

private void initialize(
                 javax.resource.cci.Connection con,
                 javax.resource.cci.ConnectionFactory cf,
                 boolean isInitial) {
      try {
      javax.resource.cci.Interaction ix = 
           con.createInteraction();
      com.microfocus.cobol.connector.cci.CobolInteractionSpec 
           iSpec = new 
           com.microfocus.cobol.connector.cci.CobolInteractionSpec();
      iSpec.setFunctionName("initialize");
      javax.resource.cci.RecordFactory rf = 
           cf.getRecordFactory();
      javax.resource.cci.IndexedRecord irec = 
           rf.createIndexedRecord("beanArgs");
      irec.add(new Boolean(isInitial));
      javax.resource.cci.Record orec = 
           ix.execute(iSpec, irec);
      ix.close();
   } catch(javax.resource.ResourceException ex) {
      throw new javax.ejb.EJBException(
           "initialize threw ResourceException: ", ex);
   }
}

Sample Custom Record

The above example uses the group record Calculator in the COBOL service, myservice.add. In the resource adapter CCI, this group record is expressed as a custom record. The following code is the custom record class, Calculator.java, corresponding to the group record:

/*******************************************************
This is a file generated by Micro Focus Net Express 4.0
This file represents the Custom Class for Calculator
*******************************************************/

public class Calculator extends 
      com.microfocus.cobol.connector.cci.CustomRecord {

   private java.math.BigDecimal arg1 = 
           java.math.BigDecimal.valueOf(0);
   private java.math.BigDecimal arg2 = 
           java.math.BigDecimal.valueOf(0);
   private java.math.BigDecimal result = 
           java.math.BigDecimal.valueOf(0);
   private java.math.BigDecimal storage = 
           java.math.BigDecimal.valueOf(0);
   public Calculator() {
   }
   public java.math.BigDecimal getArg1() {
       return arg1;
   }
   public void setArg1(java.math.BigDecimal ___p) {
       arg1 = ___p ;
   }
   public java.math.BigDecimal getArg2() {
       return arg2;
   }
   public void setArg2(java.math.BigDecimal ___p) {
       arg2 = ___p ;
   }
   public java.math.BigDecimal getResult() {
       return result;
   }
   public void setResult(java.math.BigDecimal ___p) {
       result = ___p ;
   }
   public java.math.BigDecimal getStorage() {
       return storage;
   }
   public void setStorage(java.math.BigDecimal ___p) {
       storage = ___p ;
   }
   public Object[] getParameters() {
       Object[] objs = new Object[4];
       objs[0] = arg1;
       objs[1] = arg2;
       objs[2] = result;
       objs[3] = storage;
       return objs;
   }
   public void setParameters(Object[] objs) {
       arg1 = (java.math.BigDecimal)objs[0];
       arg2 = (java.math.BigDecimal)objs[1];
       result = (java.math.BigDecimal)objs[2];
       storage = (java.math.BigDecimal)objs[3];
   }
}

Sample Calculator COBOL Program

The calculator COBOL program used in the sample service is:

$set intlevel(4)
 identification division.
 program-id. calculate.

 environment division.

 data division.
 working-storage section.
 01 calmemory      pic s9(9) comp-5 value 0.

 linkage section.
 01 calculator.
    05 arg1        pic s9(19)v9(19) comp-3.
    05 arg2        pic s9(19)v9(19) comp-3.
    05 result      pic s9(19)v9(19) comp-3.
    05 storage     pic s9(19)v9(19) comp-3.

 procedure division.
     exit program.

 entry "add" using calculator.
     move arg1 to result
     add  arg2 to result
     add  result to calmemory
     move calmemory to storage
     exit program.

 entry "subtract" using calculator.
     move arg1 to result
     subtract arg2 from result
     add  result to calmemory
     move calmemory to storage
     exit program.

 entry "multiply" using calculator.
     move arg1 to result
     multiply arg2 by result
     add  result to calmemory
     move calmemory to storage
     exit program.

 entry "divide" using calculator.
     move arg1 to result
     divide arg2 into result
     add  result to calmemory
     move calmemory to storage
     exit program.

Copyright © 2006 Micro Focus (IP) Ltd. All rights reserved.