This chapter describes mapping a Java interface onto a COBOL program and using the Micro Focus resource adapters.
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.
The EJB is generated automatically when you use the Deploy tool Interface Mapping Toolkit and when you generate a client. See the section Deploy Tool in the chapter Interface Mapper.
The generated EJB and optional client are packaged into archive files (.jar, .war and .ear), together with manifest files and deployment descriptors. These files are located in the directory structure under myProject\repos\myService.deploy. The following archive files are created:
You can view the contents of these archive files using the jar command or through a zip utility such as Winzip.
When you generate an EJB, it is packaged into a Java archive file (myService.jar) together with the following files:
| ejb-jar.xml | Generic deployment descriptor, defining the EJB |
| myServiceBean.class | Bean class for the EJB |
| myServiceHome.class | Home interface for the EJB |
| myService.class | Remote interface for the EJB |
| myRecord.class | custom record, if needed by the EJB |
| manifest.mf | Manifest describing this .jar file |
| *.xml, such as weblogic-ejb-jar.xml | For some J2EE application servers (such as WebLogic), a deployment descriptor for deploying the EJB to that application server |
The source code for the EJB classes are generated in the directory com\mypackage\myService.
When you generate a client for an EJB , it is packaged into a Web archive file myService.war file together with the following files:
| *.jsp | JSP files. These pass data back and forth between the end user and the servlet. |
| myServiceJspBean.class | This file contains the getter and setter methods that are used to move information back and forth between the servlet and JSP. |
| myServiceServlet.class | This file is the servlet. It processes the incoming requests from the JSP, invokes an instance of the stateless EJB, and forwards the response back to the JSP. |
| myServiceSessionMonitor.class | This is a helper class, which stores the EJB instances for the stateful session bean. |
| manifest.mf | Manifest describing this .war file |
| mfejlib.jar | .. custom records |
| web.xml | Generic deployment descriptor, defining the client servlet and the EJB reference |
| *.xml, such as weblogic.xml | For some J2EE application servers (such as WebLogic), a deployment descriptor for deploying the .war file to that application server |
When you generate a client for an EJB , the EJB and the client are packaged together into an enterprise archive file myService.ear file together with the following files:
| application.xml | Generic deployment descriptor, defining the .jar and the client .war files |
| myService.jar | EJB archive file |
| myService.war | Client archive file |
| manifest.mf | Manifest describing this .jar file |
| mfejlib.jar | .. custom records |
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:
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.
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.
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:
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.
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.
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
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.
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:
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:
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.*;
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:
mcf.setServerHost("localhost");
This is the name of the machine where the resource adapter is located.
mcf.setServerPort("9003");
This is the port where the enterprise server listens for resource adapter communication.
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.
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);
}
}
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];
}
}
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.