A development we were working on required us to submit an AS400 job and wait for that job to complete. It was quite a long process that involved numerous file operations and sockets communication to various sub systems.
We had to submit the job using the SBMJOB
command which looked similar to this...
SBMJOB CMD(CALL PGM(ORD040CL) PARM('0000157')) JOB(CREATE_ORDS) JOBQ(*JOBD)
This is simple enough using either the COM interop library cwbx.dll (IBM AS/400 iSeries Access for Windows ActiveX Object Library) or the managed .NET provider IBM.Data.DB2.iSeries. However, because you are submitting the job rather than running it interactively, responsibility for processing that job is passed to the AS400. Using either the COM or .NET tools, there was no simple way to search for jobs by name or system.
After a bit of searching and speaking with smug Java colleagues, I learned that this is very simple to do in Java using the open source toolkit jtOpen.
jtOpen exposes a number of classes that aren't available in either of the COM or .NET libraries. The main class I was interested in was JobList. IBM even has a nice example of exactly what I was trying to achieve:
Since the code is open source, I thought I'd have a quick look and see if it would be a simple case to port the code I was interested in into a .NET library. Unfortunately, this wasn't the case - the JobList
class actually performs a number of API calls in order to retrieve a handle to a list of objects and iterate them. You can view the source here if you like.
What I wanted to do was simply use the Java code from within my .NET code. This is where IKVM comes to the rescue.
IKVM ships with a Bytecode compiler named ikvmc. Using this tool, you can run the jar file through ikvmc and create a DLL file that you can reference from your .NET code.
Have a look at the command line options available for ikvmc. The JobList
class exists in the main jt400.jar file, so to convert it to a DLL, you would use syntax similar to:
ikvmc -target:jt400.jar -out:jt400.dll
You might see a few warnings while creating the DLL, but you should still find that jt400.dll has been created OK.
Once the DLL is ready, go to Visual Studio and reference the file in your project. You might think that's all that's required, but you still need to add all the references to provide the bridging between your .NET code in the Java source. If you look in the bin directory of your IKVM download, you'll find numerous libraries prefixed IKVM.OpenJDK
- you'll need to include some of these so that your jt400 library will work OK.
I couldn't find any obvious reference for which files were required, so a bit of trial and error was needed here. Eventually, the minimum references that I needed for jt400 to work were...
IKVM.OpenJDK.Beans.dll
IKVM.OpenJDK.Core.dll
IKVM.OpenJDK.SwingAWT.dll
IKVM.OpenJDK.Text.dll
IKVM.OpenJDK.Util.dll
IKVM.OpenJDK.Runtime.dll
Once these references are included, you should be able to use the library OK. Taking the IBM example link from earlier in this article, you could use library to find jobs that match a name by writing a .NET method similar to:
[Serializable]
public class JobDetails
{
public string Status { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
public List<JobDetails> GetJobsByName(string system, string user, string password, string jobName)
{
List<JobDetails> results = new List<JobDetails>();
AS400 server = new AS400();
server.setSystemName(system);
server.setUserId(user);
server.setPassword(password);
JobList list = new JobList(server);
list.addJobSelectionCriteria(JobList.SELECTION_JOB_NAME, jobName);
try
{
Enumeration items = list.getJobs();
while (items.hasMoreElements())
{
Job job = (Job)items.nextElement();
var details = new JobDetails
{
Name = job.getName().Trim(),
Number = job.getNumber().Trim(),
Status = job.getStatus().Trim()
};
results.Add(details);
}
if (server.isConnected())
{
server.disconnectAllServices();
}
}
catch (Exception ex)
{
throw new ApplicationException(
string.Format("Failed to retrieve jobs from server {0}", system), ex);
}
return results;
}
There are a number of attributes you can use to filter and search the jobs on the server, however, for this example I only needed to find jobs that matched a specified JOB_NAME
. I created a simple class to hold the Job Details I was interested in (Status, Number and Name) and had my method return that rather than anything from the jt400 DLL.
This works really well and we can now find all jobs that match a specifed job name from our .NET code - happy days.
The only downside to using jtOpen in .NET is that I don't particularly like mixing the Java cased language with .NET, but there's no way around this if you want to consume the library without porting it by hand. Instead, think about keeping code that uses jtOpen separate from your main application code and write a wrapper method similar to GetJobsByName
that hides the jtOpen syntax and returns .NET objects you have created. This will keep your source clean and consistent.
Hope that helps anyone else who wants to use jtOpen in .NET!
CodeProject