No matter which way you try it, interfacing a mainframe from an
application server or servlet is never fun. Among other hurdles to
overcome, the mainframe could exist on a different platform or use a
different character set. Think you can simply access the data directly
and rebuild your business logic? Perhaps, if your database is not
hierarchical and you enjoy reinventing the wheel. However, a few tricks
using XML, XSL, and Java can make it easier than you think.
XML describes the structure of the data you are sending. Add XSL to
complete some simple transformations. Use Java to encapsulate it with a
few simple classes. You will then leverage a host of legacy system
transactions written decades ago and format them into an XML document.
Once your data is in an XML format, manipulating it becomes a much less
daunting task, and development becomes easier. In addition, the
solution you employ is realtime, which circumvents the frustrations and
problems that arise from working with an extract file or batch
interface.
The versatile XML
While many may only think of XML in terms of marking up structured
documents, you can use XML to describe anything that has a particular
structure. For the purposes of this article, we shall assume that our
legacy system stores data in a hierarchical database that may be
accessed through COBOL programs residing on the system. Why not access
the database directly to retrieve the information? While the
hierarchical database offers some advantages for the mainframe system,
directly accessing it requires extensive knowledge of the database.
Usually, the underlying database features significant complexity, which
makes traversing it exceedingly difficult, if not downright impossible.
Since the COBOL programs are already available for that purpose, there
remains no reason to undertake such a complicated task.
You must know the structure of the transaction you will interface in
order to invoke the COBOL program. To obtain that knowledge, refer to
the program copybook, which contains the directions for use. Those
directions include information about the length of the field, name,
left or right justification, etc. Think of those descriptors as a set
of fields that are described by attributes. Those descriptors provide
directions on how to format the request and how to parse the returning
data from the subsequent call.
Using XML, you can now implement that copybook metadata to generate
your copybook markup language. Below, this short, simplistic example of
an XML document containing our COBOL program's metadata retrieves a
name when given a social security number:
<.transaction>
<.configuration>
<.name>CobolNameProgram<./name>
<.requestlength>30<./requestlength>
<.replylength>200<./replylength>
<./configuration>
<.request>
<.field identifier="SSN", justification="R", length="12"/>
<.field identifier="username", justification="L",
length="8"/>
<./request>
<.reply>
<.field identifier="firstname", length="15"/>
<.field identifier="lastname", length="25"/>
<./reply>
<./transaction>
The name describes the name of the COBOL program you invoke, and the
lengths of the corresponding request and reply messages. The attributes
of each field you will encounter describe the name, field length,
justification, or any item you need to know to process this request.
The Java engine
Referencing the structure above, you can write the code to hook up your
values into your request's structure and parse the incoming reply with
another document containing the name/value pairs that correspond to the
field identifiers. That sample incoming document may look like this
after some initial processing:
<.CobolNameProgram>
<.field name="SSN", value="123456789"/>
<.field name="username", value="mickey"/>
<./CobolNameProgram>
To format the request, the code simply needs to search for and match
the identifier for each element, and write the value according to the
attributes' rules by iterating through the fields.
XSL style
Developers use the XSL language for manipulating XML from one structure
into another. It can be implemented for transforming XML into HTML or
other XML document structures.
You will use XSL to format an incoming document structure to the
name/value-pair structure described above, which the Java code
processes into the COBOL structure. XSL will also format the data
returned from the legacy system -- once the Java code transforms it
back into XML -- into a usable structure for the function or
application using this API. XSL allows you to build Java code that will
be insulated from changes to the external format of both the calling
application and the legacy system. I will describe more on that
advantage later.
The Xerces parser allows for easy XML manipulation within Java. Assume
that an application using your API will pass the data your request
needs as an XML document. It will feature whatever structure that the
application requires. We need not concern ourselves with it since our
application can apply XSL to style the structure into our usable
name/value-pair configuration described above. That resulting
name/value-pair structure can then be passed to the Java code for
manipulation into the COBOL structure.
After you obtain the name/values pairs containing the data necessary
for the request, and the metadata describing the structure of the COBOL
transaction, you can write the Java code that manipulates the request:
package JavaWorldExample;
import org.apache.xerces.parsers.*;
import org.xml.sax.*;
import java.io.*;
import org.w3c.dom.*;
import com.lotus.xsl.*;
public class TransformMessage {
public TransformMessage() {
}
byte [] formatMessage(Document doc) {
int txFieldLength = 0;
byte [] txFieldLengthBytes;
int txFieldIndex = 0;
byte [] txField;
StringBuffer txInputBuffer = new StringBuffer();
String value = "";
String szLen = "";
try {
// Apply XSL to document to style into name/value format
StringWriter writer = new StringWriter();
XSLProcessor processor = new XSLProcessor();
processor.reset();
processor.process( new XSLTInputSource(doc),
new XSLTInputSource(new FileReader
("c://input//CommonFormat.xsl")),
new XSLTResultTarget(writer) );
String formattedxml = writer.toString();
//Get the element list and root node
DOMParser lparser = new DOMParser();
lparser.parse(new InputSource(new StringReader(writer.toString())));
doc = lparser.getDocument();
NodeList transNlist = doc.getElementsByTagName("GetName");
Element dataNode = (Element) transNlist.item(0);
// Get the transaction metadata
DOMParser parser = new DOMParser();
parser.parse(new InputSource(new FileReader
("c://input//Samplemetadata.xml")));
Document metadoc = parser.getDocument();
// Apply the metadata and rules to the message
NodeList nlist = metadoc.getElementsByTagName("FIELD");
for (int i = 0; i <. nlist.getLength(); i++) {
txFieldIndex = 0;
//get the field length from the meta data
if ( nlist.item(i).getAttributes().getNamedItem("LTH") == null)
szLen="0";
else
szLen = nlist.item(i).getAttributes().getNamedItem
("LTH").getNodeValue().trim();
//calculate the length of current field
txFieldLength = Integer.parseInt(szLen);
//create transaction-field byte array
txField = new byte [txFieldLength];
// find the field in the application XML Document & get the
attributes
NodeList dataNlist = dataNode.getElementsByTagName(nlist.item
(i).getAttributes().getNamedItem("NAME").getNodeValue().trim());
if (dataNlist.getLength() > 0) {
value = new String (dataNlist.item(0).getAttributes
().getNamedItem("VALUE").getNodeValue().trim());
}
//add the actual value of field
txFieldIndex = CommonUtilities.buildRI(txField, value.getBytes
(), txFieldIndex, value.length());
//Determine the justification of the field
if ( nlist.item(i).getAttributes().getNamedItem
("JUST").getNodeValue().equals("L")) {
//Left Justify
for(int k=0; k <. (txFieldLength-txFieldIndex); k++) {
txField[k+txFieldIndex]=(byte)(' ');
}
}
else { //Right Justify
CommonUtilities.rightJustify(txField);
}
//add field to input buffer
txInputBuffer.append(new String(txField));
}// end for all fields
}
catch (Exception e) {
e.printStackTrace();
}
return txInputBuffer.toString().getBytes();
} // End function
} //End class TransformMessage
I've described all that you need to accomplish to set up your outgoing
structure. To format the return, a like strategy is utilized. Data
manipulation transforms the response from a byte array or similar
structure into an XML document. Essentially, the code matches the
fields with the value from the array and creates name/value pairs that
are suitable for a simplistic XML document. Once that is complete, XSL
styles the information in any way desired. It is also important that
you set up some sort of transmission method to the environment in which
you execute the COBOL program. As the focus of this article is the
server-side application, I do not delve into that discussion here.
Framework advantages
It may be helpful at this point to provide an illustration of the
process as it has evolved to this point.
While it may not be readily apparent, this layout offers several
distinct advantages:
- Since XSL is applied to the incoming document as well as the
outgoing document, the Java engine, once written, is insulated
from changes in the incoming message structure. The entire DTD,
or schema, of the incoming message could be changed completely. A
programmer would only have to modify the XSL within this
framework that styles the document into your name/value-pair
format. In addition, if you store the XSL in some sort of
database or flat file that is looked up, you can modify it
without even recompiling our code.
- If the mainframe format changes, you could alter the XML metadata
to reflect those shifts, providing the same benefits as above.
- The transmission method is separate from the data manipulation.
You could plug in another transmission method with minimal effort
should the need arise or a better method come along.
- The existing legacy programs are used as is -- you don't need to
modify the mainframe.
Conclusion
XML, XSL, and Java work hand in hand to solve the complex problem of
mainframe transaction access. Implementing XSL styling creates
supplementary layers in the framework that allow the solution to
configure changes from the application server or the mainframe programs
without recompiling the Java code that performs the mapping. XML allows
us to describe the structure of the COBOL transactions, providing
directions to the Java engine on how to build the request or parse the
response. I used this framework successfully in the last two e-commerce
projects I participated in, and I will not hesitate to implement it
again in the future.