Helping ordinary people create extraordinary websites!
HOME TUTORIALS SCRIPTS WEB HOSTING BLOG FORUM
Get Our Newsletter
Email:

Java and SNA: A case study

By Matt MacKinnon, Adam King, David Kaminsky
2003-05-24


Classic Transaction #1: The Pipe

To introduce the API, we'll start by examining the first classic transaction: the Pipe. We present the example by interleaving code with commentary.

We based our transaction code on that given in CPI-C Programming in C, an excellent reference written by John Q. Walker and Peter J. Schwaller. For further information on CPI-C, we recommend the book highly.

First, we import the CPIC package, our Java/CPI-C bindings. A CPIC object is the interface to our LU6.2 code. It contains many constants defined in CPI-C, such as the length of a conversation ID, along with methods that are passed through to the native CPI-C calls.

The programmer need only declare one CPIC object per class. Java will load the dynamic link library (DLL) containing the native methods when that CPIC object is instantiated.



/*--
* Pipeline transaction, client side.
*--*/
import com.ibm.cali.net.CPIC.*;
public class Pipe extends Object {
public static void main(String args[]) {

// Make a CPIC object
CPIC cpic_obj = new CPIC();

Each type of parameter has its own class, and each of these classes has associated constants defined as class variables. For example, the CPICReturnCode class has the success return code, CM_OK, defined in it.

There were two major reasons for having a class for each type of parameter. Most importantly, because Java passes all parameters by value, there was no way to return data in simple types, such as integer. If we pass an object as a parameter to a method, the method can set a variable in that object, thus returning data to the caller. The second reason to use objects is to encapsulate constants within the objects that understand those constants--a standard information-hiding technique.



// Return Code
CPICReturnCode cpic_return_code =
new CPICReturnCode(CPICReturnCode.CM_OK);

// Request to send received?
CPICControlInformationReceived rts_received =
new CPICControlInformationReceived(
CPICControlInformationReceived.CM_NO_CONTROL_INFO_RECEIVED);

The CPI-C send function expects a C-language buffer--that is, allocated space of no specific type. Unlike C, Java has no facility to allocate untyped memory; besides primitives, everything in Java is an object. So whatever the program wants to send must be converted from its object type into an C-style array of bytes. In fact, for each call, the CPIC library must convert from the Java types to a C type.

Java does provide methods that facilitate such conversions. For example, Java can convert a String into a Java array of bytes. While an array of bytes is an object in Java, Java allows you to extract the data--the bytes--from an array of bytes with a native method.

So the programmer must convert his application data into an array of bytes; our code does not do automatic marshalling. While the conversion is not onerous, as we demonstrate below, we are considering augmenting our code to provide this function.



// String to Send
String sendThis = "Test of the PipeLine Transaction";

// Length of String to send
CPICLength send_length = new CPICLength(sendThis.length());

// Convert String to send to a Java array of bytes
byte[] stringBytes = new byte[ send_length.intValue()];
sendThis.getBytes(0,send_length.intValue(),stringBytes,0);

Like buffer processing, the CPI-C native calls expect symbolic destination names to be C-strings, not Java Strings. Our tool kit automatically converts them from Java Strings to a C-strings as necessary. In general, automatic conversion is possible when the tool kit expects a specific Java type.

The conversation ID is a Java array of bytes that is converted automatically by our tool kit to a C array of bytes--that is, a simple block of bytes.



// this hardcoded sym_dest_name must
// be 8 chars long & blank padded
String sym_dest_name = "PIPE ";

// Space to hold a conversation ID
// (which is just a bunch of bytes)
byte[] conversation_ID = new byte[CPIC.CM_CID_SIZE];

Now the programmer is ready to make the CPIC calls almost exactly as he would in C. The only noteworthy differences are that he prefaces every CPIC call with the name of the CPIC object and that none of the parameters are prefixed by the pass by reference (&) symbol.



//
// Initialize CPI-C
//
cpic_obj.cminit( /* Initialize_Conversation */
conversation_ID, /* O: returned conversation ID */
sym_dest_name, /* I: symbolic destination name */
cpic_return_code); /* O: return code from this call */
//
// ALLOCATE
//
cpic_obj.cmallc( /* Allocate Conversation */
conversation_ID, /* I: conversation ID */
cpic_return_code); /* O: return code from this call */
//
// SEND
//
cpic_obj.cmsend( /* Send_Data */
conversation_ID, /* I: conversation ID */
stringBytes, /* I: send this buffer */
send_length, /* I: length to send */
rts_received, /* O: was RTS received? */
cpic_return_code); /* O: return code from this call */
//
// DEALLOCATE
//
cpic_obj.cmdeal( /* Deallocate */
conversation_ID, /* I: conversation ID */
cpic_return_code); /* O: return code from this call */
} // end main method
} // end the class

