Web Enabling System/390 Applications Using WebSphere for OS/390, Java, and MQSeries Tony Newling Senior Information Technology Specialist IBM Australia Limited newlingt@au1.ibm.com February 2000 Abstract This paper describes a technique for making existing computer applications available to users from a standard Web browser, over the Internet or a private intranet. It describes an infrastructure for Web serving based on WebSphere for OS/390, Java for OS/390, and MQSeries for OS/390. It also describes the design and implementation of programs to connect the Web browser user to any application, regardless of where the application resides. Finally, the paper describes the advantages of implementing such an infrastructure on OS/390. The techniques described in this paper have been successfully implemented as a proof of concept at a large Australian compan y. Pre-requisite Knowledge This paper is designed for readers who are broadly familiar with the following topics: [1] The architecture and purpose of System/390 and OS/390 [2] The architecture and purpose of OS/390 UNIX System Services [3] The architecture and purpose of CICS Transaction Server for OS/390 [4] The architecture and purpose of MQSeries for OS/390 [5] The architecture and purpose of Java Specifically, the paper will be useful for OS/390 System Programmers, Technical Managers, Application Designers and Programmers, and System Architects . Purpose of this Paper Organizations that use System/390 and OS/390 “mainframe” computers typically have large collections of application software that: 1. Have been developed over many years (in some cases, over a period of 30 years). 2. Continue to fulfill the needs of the organization. 3. May run on OS/390 or other computing systems/platforms. 4. Could be effectively made available to new users (such as customers, business partners, and others) using Internet technologies. © Copyright IBM Corporation 2000 Page 1 of 23 This paper describes a tactical approach to make such applications available to Web browser users. The approach described requires more effort than a “screen-scraping” approach (for example using Host on Demand or Host Publisher), but less effort than development of a new application architecture based on components (for example using Enterprise Java Beans or Component Broker). The approach requires that the application be able to exchange an MQSeries message with the WebSphere Application Server. Applications might require some modification if they cannot currently exchange MQSeries messages. The example application used in this paper is a CICS application, written in COBOL, which is callable using Distributed Program Link (DPL). Overview of the Architecture The components of the Web enablement architecture described in this paper are illustrated in the following diagram, with explanatory notes following the diagram . Web Browser MQSeries MQSeries WebSphere Application Server CICS Appl. Java 1.1.x WAN vbg IBM HTTP Server TCP/IP LAN OS/390 2.5 Logical Partition LAN connect LPAR System/390 Processor These notes describe the components of the Web enablement architecture, starting with the application and working back to the end-user. CICS (Application) The example application described in this paper is a CICS application. The CICS application is callable using EXEC CICS LINK. Any application that can exchange messages using MQSeries is a candidate application for this architecture. In this case, the application resides on a different OS/390 system than the Web server. This illustrates that the target application need only have an MQSeries client or server available to send and retrieve messages. It also illustrates a technique for isolating your production system from your “Web system” if that is required. The sample application uses the CICS/MQSeries bridge. This bridge allows CICS programs to be invoked automatically when messages for those programs are received on © Copyright IBM Corporation 2000 Page 2 of 23 the production system by MQSeries. The CICS/MQSeries bridge is available with MQSeries Version 1 Release 2 for MVS/ESA, or from the MQSeries SupportPacs Web site. MQSeries MQSeries is installed on both the OS/390 “ Web system” (the system where WebSphere Application Server runs) and the system running the application program (this might be OS/390, or some other system). Messages are passed between the MQSeries systems in the two computer systems. WebSphere Application Server Websphere is a component of OS/390 releases after (and including) OS/390 Version 2 Release 5. Recent releases have WebSphere included in the ServerPac. If you do not have WebSphere installed, it can be downloaded from the IBM software Web site. WebSphere runs on the IBM HTTP Server and provides a servlet engine for OS/390. WebSphere has a pre-requisite of Java for OS/390. The Java Developer’s Kit (levels 1.1.8 and 1.1.6) can be downloaded from the IBM System/390 Web site. For the architecture described in this paper, the MQSeries Bindings for Java are required. These are a set of Java class libraries which allow Java programs to put and get messages from MQSeries queues on the same OS/390 system as the bindings are installed (the “Web” system). IBM HTTP Server This is a Web server for OS/390, and is a component of OS/390. All releases of OS/390 after Version 1 Release 3 have included a Web server, although they have had different names. The most recent releases of OS/390 include the IBM HTTP Server. The WebSphere Web site specifies which levels of Web server are required to run WebSphere. TCP/IP Provides the communications transport between the W eb server and the Web browser. TCP/IP is a component of the OS/390 Communications Server. OS/390 An operating system designed for business users of the System/390 computing architecture, OS/390 p rovides the operating environment for the Web server, WebSphere, Java, and MQSeries, among other things. A minimum level of OS/390 Version 2 Release 5 is required to run WebSphere. Note that your production system may be at a lower level of OS/390, you only need this level in your “Web” system. You can connect to down-level OS/390 systems using MQSeries. Logical Partition System/390 processors from IBM provide a facility to logically partition a single computer into up to 15 logical systems. Many IBM customers use this LPAR facility to run production, development, and testing systems all on a single computer. An example use of LPAR is illustrated in the diagram. LAN Connect Some mechanism for connecting the System/390 computer to a local area network is required in order to use this architecture. IBM S/390 computers include the Open Systems Adapter (OSA) which can provide Ethernet (up to Gigabit speeds), Token Ring, ATM, and FDDI connections to LANs. Alternatively, you can use channel-attached devices to connect to a network. © Copyright IBM Corporation 2000 Page 3 of 23 System/390 Processor This is the computer that runs OS/390. There are no specific considerations for the computer in this architecture. You can use your existing processor for this architecture. Client Web Browser User station which provides the user interface to the e-business applications. There are no specific considerations for the client Web browser in this document, although a reasonably recent level of browser is required. Overview of the Application Flows Having reviewed the overall Web enablement architecture, an analysis of the flow of data through this architecture completes the overview. The flow illustrated in the above diagram is further described as follows: MQSeries WAS Web Browser JSP Application System with MQSeries Request Queue Reply Queue Extract data Build msg Send Wait for response Get message Parse data Return H T T P S e r v e r T C P / I P Get home page (index.html) Click on link in page to get first application page Fill out form in retrieved page. Form fields reflect data required by application. Some fields can be hidden. Display results Results page could be another form, which could invoke another program. Iterate as appropriate "Web" Logical Partition Phase 1: HTML Static Pages Retrieved by Client Before any of the processing to access the application can take place, an HTML page which includes a form to initiate the application call must be retrieved by the client. For example, a Web client may enter http://your.server.name/ to retrieve the server’s home page. This is a standard HTTP request and it is processed by the IBM HTTP server according to the rules you have defined for the server. Retrieval of static HTML documents is not described in this paper. If you need more details, please refer to OS/390 e-business Infrastructure: IBM HTTP Server 5.1 - Customization & Usage , SG24-5603, available from the IBM Redbooks Web site at http://www.redbooks.ibm.com © Copyright IBM Corporation 2000 Page 4 of 23 Your home page may then have a link to the application page, which in turn contains a form which collects the information needed by the application and invokes the application when the submit button is pressed. Phase 2: User Clicks on Button to Invoke Application Processing The user fills out the application form, entering the data required by the application. For example, if the application requires the user’s name, address, and property valuation in order to provide an insurance quotation, the HTML form would have fields to collect that information. Once the form is completed, the user presses a submit button (which might be labelled as “Obtain Quotation”) which causes the browser to request a Java Server Page file from the server. Phase 3: Web Server Processes Request The Web server receives the request for the JSP file and begins analysis to determine how to processes the request, in the normal way. The client user ID is checked, then the request is parsed. The server has a mapping rule which maps *.jsp to a location in the UNIX System Services hierarchical file system (usually /usr/lpp/WebSphere/AppServer/lib/libadpter.so:AdapterService ). This is the WebSphere DLL program which invokes Java processing. The client user ID is then validated and checked to see whether it has authority to retrieve the requested file (or in this case run the WebSphere program). Assuming it has, the plug-in program is invoked to compile the JSP if appropriate (if it is already compiled and no changes have been made since it was compiled, the compiled page will be loaded). The compiled JSP is a Java servlet. The servlet runs on a thread within the Web server address space. Phase 4: Servlet Processing Begins The Java servlet program starts and performs the following actions: 1. Parse the data provided by the user in the HTML form which called the JSP/servlet. 2. Call a Java bean, passing it the data from the form in an appropriate format. 3. The Java bean formats an MQSeries message and puts it on an appropriate queue. This message includes the name of the application program to be invoked on the application system, and appropriate data for that program. 4. The Java bean issues an MQSeries get message to an appropriate queue. It waits for a message or a timeout interval. Phase 5: MQSeries Processing The message placed on the MQSeries “outbound” queue is routed by MQSeries to an “inbound” queue on an appropriate system. This is “business as usual” processing for MQSeries, and your MQSeries administrator can set up the system to arrange for the appropriate message routing. On the system running the application being Web-enabled, the MQSeries/CICS bridge program is invoked when the message sent by the JSP/servlet arrives on its “inbound” queue. The bridge determines the name of the CICS program to be invoked from the first eight bytes of the message. It extracts the remainder of the message, builds a COMMAREA (data area), and calls the CICS program with EXEC CICS LINK. When the CICS program completes, it returns to the bridge program with an updated COMMAREA. This COMMAREA is sent as a message to the “reply-to” queue specified by the calling program (the JSP/servlet). © Copyright IBM Corporation 2000 Page 5 of 23 Phase 6: Servlet Processing Completes The JSP/servlet program has been waiting for an MQSeries message to be returned from the original call. When the message arrives, the following actions are taken: 1. Extract the message from the queue. 2. Parse the message according to the standards for the application. 3. Insert data into appropriate fields in the HTML that is part of the JSP. 4. Return the output to the user as HTML. In the case of Java Server Pages, the servlet replaces data returned by CICS into the specified fields in the JSP page. The output HTML could include another form to invoke further CICS processing. This concludes our overview of the architecture of the Web-enabled application. The following sections discuss particular components of the architecture in greater detail. © Copyright IBM Corporation 2000 Page 6 of 23 What Is Needed to Use the Architecture? The following components are required to use the architecture described in this paper: w “Web” system - the system running the WebSphere Application Server é A System/390 processor, with a LAN connection é OS/390 Version 2 Release 5 or later, with ë UNIX System Services fully enabled ë TCP/IP services of OS/390 Communications Server enabled ë IBM HTTP Server (or an earlier, compatible equivalent) installed and operating ë Java 1.1.x for OS/390 installed and operating ë WebSphere Application Server 1.1 or 1.2 installed and operating ë MQSeries installed and operating ë MQSeries Bindings for Java installed and operating w “Application” system - the system running the application you wish to Web enable é An MQSeries client or server é The application, capable of exchanging messages with MQSeries é Network connectivity to the OS/390 system, using TCP/IP or SNA The references section of this paper provides pointers to information about each of these topics. What is a Java Server Page? Increasingly, Internet technologies are moving from a client orientation to a server orientation. That is, the server controls the content which is provided to the client. Java servlets are programs, written in the Java programming language, which run on a server and allow access to server systems such as files, databases, and transaction systems. You can use a servlet on OS/390 to provide access to DB2 databases, CICS transactions, and MQSeries queues, among others. Using servlets rather than other techniques (such as Common Gateway Interface programs) is attractive because servlets can be moved with recompilation to different server platforms that implement the Java servlet standard as provided by SUN Microsystems. Therefore, it is possible to write a servlet which connects to CICS and displays the results in an HTML page. There are a number of significant problems with this approach, however: w Variable data, such as the CICS application program name, and the MQ queue names you wish to use need to be hard-coded in the servlet (or you have to carefully architect the servlet to accept this information as parameters in some way). To change these, the servlet must be edited and recompiled. w The presentation logic (the HTML produced) is hard-coded, and you have to recompile the servlet if you want to change it. w Because the HTML is embedded in Java code, it is difficult to use an HTML builder tool to make HTML that looks attractive. Java Server Pages solve this problem by turning everything around. With a servlet, you write the Java code and include the HTML. With Java Server Pages, you write the HTML (usually with an HTML building tool) and include the Java code in the HTML page. WebSphere then compiles the entire JSP into a servlet dynamically when the JSP is called. The JSP is compiled by WebSphere only when it is changed. A compiled version is kept in the file © Copyright IBM Corporation 2000 Page 7 of 23 system (usually in /usr/lpp/WebSphere/AppServer/servlets/pagecompile ) for use when no changes have been made. A standard for JSPs has also been produced by SUN Microsystems, and therefore JSPs can be moved among systems that implement the standard. WebSphere is an example of a server that has implemented the standard. Be cautious, however, at the time of writing WebSphere on OS/390 has implemented JSP 0.91, while the current level of the standard is 1.1. A JSP Example A sample JSP is instructive to understand the concepts. The following sample has explanatory notes below it. Large amounts of the JSP have been removed so that I can illustrate the salient points. Items of interest in the HTML code are marked as [x] , where x is a cross reference to the notes that f ollow. <html> <head> <title>MQTest Output</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body bgcolor="#FFFFFF" background="images/bground.gif"> <BEAN NAME="mqb" TYPE="MQSeries.RSAMessage" SCOPE="REQUEST" INTROSPECT="NO"> </BEAN> [1] <% String String String String String mqmgr = (String) request.getParameterValues("mqmgr")[0]; [2] outputqueue = (String) request.getParameterValues("outputqueue")[0]; [2] inputqueue = (String) request.getParameterValues("inputqueue")[0]; [2] message = (String) request.getParameterValues("message")[0]; [2] timeout = (String) request.getParameterValues("mqtimeout")[0]; [2] String outdata = new String(); mqb.setQueuemanager(mqmgr); [3] mqb.setOutputqueue(outputqueue); [3] mqb.setInputqueue(inputqueue); [3] mqb.setOutputmessage(message); [3] mqb.setGettimeout(timeout); [3] mqb.putMessage(); [4] mqb.getMessage(); [5] %> <table width="81%" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="45%"><font face="Arial, Helvetica, sans-serif">The queue manager you used was:</font></td> <td width="55%"><font face="Arial, Helvetica, sans-serif" color="#00FF00"><%=mqb.getQueuemanager() %></font></td> [6] </tr> <tr> <td width="45%"><font face="Arial, Helvetica, sans-serif">The output queue was:</font></td> <td width="55%"><font face="Arial, Helvetica, sans-serif" color="#FF00FF"><%=mqb.getOutputqueue() %></font></td> </tr> <tr> <td width="45%"><font face="Arial, Helvetica, sans-serif">The input queue was:</font></td> © Copyright IBM Corporation 2000 Page 8 of 23 <td width="55%"><font face="Arial, Helvetica, sans-serif" color="#3399FF"><%=mqb.getInputqueue() %></font></td> </tr> </table> <br> <table width="81%" border="0" cellspacing="0" cellpadding="0"> <tr> <td><font face="Arial, Helvetica, sans-serif"> <% [7] boolean err = false; if (mqb.getErrorMessage() == "") { %> Your message text is: <% outdata = mqb.getOutputmessage(); } else { %> An error occurred, the error text is: <% outdata = mqb.getErrorMessage(); err = true; } %> [8] </font></td> </tr> <tr> <td> <% if (!err) { %> <font face=’Arial, Helvetica, sans-serif’ color=’#000099’> <% } else { %> <font face=’Arial, Helvetica, sans-serif’ color=’#993300’> <% } %> <%=outdata %></font></td> [9] </tr> </table> <p>&nbsp;</p> </body> </html> Some points to note from this source: w A JSP looks like a standard HTML file, containing some JavaScript. The HTML file can be built using any standard HTML tool. NetObjects Fusion (http://www.netobjects.com/) is a good example of an HTML building tool. WebSphere Studio also has good tools for building JSP files. w The <bean> tag [1] references Java compiled programs which provide services to this JSP. The mqb bean (source code provided on page 11) provides services to construct a message for MQSeries, put the message on a queue, and retrieve a message from a queue. It is my practise to build a generic Java bean which can provide services to any JSP, and then put the information unique to each application in the Java code within the JSP. © Copyright IBM Corporation 2000 Page 9 of 23 w JavaScript code is encapsulated within <% and %> delimiters. I have had problems when w I put code on the same line as a delimiter (eg <% int index=0); and this may be a function of the level of JSP (0.91) implemented in WebSphere for OS/390. For scripts, put delimiters on their own line and you won’t have a problem. After the first script delimiter, there are a series of lines that extract the data from the form that called this JSP [2]. Lines of the form String mqmgr = (String) request.getParameterValues("mqmgr")[0]; extract the field name from the form and assign the value to a variable (in this case with the same name) within the servlet. w The next step in the JSP is to take the fields from the form and use them to set initial values for the bean [3]. In this case we are using the values set up in the lines marked [2]. w The message constructed by the bean is put on an output MQSeries message queue in line [4]. w The JSP then waits for a reply message (line [5]). w To display the contents of a Java variable created within the JSP, use HTML of the form <%= variablename %> (example in line [6]). Make sure in particular you use <%= with no spaces in between, or you will end up with an error (in the WebSphere ncf.log) like /usr/lpp/WebSphere/AppServer/servlets/pagecompile/_StaffMember_xjsp.java:49: ’;’ expected. data[0].writeChars(0, 314, out); and usually a response on the Web browser like Unable to compile /usr/lpp/ServletExpress//servlets/pagecompile/_test2_xjsp.java w If you wish to produce HTML within a loop (for example, while) or within any Java conditional logic (for example, if) you must close the Java block beginning the conditional construct, then include the HTML you want produced, and then place another Java block closing the conditional or loop block. An example is shown between markers [7] and [8] in the code above. In other words, the JavaScript code cannot contain HTML elements. Line [9] is an example of variable output – if the call to MQSeries is successful, the output message is displayed. If the call is not successful, the MQSeries return code is displayed. w JSPs fail if <%= variablename %> is evaluated at run time to a null value. Often, these variables contain Java strings, so a null string would be “”. Nulls are quite common in databases, so good practise would be to initialise all variables to non-null values in your database access code (don’t change the database!). Your beans which access the database should do this. A good practise would be for your bean’s getter methods (the functions which get the data) to test the result they are sending. If the value to be returned is null, the getter method should change the value to a non-null (for example, a null string is converted to a single space). Use of Compiled Java Code As you can see from the above JSP extract, control of the application and display of the results is done using JavaScript code. Note that this JavaScript is processed on the server, not on the client, so you should not have security concerns about using JavaScript in this instance. The end user only sees HTML, the JSP is a development entity; remember that it is compiled into a servlet at run time, and the servlet produces HTML for the end user. When designing applications that use JSPs, you will quickly notice that each JSP you develop shares a set of common Java code. For example, for the sample application using CICS, common routines are required, among other things, to: © Copyright IBM Corporation 2000 Page 10 of 23 w w w w w Construct an MQSeries message. Put a message on an MQSeries queue. Get a message from an MQSeries queue. Parse an MQSeries message. Handle error conditions signalled by MQSeries. This common code should be compiled into a Java bean. The bean can be a Java class file, which provides services to the JSP as Java methods. By way of illustration, the source for the bean used in the JSP described earlier is listed following. Notes are included within the code as comments, and where appropriate following the code. mqb Bean This bean (RSAMessage.class) must be placed somewhere in the WebSphere class path, in an MQSeries subdirectory (since it has been defined as being part of the MQSeries package). package MQSeries; import com.ibm.mq.*; // This is a reference to the MQSeries bindings for Java package, // available from the MQSeries SupportPacs web site import java.util.Hashtable; /** * This type was created in VisualAge. * VisualAge for Java was used to build this bean. One significant advantage of VAJ * for building such code is that on defining an attribute, VAJ can automatically * build getter and setter methods for you, significantly reducing your coding effort. * Incremental compilation is another significant advantage. * No use of VAJ connectors was made when building this code. */ public class RSAMessage { private String outputqueue = "Output queue name is not set"; private String inputqueue = "Input queue name is not set"; private String queuemanager = "Queue manager name is not set"; private String inputmessage = "Input message is not set"; private String outputmessage = "Output message is not set"; private String errormessage = ""; // The above attributes are set up with default values. // This is done in case a value is not properly set by the JSP, in // which case the default value will be displayed on the output web page, // making diagnosis of JSP coding errors simpler. private byte messageID[]; // required by MQ Bindings for Java private int gettimeoutms = 60000; // default MQ timeout is 60 seconds /** * RSAMessage constructor comment. */ public RSAMessage() { super(); } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void appendErrorMessage(String newValue) { this.errormessage += newValue; } /** © Copyright IBM Corporation 2000 Page 11 of 23 * This method was created in VisualAge. * @return java.lang.String */ public String getErrorMessage() { return errormessage; } /** * This method was created in VisualAge. * @return int */ public int getGettimeoutms() { return gettimeoutms; } /** * This method was created in VisualAge. * @return java.lang.String */ public String getInputmessage() { return inputmessage; } /** * This method was created in VisualAge. * @return java.lang.String */ public String getInputqueue() { return inputqueue; } /** * This method was created in VisualAge. */ public void getMessage() { // This method assumes that the following methods have been run: // 1. PutMessage() // It is used to get an expected message from a reply queue try { // Create a connection to the queue manager MQQueueManager qmgr = new MQQueueManager(this.getQueuemanager()); // Set up options for the call int openOptions = MQC.MQOO_INPUT_AS_Q_DEF ; // Define the queue to place the message on MQQueue q = qmgr.accessQueue(this.getInputqueue(), openOptions, null, null, null); // Define the message to be sent MQMessage msg = new MQMessage(); // and set the message ID to be that originally sent msg.messageId = getMessageID(); // Set up options for the get as default MQGetMessageOptions gmo = new MQGetMessageOptions(); // Set up to wait for a message gmo.options = MQC.MQGMO_WAIT; gmo.waitInterval = 1; // Now get the message q.get(msg,gmo); // and put it in our message container setInputmessage(msg.readString(msg.getMessageLength())); // Now disconnect © Copyright IBM Corporation 2000 Page 12 of 23 q.close(); qmgr.disconnect(); } catch (MQException ex) { appendErrorMessage("An MQSeries error occurred : Completion code " + ex.completionCode + " Reason code " + ex.reasonCode); } // Was it a Java buffer space error? catch (java.io.IOException ex) { appendErrorMessage("An error occurred whilst writing to the message buffer: " + ex); } } /** * This method was created in VisualAge. * @return byte */ public byte[] getMessageID() { return messageID; } /** * This method was created in VisualAge. * @return java.lang.String */ public String getOutputmessage() { return outputmessage; } /** * This method was created in VisualAge. * @return java.lang.String */ public String getOutputqueue() { return outputqueue; } /** * This method was created in VisualAge. * @return java.lang.String */ public String getQueuemanager() { return queuemanager; } /** * Starts the application. * @param args an array of command-line arguments */ public static void main(java.lang.String[] args) { // A main method means this bean can be called from a shell environment // for testing. RSAMessage m = new RSAMessage(); System.out.println("Starting application..."); m.setQueuemanager("CSQ6"); m.setOutputqueue("CSQ5.LOOP.QUEUE"); m.setInputqueue("CSQ6.LOCAL.QUEUE"); m.setOutputmessage("This is my test message 1234567890"); m.setGettimeout("120000"); System.out.println("Putting output message..."); m.putMessage(); System.out.println("Finished putting output message..."); System.out.println("Getting input message..."); m.getMessage(); System.out.println("Finished getting input message..."); © Copyright IBM Corporation 2000 Page 13 of 23 System.out.println("Retrieved message is..."); System.out.println(""); System.out.println(m.getInputmessage()); System.out.println(""); System.out.println("Error messages are..."); System.out.println(""); System.out.println(m.getErrorMessage()); } /** * This method was created in VisualAge. */ public void putMessage() { // This method assumes that the following methods have been run: // 1. setQueuemanager(String) // 2. setOutputqueue(String) // 3. SetOutputmessage(String) // It is used to put a message on an outbound queue. try { // Create a connection to the queue manager MQQueueManager qmgr = new MQQueueManager(this.getQueuemanager()); // Set up options for the call int openOptions = MQC.MQOO_OUTPUT; // Define the queue to place the message on MQQueue q = qmgr.accessQueue(this.getOutputqueue(), openOptions, null, null, null); // Define the message to be sent MQMessage msg = new MQMessage(); // Set up message ID to default -queue manager will assign a unique message ID msg.messageId = MQC.MQMI_NONE; // Set up correlation ID to required for new sessions msg.correlationId = MQC.MQCI_NEW_SESSION; // Set up format msg.format = MQC.MQFMT_STRING; // Set up reply queue msg.replyToQueueName = inputqueue; // and put the message in it msg.writeString(outputmessage); // Set up options for the put as default MQPutMessageOptions pmo = new MQPutMessageOptions(); // Now put the message q.put(msg,pmo); // Remember the message id for later setMessageID(msg.messageId); // Now disconnect q.close(); qmgr.disconnect(); } catch (MQException ex) { appendErrorMessage("An MQSeries error occurred : Completion code " + ex.completionCode + " Reason code " + ex.reasonCode); } // Was it a Java buffer space error? catch (java.io.IOException ex) { © Copyright IBM Corporation 2000 Page 14 of 23 appendErrorMessage("An error occurred whilst writing to the message buffer: " + ex); } } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void setErrorMessage(String newValue) { this.errormessage = newValue; } /** * This method was created in VisualAge. * @param input java.lang.String */ public void setGettimeout(String input) { // this method takes a string and sets the MQ message get // timeout value to the integer value derived from the String try { Integer toms = new Integer(input); this.gettimeoutms = toms.intValue(); } catch (NumberFormatException ne) { // do nothing, just take the default timeout set in the constructor } } /** * This method was created in VisualAge. * @param newValue int */ public void setGettimeoutms(int newValue) { this.gettimeoutms = newValue; } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void setInputmessage(String newValue) { this.inputmessage = newValue; } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void setInputqueue(String newValue) { this.inputqueue = newValue; } /** * This method was created in VisualAge. * @param newValue byte */ public void setMessageID(byte[] newValue) { this.messageID = newValue; } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void setOutputmessage(String newValue) { this.outputmessage = newValue; } /** * This method was created in VisualAge. * @param newValue java.lang.String */ © Copyright IBM Corporation 2000 Page 15 of 23 public void setOutputqueue(String newValue) { this.outputqueue = newValue; } /** * This method was created in VisualAge. * @param newValue java.lang.String */ public void setQueuemanager(String newValue) { this.queuemanager = newValue; } } Notes from the Java bean source code: w This code was built for a proof-of-concept. It was not engineered to be production ready. You are free to use the code, but must do so at your own risk. To be made production ready, a significant amount of work needs to be done on error checking and handling. In addition, no parser is provided. For the proof-of-concept, I wrote a parser in JavaScript within the JSP file. w XML is ideally suited to describing the message that passes between WebSphere and the application. This would be a good subject for another paper. Creating JSPs I use NetObjects Fusion (http://www.netobjects.com) to create my Web pages and JSPs; you of course can use any tool you consider appropriate. Here are a few tricks I have developed to build JSPs using an HTML builder: w Build your HTML as normal. w For JSPs, make sure you change the extension of the file produced by the tool to .jsp. w If you require tabular output, where one row of HTML is produced for each row returned from an application, the best way I have found is: 1. Lay out the table with two rows, one for the header and one as a model for the results. 2. In the results row, enter the variable names to be evaluated in the appropriate columns. Set up the fonts and colours you wish to use. However, you probably cannot code <%= variablename %> because the tool will most likely change the < to &lt; and > to &gt; (URL escapes) because these characters are reserved for HTML. Web browsers translate these characters back to < and >, but you want them evaluated by the server (servlet), not the browser. I therefore use a trick like ZZvariablenameYY, and on the OS/390 system edit the file and change all ZZ to ‘<%= ‘ and all YY to ‘ %>’. If anyone can find a better way (or stop the tool from URL escaping these characters, please let me know. 3. Position the cursor in the body of the document (not in the layout region or margins) and click the HTML button to insert your bean tags after the body tag. 4. Use the tool ROW HTML button to: a. Insert the Java code for the beans call and loop opening BEFORE the row tag. b. Insert the Java code to close the loop and increment the counter AFTER the row tag. © Copyright IBM Corporation 2000 Page 16 of 23 Proof of Concept Application The proof of concept CICS application is a quoting application for building or motor insurance. This is a simple application that requires only specification of the type of insurance, postcode, and sum insured to generate a quote. An HTML page is used to collect this information from the client. A fragment from such a page is shown following: Clicking “Request Quote” on this page makes a call to the JSP listed following: <html> <head> <title>CICSTest Output</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> </head> <body bgcolor="#FFFFFF" background="images/bground.gif"> <BEAN NAME="mqb" TYPE="MQSeries.RSAMessage" SCOPE="REQUEST" INTROSPECT="NO"> </BEAN> [1] <% // get system values from the form. Note that these are provided // in hidden fields in the input HTML form for this Proof of Concept String mqmgr = (String) request.getParameterValues("mqmgr")[0]; [2] String outputqueue = (String) request.getParameterValues("outputqueue")[0]; String inputqueue = (String) request.getParameterValues("inputqueue")[0]; String timeout = (String) request.getParameterValues("mqtimeout")[0]; String program = (String) request.getParameterValues("program")[0]; // application values: String operator = (String) request.getParameterValues("operator")[0]; [3] String typeoi = (String) request.getParameterValues("type")[0]; String postcode = (String) request.getParameterValues("postcode")[0]; String suminsured = (String) request.getParameterValues("suminsured")[0]; String String String String String outdata = new String(); message = new String(); omessage = new String(); blah = new String(); toi = new String(); // test the length of the program name to be called - provided by the form program.trim(); © Copyright IBM Corporation 2000 Page 17 of 23 if (program.length() != 8) { // this is an ugly solution and needs to be fixed properly // concatenate blanks to the provided program name blah = program.concat(" "); // then substring to 8 characters omessage = blah.substring(0,8); } // pad suminsured with 0’s if length is not 6. String sum = "000000"; String outsum = new String(); int sumlength = suminsured.length(); if (sumlength != 6) { outsum = sum.substring(0, (6 - sumlength)); outsum += suminsured; } else { outsum += suminsured; } message += operator += typeoi += postcode += outsum; message += " "; omessage += message; [5] [4] mqb.setQueuemanager(mqmgr); [6] mqb.setOutputqueue(outputqueue); [6] mqb.setInputqueue(inputqueue); [6] mqb.setOutputmessage(omessage); [6] mqb.setGettimeout(timeout); [6] mqb.putMessage(); [7] mqb.getMessage(); [8] boolean err = false; outdata = mqb.getInputmessage(); String errormessage = new String(); // look for a comma, if we get one the data is real, otherwise it is // an error message [9] if (outdata.indexOf(",") == -1) { err = true; errormessage = outdata; } if (mqb.getErrorMessage() != "") { err = true; errormessage = mqb.getErrorMessage(); } String String String String String String outbasicpremium = " "; [10] outtaxes = " "; [10] outtotalpremium = " "; [10] outpostcode = " "; [10] outsuminsured = " "; [10] testit = new String(); © Copyright IBM Corporation 2000 Page 18 of 23 if (!err) { [11] int counterc = outdata.indexOf(","); int counterm = outdata.indexOf(",", counterc+1); outbasicpremium = outdata.substring(counterc+1, counterm); counterc = counterm; counterm = outdata.indexOf(",", counterc+1); outtaxes = outdata.substring(counterc+1, counterm); counterc = counterm; counterm = outdata.indexOf(",", counterc+1); outtotalpremium = outdata.substring(counterc+1, counterm); counterc = counterm; counterm = outdata.indexOf(",", counterc+1); outpostcode = outdata.substring(counterc+1, counterm); counterc = counterm; counterm = outdata.indexOf(",", counterc+1); outsuminsured = outdata.substring(counterc+1, counterm); // set up type of insurance text testit = typeoi.substring(0,3); if (testit.compareTo("001") == 0) { toi = "building"; } else { toi = "contents"; } } %> <table width="91%" border="0" cellspacing="0" cellpadding="0"> <tr> <td width="0%"><img src="images/title.gif" width="406" height="68"></td> <td width="73%">&nbsp;</td> <td width="27%"><img src="images/logo.gif" width="170" height="58"></td> </tr> <tr> <td width="0%">&nbsp;</td> <td width="73%">&nbsp;</td> <td width="27%">&nbsp;</td> </tr> <% // if we get a valid result, print the following if (!err) [12] { %> <tr> <td width="100%" colspan="3"> <h2>CICS Quoting Application</h2> <p><font face="Arial, Helvetica, sans-serif">Thank you for your interest in insuring your <b><%=toi %></b> with us. Your quote is:</font></p> [13] </td> </tr> </table> © Copyright IBM Corporation 2000 Page 19 of 23 <br> <table width="293" border="0" cellpadding="0" cellspacing="0"> <tr> <td width="68%"><font face="Arial, Helvetica, sans-serif">For postcode:</font></td> <td width="32%"><font face="Arial, Helvetica, sans-serif" color="#00FF00"><%=outpostcode%></font></td> [13] </tr> <tr> <td width="68%"><font face="Arial, Helvetica, sans-serif">and for sum insured:</font></td> <td width="32%"><font face="Arial, Helvetica, sans-serif" color="#00FF00">$<%=outsuminsured%></font></td> [13] </tr> <tr> <td width="68%">&nbsp;</td> <td width="32%">&nbsp;</td> </tr> <tr> <td width="68%"><font face="Arial, Helvetica, sans-serif">Basic Premium</font></td> <td width="32%" align="right"><font face="Arial, Helvetica, sans-serif" color="#3399FF">$<%=outbasicpremium%></font></td> [13] </tr> <tr> <td width="68%"><font face="Arial, Helvetica, sans-serif">Taxes and Charges</font></td> <td width="32%" align="right"><font face="Arial, Helvetica, sans-serif" color="#3399FF">$<%=outtaxes%></font></td> [13] </tr> <tr bgcolor="#00CCFF"> <td width="68%"><b><font face="Arial, Helvetica, sans-serif">Total Premium</font></b></td> <td width="32%" align="right"><b><font face="Arial, Helvetica, sans-serif" color="#0000FF">$<%=outtotalpremium%></font></b></td> [13] </tr> </table> <p>&nbsp;</p> <% // else if message not OK, print this } else [14] { %> <!table width="75%" border="0" cellspacing="0" cellpadding="0"> <tr> <td><font face="Arial, Helvetica, sans-serif">Sorry, we were unable to generate a quote. Please try again later.</font></td> </tr> <tr> <td><font face="Arial, Helvetica, sans-serif">Error message is : <%=errormessage %> [15] </font></td> </tr> <p>&nbsp;</p> <% // end if } %> </body> </html> [16] Notes from the JSP: [1] Once again, we use the Java bean explained earlier. © Copyright IBM Corporation 2000 Page 20 of 23 [2] System values such as MQSeries queue manager name, and input and output queues, are provided to the JSP in hidden fields from the form which invokes the JSP. This is not a secure solution, a more engineered solution would probably use servlet properties files or initialization files to specify site specific information. [3] Application values are retrieved from the form here. [4] The MQSeries message is constructed, to the format required by the application being called. This has been agreed in advance with the owner of the application. [5] The MQSeries/CICS bridge requires the CICS program name, with length of eight bytes, followed by the COMMAREA data to be passed to the CICS program. [6] These lines set up important data for the Java bean, which determine which MQSeries queues to be used and so on. [7] The message is placed on the outbound queue, and the JSP waits for a response on the inbound queue [8]. [9] The response from the application should be comma delimited. This has been agreed with the application owner. The code following this comment checks for a valid response message. [10] These lines initialize the strings which will be used for output. Since JSPs fail if null values are output, the strings are initialized to a single space to ensure the JSP will not fail due to nulls. [11] The if block commencing here parses the data by scanning for commas (as agreed with the application owner. The order of variable values has also been agreed. This is a very simple design, and a production application would use a more robust design, perhaps using something like XML to describe the message contents. [12] As in the earlier JSP, there is an if block which produces the following HTML if there is no error. Note that the JavaScript must be ended (even though the logic has not ended) before HTML code is included. [13] These lines are examples of outputting data parsed from the MQSeries message. [14] This else block is associated with the if in line [12]. [15] In case of an error, an apology is produced along with the MQSeries message. [16] The end of the JavaScript if block. The output of the JSP is shown following (fragment of HTML page): JSPs allow you to present your application in an attractive way, making use of graphics, colours, and fonts (along with any other HTML or browser feature you wish to use). © Copyright IBM Corporation 2000 Page 21 of 23 Why Use OS/390 There are a number of documents that describe the advantages of using OS/390 as a Web server/concentrator. These include the OS/390 e-business Infrastructure books listed in the references. However, there are a number of reasons OS/390 was chosen as the server for the proof-of-concept project which generated this paper. These were: w Response time. Experiences with access to CICS applications using MQSeries from NT servers provided a benchmark for response times, which typically were in the order of a few seconds. Without any tuning or other special work, a response time in the order of one second was achieved for the architecture described in this paper. w Capacity. OS/390 has the capability to run more work than most other commercial w servers. Security. Users can be validated using OS/390 Security Server, to ensure that have authority to access the resources they are asking for. © Copyright IBM Corporation 2000 Page 22 of 23 References Web Server IBM HTTP Server for OS/390 Planning, Installing, and Using , SC31-8690. IBM HTTP Server for OS/390 Web Programming Guide , SC34-4743-01. These documents are available from the software Web site, http://www.ibm.com/software/webservers/httpservers/doc51.html. OS/390 e-business Infrastructure: IBM HTTP Server 5.1- Customization & Usage , SG24-5603-00 (check http://www.redbooks.ibm.com for availability). WebSphere Application Server WebSphere Application Server for OS/390 Program Directory , GI10-6780, available from http://www.ibm.com/software/webservers/appserv/ (follow the links to WebSphere for OS/390). WebSphere Application Server for OS/390 Planning, Installing, and Using , available from http://www.ibm.com/software/webservers/appserv/ (follow the links to WebSphere for OS/390). A trouble shooting guide is also available from this location. OS/390 e-business Infrastructure: IBM WebSphere Application Server 1.1 - Customization & Usage, SG24-5604-00 (check http://www.redbooks.ibm.com for availability). Java for OS/390 Check the Web site, http://www.s390.ibm.com/java e-business Application Solutions on OS/390 Using Java: Volume I , SG24-5342-00 (check http://www.redbooks.ibm.com for availability). Java Programming Guide for OS/390, SG24-5619 (check http://www.redbooks.ibm.com for availability). MQSeries Check the Web site for information about MQSeries, MQSeries bindings for Java, and the MQSeries/CICS bridge - http://www.ibm.com/software/ts/mqseries/ © Copyright IBM Corporation 2000 Page 23 of 23