September 2006
This document contains information that will help you use the development tools in this release of WSIT for OpenVMS.
Software Version
Web Services Integration Toolkit Version 1.2
Hewlett-Packard
Company
Palo Alto, Calif.
© 2006 Hewlett-Packard Development Company, L.P.
C O N T E N T S
INTRODUCTORY INFORMATION
– FOR ALL USERS
1. USING THE WEB SERVICES INTEGRATION TOOLKIT FOR OPENVMS
1.2 Preparing the Original (Legacy) Application
1.3 Exposing an OpenVMS 3GL Application: Typical Development Steps
1.4 Wrapping a 3GL Application: C Sample
1.4.1 Server/Application Build Procedure
1.4.2 Customizing the Build Environment
1.5 Wrapping an ACMS Application: ACMS Sample
1.6 Generating Sample Clients
1.7 Using ANT with the Web Services Integration Toolkit
1.7.1 Ant Setup
1.7.2 Configuring the wsit-ant-user.properties File
1.7.3 Using the wsit-ant-userbuild.xml Build File
1.7.4 Ant Property Descriptions
1.7.5 Ant Target Descriptions
1.7.6 Custom Ant Tasks
1.8
Using Distributed NetBeans with the Web Services Integration Toolkit
1.8.1 WSIT Build Templates
1.8.2 Using the WSIT-Supplied Ant Version
1.9 Security Considerations
1.9.1 Server Process Security
1.9.2 Per User Security
1.10 WSIT Tools and Parameters
1.10.1 In-Process/Out-of-Process
Parameters
1.10.2 POJO/JSP Sample Client Parameters
2.1 Types of OpenVMS Applications
2.3.1 Sessions
2.3.2 Application Reusability
2.3.3 Using Multiple Processes to Scale Applications
2.3.4 Specifying Out-of-Process Deployment
Options
2.3.4.1 Out-of-Process Account
Preparation and Requirements
2.4 Web Services Integration Toolkit Interfaces
2.4.1 Application Interfaces (User Supplied)
2.4.2 OpenVMS Datatypes Supported by WSIT
2.4.3 Passing Mechanisms
2.4.4 JavaBean Interface (Generated by WSIT)
2.4.5 Datatype Mapping
2.4.5.1 String Datatype
2.4.6 Parameter Usages
2.5 Design Restrictions for Wrapped Applications
2.5.1 Pointer Types Not Supported
2.5.2 Instantiated WSIT JavaBeans Cannot Be Shared Among
Clients
2.5.3 Languages Tested with Web Services Integration Toolkit
2.5.4 Tips and Hints for Supported Languages
2.5.5 Tips and Hints for OpenVMS Alpha Users
ADVANCED INFORMATION –
FOR EXPERIENCED USERS
3. ADVANCED OUT-OF-PROCESS CONFIGURATION
3.2 Case B: Sequentially Reusable
3.3 Case C: Concurrently Reusable
3.4 Case D: Concurrently Reusable with Multiple Threads
4. USING TEMPLATES TO GENERATE CODE
4.1 Modifying Velocity Templates
4.2 Generating Code with IDL2CODE.JAR
4.3 Example 1: Writing a New Template
4.4 Example 2: Modifying an Existing Template
5.3 Enumerator Block
5.4 Typedef Block
5.5 Primitive Block
5.6 Structure Block
5.7 Field Block
5.7.1 Field Array Tag
5.8 Routine Block
5.9 Parameter Block
5.9.1 Parameter Array Tag
B. Program Listing - STOCK.XML
C. Program Listing - StockCaller.Java
D.
Program Listing - MATH.C
F. Program Listing - mathcaller.java
This Developer’s Guide contains information about how to use the tools in the Web Services Integration Toolkit for OpenVMS, and things to consider as you prepare your legacy application.
The Installation Guide and Release Notes includes system requirements and installation instructions for OpenVMS, as well as release notes for the current release of the Web Services Integration Toolkit for OpenVMS.
For the latest release information, refer to the Web Services Toolkit for OpenVMS web site at http://www.hp.com/products/openvms/webservices/.
The Web
Service Integration Toolkit for OpenVMS (WSIT) contains a collection of
integration tools. These tools are easy to use, highly extensible, based on
standards and built on open source technology. The toolkit can be used to call
OpenVMS applications written in 3GL languages, such as C, BASIC, COBOL,
FORTRAN, and ACMS from newer technologies and languages such as Java, Microsoft
.NET, Java -RMI, JMS, and web services.
The Web
Service Integration Toolkit is focused on integrating at the API level. It
generates a JavaBean wrapper for a supplied OpenVMS application interface
(API). At runtime, you can specify if the application will be run in the
process of the caller (in-process) or in separate processes (out-of-process)
managed by the WSIT runtime.
1.2 Preparing the Original (Legacy) Application
Using the Web Services Integration Toolkit for OpenVMS, as with all programmatic integration, requires some upfront development work before you can begin performing the integration. Your existing application is likely to have been written long ago and will benefit from having a wrapper expose a new and clean interface. The new interface will expose the legacy implementation. Separating the interface from the implementation provides encapsulation and the ability to easily extend and reuse the implementation.
Before you use the Web Services Integration Toolkit or any other integration technology, you must evaluate the original application and design one or more interface classes to expose different features of the business logic. These new interfaces should be tested with a simple client before you use the Web Services Integration Toolkit. When you know that the interface classes are working properly, you can use WSIT to extend the use of the new interface to the Java environment.
After you have prepared the application, WSIT can extend the features of the new interface to Java as shown in the following diagram.
1.3 Exposing an OpenVMS 3GL Application: Typical Development Steps
Following are the development steps required to use the Web Services
Integration Toolkit to expose an OpenVMS 3GL or ACMS application. Note that
these steps are only required for the development phase. It is expected that
the application has been prepared as discussed in the previous section.
Note: These tools were renamed in a pre-V1.0 field test kit. See Chapter 3 in the Installation Guide and Release Notes for a table containing the old and new file names.
1. Create XML IDL file (on I64)
Create an XML interface definition file (IDL) that describes the interface to be exposed. You create an XML IDL file using the tool named OBJ2IDL.EXE (for 3GL languages) or STDL2IDL.JAR (for ACMS). Note: OBJ2IDL.EXE runs on OpenVMS I64 only. If you are using WSIT on OpenVMS Alpha, see Section 2.5.5 for information about the HP TestDrive program.
2. Validate XML IDL file
Verify that the XML IDL file correctly describes the interface being exposed. If it does not, manually update the XML IDL file until the interface definition is correct. VALIDATE.JAR allows you to verify that an XML IDL file conforms to the openvms-integration.xsd schema.
3. Generate components
For the interface being exposed, generate one WSIT server interface wrapper and one WSIT Java
Bean using IDL2CODE.JAR. The generated source code must be built on the OpenVMS system that hosts the application.
4. Use the generated code
Call the generated WSIT JavaBean from the technology of your choice, including BEA WLS, Apache Axis, JMS, Java RMI, J2EE or another JavaBean.
The following steps demonstrate how to wrap a 3GL application using the math sample program found in WSI$ROOT:[SAMPLES.C]. Other 3GL sample programs can be found in WSI$ROOT:[SAMPLES.COBOL] and WSI$ROOT:[SAMPLES.BASIC]. (See Section 1.5 for information about a sample program that wraps an ACMS application.)
The information in this section is also included in WSI$ROOT:[SAMPLES.C]MATH-SAMPLE.README.
Note: For demonstration purposes only, the steps below use the wsi$root:[samples.c] directory
as the default directory. HP recommends that you copy the contents of this directory into
your own local directory before performing these steps.
The tool OBJ2IDL.EXE is used to generate an XML interface definition file (IDL). (For information about manually reading or modifying an IDL, see Chapter 5.)
Establish a foreign command:
$ obj2idl = "$WSI$ROOT:[tools]obj2idl.exe"
Compile the wrapper that exposes the new interface:
$ set def WSI$ROOT:[samples.c]
$ cc/debug/noopt math.c
Note: Your code must be compiled with the /DEBUG option for the OBJ2IDL parser to work properly.
Use OBJ2IDL to generate an XML file with the interface definition:
$ obj2idl -f WSI$ROOT:[samples.c]math.obj
The tool OBJ2IDL creates the file math.xml. See the Appendix for a full listing of math.xml.
You should become familiar with the XML description of OpenVMS applications. Review the math.xml file and notice the overall structure of the file. Following are the level 1 tags used to define an interface. These tags contain lower level tags and more information.
<OpenVMSInterface>
<Primitives></Primitives> Define the fundamental types referenced in the interface.
<Routines></Routines> Define the callable routines of the
interface.
<Structures></Structures> Define the structures of the
interface.
<Typedefs></Typedefs> Define the type definitions of the interface.
</OpenVMSInterface>
Note: To view the XML file with coloring and a collapsible
outline, use Internet Explorer.
The OBJ2IDL tool is sometimes unable to extract a complete interface definition from the supplied object file. When the tool is missing data or has made assumptions, a comment is placed in the XML file below the line of concern.
The file math.log is also generated from OBJ2IDL. Use this file to conveniently see an overview of the comments within the XML file. (ACMS does not create a .log file.)
$ ty math.log
Generated IDL file: WSI$ROOT:[samples.c]math.xml
Tue Apr 5 11:22:37 2005
In this case the tool did not report any issues. However, even in cases where the log file has not generated any error or warning, you should always review the XML file to ensure that the interface definition is exactly correct. It is very important that the XML IDL describe the interface accurately to generate correct code in Step 3.
The validate.jar tool is provided
to allow you to verify that an XML IDL file conforms to the openvms-integration.xsd schema. Use this tool to validate all
XML IDL files before they are passed to the IDL2CODE tool. The IDL2CODE
tool does not validate the XML IDL file.
The validate tool is an executable JAR file. To run the tool, you must supply two parameters: an XML IDL file and the openvms-integration schema. For example:
$ java -jar
wsi$root:[tools]validate.jar -x wsi$root:[samples.c]math.xml
–s wsi$root:[tools]openvms-integration.xsd
Use the tool IDL2CODE.JAR (also called the Generator) to create a server wrapper for the application and a JavaBean client. This tool requires certain JAR files to be in the Java classpath. A command procedure is supplied to add these files to the java$classpath logical. (The java$classpath logical lets you define a class path using OpenVMS file specification syntax. Defining this logical overrides the classpath logical, if set.)
$ @WSI$ROOT:[tools]wsi-setenv - wsi$dev
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
$
To generate files for the math demo, use the following command. In this case, the tool is passed the math.xml file and the application is named math. All generated files for the application are placed in a subdirectory named generated.
$ create/dir [.generated]
$ java "com.hp.wsi.Generator" -i math.xml -a math -o [.generated]
File: ./generated/mathServer/build-math-server.com generated.
File: ./generated/mathServer/methIds.h generated.
File:
./generated/mathServer/structkeys.h generated.
File: ./generated/mathServer/math.wsi generated.
File: ./generated/mathServer/math.opt generated.
File: ./generated/mathServer/math-server.h generated.
File: ./generated/mathServer/math-server.c generated.
File: ./generated/math/build-math-jb.com generated.
File: ./generated/math/Imath.java generated.
File: ./generated/math/mathImpl.java generated.
*** Application math generated! ***
$
Build the server:
This command procedure installs the server image after it has been built. This requires writing to the WSI$ROOT:[DEPLOY] directory, which may be write protected on your system. (This is a security measure. Have your system manager assist you if your account does not have the required privileges.)
$ set def WSI$ROOT:[samples.c.generated.mathserver]
$ @BUILD-MATH-SERVER
Begin server build procedure.
..configuring switches and compiler options
..compiling native server code
..linking shareable image
..installing server image
End server build procedure.
$
Build the client:
The JavaBean build procedure creates a JAR file that contains the WSI Java classes used to call the server created earlier.
$ SET DEF WSI$ROOT:[samples.c.generated.math]
$ @BUILD-MATH-JB
Begin java bean build procedure.
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86D5AE00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
..Compiling structure classes
..Compiling math Interface classes
..Creating math.JAR file from classes
End of JavaBean build procedure.
You can run the math sample program in-process or out-of-process. In-process means that the application will be run in the process of the caller. (Follow the instructions in step 5b instead of 5a if you want to run the sample out-of-process.)
Add the math.jar file to the java$classpath.
$ @WSI$ROOT:[tools]wsi-setenv – WSI$ROOT:[samples.c.GENERATED.math]math.jar
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
= "WSI$ROOT:[SAMPLES.C.GENERATED]MATH.JAR"
$
In the normal course of development, you would now need to write a JavaBean to call the math JavaBean that was generated above. However, for the purpose of this demonstration, a JavaBean file named mathcaller.java is provided in the directory WSI$ROOT:[samples.c]. See the Appendix for a source listing of this file.
Compile the supplied JavaBean:
$ set def WSI$ROOT:[samples.c]
$ javac mathcaller.java
Run the supplied JavaBean:
$ java mathcaller
Sum of 10 and 15 is 25
Product of 10 and 15 is 150
$
You can run the math sample program either in-process or out-of-process. Out-of-process means that the sample will be run in a separate process managed by the WSIT runtime. (Follow the instructions in step 5a instead of 5b if you want to run the sample in-process.)
Add the math.jar file to the java$classpath.
$ @WSI$ROOT:[tools]wsi-setenv - WSI$ROOT:[samples.c.GENERATED.math]math.jar
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
= "WSI$ROOT:[SAMPLES.C.GENERATED.MATH]MATH.JAR"
$
In the normal course of development, you would now need to write a JavaBean to call the math JavaBean that was generated above. However, for the purpose of this demonstration, a JavaBean file named mathcaller.java is provided in the directory WSI$ROOT:[samples.c]. See the Appendix for a source listing of this file.
To run the math sample out-of-process, make the following changes to mathcaller.java:
· Call a different constructor
· Call remove when done with server
These changed lines are underlined in the following listing of mathcaller.java.
$ type mathcaller.java
import math.*;
import java.io.*;
import com.hp.wsi.WsiIpcContext;
public class mathcaller {
/** Creates a new instance of Main */
public mathcaller() {
}
public static void main(String[] args) {
try {
mathImpl math = new mathImpl(new WsiIpcContext());
int num1 = 10;
int num2 = 15;
int result;
result = math.sum(num1, num2);
System.out.println("Sum of " + num1 + " and " + num2 + "is " + result);
result = math.product(num1, num2);
System.out.println("Product of " + num1 + " and " + num2 + "is " + result);
math.remove();
} catch (Exception e) {
System.out.println("Exception thrown");
}
}
}
Important: Review WSI$ROOT:[DEPLOY]MATH.WSI. By default, the deployment configuration file is the most restrictive. It assumes the application is not reusable, therefore it needs a new server process for every client. After evaluating your application, you can modify math.wsi to scale the deployment configuration for the application. See Chapter 2, Deployment Considerations, for more information.
Compile the supplied JavaBean:
$ set def WSI$ROOT:[samples.c]
$ javac mathcaller.java
Run the supplied JavaBean:
$ java mathcaller
Sum of 10 and 15 is 25
Product of 10 and 15 is 150
$
1.4.1 Server/Application Build
Procedure
The Web Services Integration Toolkit generates a command procedure to build a server. The generated command procedure, named build-<appname>-server.com, creates a shareable image named <appnam>.exe and copies it to the deployment directory WSI$ROOT:[DEPLOY]. The WSIT runtime loads this shareable image to process requests from the WSIT generated JavaBean.
The shareable image <appnam>.exe is composed of three parts:
· The object file provided by the user (in the XML IDL file) to expose the application interface. For example, wsi$root:[samples.c]math.obj located in wsi$root:[samples.c]math.xml.
·
A WSIT object file
named <appname>-server.obj which exposes the application interface
with a set of fixed WSIT entry points. The source file for this object file is <appname>-server.c.
· A WSIT shareable image containing common reusable procedures. This shareable image is named SYS$LIBRARY:WSI$COMMON.EXE.
This shareable image must provide entry points for the WSIT runtime to call. The entry points for all WSIT applications are always the same. The entry points are as follows:
Symbol Name Symbol
Type
WSI$INIT PROCEDURE
WSI$EXIT PROCEDURE
WSI$START_SESSION PROCEDURE
WSI$END_SESSION PROCEDURE
WSI$ACMS_SIGN_IN PROCEDURE
WSI$ACMS_SIGN_OUT PROCEDURE
WSI$VMS_LOGIN PROCEDURE
WSI$VMS_LOGOUT PROCEDURE
WSI$INVOKE PROCEDURE
WSI$INVOKE_DCL PROCEDURE
WSI$GET_FILE PROCEDURE
WSI$INFO_BLOCK DATA
WSI$DCL_PROC_MAPS DATA
WSI$FILENAME_MAPS DATA
1.4.2
Customizing the Build Environment
In the default behavior described in the preceding section, the application’s interface object module is expected to process the requests without calling others modules. While this approach allows WSIT applications to be quickly prototyped, it is obviously not sufficient for “real” applications.
The application being wrapped will almost always be composed of many object modules, object libraries, and/or shareable images. These object modules need to be packaged into a shareable image that includes the WSIT files described above.
You can package the object modules in two
ways, as follows:
· Add the few WSIT build elements to the existing application’s build environment. (This is the recommended method.)
· Add the application files to the WSIT server build command procedure.
If you choose the recommended option above, the file <appname>.opt provides an overview of the files and entry points that must be added to the new application’s shareable image.
If you decide to integrate the WSIT files
into your application, remember that the application must be built as a
shareable image named <appnam>.exe and must be copied to the WSIT
deployment directory WSI$ROOT:[DEPLOY].
On the OpenVMS system on which you installed WSIT, log in using an account with SYSTEM privileges.
Create a directory to set up the application. For example:
$ create /dir [.acmsgenerated]
Set default to the newly created directory:
$ set def [.acmsgenerated]
Execute the following command:
$ @WSI$ROOT:[samples.acms]acmsexample_setup.com
This assumes that the ACMS$EXAMPLES logical is present and correct on your system.
This DCL script does the following:
· Creates a local data dictionary for this application
· Defines a CDD (common dictionary data) record (using the supplied .CDO files)
· Defines a CDD entry task
· Builds the application, generating a STDL file (used to import ACMS task and structure definitions)
· Starts the ACMS application
When prompted for a CDD directory, you can press Enter to accept the default (which will be under the directory you just created and set default to), or you may choose another name or location.
For example:
CDD Directory? DKA100:[USER.ACMSGENERATED.DICTIONARY] :
The sample application is set up and started when you see the following:
%ACMSINS-S-ADBINS, Application
DISK:[USER.ACMSGENERATED]EMPLOYEE_INFO_APPL_BWX.ADB;
has been installed to ACMS$DIRECTORY
Use the STDL2IDL.JAR tool to generate an XML interface definition (IDL file) from the STDL file generated in Step 1.
Run the STDL2IDL importer:
$ java -classpath WSI$ROOT:[TOOLS]stdl2idl.jar "com.hp.wsi.Import"
-a AcmsApp -f EMPLOYEE_INFO_APPL_WSI.STDL
Import File was successfully processed.
File: ./acmsapp2_idl.xml generated.
*** Files for Application acmsapp2
successfully generated! ***
Because STDL files completely describe the ACMS application, the STDL2IDL tool is able to use the STDL file to create a complete WSIT interface definition representation of that ACMS application. However, even if the STDL2IDL tool specifies that the IDL generation was successful, you should review and validate the generated XML file to ensure complete accuracy. The XML IDL must accurately describe the interface to generate correct code in Step 4.
For this reason, WSIT includes the validate.jar tool to allow you to verify that an XML IDL file conforms to the openvms-integration.xsd schema before it is passed to the IDL2CODE.JAR tool. (The IDL2CODE.JAR tool does not validate the XML IDL file.) To run the validate.jar tool, supply two parameters: an XML IDL file and the openvms-integration schema. For example:
$ java -jar wsi$root:[tools]validate.jar
-x wsi$root:[samples.acms]AcmsApp_idl.xml
-s wsi$root:[tools]openvms-integration.xsd
Use the IDL2CODE.JAR tool to create a server wrapper for the application and a JavaBean client. This tool requires certain Jar files to be in the Java classpath. A command procedure is supplied to add these files to the java$classpath logical.
$ @WSI$ROOT:[tools]wsi-setenv - wsi$dev
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
$
To generate files for the ACMS sample, use the following command. In this case we pass the tool the AcmsApp_idl.xml file (generated above) and we call the application AcmsApp. We also place all generated files for the application in a subdirectory named generated.
$ create/dir [.generated]
$ java "com.hp.wsi.Generator" -i AcmsApp_idl.xml -a AcmsApp -o [.generated]
File: ./generated/acmsapp_server/build-acmsapp-server.com generated.
File: ./generated/acmsapp_server/methIds.h generated.
File: ./generated/acmsapp_server/structkeys.h generated.
File: ./generated/acmsapp_server/acmsapp.wsi generated.
File: ./generated/acmsapp_server/acmsapp.opt generated.
File: ./generated/acmsapp_server/acmsapp-server.h generated.
File: ./generated/acmsapp_server/acmsapp-server.c generated.
File: ./generated/acmsapp_server/build-acmsapp-jb.com generated.
File: ./generated/acmsapp/Iacmsapp.java generated.
File: ./generated/acmsapp/acmsappImpl.java generated.
File: ./generated/acmsapp/CONTROL_WORKSPACE.java generated.
File: ./generated/acmsapp/EMPLOYEE_INFO_WKSP.java generated.
*** Application acmsapp generated! ***
$
Build the server:
The server build procedure links the generated server files with the user's application, which creates a dynamically loadable shareable image.
$ set def [.generated]
$ @BUILD-ACMSAPP-SERVER
Begin server build procedure.
..configuring switches and compiler options
..compiling native server code
..linking shareable image
..installing server image
End server build procedure.
$
Build the client:
The JavaBean build procedure creates a JAR file that contains the WSIT Java classes used to call the server created earlier.
$ @BUILD-ACMSAPP-JB
Begin Java bean build procedure.
The New JAVA$CLASSPATH is:
"JAVA$CLASSPATH" = "WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
..Compiling structure classes
..Compiling acmsapp Interface classes
..Creating acmsapp.JAR file from classes
End of JavaBean build procedure.
Add the AcmsApp.jar file to the java$classpath.
$ @WSI$ROOT:[tools]wsi-setenv - acmsapp.jar
The new JAVA$CLASSPATH is:
"JAVA$CLASSPATH" =
"WSI$ROOT:[LIB]WSIRTL.JAR" (LNM$JOB_86F82E00)
= "[]"
= "WSI$ROOT:[LIB]VELOCITY-DEP-1_4.JAR"
= "WSI$ROOT:[TOOLS]IDL2CODE.JAR"
= "ACMSAPP.JAR"
$
In the
normal course of development, you would now need to write a client to call the
AcmsApp JavaBean that was generated above. However, for the purpose of this
sample, a client file named acmscaller.java is provided in the directory
WSI$ROOT:[samples.acms].
Compile the supplied client:
$
set def WSI$ROOT:[samples.acms]
$ javac acmscaller.java
Run the supplied client:
$
java acmscaller
******* Creating JavaBean & Server **********
************ Calling AcmsSignIn ***************
***** Calling add and get empl_info tasks ******
************ Calling AcmsSignOut ***************
123456
John Adams
1 Beacon Hill
Boston
MA
01776
******** Removing the JavaBean & Server *********
*********** End ACMS Client *************
$
The
output from
the Java program shows the code that the client is executing, as well as the
calls that it is making into ACMS. The data displayed was first entered into
an Rdb database via ACMS, then retrieved using ACMS for display purposes.
The Web Services Integration Toolkit allows you to generate two kinds of sample clients: JSP and POJO (Plain Old Java Object). The sample clients call the application in-process by default. See Section 1.10 for information about loading your application in a separate process (out-of-process).
You can specify the type of client you want the WSIT generator (IDL2CODE) to generate by using the –C parameter. Specifying –c S generates only the POJO command line client. Specifying –c J generates only the JSP client, and –c SJ generates both kinds of clients.
For example, to generate sample clients for the C math application from Section 1.4, follow the same sequence of steps from 1 to 4. At step 3, however, pass in the additional switch shown below.
Note: WSIT generated JSP samples require a server environment
that supports the JSP V2.0. Examples include Tomcat 5.5.9 and WebLogic Server
V9.0.
$ java "com.hp.wsi.Generator" -i math.xml -a math -c SJ -o [.generated]
File: ./generated/mathServer/build-math-server.com generated.
File: ./generated/mathServer/methIds.h generated.
File: ./generated/mathServer/structkeys.h generated.
File: ./generated/mathServer/math.wsi generated.
File: ./generated/mathServer/math.opt generated.
File: ./generated/mathServer/math-server.h generated.
File: ./generated/mathServer/math-server.c generated.
File: ./generated/math/build-math-jb.com generated.
File: ./generated/math/Imath.java generated.
File: ./generated/math/mathImpl.java generated.
File: ./generated/mathSamples/POJO/mathMain.java generated.
File: ./generated/mathSamples/POJO/build-math-PoJoClient.com generated.
File: ./generated/mathSamples/JSP/index.html generated.
File: ./generated/mathSamples/JSP/mathMethodList.html generated.
File: ./generated/mathSamples/JSP/mathPopulate.jsp generated.
File: ./generated/mathSamples/JSP/mathDoCall.jsp generated.
File: ./generated/mathSamples/JSP/build-math-JspClient.com generated.*** Application math generated! ***
$
Using the generated POJO client
sample:
Normally this class will be written to integrate the WSIT generated JavaBean with the Java technology of your choice.
The sample must first be built as shown below.
$ @wsi$root:[tools]wsi-setenv - WSI$ROOT:[samples.c.generated.math]math.jar
$ set default WSI$ROOT:[samples.c.generated.mathSamples.POJO]
$ @build-math-PoJoClient
Begin client build procedure.
..Compiling mathMain client class
End of client build procedure.
To run this client, type the following
at the command line:
$ java "math.mathMain"
The sample client is able to make calls
to the methods of the generated JavaBean. There is a limitation that only
methods with primitive arguments can be called. To see which methods the sample
client can call, use the switch –m as shown below.
$ set default WSI$ROOT:[samples.c.generated.mathSamples.POJO]
$ java math.mathMain -m
The list of available methods within math are:
sum(int P1, int P2)
product(int P1, int P2)
(Methods that take structures or arrays as parameters are not callable from this command line interface. These methods are denoted by the * next to them.)
$
To call the sum and product methods with arguments of 5 and 2, use the commands as shown below.
$
set default WSI$ROOT:[samples.c.generated.mathSamples.POJO]
$ java math.mathMain -m sum -p1 5 -p2 2
Calling mathImpl.sum:
P1 = 5
P2 = 2
Return value = 7
++ The client was successful ++
$ java math.mathMain -m product -p1 5 -p2 2
Calling mathImpl.product:
P1 = 5
P2 = 2
Return value = 10
++ The client was successful ++
$
Using the generated JSP client sample:
Similar to the POJO sample, the JSP sample client must first be built as shown below.
$ @wsi$root:[tools]wsi-setenv – WSI$ROOT:[samples.c.generated.math]math.jar
$ set default WSI$ROOT:[samples.c.generated.mathSamples.JSP]
$ @build-math-JSPClient
Begin JSP client build procedure.
Unpacking static files into current location.
Copying math.jar into local [.WEB-INF.lib] directory
Creating mathJsp.war file
End of JSP client build procedure.
To deploy this client:
Copy mathJsp.War into the deployment directory for your JSP server.
$
To deploy the JSP, copy the mathJsp.war file to a web server servlet deployment directory.
For example, if you have installed Tomcat (CSWS_JAVA) on OpenVMS, the command
is similar to the following:
$ copy mathJSP.war
sys$common:[apache.jakarta.tomcat.webapps]
After the war file has been copied,
you can view the JSP pages by using a URL similar to the one shown below.
(Replace yourwebserver.hp.com with the actual name of your web server.) By
default, Tomcat listens on port 8080. If the system manger changed the port
number, replace 8080 with the new number.
$ copy mathJSP.war sys$common:[apache.jakarta.tomcat.webapps]
The POJO client is not supported when the –l switch is used on IDL2CODE.
Note: Web applications deployed as Java classes are seen and used immediately, but web applications deployed as JAR files may require a Tomcat restart in order for them to be seen and used. For information about restarting Tomcat, see the CSWS_JAVA (Tomcat) for OpenVMS documentation at http://h71000.www7.hp.com/openvms/products/ips/apache/csws_java_relnotes.html
The following screen captures illustrate the JSP sample client calling the C Math application.
Example Web Page 1: The mathJSP Application
Example Web Page 2: The MathJSP Application Methods
Example Web Page 3: The MathJSP Application Method Product
Example Web Page 4: The MathJSP Application Method Product Results
1.7 Using ANT with the Web Services Integration Toolkit
The Web Services Integration Toolkit provides the capability to use Ant to automate the
tasks for exposing your application (described in Section 1.4). Ant is a powerful Java-based build
tool that is an open source Apache project. Ant is platform independent and highly extendable.
The build scripts are XML files containing targets and specifying tasks and properties.
For more information about Ant, see the web site for the Apache Ant Project at
http://ant.apache.org and the Ant Manual at http://ant.apache.org/manual/index.html.
1.7.1 Ant Setup
The Web Services Integration
Toolkit includes its own binary distribution of Ant 1.6.5.
To set up Ant, establish the foreign command by entering the following command:
$ ant ==
“@WSI$ROOT:[tools.ant]ant.com”
1.7.2 Configuring the wsit-ant-user.properties File
Before you run Ant to build your
application, you must configure the wsit-ant-user.properties
file by specifying a set of property values. Perform the following steps to
complete the configuration:
1.
Copy the wsit-ant-user.properties file from WSI$ROOT:[tools.ant] to your local directory where you will be running the Ant
build procedure.
2.
Set the application type property to be one of the following,
based on the kind of application you are building:
3GL.with.OBJ
3GL.with.IDL
ACMS.with.STDL
For detailed Ant property descriptions, see Section 1.7.4.
3.
Specify values for
all required properties for the kind of application you are building, in the
section marked “BEGIN properties for …”.
4. Specify values for properties in the section “BEGIN COMMON properties to customize.”
1.7.3 Using the wsit-ant-userbuild.xml Build File
After you have configured the properties, you can build the full WSIT application and any generated sample
clients by copying the wsit-ant-userbuild.xml file from wsi$root:[tools.ant] to your local directory and executing the following command:
$ ant "-f
wsit-ant-userbuild.xml"
Buildfile: wsit-ant-userbuild.xml
checkinput:
[echo] Verifying properties ...
getidl:
[echo] Calling obj2idl ...
obj2idl:
[echo] Creating XML IDL file ...
[obj2idl] WSIT IDL Generator version is: V1.0
validate:
[echo] Validating XML IDL file ...
[java] XML file validated successfully
idl2code:
[idl2code] %WSI-I-GENCREOUT, The specified Output directory does not exist,
creating /WSI$ROOT/samples/c/generated
[idl2code] %WSI-I-GENCREOUT, The specified Package directory does not exist,
creating /WSI$ROOT/samples/c/generated/math
[idl2code] %WSI-I-GENCREOUT, The specified Server directory does not exist,
creating /WSI$ROOT/samples/c/generated/mathServer
[idl2code] %WSI-I-GENCREOUT, The specified Samples directory does not exist,
creating /WSI$ROOT/samples/c/generated/mathSamples
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/build-math-server.com
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/methIds.h generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/structkeys.h
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/math.wsi generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/math.opt generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/math-server.h
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathServer/math-server.c
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/math/build-math-jb.com
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/math/Imath.java generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/math/mathImpl.java generated.
[idl2code] %WSI-I-GENCREOUT, The specified directory does not exist, creating
/WSI$ROOT/samples/c/generated/mathSamples/POJO
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/POJO/mathMain.java
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/POJO/build-math-PoJoClient.com
generated.
[idl2code] %WSI-I-GENCREOUT, The specified directory does not exist, creating
/WSI$ROOT/samples/c/generated/mathSamples/JSP
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/index.html
generated.
[idl2code] File:
/WSI$ROOT/samples/c/generated/mathSamples/JSP/sessiontimeout.html generated.
[idl2code] File:
/WSI$ROOT/samples/c/generated/mathSamples/JSP/mathMethodList.jsp generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/mathPopulate.jsp
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/mathDoCall.jsp
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/mathVerify.jsp
generated.
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/build-math-JspClient.com
generated.
[idl2code] %WSI-I-GENCREOUT, The specified directory does not exist, creating
/WSI$ROOT/samples/c/generated/mathSamples/JSP/WEB-INF
[idl2code] File: /WSI$ROOT/samples/c/generated/mathSamples/JSP/WEB-INF/web.xml
generated.
[idl2code] *** Application math generated! ***
buildserver:
[echo] Building server ...
[echo] /WSI$ROOT/samples/c/generated/mathServer
[echo] @build-math-server.com
[exec] Begin server build procedure.
[exec] ..configuring switches and compiler options
[exec] ..compiling native server code
[exec] ..linking shareable image
[exec] ..installing server image
[exec] End server build procedure.
buildjavabean:
[echo] Building Java Bean ...
[exec] Begin java bean build procedure.
[exec] ..Compiling structure classes
[exec] ..Compiling math Interface classes
[exec] ..Creating math.JAR file from classes
[exec] End of JavaBean build procedure.
buildpojoclient:
[echo] Building Sample POJO Client ...
[javac] Compiling 1 source file to
WSI$ROOT/samples/c/generated/mathSamples/POJO
[jar] Building jar:
WSI$ROOT/samples/c/generated/mathSamples/POJO/mathClient.jar
[echo]
[echo] To run this client, type the following commands:
[echo]
[echo] $ @wsi$root:[tools]wsi-setenv - wsi$dev
[echo] $ @wsi$root:[tools]wsi-setenv -
/WSI$ROOT/samples/c/generated/math/math.jar
[echo] $ @wsi$root:[tools]wsi-setenv -
/WSI$ROOT/samples/c/generated/mathSamples/POJO/mathClient.jar
[echo] $ java "math.mathMain"
[echo]
buildjspclient:
[echo] Building Sample JSP Client ...
[exec] Begin JSP client build procedure.
[exec] Unpacking static files into current location.
[exec] Copying math.jar into local [.WEB-INF.lib] directory
[exec] Creating mathjsp.war file
[exec] End of JSP client build procedure.
[exec] To deploy this client:
[exec] Copy WSI$ROOT:[SAMPLES.C.GENERATED.MATHSAMPLES.JSP]mathjsp.war
nto the deployment
[exec] directory for your JSP server.
buildall:
[echo]
[echo] Completed building the math application ...
[echo]
BUILD SUCCESSFUL
Total time: 1 minute 1 second
$
To run a specific target only (for
example, the help target), execute the following command in the directory where
the build file is located. (For detailed target descriptions, see Section 1.7.5.)
Note: The file wsit-ant-userbuild.xml cannot be used with versions of WSIT earlier than V1.1.
$ ant "-f
wsit-ant-userbuild.xml help"
Buildfile:
wsit-ant-userbuild.xml
help:
[echo]
[echo] [echo] Most useful targets:
[echo]
[echo] buildall : Executes all of the targets in this build file.
[echo]
obj2idl : Creates IDL file from the 3GL application's object module
(IA64 only).
[echo] stdl2idl : Creates IDL file from the ACMS application's STDL file.
[echo]
validate : Verifies the application's IDL file conforms to the
schema.
[echo]
idl2code : Creates a WSIT server interface wrapper, a WSIT Java Bean
and sample client code.
[echo]
buildserver : Builds a shareable image by linking the WSIT server wrapper
with the application.
[echo]
buildjavabean : Creates a jar file that contains the WSI Java classes to
call the server.
[echo]
buildpojoclient : Builds the generated POJO client code to call the
application.
[echo]
buildjspclient : Builds the generated JSP client code to call the
application.
[echo] Note: You will need to customize your property values in
wsit-ant-user.properties before running ant
[echo]
BUILD SUCCESSFUL
Total time: 2 seconds
$
1.7.4 Ant Property Descriptions
Required: Set the apptype
property, which specifies application type, to one of the following values:
3GL.with.OBJ
3GL.with.IDL
ACMS.with.STDL
Name |
Description |
Value of apptype |
|
A 3GL application based on an object (OBJ) file, compiled DEBUG (I64 only, not supported on Alpha). |
3GL.with.OBJ |
apptype |
A 3GL application based on an IDL file that you have already written or generated. |
3GL.with.IDL |
|
An ACMS application based on the application's STDL file. |
ACMS.with.STDL |
Properties for applications of type 3GL.with.OBJ. Required if apptype is set to 3GL.with.OBJ.
Name |
Description |
Value (example) |
obj.file |
Specific location and name of object file (compiled debug) from which WSIT will generate IDL. |
/disk$ods5/math/source/math.obj |
idl.file |
Specific location and name of idl file that WSIT will generate using the target OBJ2IDL. |
/disk$ods5/math/source/math.xml |
Properties for applications of type 3GL.with.IDL. Required if apptype is set to 3GL.with.IDL.
Name |
Description |
Value (example) |
idl.file |
Specific location and name of idl file that WSIT will use to generate a JavaBean wrapper. |
/disk$ods5/math/source/math.xml |
Properties for applications of type ACMS.with.STDL. Required if apptype is set to ACMS.with.STDL.
Name |
Description |
Value (example) |
Stdl.file |
Specific location and name of ACMS STDL file from which WSIT will generate IDL. |
/disk$ods5/math/source/math.stdl |
idl.file |
Specific location and name of idl file that WSIT will generate using the target STDL2IDL. |
/disk$ods5/math/source/math.xml |
Common properties for all types of applications. (Required)
Name |
Description |
Value (example) |
appname |
Specify your application name. |
Math |
build.dir |
Specifiy the root of a directory that WSIT should use when generating code. |
/disk$ods5/math/generated |
Common properties for all types of applications. (Optional)
Name |
Description |
Value (actual) |
sample.POJO |
Specify if sample POJO client that illustrates how to call the WSIT generated JavaBean should be generated. |
True/False |
sample.JSP |
Specify if sample JSP client that illustrates how to call the WSIT generated JavaBean should be generated. |
True/False |
1.7.5 Ant Target Descriptions
Name |
Description |
buildall |
Executes all of the targets in this build file. |
Obj2idl |
Creates IDL file from the 3GL application's object module (IA64 only). |
Stdl2idl |
Creates IDL file from the ACMS application's STDL file. |
validate |
Verifies the application's IDL file conforms to the schema. |
idl2code |
Creates a WSIT server interface wrapper, a WSIT Java Bean and sample client code. |
buildserver |
Builds a shareable image by linking the WSIT server wrapper with the application. |
buildjavabean |
Creates a jar file that contains the WSI Java classes to call the server. |
buildpojoclient |
Builds the generated POJO client code to call the application. |
buildjspclient |
Builds the generated JSP client code to call the application. |
checkinput |
Verifies all properties have been correctly set. |
getidl |
Determines if IDL file exists, if not calls appropriate target to generate it, and then validates it. |
Help |
Displays help information. |
WSIT defines custom ant tasks for the IDL2CODE, OBJ2IDL, and STDL2IDL tools.
1.7.6.1 IDL2CODE Task
Runs the Generator (IDL2CODE) to create a server wrapper for the application and a JavaBean client.
1.7.6.2 IDL2CODE Parameters
Attribute |
Description |
Type |
idlfile |
Required. Filespec for XML IDL file describing the application to wrap. |
java.lang.String |
appname |
Required. Name to be given to the WSIT generated application. |
java.lang.String |
outdir |
Optional. Directory in which to generate the wrapper files. |
java.lang.String |
authenticate |
Optional. Force OpenVMS authentication to be used with this interface. |
boolean |
javadoc |
Optional. Create JavaDoc based documentation for the generated interface. |
boolean |
tracinglevel |
Optional. Ouput tracing information at runtime, specify level 1 to 5. |
int |
samplePOJO |
Optional. Generate sample POJO client for the generated interface. |
boolean |
sampleJSP |
Optional. Generate sample JSP client for the generated interface. |
boolean |
1.7.6.3 OBJ2IDL Task
Runs the OBJ2IDL tool to generate an XML interface definition from a 3GL application’s object module (I64 only).
1.7.6.4 OBJ2IDL Parameters
Attribute |
Description |
Type |
objfile |
Required. Filespec for the object module. |
java.lang.String |
outfile |
Optional. Filespec for XML IDL output file. |
java.lang.String |
mapfile |
Optional. Filespec for map file, default is wsi$root:[tools]openvms-basetypes.xml. |
java.lang.String |
version |
Optional. Display version information for this tool. |
boolean |
1.7.6.5 STDL2IDL Task
Runs the STDL2IDL tool to generate an XML interface definition from an ACMS application’s STDL file.
1.7.6.6 STDL2IDL Parameters
Attribute |
Description |
Type |
stdlfile |
Required. Name of the STDL file to parse. |
java.lang.String |
idlfile |
Optional. Filespec for XML IDL output file (relative paths are not supported). |
java.lang.String |
version |
Optional. Display version information for this tool. |
boolean |
With the Web Services Integration Toolkit and Distributed NetBeans for OpenVMS working together, you can do the following:
· Edit text files generated by the WSIT tools using Distributed NetBeans and a remote FTP filesystem
· Remotely compile your language source files
· Remotely execute DCL command procedures
· Remotely execute Ant scripts
For more information about remote operations and Distributed NetBeans in general, see the Distributed NetBeans online help. The online help is available when you install Distributed NetBeans on your desktop system, and from http://h71000.www7.hp.com/openvms/products/ips/netbeans/documents.html
The WSIT Build Template files are included with Distributed NetBeans so that you can use the NetBeans template system to create your WSIT build script and property file from within Distributed NetBeans. To create your WSIT Ant build script and property file using the template, perform the following steps:
1. Select the remote directory in the filesystem explorer where you would like to place the build template, right mouse click and select New/All Templates.
2. Select WSIT Templates/WSIT-Build Ant Script Files. Click Next.
3. Name your script, and click OK.
Two files are created in your directory: an Ant build script that is named according to the previous step, and a property file named wsit-ant-user.properties. You must now customize the property file for your application. Follow the instructions in the property file to customize. In addition, you can customize the Ant build script if desired.
Once you have completed your modifications to the build script and property file for your application, you should modify the version of Ant that will used to remote execute your Ant script.
1.8.2 Using the WSIT-Supplied Ant Version
In order to remote execute your WSIT Ant build script, you must use the WSIT version of Ant when executing your build scripts. You can change the Ant executor in the Distributed NetBeans IDE to point to the WSIT version of Ant. To make that change in the IDE, perform the following steps.
1. Select Tools/Options.
2. Open Debugging and Execution/Execution Types/Remote Ant Script Execution.
3. Select the […] button to the right of the Remote External Process property.
4.
Change the value of
the Process property to
pipe ant == "@WSI$ROOT:[tools.ant]ant.com"
; ant
5. Click OK.
6. Click Close on the Options dialog box.
The Web Services Integrated Toolkit provides an easy to use set of utilities that can turn standalone applications into distributed applications, making them more widely accessible. While this is great, this new found accessibility may raise security concerns. Because of this, WSIT implements 2 different ways of restricting access to a wrapped application and/or the system resources that the application accesses.
Depending on the environment and the granularity needed, you can either set a blanket setting within the server process that all users are restricted to, or you can force all users to login using their own account.
Each is discussed below.
In an application environment where the application’s generated JavaBean and
server wrapper are run in two different processes, you can specify under which
OpenVMS account the server process is to run. You do this by modifying the <Account>
attribute within the deployment descriptor (.wsi
file) associated with the application, as shown in the following example. (The deployment descriptors can be found
in the WSI deployment directory, wsi$root:[deploy].)
<!-- Server Application Options -->
<Account>MyAccount</Account> <!-- Name of the account the server runs in -->
Note: When the <Account></Account > property is not specified within the application deployment configuration file (.wsi), WSIT runs the out-of-process servers in the same account that the wsi$manager is running from. In most cases, this is the SYSTEM account.
This method of restricting access has an application level granularity. This means that all of the application’s server processes run under the specified account. For example, you can set up the Payroll application to always run under the Payroll account regardless who is connecting to it.
The server process method of restricting access has both pros and cons, as follows:
Reasons to use server process security:
· It is fast and easy to change during and after deployment.
· All users of a given application have the same access to the system.
· Requires no change to the client.
· Users do not need their own account to use the application.
Potential problems with server process security:
· Does not keep users from accessing the application itself.
· Makes no distinction between users.
· Specified accounts require minimum privileges.
· Requires the JavaBean and server wrapper to run in two different processes.
1.9.2 Per User Security
If you need to restrict access to the application itself, or need
a finer granularity in limiting access to system resources, you can do that by
using the optional per user security. You choose this at generation time by
specifying the –L switch on the IDL2CODE
command line. When you specify this option, WSIT generates an application with
two additional methods in the interface, as follows:
OpenVmsLogin (username, password)
OpenVmsLogout()
Note: POJO clients are not supported when the -L switch is used on the IDL2CODE command line.
Applications that have these methods in the interface can only be accessed after OpenVmsLogin() has been successfully called. (The error “Must login first” is returned until a successful login occurs.) After the user has successfully logged into an account, that account’s privileges and quotas are used when calling into the application. This means that resources used by the application can be protected on a per user basis.
The per user method of restricting access has both pros and cons,
as follows:
Reasons to use per user security:
· Distinguishes between users, allowing better access control over resources.
· Can block access to the application itself.
· Works whether the JavaBean and server wrapper are in the same process or different processes.
Potential problems with per user security:
· Decision to use must be made at code generation time.
· Requires client to call Login and Logout methods.
· All users require an OpenVMS account in order to access the application.
1.10  WSIT Tools and Parameters
OBJ2IDL
Usage: obj2idl <parameters>
Required Parameters:
-f Specify the object file name along with its location
Optional Parameters:
-m Specify the map file name along with its location.
Default is
wsi$root:[tools]openvms-basetypes.xml
-o Specify the output file name along with its location.
-v Version information.
VALIDATE
Usage: validate <parameters>
Required Parameters:
-x xmlfile Location and name of the xml file to be validated.
-s schemafile Location and name of a schema file (usually .xsd) used to validate the XML.
IDL2CODE
Usage: idl2code <parameters>
Required Parameters:
-i <IDL filespec> XML IDL file describing the application to wrap.
-a <Application Name> Name to be given to the WSIT-generated application.
Optional Parameters:
-o <Output Directory> Directory in which to generate the wrapper files.
-p <Velocity prop file> Velocity properties file to replace WSIT templates.
-l Require
OpenVMS authentication to be used with this interface.
POJO clients do not work with the –l parameter. See Section 1.9.2 for more information.
-j JavaDoc-based documentation for the generated interface.
-d <Tracing Level> Output tracing information while the generator is running, 1 -> 5.
-w Generate the Web Services interface classes.
-c <S|J> Generate sample client(s) for the generated interface.
-v Print out the version number for this generator.
-h or –help Print this list of options.
1.10.1 In-Process/Out-of-Process Parameters
JSP and POJO (Plain Old Java Object) sample clients call the application in-process by default. To load your application in a separate process (out-of-process), do the following:
· For a JSP sample client: Specify “outproc” as P1 on the command line when building the JSP sample client.
· For a POJO sample client: Specify “-o” when running the POJO client.
1.10.2 POJO or JSP Sample Client Parameters
The optional switch –c is provided to tell the WSIT generator (IDL2CODE) to generate a sample client with a command line interface (S) or generate a sample client with a JSP interface (J). These samples are provided to make testing and development with WSIT easier.
Specifying –c S generates only the POJO command line client.
Specifying –c J generates only the JSP client, and –c SJ
generates both kinds of clients.
2 D E P L O Y M E N T C O N S I D E R A T I O N S
Applications running on OpenVMS systems can be roughly divided into two groups, as follows:
· Applications designed for a single client environment
· Applications that can be called by multiple clients
The first group, applications designed for a single client environment, are often older OpenVMS applications that assume a timesharing runtime environment. The user logs into the OpenVMS system, which in turn creates a process. The applications are typically executed entirely in the user’s process. In this design, there is a single user (the client). There is an assumed one-to-one relationship between the client and the application.
The second group, applications that can be called by multiple clients, are often newer OpenVMS applications. These applications are designed to serially process multiple clients (one at a time), or to concurrently process multiple clients (all at the same time).
When the Web Services Integration Toolkit exposes an OpenVMS application as a JavaBean, the application becomes callable from the second (newer) design model in which multiple clients can call the application from multiple processes or threads. You should understand in which group your wrapped application belongs (the specific design model) and manage client access to the application accordingly. WSIT provides a number of features to help in managing this interaction, which are discussed in the following sections.
In the following sections, the term application is used to represent the original application being exposed. The term client is used to represent the JavaBean caller which makes calls to the WSIT-generated JavaBean.
There are two ways in which you can deploy your application using WSIT: in-process deployment and out-of-process deployment.
In-process deployment occurs when the application and the client are called from the same process, as illustrated in the following diagram.
There are advantages and disadvantages to using in-process deployment.
Advantages: Fastest return time for client calls to application. No overhead added by the WSIT runtime.
Disadvantages: A crash will bring down all components in the process (client and application).
There are no WSIT deployment settings for in-process applications --
the interaction between the client and the application is not managed by the WIST runtime. In-process deployment provides the fastest execution time, but it requires that the developer ensure that the client does not establish an environment in which the application will fail.
For example, some J2EE application servers may use multiple threads to call the client. This requires that the developer determine if the application can successfully operate in this environment. If the developer determines that the application can only support one client at a time, then the client must use a mechanism to order the calls before they are sent to the application (via the WSIT-generated objects).
If you do not specify out-of-process deployment settings (described in the following sections), your application will run in-process by default.
Out-of-process deployment occurs when the client and application are run in different processes, as illustrated in the following diagram. The WSIT runtime environment manages the interaction between the two processes. You can customize this environment by modifying a deployment descriptor file.
There are advantages and disadvantages to using out-of-process deployment.
Advantages: Typically scales better than in-process deployments. Allows the use of the WSIT runtime deployment properties.
Disadvantages: Adds complexity and overhead to every call.
Most older applications benefit from using an out-of-process deployment to avoid complex issues that result from mixing older and newer environments. The WSIT deployment properties, described in the following sections, allow out-of-process applications to choose from a wide variety of configurations.
A session is the period of time in which a client uses an application. A session can last for:
· The duration of a single call
· The lifetime of the client
The type of session you use should mimic the original design of the application. For example, in older timesharing applications, a session is often the entire time that the client uses the application. In newer applications, the client may use a session to perform a specific task and then declare that it is finished with the session.
WSIT allows the developer to specify when a session with an application begins and when it ends. The WSIT-generated JavaBean has a constructor named <application-name>Impl. For example, the stock sample has a constructor named stockImpl. To establish an out-of-process deployment, call the constructor with an instance of the class WsiIpcContext. The WsiIpcContext constructor can be called with one of three different session types.
1.
LIFETIME_SESSION: This is the default session type. The
session begins when the applications Impl object is created and the session
ends when the remove method is called.
2.
NO_SESSION: The session begins when a method call
is made on the application and the session ends when that call returns. The
lifetime of the session is a single method call.
3. TX_SESSION: The session begins when the client logs into the application by calling the methods AcmsSignIn or OpenVMSLogin of the application Impl object. The session ends when the client calls the methods AcmsSignOut or OpenVMSLogOut.
When deploying an application out-of-process, WSIT allows the creation of a process pool, which is a collection of processes for the application that WSIT manages in the background to improve response time. Each process is running the application. The XML tag <ProcessPooling> is used to configure the properties of the pool.
· Use the tag <MaximumProcesses> to specify an upper limit for the largest number of processes that WSIT can create for the application.
· Use the tag <MinimumProcesses> to specify a lower limit for the fewest number of processes that WSIT should maintain for the application. The number specified will be the number of processes WSIT starts initially.
· Use the tag <MinimumIdleProcesses> to specify the number of non-busy processes to keep on an ongoing basis. WSIT creates more processes as needed to maintain these free processes. WSIT does not create more than <MaximumProcesses> of processes.
· Use the tag <MaxInactivitySeconds> to specify when a process should be removed from the pool and run down. Specify the maximum number of seconds that an application can be idle before it is automatically stopped.
Running your application out-of-process allows you to specify configuration options. These options are contained in the XML file wsi$root:[deploy]application-name.wsi.
The out-of-process configuration options are as follows:
|
|
Account (Username) |
Name of the account you want the server to run in, which determines the access rights and quotas that the server will have. Requires NETMBX and TMPMBX privileges. |
WorkingDirectory |
Working directory for the server component. This is important if the server component opens files with names relative to some assumed working directory of the application. |
SetupCommandFile |
File specification of a DCL command file you want to run before the server component starts up. |
ServerPath |
Complete file specification where the server component image is located. |
StackSize |
Stack size to use for each thread within the server component. The default of 0 means to use the default DECthreads (POSIX Threads) stack size. |
Reusable |
Default is not reusable. Uncomment this option if the server application is reusable, which means the server can be called by more than one client sequentially. (See Advanced Out-of-Process Configuration chapter.) |
MaximumClients |
Maximum number of clients handled per server. If the server is not reusable, the default is 1. Modify MaximumClients if, in addition to being reusable, the server application process can handle multiple clients concurrently. If this property is greater than 1, the order of client calls coming into the server process is indeterminate. (See Advanced Out-of-Process Configuration chapter.) |
MaximumThreads |
Maximum number of threads allowed to run concurrently. This option is never greater than MaximumClients. If the server is not reusable, the default is 1. Modify MaximumThreads if, in addition to being able to handle multiple clients, the server application is also thread safe. (See Advanced Out-of-Process Configuration chapter.) |
|
|
MaximumProcesses |
Defines the maximum number of server processes that are allowed to run concurrently to handle client requests. The total capacity of the application is MaximumProcesses multiplied by MaximumClients. The default is 5. |
MinimumProcesses |
Minimum number of server processes that are automatically started to service requests from clients. This value is never greater than MaximumProcesses. The default is 0. |
MinimumIdleProcesses |
Sets the number of server processes that will be maintained as idle to serve requests from clients. As servers become busy, new server processes are started to act as idle servers. The number of idle server processes can reach (but never be greater than) the number of MaximumProcesses. |
MaxInactivitySeconds |
Maximum number of seconds that a server can be idle before it is automatically stopped. The default is 1000 seconds. |
MaxStartupSeconds |
Maximum number of seconds to wait for a process to startup. Default is 45 seconds. |
ClientsWaitForServer |
Specifies whether a client request should wait for a server process to become available. If set to 0 (the default), the client request fails with an error if a server is unavailable. If set to 1, the client waits for an available server. Waiting may appear to be a hung client if no server processes become available. |
2.3.4.1 Out-of-Process Account Preparation and Requirements
If you are specifying an account in which to run out-of-process servers, you may want the account to have a minimal amount of privileges.
You can specify an account to run out-of-process servers that has only the NETMBX and TMPMBX privileges. To use an account with these privileges, perform the following steps:
1. Create an identifier within the system UAF with the name WSI$SERVER. (Perform this step one time only.)
2. Grant the WSI$SERVER identifier to each account used to run a WSIT out-of-process server.
If you do not perform these steps, the privileges required by the
account are as follows:
BYPASS
SYSNAM
SYSPRV
IMPERSONATE
DETACH
TMPMBX
The primary goal of the Web Services Integration Toolkit is to
take the interface exposed by a user’s application and present it as a Java
based interface. These interfaces are defined by their set of routine calls,
the parameters passed in and out of these routines, and the mechanisms used to
pass those parameters. The following sections discuss this in more detail, and
provides a background on the actions WSIT takes to wrap an application and
provide it with a new interface.
2.4.1 Application Interfaces (User Supplied)
The Application’s Programming Interface (API) is where the work
begins for WSIT. The application’s interface, provided by the user, is parsed
by the WSIT tools OBJ2IDL or STDL2IDL.
These tools create a WSIT-specific Interface Definition Language (IDL) file
describing the application’s interface. This definition includes the set of
routines included within this interface. For each routine, the IDL describes
the parameter list in detail, including the parameter names, the parameter
datatypes, and the passing mechanisms used to pass these parameters.
2.4.2 OpenVMS Datatypes Supported by WSIT
The datatype specified for each parameter must be one of the following:
· a standard OpenVMS datatype (as defined by the OpenVMS Calling Standard)
· an array of these datatypes
· a structure composed of these datatypes
Internally, WSIT uses the Descriptor datatype definition values, DSC$K_DTYPE_*, to identify all datatypes. However,
depending on the language that you are using, these may more readily be
recognized as float, double, short, and so on. See the Datatype Mapping
section for a table that lists all of the OpenVMS datatypes that WSIT supports,
along with their Java type mappings.
2.4.3 Passing Mechanisms
WSIT supports the three passing mechanisms described by the OpenVMS Calling
Standard. This standard does not dictate which passing mechanism must be used
by a given language compiler. (Note that language semantics and interoperability
considerations might require different mechanisms in different situations.)
WSIT generates the code needed to pass each parameter using the mechanism
specified within the IDL file. The three passing mechanisms are as follows:
· By “Value”
An immediate value argument item contains the
value of the data item. The argument item, or the value contained in it, is
directly associated with the parameter.
· By “Reference”
A reference argument item contains the address
of a data item such as a scalar, string, array, or structure. This data item is
associated with the parameter.
· By “Descriptor”
A descriptor argument item contains the address of a descriptor, which contains structural information about the argument's type (such as string length) and the address of a data item. This data item is associated with the parameter.
An example of a C module whose interface has been parsed can be
found in:
wsi$root:[samples.c]math.c
The IDL generated from parsing math.c can be found in the Appendix.
2.4.4 JavaBean Interface (Generated by WSIT)
The previous section discussed what the user’s application exposes as an interface and how it gets described. This section discusses the Java based interface that WSIT generates from that description of the user’s API. This includes how the OpenVMS datatypes map into Java types, as well as how WSIT accommodates the different passing mechanisms.
For each routine that is exposed by the user’s application, a
method is generated in the new Java based interface. Although the generated
methods are named the same as their routine counterparts, the casing may be
different to better accommodate Web Services based clients. The parameters for
each method have a 1-to-1 mapping to their user application counterparts. This
mapping is discussed in the following section.
2.4.5 Datatype Mapping
When defining the interface within WSIT, you do not regularly need to be
concerned with most issues related to datatype conversion. When you specify the
OpenVMS datatypes for the parameters, WSIT converts them to appropriate Java
types. WSIT converts primitive types from OpenVMS to Java as described in the
mapping table below. WSIT also maps arrays of these types to Java arrays, and
structures comprising of these types to JavaBean style classes that encapsulate
the mapped types.
OpenVMS Type |
Description |
Java Type |
Java In/Out Classes |
DSC$K_DTYPE_BU |
unsigned byte |
byte |
ByteHolder |
DSC$K_DTYPE_WU |
unsigned word |
short |
ShortHolder |
DSC$K_DTYPE_LU |
unsigned long |
int |
IntHolder |
DSC$K_DTYPE_QU |
unsigned quadword |
long |
LongHolder |
DSC$K_DTYPE_OU |
unsigned octaword |
BigInteger |
BigIntegerHolder |
DSC$K_DTYPE_B |
Byte |
byte |
ByteHolder |
DSC$K_DTYPE_W |
Word |
short |
ShortHolder |
DSC$K_DTYPE_L |
Long |
int |
IntHolder |
DSC$K_DTYPE_Q |
quadword |
long |
LongHolder |
DSC$K_DTYPE_O |
octaword |
BigInteger |
BigIntegerHolder |
DSC$K_DTYPE_F |
32bit F float |
float |
FloatHolder |
DSC$K_DTYPE_G |
64bit G float |
double |
DoubleHolder |
DSC$K_DTYPE_D |
64bit D float |
double |
DoubleHolder |
DSC$K_DTYPE_H |
128bit H float |
double¹ |
DoubleHolder* |
DSC$K_DTYPE_FX |
128bit IEEE float |
double¹ |
DoubleHolder* |
DSC$K_DTYPE_FS |
32bit IEEE float |
float |
FloatHolder |
DSC$K_DTYPE_FT |
64bit IEEE float |
double |
DoubleHolder |
DSC$K_DTYPE_T |
String ² |
string |
StringHolder |
DSC$K_DTYPE_VT |
varying string |
string |
StringHolder |
DSC$K_DTYPE_NU |
decimal string unsigned |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_NL |
decimal string left separate sign |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_NLO |
decimal string left overpunch sign |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_NR |
decimal string right separate sign |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_NRO |
decimal string right overpunch sign |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_NZ |
decimal string zoned |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_P |
Packed-decimal |
BigDecimal |
BigDecimalHolder |
DSC$K_DTYPE_V |
aligned bit |
boolean |
BooleanHolder |
DSC$K_DTYPE_ADT |
Absolute Date & Time |
calendar |
CalendarHolder |
¹ 128 bit floating point
datatypes are mapped to doubles within Java, limiting their range and
precision.
² See Section 2.4.5.1 for a detailed description of the String datatype.
Note: All unsigned integer types are mapped to
their signed counterparts when converted. This shifts the range of values that
can be represented by a given datatype. For example, an unsigned word, which
has a range of 0 to 65535, is mapped to a short, which has a range of 32767 to
-32768. Be sure to account for this in your client if the values are expected
to exceed those of the signed counterpart.
There are three attributes associated with the string datatype (DSC$K_DTYPE_T) within the IDL, as follows:
Size The string size required by the routine being called. WSIT truncates or pads as needed to make the passed in string the size specified. (Note that a specified size of 0 means that the size is dynamic, and that the called routine can handle any size string. It is assumed that the routine has some other way of determining the size of the passed in string, such as another argument, or by using the null terminator.)
NullTerminatedFlag This flag specifies that a null terminator is to be put into the string after the last significant character of the string. If a size is specified and padding is required, the padding occurs after the null character. If a size is specified and truncation is required, then one extra byte is truncated to make room for the null character.
FixedFlag This informational flag specifies how to interpret the size attribute. If a size is specified, then this flag should be set to 1 to indicate that the string has a fixed size. If the size is 0, then this should be set to 0 to specify that the string has a dynamic size. (Note that this attribute is not used by the WSIT Generator.)
For example:
<Primitive Name =
"AutoGen_NullTermString"
Size = "0"
VMSDataType = "DSC$K_DTYPE_T"
NullTerminatedFlag = "1"
FixedFlag = "0"/>
2.4.6 Parameter Usages
The Application Interface section described how parameters are passed using specific passing mechanisms. Although Java does not support these different passing mechanisms for passing parameters, there is one aspect of the passing mechanism that does apply. The usage of a parameter describes how the called routine intends to affect that parameter. The variations are as follows:
· In Only
In Only states that the called routine intends to only read the parameter and not modify or write to the parameter. This is the default usage for the by “Value” passing mechanism, but may be used with by “Reference” or by “Descriptor” if the developer is sure that the routine is not going to change the parameter value.
· In / Out
In / Out states that the called routine intends to both read, and then modify the contents of the specified parameter. The caller of the routine must pick up the new value for the parameter on return. This is the default usage for both the by “Reference” and by “Descriptor” passing mechanisms.
· Out Only
Out Only states that the called routine intends to only write to the specified parameter and not read it. As with In/Out, the caller of this routine must pick up the new value for the parameter on return. This is associated with either the by “Reference” or by “Descriptor” passing mechanisms.
If the usage of a parameter is In Only, then the generated Java method can take the Java type directly, because it does not need to look for a modified parameter value. However, if the usage is In/Out or Out Only, then the generated Java method must take a wrapper or “Holder” class for the mapped Java type. This Holder class allows the client to retrieve the possibly modified parameter value. Each OpenVMS to Java type mapping contains an associated Java Holder class for parameters that have a usage other than In Only. (For more information, see the Mapping table in the previous section under the “Java in/out classes” column.)
The supplied math sample (found in wsi$root:[samples.c]) has the following C based routine:
unsigned int sum (int number1, int number2);
Based on the mapping above, the Java method generated for it is:
int Sum (int number1, int number2)
The Java client code is:
int result = myapp.Sum (56, 72);
If the above C routine was changed to take an in/out parameter,
the code would be as follows:
void sum (int number1, int number2, int *result);
Based on the mapping table above, the Java method generated is:
void Sum (int number1, int number2, IntHolder result);
The Java client code is:
IntHolder result = new IntHolder();
myapp.Sum (56, 72, result);
int iresult = result.value;
2.5 Design Restrictions for Wrapped Applications
The Web Services Integration Toolkit is an API level wrapping tool. This means that an appropriate programming interface into the application must be presented to the Toolkit for it to successfully work. This includes items such as no terminal input in the exposed routines, using standard OpenVMS calling mechanisms for passing arguments, and so on.
Beyond the standard restrictions mentioned above, the Web Services Integration Toolkit contains other restrictions that you must be aware of when wrapping your application. These restrictions are discussed in the sections below.
2.5.1 Pointer Types Not Supported
Because of the distributed nature of WSIT-wrapped applications, pointer types are problematic because their value is dependent on the process space in which they were created. Although pointers used within the context of the Pass-by-Reference and Pass-by-Descriptor passing mechanisms are supported, all other uses of pointers are not supported by WSIT.
The following table lists the common cases in which pointers are found, and identifies the pointers that are supported and those that are not supported. (The descriptions are expressed in C syntax but are relevant for all languages.)
Restriction
|
Description |
Routine parameters cannot be defined as “pointer to pointer.”
However, a single pointer, commonly referred to as pass-by-reference, is supported. |
// This is not supported void myfunction( int **p)
// This is supported void myfunction( int *p)
|
User-defined structures cannot contain pointers to other user-defined structures. (*See Note at end of table.)
However, nested structures are supported. |
// For the structure buyerData: typedef struct _buyerData { char buyer_name[MAX_STRING];; } buyerData;
// This is not supported typedef struct _customerData { buyerData *pbuyer; } customerData;
// This is supported typedef struct _customerData { buyerData buyer; } customerData;
|
Routine return values must be returned by value and cannot be user-defined structures.
However, the interface can add a special parameter to the routine to return the same structure. |
// For the structure buyerData: typedef struct _buyerData { char buyer_name[MAX_STRING];; } buyerData;
// This is not supported
// This is supported int buy(buyerData *return_value)
|
Note: If a structure contains a pointer to a type, WSIT passes the pointer as an integer without any regard for the type. The application must handle the memory appropriately. This memory is only valid in the context of the application being wrapped and is not valid in the generated Javabean.
2.5.2 Instantiated WSIT JavaBeans Cannot Be Shared Among Clients
The WSIT runtime supports a many-to-one relationship between clients and backend servers. However, each client must have its own copy of the JavaBean object (unless you manually add synchronization code to the generated JavaBean class). The JavaBean object acts as the client's personal interface into the backend server. It allows WSIT to make sure that each client gets the correct context within the server. If a single JavaBean instantiation is shared among clients, they will also share a single server context. If concurrent calls are then made without synchronization code put in place, this could lead to unexpected results, including incorrect call data and memory management exceptions.
See Section 4.4, Modifying an Existing Template, for information about how to manually add
synchronization code.
2.5.3 Languages Tested with Web Services Integration Toolkit
The Web Services Integration Toolkit was written to wrap ACMS applications and any 3GL-based applications that are callable using the defined OpenVMS calling standard. However, only the following languages have been completely tested:
· ACMS
· BASIC
· C
·
COBOL
Other languages that adhere to the
OpenVMS calling standard (including FORTRAN) should work, but have had limited
testing only.
2.5.4 Tips and Hints for Supported Languages
The following issues apply to all WSIT-supported languages (ACMS, BASIC, C, and
COBOL).
·
The exception java.lang.UnsatisfiedLinkError:
no WSI$JNISHR may be generated:
If you have not started WSIT by calling sys$startup:wsi$startup, an exception is thrown when you run the generated JavaBean.
The following issues apply to the BASIC language only.
·
For formal
parameters, passed by value, with types other than strings or signed decimal
data:
OBJ2IDL.EXE defaults to a passing mechanism of
reference and a usage of IN/OUT. Modify the XML to specify a passing mechanism
of value and a usage of IN.
·
For formal
parameters, passed by descriptor:
OBJ2IDL.EXE does not recognize the type of the
formal parameter. In such cases, the type defaults to a null terminated
string. Modify the XML to specify the correct type for the formal parameter.
In some cases, you may need to add the type (primitive or structure) to the
XML.
·
For formal
parameters that are arrays, if the passing mechanism is descriptor:
OBJ2IDL.EXE does not recognize the arrays. Modify
the XML to specify the array. (See the example of syntax in the C language
section.)
The following issues apply to the C language only.
·
When passing a
formal parameter of byte (type char) by reference:
If a char is being used to represent a single byte and is passed by reference
as a formal parameter, then the generated XML will specify the parameter as
having a type of type=”AutoGen_NullTermString”. Modify the XML to specify type=”char” which will properly resolve to a byte (DSC$K_DTYPE_B).
·
For C
applications, OBJ2IDL.EXE does not recognize formal parameters
that are arrays:
For example, if an array of userstruct with
size 3 is passed as a parameter, then the XML that is generated will be as
follows:
<Routine Name =
"incrementArrayOfStructures" ReturnType = "signed int">
<Parameter Name = "array" Type = "userstruct"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
</Routine>
Modify the XML to specify the array as follows:
<Routine Name =
"incrementArrayOfStructures" ReturnType = "signed int">
<Parameter Name = "array" Type = "userstruct"
PassingMechanism = "Reference"
Usage = "IN/OUT" ArrayDimension = "1">
<Array LowerBound = "0" UpperBound = "2"/>
</Parameter>
</Routine>
The following issues apply to the COBOL language only.
·
For all formal
parameters:
OBJ2IDL.EXE defaults the usage to IN/OUT.
OBJ2IDL.EXE defaults the passing mechanism to pass by reference.
2.5.5 Tips and Hints for OpenVMS Alpha Users
Using I64 generated XML IDL on Alpha: If you are using the Web Services Integration Toolkit on an
OpenVMS Alpha system, you can generate
your XML file on OpenVMS I64, and in most cases, copy it to OpenVMS Alpha with
few or no modifications.
OpenVMS Alpha users who do not have an I64 system can use an
OpenVMS I64 system provided by the HP TestDrive Program. This system has
WSIT installed. To access this resource you must register (for free) at http://www.testdrive.hp.com/accounts/register.shtml
When using an I64 generated IDL on OpenVMS Alpha, be aware that
some compilers may have different default values on I64 than on Alpha. These
differences need to be addressed. For example, the C compiler uses a different
VMSDataType for primitive types float and double:
C Primitive |
Default Value on I64 |
Default Value on Alpha |
float |
DSC$K_DTYPE_FS |
DSC$K_DTYPE_F |
double |
DSC$K_DTYPE_FT |
DSC$K_DTYPE_G |
An application that uses a float must replace the following:
<Primitive Name =
"float” Size = "4” VMSDataType = "DSC$K_DTYPE_FS"/>
with
<Primitive Name =
"float" Size = "4" VMSDataType =
"DSC$K_DTYPE_F"/>
An application that uses a double must replace the following:
<Primitive Name =
"float” Size = "4” VMSDataType = "DSC$K_DTYPE_FT"/>
with
<Primitive Name =
"float" Size = "4" VMSDataType =
"DSC$K_DTYPE_G"/>
Before you configure the out-of-process deployment file, identify your application’s level of reusability. If your application is reusable, you can significantly reduce the number of processes needed to service the clients.
Next, to determine if a single instance of an application can handle multiple clients, consider how you maintain state and manage I/O within your application. Applications are frequently designed to accumulate state from call to call. For example, the first call opens a file, the second call reads from the file, and the third call updates and writes back the modified record. In cases like this, multiple clients within the same application may “step on” each other trying to access the same files using the same channels.
To help you determine your application’s level of reusability, the following sections describe four applications, each with a different level of reusability or combination of reusability and multiple threads.
This is the default configuration for all WSIT out-of-process applications.
An application is not reusable when it can only be used for one client session. When the session is finished, the application has created state that prevents it from being called again. The next client session requires a new instance of the application. This situation can exist in older applications that assume a single long-lived client is their only client. To identify this situation look for global (or static) variables that are used to identify stored client-specific data. The following figure shows an application that is not reusable:
For example, an application may not be reusable if it has a global variable to hold a client account number and the account number cannot be modified or reset with a subsequent call or other mechanism. If a second session requires a different account number to be set, then the application is not reusable.
Deploying an application as not reusable is the most restrictive case and has the highest runtime overhead, but is also the safest configuration. When an application is not reusable, WSIT ensures that the client always receive a new instance of the application.
The order of events for a non-reusable application is as follows:
1.
The client
instantiates the WSIT-generated JavaBean. This starts a session with a free
application.
2. WSIT assigns the client the exclusive use of a process that is
running the application. The process may be newly created or may have been
previously created but never used.
3. The client uses the application as it desires. One or more
calls are made as part of the session.
4. The client tells the WSIT runtime that it is finished with the
session by calling the remove method of the WSIT-generated JavaBean. This
assumes that a session type of LIFETIME_SESSION
is being used. A non-reusable application should not use a NO_SESSION session because of the extremely high
overhead which occurs from creating and deleting a process for every method
call.
5. WSIT deletes the process.
3.2 CASE B: SEQUENTIALLY REUSABLE
An application is sequentially reusable when it is able to process more than one client session, but requires that exactly one session be active at a time. The application must initialize its state before processing the next client session.
When an application is sequentially reusable, WSIT will not delete the application process when the client is finished using it. WSIT ensures that only one client can have a session outstanding with the application.
The following figure shows an application that is sequentially reusable.
For example, an application is serially reusable if it has a global variable to hold a client account number and also a method to initialize (or modify) the account number. In this way, each client can call the initialize method to erase the state of a previous client’s session.
The order of events for a sequentially reusable application is as follows:
1.
The client instantiates
the WSIT generated JavaBean. This starts a session with a free application.
2.
WSIT assigns the
client the exclusive use of a process that is running the application. The
process may be newly created or may have been previously created.
3.
The client uses the
application as it desires. One or more calls are made as part of the session.
4.
The client tells the
WSIT runtime it is finished with the session based on the type of session used.
5. WSIT places the application in a pool so that it is available for another client to use.
To deploy an application as sequentially reusable, make the following change to the file wsi$root:[deploy]<application-name>.wsi:
· Uncomment the XML tags <Reusable> </Reusable>
3.3 CASE C: CONCURRENTLY REUSABLE
An application is concurrently reusable when it can be called from multiple clients without regard to the order of the clients’ sessions. This type of application has a mechanism for keeping the state of each of the clients separated. WSIT uses a single thread when forwarding the clients’ calls to the application. From the application’s perspective, the clients’ sessions may be nested. This ensures that the application processes one client call at a time.
The following figure shows an application that is concurrently reusable.
For example, an application is concurrently reusable if its interface uses a context block to hold client data. In this way, the logic in the application is generic in regard to the clients.
The order of events for a concurrently reusable application is as follows:
1.
The client
instantiates the WSIT-generated JavaBean. This starts a session with a free
application.
2.
WSIT assigns the
client the use of a process that is running the application. The process may be
newly created or may have been previously created. Other instances of the
client may also be using the same application, but WSIT ensures that all method
calls are made one at a time on the same thread.
3.
The client uses the
application as it desires. One or more calls are made as part of the session.
4.
The client tells the
WSIT runtime it is finished with the session based on the type of session used.
5. WSIT places the application in a pool so that it is available for another client to use.
To deploy an application as sequentially reusable make the following changes to the file wsi$root:[deploy]<application-name>.wsi:
1.
Uncomment the XML
tags <Reusable>
</Reusable>
2. Uncomment the XML tag <MaximumClients> and specify a number greater than one for the number of client sessions that the application can process
3.4 CASE D: CONCURRENTLY REUSABLE WITH MULTIPLE THREADS
An application is concurrently reusable and thread-safe when it can be called from multiple clients, at the same time, on multiple threads. WSIT allows multiple client sessions to call the application without any attempt to serialize them. The application was designed to lock shared data when called by multiple threads. It is also written in a language that is capable of generating thread-safe code. (For example, COBOL and BASIC do not generate thread-safe code.)
To determine if the application can handle calls from different clients concurrently, consider the following:
· Are all of the application resources that are shared among clients protected in a thread-safe way? For example, using global symbols can cause problems unless they are protected by a mutex or equivalent concept.
· Is the language that was used to write the application thread-safe?
The following figure shows an application that is concurrently reusable with multiple threads.
For example, an application is concurrently reusable and thread safe if its interface uses a context block to hold client data, and all access to global data, such as a global queue of client context blocks, is protected by a thread-safe locking mechanism such as a mutex.
The order of events for a concurrently reusable with multiple threads application is as follows:
1.
The client
instantiates the WSIT-generated JavaBean. This starts a session with a free
application.
2.
WSIT assigns the
client the use of a process that is running the application. The process may be
newly created or may have been previously created. Other instances of the
client may also be using the same application. WSIT uses multiple threads to
call the application.
3.
The client uses the
application as it desires. One or more calls are made as part of the session.
4.
The client tells the
WSIT runtime it is finished with the session based on the type of session used.
5. WSIT places the application in a pool so that it is available for another client to use.
To deploy an application as sequentially reusable make the following changes to the file wsi$root:[deploy]<application-name>.wsi:
· Uncomment the XML tags <Reusable> </Reusable>
· Uncomment the XML tags <MaximumClients> </MaximumClients> and specify a number greater than one for the number of client sessions that the application can process.
· Uncomment the XML tag <MaximumThreads> </MaximumThreads> and specify a number greater than one for the number of threads that WSIT can use to call the application.
The number of threads allowed to run concurrently should be a percentage of the number of clients specified. A good rule of thumb is to look at the average amount of time that each application call is expected to take.
· If the calls are small and quick, then the number of threads allowed to run concurrently could be 25% of the number of clients.
· If you expect calls to take longer, then you should use a larger value, such as 50 to 60%.
For example, if you specify ten clients per application, and each application call will take some time, then allow six threads to run. Note that once a system is in place, this number should be monitored and adjusted as needed.
The Web Services Integration Toolkit (WSIT) provides a number of different tools that complement each other in the process of wrapping existing OpenVMS applications. One of the tools in the toolkit is IDL2CODE.JAR, also known as the WSIT generator.
The WSIT generator uses a mechanism based on Velocity templates. A set of template files are read, and placeholders within those templates are replaced by application-specific values. This becomes the generated code.
More specifically, the generator reads a WSIT-specific IDL description of the application to be wrapped, then generates code based on this description. The generated wrapping code contains the following:
· Server wrapper component that builds against the existing application
· JavaBean component that provides the new interface into this application
The standard code that is generated out of the box has been tested and is robust enough to handle most cases. However, you may want to tailor what is generated by IDL2CODE.JAR. The following sections describe the process that IDL2CODE.JAR uses to generate code, and then describes how you can modify what is generated.
The generation process occurs in four distinct phases. The first three phases offer you an opportunity to modify what ultimately is generated. The phases are described in the following sections.
In Phase 1, the generator reads the WSIT IDL file describing the application, parses it, and then populates an object model representation of its contents. This object model is directly accessed by the templates and template engine in later phases. The IDL should accurately reflect the interface to the application being wrapped. This phase is your first opportunity to affect what is generated.
See Section 1.3, Exposing an OpenVMS 3GL Application, for more information.
In Phase 2, the generator generates a master list called Master.lst of files to generate based on the template file called Master.vm. (In the next phase, the generator steps through this list of files to generate the actual files.) Modifying Master.vm allows you to change the list of files to generate, as well as to change which templates to use in generating these files.
Each line within Master.vm and Master.lst has the following format:
<Object > < Name> <Output Filename> <Template Filename> <Output Subdirectory>
where:
Object describes the component to which this generated file will belong. Object can have one of the following values:
SW File belongs to the server wrapper component
The generated file is placed into the
subdirectory [.appnameServer]
JB File belongs to the JavaBean component
The generated file is placed into the
subdirectory [.appname]
I File represents an interface within the JavaBean
The generated file is placed into the
subdirectory [.appname]
S File represents a structure definition within the Javabean
The generated file is placed into the
subdirectory [.appname]
C File is part of a generated sample
client
The generated
file is placed into the subdirectory [.appnameSamples…]
Name
identifies the name of the object within the object model that this file
represents.
Output filename is the filename of the file to be generated.
Template filename is the filename of the template to use in creating this file.
Output Subdirectory optionally specifies the subdirectory in
which to generate the file.
(If used, it overrides the default subdirectory specification.)
In Phase 3, the generator reads the previously generated Master.lst file, then generates the listed files.
Each line within Master.lst contains an output filename and an associated template file to use in its generation. It uses these mappings, along with this previously populated object model, to create the output files.
You can modify the template files to change the contents of the individually generated files. The object model can be accessed using Velocity identifiers.
In Phase 4, the generator optionally runs the Javadoc utility against the generated JavaBean files, creating a set of .html files that document the generated interface.
The following example shows you how to write a new template and add it to the master list so that it will be used within the generation process.
This example assumes the following simple WSIT IDL:
<?xml version="1.0"
encoding="UTF-8"?> <OpenVMSInterface xmlns="hp/openvms/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="hp/openvms/integration
openvms-integration.xsd" ModuleName="simple.OBJ" Language="C89"> <Primitives> <Primitive Name = "signed int" Size = "4" VMSDataType =
"DSC$K_DTYPE_L"/> </Primitives> <Routines> <Routine Name = "add" ReturnType = "signed
int"> <Parameter Name =
"p1" Type =
"signed int" PassingMechanism = "Value" Usage =
"IN"/> <Parameter Name =
"p2" Type =
"signed int" PassingMechanism = "Value" Usage =
"IN"/> </Routine>
</Routines> </OpenVMSInterface>
Step 1: Write Template using Velocity
For this example, we will write a template file using Velocity that generates a log file containing the list of the routines being exposed, along with their parameters. (Save the file as app-logfile.vm.) The completed file will look similar to the following:
#set( $server = $application.Server ) Logfile for
${application.Name}
--------------------------------- Routines being exposed Parameters ---------------------------------------------------------------------- #foreach( $routine in $server.Routines) ${routine.Name} Description: ${routine.Description} Return Type: #if( $routine.Returnparam )
$routine.Returnparam.SWFormalDefinition#else void#end #foreach( $param in $routine.Parameters) ${param.Name}
($param.SWFormalDefinition) #end #end
Note: The Velocity syntax that is used to pull information from the provided object model. Within WSIT:
· All templates are passed $application, which is a reference to the top level genConnection object.
· All structure type templates are passed $structure, which is a reference to the genStructure object.
· All interface templates are passed $interface, which is a reference to the genInterface object.
The template files located in WSI$ROOT:[TOOLS.TEMPLATES]show many different examples of using these tags.
When you finish writing the template, place it where Velocity can find it. The path(s) that the Velocity engine uses to find template files is specified in the file velocity.properties. You can modify this file to add your directory to the search path, or you can copy your newly written template into a directory that is already in the path.
Step 2: Modify Master.vm
Next, modify Master.vm to add the new file to the list of files that are generated. The new file that you created in Step 1 is considered a server wrapper template file because it lists the interface as exposed by the application.
Add the following line to Master.vm in the appropriate place. Type the line exactly as shown below. (Like any other template file, the ${application.Name} placeholder is automatically replaced with the name of the application, causing the generated file to contain the application name in its filename.)
SW ${application.Name} ${application.Name}.log app-logfile.vm
Step 3: Run IDL2CODE.JAR
Run the generator and review the newly generated files. If the run is successful, a log file that looks similar to the following can be found in the [.ServerSimple] subdirectory.
Example 1 showed you how to write and add your own new template. However, there may be cases in which you want to directly modify the behavior of an existing WSIT template.
For instance, you may want to remove the restriction that every client needs to have its own instantiation of the JavaBean interface class. The way to remove this restriction is to make sure that the generated JavaBean class has appropriate synchronization code to serialize all calls through it. (This is not generated by the default WSIT templates.) This example steps you through this simple process.
Step 1: Set Default Directory
Assuming the default location for the templates, set your default directory to
WSI$ROOT:[tools.templates.javabean].
This is where you will find the templates used to generate the javabean files.
Step 2: Edit Files to Add Synchronize Keyword
Assuming that the templates have their default names, edit the files
INTERFACE-JAVA.VM and INTERFACEIMPL-JAVA.VM.
These files define the interface, and the implementation of the interface, for the newly generated application.
For every public method definition within the two files, you must add the synchronized keyword. In particular, add the synchronized keyword to the: AcmsSignIn, AcmsSignOut, OpenVmsLogin, OpenVmsLogout, and remove methods in each file.
Next, add the synchronized keyword to each method definition within $interface.Methods and $interface.AcmsMethods.
For example:
Before: public#if($routine.Returnparam)
$dtutility.getJBtype($routine.Returnparam.Datatype)#else void#end
${routine.WebServiceName} ($paramformal)
throws WsiException; After: Public
synchronized#if($routine.Returnparam) $dtutility.getJBtype($routine.Returnparam.Datatype)#else
void#end ${routine.WebServiceName} ($paramformal)
throws WsiException;
Step 3: Run IDL2CODE.JAR
Run IDL2CODE.JAR to generate an application wrapper. The generated interface methods are synchronized. All method calls to each JavaBean is serialized.
5 M O D I F Y I N G I D L F I L E S
To wrap an application, the Web Services Integration Toolkit generates and passes a description of the application’s API that is to be wrapped. Although it is primarily the WSIT tools that interact with this interface definition, there may be times when a developer wants to read or modify the IDL manually. For this reason, consideration was given to the layout of the WSIT Interface Definition Language (IDL) file in order to make it as easy as possible for a developer to manually read and modify it.
A WSIT IDL file is an XML file that has an easy to understand nested layout that allows a developer to completely describe their application in a language-neutral way. It does this by allowing the definition of all routines and structures that are to be exposed by the application. Within these routine and structure definitions, all parameter and field datatypes are mapped (translated) into their OpenVMS equivalent datatypes. In general, the mapping takes one of the following two forms:
“User datatype specification” → typedef translation[n] → Primitive translation → OpenVMS primitive (datatype)
or
“User datatype specification” → typedef translation[n] → Structure definition
Note: The [n] shows that any number of typedef translations may occur before the final translation to an OpenVMS datatype (primitive) or structure definition.
The following sections describe how each component (routine, structure, and so on), and each type of translation (mapping), is defined within the WSIT IDL file.
5.1 OpenVMS Interface Block
The
<OpenVMSInterface> block is the main block that encapsulates all of the
blocks that collectively describe the application’s interface. It has the
follow format:
<OpenVMSInterface
xmlns="hp/openvms/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="hp/openvms/integration
openvms-integration.xsd"
ModuleName="DISK:[MYDIR.STOCK]stock.OBJ"
Language="C89">
.
<Enumerations>
</Enumerations>
.
<Typedefs>
</Typedefs>
.
<Primitives>
</Primitives>
.
<Structures>
</Structures>
.
<Routines>
</Routines>
.
</OpenVMSInterface>
Except for the first line in the XML file, <?xml version="1.0" encoding="UTF-8"?>, all lines within the WSIT IDL file reside within the <OpenVMSInterface> block.
The properties within the <OpenVMSInterface> tag (in bold above) are primarily generic header information that is required, and is identical, for all WSIT IDL files. The two notable exceptions are the ModuleName and Language properties, described in the following table:
Property Name |
Description |
ModuleName |
For 3GL based applications, this is the fully qualified file specification of the OBJ module that contains the application’s interface. For ACMS based applications, this is the ACMS application name. |
Language |
This is the language in which the interface module was written in, such as C89, BASIC, COBOL, and ACMS, … |
The blocks nested within the <OpenVMSInterface> block (shown above), contain the collection of definitions corresponding to that component or translation type. For example, the <Routines> block contains all of the individual <Routine> blocks that describe the exposed routines of an application. The <Structures> block contains the list of <Structure> definitions; the <Primitives> block contains the list of <Primitive> or OpenVMS datatype translations; the <Typedefs> block contains the list of <Typedef> definitions; and the <Enumerations> block contains the list of <Enumeration> definitions. All of the individual definition blocks and tags are described in greater detail in the following sections.
5.2 Enumeration
Block
The
collection of <Enumeration> blocks contains all of the constant definitions
that are defined as enumerations within the application. An
<Enumeration> is made up of a name, an OpenVMS datatype, an optional size
in bytes, and the list of Name/Value pairs. The format of the block is as
follows:
<Enumerations>
<Enumeration Name = “myenums”
VMSDataType = “DSC$K_DTYPE_L”
ByteSize = “4”>
[…see Enumerator block for more information…]
</Enumeration>
</Enumerations>
The
properties of the <Enumerations> tag are defined as follows:
Property Name |
Description |
Name |
The name given to this collection of enumerators. |
VMSDataType |
The equivalent OpenVMS datatype of the enumeration. The DSC$K_DTYPE_* values are used to specify them in a language & application independent way. |
ByteSize |
The size, in bytes, of the specified datatype. |
5.3 Enumerator
Block
Each
Enumerator within an enumerator collection (an Enumeration) specifies a
name/constant value pair. These pairs make up the set of valid values for the
Enumeration. The format of an Enumerator is as follows:
<Enumeration …>
<Enumerator Name = “PIC$SIZE1” ConstantValue = “1”/>
<Enumerator Name = “PIC$SIZE2” ConstantValue = “2”/>
</Enumeration>
The
properties within the <Enumerator> tag are as follows:
Property Name |
Description |
Name |
The name given to the specified constant value. |
ConstantValue |
The constant value associated with the specified name. |
5.4 Typedef Block
The
collection of <Typedef> blocks contains all of the typedef translations
used within the application. Each <Typedef> tag describes a user defined
mapping of a type name to an equivalent type. In C, this looks similar to the
following:
typedef myint unsigned int;
Each
<Typedef> tag has the following format:
<Typedef Name = “myint”
TargetName = “unsigned int”/>
Where each property is defined below:
Property Name |
Description |
Name |
The user defined name associated with the typedef within the application. |
TargetName |
The equivelant datatype that this typedef maps to. This may specify another typedef, a primitive, or a structure definition. |
5.5 Primitive
Block
The collection of <Primitive> blocks contains the datatype translations to their OpenVMS equivalents for all datatypes used within an application. Each <Primitive> mapping contains the datatype, the OpenVMS datatype (primitive) that it maps to, and any other information needed to completely describe that primitive. For example, the format for a <Primitive> tag that describes a Packed Decimal is as follows:
<Primitive Name = "DSC$K_DTYPE_P_5_2"
Size = "5"
Scale = "2"
VMSDataType = "DSC$K_DTYPE_P" />
The
properties of the <Primitive> tag are described below:
Property Name |
Description |
Name |
The application or language specific name for the specified datatype, such as unsigned int or PIC 9(8). See Note. |
VMSDataType |
The equivalent OpenVMS datatype specification. The DSC$K_DTYPE_* values are used to specify them in a language neutral way. |
Size |
The size in bytes of the primitive being defined. This is ignored for datatypes whose size is constant, such as DSC$K_DTYPE_L. If the datatype is a string, and the size is 0, then the string is considered dynamically sized. |
Scale |
Only used with scaled numeric datatypes, this property specifies the scale factor for the primitive being defined. Note that a positive scale factor specifies that the decimal point moves to the left. (The example above would represent a number with the format of 123.45.) |
FixedFlag |
Only used with string datatypes, this informational property specifies that the string being defined is of fixed size. A value of 1 specifies fixed size, while a 0 specifies that the string is dynamically sized. |
NullTerminatedFlag |
Only used with string datatypes, this property specifies if a null terminator should be appended to the end of the string. For fixed length strings, the string will be truncated if needed in order to append the null terminator. A value of 1 says to append a null, while a value of 0 specifies no null. |
Note For datatypes that are the same but differ in size and/or scale, the Primitive Name must be unique. One way to do this is to embed the size and scale values into the Primitive Name itself. (See Packed Decimal example above.)
5.6 Structure
Block
The
collection of <Structure> blocks contains all of the user defined structure
(record) definitions. Each <Structure> block represents a single user
defined structure (record) definition. All parameters and fields must
eventually map to an OpenVMS primitive, or one of these structure definitions.
The format of the <Structure> block is as follows:
<Structures>
<Structure Name = "MyStruct"
TotalPaddedSize = "128">
[…See Field Block below for more information…]
</Structure>
</Structure>
The
properties of the <Structure> tag are as follows:
Property Name |
Description |
Name |
The user specified name given to this structure (record, workspace, …) definition. |
TotalPaddedSize |
The size of the structure, including any padding added for alignment purposes. |
5.7 Field Block
Each
<Field>…</Field> block describes a single field within a
structure. The format of a <Field> block is as follows:
<Structure … >
<Field Name = "Fld1"
Type = "signed int"
Offset = "0"/>
<Field Name = "Fld2"
Type = "FixedString16"
Offset = "4"/>
<Field Name = "AryFld3"
Type = "signed int"
Offset = "20"
ArrayDimension = "1"
RowByColumn = "0">
<Array LowerBound = "0"
UpperBound = "9"/>
</Field>
</Structure>
The
properties of the <Field> tag are as follows:
Property Name |
Description |
Name |
The user specified name given to this field |
Type |
The language dependant or application specific datatype associated with this field. |
Offset |
The offset (within the structure) to the start of this field. |
ArrayDimension |
If this field is an array of elements, this property specifies the number of dimensions within the array. |
RowByColumn |
If this field is a multi-dimensional array of elements, this property specifies the ordering of the dimensions within memory. All languages, besides Fortran, use a RowByColumn layout. Use a “1” to specify RowByColumn, and a “0” to specify ColumnByRow (Fortran). |
<Array> Tag |
See below |
5.7 1 Field Array
Tag
For fields and parameters that are arrays, the <Array> tag is used to specify dimension information for a single dimension. The number of <Array> tags must match the number specified in the ArrayDimension Field property above. The format of the Array tag is shown above.
The
properties of the <Array> are as follows:
Property Name |
Description |
LowerBound |
The user specified lower bound of this dimension. |
UpperBound |
The user specified upper bound of this dimension. Note that the upper bound must be larger than the lower bound. |
5.8
Routine Block
The
collection of <Routine> blocks contains all of the definitions for the
routines being exposed by the application. Each <Routine> block contains
the complete description of a single exposed routine call, including all
parameter & return information. The format for the <Routines> block
is as follows:
<Routines>
<Routine Name = “MyRoutine”
ReturnType = “unsigned int”
Description = “This is the description for my routine”>
[…Refer to the Parameter block section below for more information…]
<\Routine>
<\Routines>
The
properties of the <Routine> tag are as follows:
Property Name |
Description |
Name |
The user specified name for this exposed routine. |
ReturnType |
The language dependant or application specific datatype associated with this routine’s return type. |
Description |
A user specified description to be associated with this routine definition. |
MethodID |
Species a value to use as the internal method ID instead of the one automatically generated for this routine. This is only useful in rare cases for backwards compatibility within the generated interface. |
<Parameter> Tag |
See below for more information. |
5.9 Parameter Block
The
<Parameter> Block is used to describe a single parameter within a
routine’s parameter list. There will be one <Parameter> tag for each
parameter passed in or out of the routine. The <Parameter> block has
the following formats:
<Routine …>
<Parameter Name = "Param1"
Type = "unsigned int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "AryParam2"
Type = "__int16"
PassingMechanism = "Reference"
Usage = "IN/OUT"
ArrayDimension = "1"
RowByColumn = "1"
ArrayDescriptorType = "DSC$K_CLASS_A">
<Array LowerBound = "0"
UpperBound = "10"/>
</Parameter>
<Parameter Name = "AryParam3"
Type = "__int16"
PassingMechanism = "Descriptor"
Usage = "IN/OUT"
ArrayDimension = "1"
RowByColumn = "1"
ArrayDescriptorType = "DSC$K_CLASS_A">
</Parameter>
</Routine>
The
<Parameter> tag has the following properties:
Property Name |
Description |
Name |
The user specified name for this parameter. |
Type |
The language dependant or application specific datatype associated with this parameter type. |
PassingMechanism |
The OpenVMS based passing mechanism used to pass this parameter. It can be “Value”, “Reference”, or “Descriptor”. |
Usage |
This property specifies how this parameter will be effected by the called routine. It is either “IN”, which specifies that it doesn’t modify the value, or “IN/OUT” which specifies that it does modify this value. |
ArrayDimension |
If this parameter is an array of elements, this property specifies the number of dimensions within the array. |
RowByColumn |
If this parameter is a multi-dimensional array of elements, this property specifies the ordering of the dimensions within memory. All languages, besides Fortran, use a RowByColumn layout. Use a “1” to specify RowByColumn, and a “0” to specify ColumnByRow (Fortran). |
ArrayDescriptorType |
If this parameter is an array passed by descriptor, this property specifies the descriptor class that should be used when passing this array. The valid values for this property are, “DSC$K_CLASS_A”, “DSC$K_CLASS_NCA”, DSC$K_CLASS_VSA. |
Resizable |
Special case only: If this parameter is specified as a single dimensional byte array, passed by descriptor, with a usage of “IN/OUT”, then setting this property to “1” defines this parameter as a resizable byte array. |
FreeMemory |
Special case only: If this parameter is defined as a resizable byte array, then setting this property to “1” will specify that a freeing of the array memory needs to take place after the call. |
<Array> Tag |
See below for more information. |
5.9.1 Parameter
Array Tag
For field arrays, and parameter arrays that are passed by reference, the <Array> tag is used to specify dimension information for a single dimension. For Parameter arrays that are passed by reference, the number of <Array> tags must match the number specified in the ArrayDimension Parameter property above. The format of the Array tag is shown above.
The
properties of the <Array> are as follows:
Property Name |
Description |
LowerBound |
The user specified lower bound of this dimension. |
UpperBound |
The user specified upper bound of this dimension. Note that the upper bound must be larger than the lower bound. |
5.10 Example WSIT IDL File
<?xml version="1.0" encoding="UTF-8"?>
<OpenVMSInterface
xmlns="hp/openvms/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="hp/openvms/integration openvms-integration.xsd"
ModuleName="disk$:[workshop.lab1]math.obj"
Language="C89">
<Primitives>
<Primitive Name = "unsigned int"
Size = "4"
VMSDataType = "DSC$K_DTYPE_LU"/>
<Primitive Name = "signed int"
Size = "4"
VMSDataType = "DSC$K_DTYPE_L"/>
</Primitives>
<Routines>
<Routine Name = "sum"
ReturnType = "unsigned int">
<Parameter Name = "number1"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "number2"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
</Routine>
<Routine Name = "product"
ReturnType = "unsigned int">
<Parameter Name = "number1"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "number2"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
</Routine>
</Routines>
</OpenVMSInterface>
A P P E N D I X
$ ty stock.c
//
// This is a sample file intended to be used to demonstrate the WSIT product.
// It defines 2 routines: (buy and sell). Each routine accepts 3 structures:
// buyerData, sellerData, tickerData.
//
// This code is intended only to illustrate the WSIT product and is not intended provide
// a usefull stock trading application.
//
//
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
const MAX_STRING = 20;
typedef struct _buyerData {
char buyer_name[MAX_STRING];
unsigned int member_number;
unsigned int balance_dollars;
unsigned int number_shares_desired;
} buyerData;
typedef struct _sellerData {
char owner_name[MAX_STRING];
unsigned int member_number;
unsigned int balance_dollars;
unsigned int number_shares_available;
} sellerData;
typedef struct _tickerData {
char symbol[MAX_STRING];
char company_name[MAX_STRING];
} tickerData;
unsigned int buy (unsigned int max_price, tickerData *symbol, sellerData *pSeller, buyerData *pBuyer) {
//
// Sell as many shares as possible
//
unsigned int shares_purchased = 0;
if ( pSeller->number_shares_available >= pBuyer->number_shares_desired) {
shares_purchased = pBuyer->number_shares_desired;
} else {
shares_purchased = pSeller->number_shares_available;
}
pSeller->number_shares_available = pSeller->number_shares_available - shares_purchased;
return shares_purchased;
}
unsigned int sell (unsigned int min_price, tickerData *symbol, sellerData *pSeller, buyerData *pBuyer) {
//
// Sell as many shares as possible
//
unsigned int shares_sold = 0;
if ( pSeller->number_shares_available >= pBuyer->number_shares_desired) {
shares_sold = pBuyer->number_shares_desired;
} else {
shares_sold = pSeller->number_shares_available;
}
pSeller->number_shares_available = pSeller->number_shares_available - shares_sold;
return shares_sold;
}
$
<?xml version="1.0" encoding="UTF-8"?>
<OpenVMSInterface
xmlns="hp/openvms/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="hp/openvms/integration openvms-integration.xsd"
ModuleName="wsi$root:[samples.c]stock.obj"
Language="C89">
<Primitives>
<Primitive Name = "unsigned int"
Size = "4"
VMSDataType = "DSC$K_DTYPE_LU"/>
<Primitive Name = "AutoGen_FixedString19"
Size = "19"
VMSDataType = "DSC$K_DTYPE_T"
NullTerminatedFlag = "0"
FixedFlag = "1"/>
</Primitives>
<Typedefs>
<Typedef Name = "tickerData"
TargetName = "_tickerData"/>
<Typedef Name = "sellerData"
TargetName = "_sellerData"/>
<Typedef Name = "buyerData"
TargetName = "_buyerData"/>
</Typedefs>
<Structures>
<Structure Name = "_tickerData"
TotalPaddedSize = "40">
<Field Name = "symbol"
Type = "AutoGen_FixedString19"
Offset = "0"/>
<Field Name = "company_name"
Type = "AutoGen_FixedString19"
Offset = "20"/>
</Structure>
<Structure Name = "_sellerData"
TotalPaddedSize = "32">
<Field Name = "owner_name"
Type = "AutoGen_FixedString19"
Offset = "0"/>
<Field Name = "member_number"
Type = "unsigned int"
Offset = "20"/>
<Field Name = "balance_dollars"
Type = "unsigned int"
Offset = "24"/>
<Field Name = "number_shares_available"
Type = "unsigned int"
Offset = "28"/>
</Structure>
<Structure Name = "_buyerData"
TotalPaddedSize = "32">
<Field Name = "buyer_name"
Type = "AutoGen_FixedString19"
Offset = "0"/>
<Field Name = "member_number"
Type = "unsigned int"
Offset = "20"/>
<Field Name = "balance_dollars"
Type = "unsigned int"
Offset = "24"/>
<Field Name = "number_shares_desired"
Type = "unsigned int"
Offset = "28"/>
</Structure>
</Structures>
<Routines>
<Routine Name = "buy"
ReturnType = "unsigned int">
<Parameter Name = "max_price"
Type = "unsigned int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "symbol"
Type = "tickerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
<Parameter Name = "pSeller"
Type = "sellerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
<Parameter Name = "pBuyer"
Type = "buyerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
</Routine>
<Routine Name = "sell"
ReturnType = "unsigned int">
<Parameter Name = "min_price"
Type = "unsigned int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "symbol"
Type = "tickerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
<Parameter Name = "pSeller"
Type = "sellerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
<Parameter Name = "pBuyer"
Type = "buyerData"
PassingMechanism = "Reference"
Usage = "IN/OUT"/>
</Routine>
</Routines>
</OpenVMSInterface>
$
$ type stockcaller.java
import stock.*;
import java.io.*;
import javax.xml.rpc.holders.StringHolder;
import javax.xml.rpc.holders.StructureHolder;
public class stockcaller {
/** Creates a new instance of Main */
public stockcaller() {
}
public static void main(String[] args) {
try {
stockImpl stock = new stockImpl();
// create a seller object and place in holder
_sellerData sellerData = new _sellerData("Mr Seller", 12345, 1000000, 1000);
StructureHolder seller = new StructureHolder(sellerData);
// create a buyer object and place in holder
_buyerData buyerData = new _buyerData("Mr Buyer", 67890, 5000, 995);
StructureHolder buyer = new StructureHolder(buyerData);
// create a ticker object and place in holder
_tickerData tickerData = new _tickerData("HPQ", "Hewitt Packard");
StructureHolder ticker = new StructureHolder(tickerData);
System.out.println("The sellers number_shares_available: " + sellerData.getNumber_shares_available());
stock.buy(27, ticker, seller, buyer);
System.out.println("The sellers number_shares_available: " + sellerData.getNumber_shares_available());
} catch (Exception e) {
System.out.println("Exception thrown");
}
}
}
$
E Program
Listing – MATH.XML
<?xml
version="1.0" encoding="UTF-8"?>
<OpenVMSInterface
xmlns="hp/openvms/integration"
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation="hp/openvms/integration openvms-integration.xsd"
ModuleName="DISK$ODS5:[aaa.wsit.math]math.OBJ"
Language="C89">
<Primitives>
<Primitive Name = "unsigned int"
Size = "4"
VMSDataType = "DSC$K_DTYPE_LU"/>
<Primitive Name = "signed int"
Size = "4"
VMSDataType = "DSC$K_DTYPE_L"/>
</Primitives>
<Routines>
<Routine Name = "sum"
ReturnType = "unsigned int">
<Parameter Name = "number1"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "number2"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
</Routine>
<Routine Name = "product"
ReturnType = "unsigned int">
<Parameter Name = "number1"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
<Parameter Name = "number2"
Type = "signed int"
PassingMechanism = "Value"
Usage = "IN"/>
</Routine>
</Routines>
</OpenVMSInterface>