That's the end of the client, so we'll turn our attention to the server. The server initializes itself, accepts a conversation, receives some data, and prints some diagnostic information. The code is similar to the client code, so we'll omit discussion of some of the redundant details.

As in the client, we instantiate classes to hold the CPI-C parameters, many of which have only an integer as instance data; recall that by using objects, we can mimic call by reference. We also allocate a byte array to hold the received data.



/*--
* Pipeline transaction, server side.
*--*/
import com.ibm.cali.net.CPIC.*;
import Java.io.IOException;

public class PipeServer extends Object {
public static void main(String args[]) {

CPIC cpic_obj = new CPIC();

// Space to hold the received data
byte[] data_buffer;
data_buffer = new byte[101];

CPICLength requested_length = new CPICLength(101);
CPICDataReceivedType data_received =
new CPICDataReceivedType(0);
CPICLength received_length = new CPICLength(0);
CPICStatusReceived status_received =
new CPICStatusReceived(0);
CPICControlInformationReceived rts_received =
new CPICControlInformationReceived(0);
CPICReturnCode cpic_return_code =
new CPICReturnCode(0);

// Space to hold a conversation ID -- a bunch of bytes)
byte[] conversation_ID;
conversation_ID = new byte[cpic_obj.CM_CID_SIZE];

The CPI-C receive call returns a Java array of bytes, while the Pipe transaction expects a String. The programmer can translate the array of bytes into a String by using the String class-constructor that takes an array of bytes as an argument.



//
// ACCEPT
//
cpic_obj.cmaccp( /* Accept_Conversation */
conversation_ID, /* O: returned conversation ID */
cpic_return_code); /* O: return code */
//
// RECEIVE
//
cpic_obj.cmrcv( /* Receive */
conversation_ID, /* I: conversation ID */
data_buffer, /* I: where to put received data */
requested_length, /* I: maximum length to receive */
data_received, /* O: data complete or not? */
received_length, /* O: length of received data */
status_received, /* O: has status changed? */
rts_received, /* O: was RTS received? */
cpic_return_code); /* O: return code from this call */
//
// Do some return code processing
//
System.out.println(" Data from Receive:");
System.out.println(" cpic_return_code = " +
cpic_return_code.intValue());
System.out.println(" cpic_data_received = " +
data_received.intValue());
System.out.println(" cpic_received_length = " +
received_length.intValue());
System.out.println(" cpic_rts_received = " +
rts_received.intValue());
System.out.println(" cpic_status_received = " +
status_received.intValue());
// Create a Java String from the array of bytes that you received
// and print it out.
String receivedString = new String(data_buffer,0);
System.out.println(
" Recevied string = "
+ receivedString );

//
// BLOCK so that the Server Window doesn't disappear
//
try{
System.out.println("Press any key to continue");
System.in.read();
}
catch
(IOException e){ e.printStackTrace(); }
}
}


Tutorial Pages:
» Java and SNA: A case study
» The Java/CPI-C API
» Classic Transaction #1: The Pipe
» Classic Transaction #5: The Database Update
» Native Calls
» Diversion: Native Calls and Applets
» Performance
» CPIC Calls That Have Been Implemented
» Conclusions
» Footnotes


First published by IBM DeveloperWorks


 | Bookmark
Related Tutorials:
» All about JAXP, Part 1
» Make Database Queries Without the Database
» Load List Values for Improved Efficiency
» 2 Ways To Implement Session Tracking
» A Simple Way to Read an XML File in Java
» Develop Aspect-Oriented Java Applications with Eclipse and AJDT