|
The iSeries Toolbox for Java Does Service Programs
by Kevin Vandever
[The code for this article is available for download.]
In "Calling a
Program Using the iSeries Toolbox for Java," I called an RPG program from a Java class with the help
of an XML extension called PCML. In "The Basics of ILE Service
Programs," I provided the inner workings of a service program and listed some of its advantages. Now
I'll combine the two techniques and call service programs from Java using the toolbox. It's not as important
as combining peanut butter and chocolate, and it may have its limits, but it won't rot your teeth.
Back to the Future
Those of you who have kept up with my articles on calling iSeries applications using Java may be saying to
yourself, "Wait a minute! In 'Calling RPG Native Methods from Java,' Kevin showed me how to call
service programs from local Java applications using Java Native Interface." And you would be correct. I
did show you how to call service programs using JNI. However, there is a slight difference between what I
did in that article and what I'm about to show you here.
Calling a service program using JNI requires that you code the service program a little differently than you
might normally. You must create the subprocedures making up that service program as Java methods; that
is, you would use the new Java-related parameters on the EXTPROC keyword and the Java object data
types that were made available with OS/400 V5R1. This allows Java to look at the subprocedures that make
up the service program as native methods, which then can be called using core Java method calls. But the
technique I'm going to explain works with regular old service programs and became available with V4R5.
If you're interested in learning this technique, take some time to read the previous article on calling
RPG using the toolbox. In that article, I provided details on downloading and installing the toolbox, as well
as step-by-step instructions on how to set up PCML and call the RPG program. In this article, I want to
show you the slight modifications necessary in order to call ILE service programs. Let's get started.
The Service Program
I've included the service program Math_Ops, and its associated prototype copybook, Math_OpsPR,
which performs the same add function as the RPG from the previous article. You can download and use it
to test this technique. I called it Math_Ops because you can add other math-related operations to it by
writing additional subprocedures. (For example, I have a version of Math_Ops that includes subprocedures
for multiplying, subtracting, and dividing the two numbers passed to them.) I only included the ADD
subprocedure because I wanted you to be able to easily refer back to my original article, "Calling a Program
Using the iSeries Toolbox for Java," and compare the PCML and Java application.
PCML
The PCML, or Program Call Markup Language, is used to define the parameters using iSeries data types
such as packed and zoned. When setting these data types in the Java program, the necessary conversion is
done for you. Take a look at the two PCML documents, ExamplePcml
and MathPcml. ExamplePcml is from the previous article and is used to call an RPG
program. It's pretty straightforward. It contains the program name and the necessary path to that program
on the iSeries. Then you have the field names defined in recognizable data types such as packed, zoned,
and char. The methods used in the Java code to set and get these parameters will handle the conversion for
you. Oh, yeah, usage is important. In RPG, we can do whatever we want with any parameter, but in using
PCML, we define our parameters as input, output, or inputoutput, as seen by our RPG program. This means
that an input parameter is passed from Java to the RPG program and is used in that program. "Output"
means that RPG passes this parameter back to Java so that the Java application can use it. "Inputoutput"
means that the parameter can be used and manipulated by both the Java and RPG programs. Ironically, this
is how service programs are designed to look at parameters.
Now take a look at MathPcml. This is the PCML used to call an ILE service program. There are only a few
differences between it and the ExamplePCML used to call a regular program. This first on is on the very
first line, the PCML version. You only need PCML Version 1.0 to call programs, but you need at least
Version 2.0 to call ILE service programs. To use the threadsafe option, on line 4, I believe you need to
employ PCML Version 3.0. Both Versions 2.0 and 3.0 of PCML have been available since V4R5 of
OS/400. (Check out the previous PCML article for download instructions.) The second difference is in the program
name. When calling service programs, you refer to the subprocedure name in the program name. Case does
not matter in the program name, except that it must match the case you use in the Java application. Unlike
the call to regular programs, when calling service programs, the program name attribute really has nothing
to do with what you called your service program on the iSeries. However, the program name attribute, as it
is with program calls, is the link between your Java application and the PCML document.
The entry point is the actual name of the subprocedure inside your service program. It must always be in
caps. The documentation says that it is case sensitive, but as I found out the hard way, that doesn't mean
case sensitive to what you have in your code; it means case sensitive to what the compiler resolved the
exported value to be, and that is all caps. So whereas the program name must match the actual RPG
program name when calling programs, it is the entry point name that must match the subprocedure when
calling service programs. When calling service programs, you can use any program name attribute you
want as long as that is the name you use in the Java application. The entry point is what matters.
The path name is where you define which service program you are using. Notice the extension .srvpgm is
used instead of .pgm, as you would when calling programs. The last difference is the additional attribute of
"threadsafe." It defaults to "false" if you don't use it, and I didn't need to use it here, but I wanted to show
you that it exists. Threading issues only come into play when your Java and service programs are on the
same iSeries. In that case, you would want to set this attribute according to how your service programs
were coded. Threading issues are very interesting, and I will discuss them another day. For now, it's OK to
not use the attribute or set it to "false." There is one more value I didn't use here, and that is the
"returnvalue" attribute. As you may know, you can have a return value in a service program, and PCML
allows you to define it. I didn't use it here because I wanted to you to compare the two examples without
adding any additional functions. Besides, I wanted you to have something new and exciting to experiment
with. I will talk more about it later in the article. That's it! Let's move on to the Java code.
Java
This is the easy part. If you look at the Java source code from the previous article, add2numbers,
and compare it with the Java application used to call a service program, prc2numbers, you
will see very little difference. That's because all the necessary differences that are required to call service
programs are handled in the PCML. In the Java application, all you have to do is use the new program
name attribute defined in your PCML to set your parameters, call the service program, and get your
returned parameters, and you are set. The Java code works the same way.
It Falls a Little Short
There are some idiosyncrasies that I discovered--some documented, some not. For one, there is a limit of
seven parameters that can be passed to a service program from the Java toolbox. This limit does not exist
when working with service programs directly on the iSeries. That one is documented. Also, if you use a
return code, you can use the returnvalue attribute in the PCML document to describe the return value;
however, you are limited to a 4-byte integer value, which, again, is not an iSeries or service program
requirement. This issue is also documented. The next concern is the one I mentioned earlier that has to do
with the case-sensitive requirement of the entry point in your PCML. The documentation says that it is case
sensitive, which is true, but what it really should say, at least in my experience, is that it should be all caps,
because that is the only way it will work. So I guess it is case sensitive, but related to how OS/400 exports
the object to the rest of the world, which is all caps, and not how it was coded inside the subprocedure. The
last issue is not documented, as far as I can find, but it will trip you up if you pass parameters by value in
your shop. You cannot use the VALUE keyword inside your service programs to define variables as pass-
by-value. Although it is a valid and preferred technique when passing values to a service program that you
don't want changed, you will get a decimal data error when calling a service program from Java that accepts
parameters by value.
So What Should You Do?
If you use service programs or plan to use service programs in your shop and want to get to them from
Java, the toolbox will allow you to do so. Just know its limits. For new service programs, the documented
limits are easy enough to get around if you design appropriately. Existing service programs could cause you
some headaches. The case issue is just something you have to learn once. However, not being able to use
the VALUE keyword could be a sticking point if you already have service programs that do so or you
really like the idea of passing by value versus passing by reference. I will continue to investigate this latter
issue and report back any findings. There are a couple of other ways to call service programs using Java:
there's the one I already wrote about and mentioned earlier in this article, and there's an older technique that
predates PCML. I have not written about that one. The former technique uses JNI and requires that the Java
and service programs run on the same iSeries. The latter technique also uses the toolbox but is not nearly as
nice as the PCML method. Still, I believe it does allow you to pass parameters by value and by reference,
so maybe I'll write a little something about it in the future. Stay tuned.
|