My aim is to call a Web Service from Java, initiated from a RPG function. (I know, its long way around, but it is what we need)
I have created a /JavaLib folder on the AS400, and copied all our needed External Jars we need.
Create a Java class with a static method WebServiceCaller.Call() to call a Web Service. When ever I run my RPG program everything is fine unto the RPG calls this method.
I get a Java exception:
Message . . . . : Java exception received when calling Java method (C G D
F).
Cause . . . . . : RPG procedure WEBSERCALR in program WAL60326/WEBSERCALR
received Java exception "java.lang.NoClassDefFoundError:
javax.xml.rpc.ServiceException" when calling method "Call" with signature
"(LwebService.Input;)LwebService.Output;" in class
"webService.WebServiceCaller".
CLASSPATH variable:
/JavaLib:/home/WAL60326/WebServiceCaller
So I believe my RPG and Java Class is fine, and I believe I have setup my CLASSPATH variable right. Not sure what else there is to check.
Update
So the jar file I need is jaxrpc.jar I have checked; it does exists in my /JavaLib.
Was able to check my Java version on the AS400 java version "1.5.0". And follow these instructions to check that my OS is V6R1.
Could it be my Java version that is out of date, for this Jar file to be loaded/work? Is that even a possibility?
Edit
Here is my source code:
Java: WebServiceCaller.Java
package webService;
import java.rmi.RemoteException;
import stocklistGetBids.GetBidsProxy;
public class WebServiceCaller {
public static Output Call(Input in) { // Input Class, is just a way to hold all the input together
Output out = null; // Output Class, holds all the output together
try {
GetBidsProxy getBidsProxy = new GetBidsProxy(); // GetBidsProxy generated by Eclipse
out = new Output(getBidsProxy.getBids(in.LogKey, in.Id));
} catch (RemoteException e) {
e.printStackTrace();
out = new Output("ERR");
}
return out;
}
}
Take note that the GetBidsProxy class in generated by Eclipse. And the Java side works well on my Windows Machine. Just not on the AS400 Machine.
RPG: WEBSERCALR.RPGLE
H DFTACTGRP(*NO)
H thread(*serialize)
D WebsercalInput DS
D ReturnCode 7A
D LogKey 20A
D ID 20A
D jString S O CLASS(*JAVA:'java.lang.String')
D jLogKey S O CLASS(*JAVA:'java.lang.String')
D jID S O CLASS(*JAVA:'java.lang.String')
D Input S O CLASS(*JAVA:'webService.Input')
D Output S O CLASS(*JAVA:'webService.Output')
D new_Input PR O EXTPROC(*JAVA:
D 'webService.Input':
D *CONSTRUCTOR)
D LogKey like(jString)
D ID like(jString)
D new_String PR O EXTPROC(*JAVA:
D 'java.lang.String':
D *CONSTRUCTOR)
D bytes 30A CONST VARYING
D Call PR like(Output)
D EXTPROC(*JAVA:
D 'webService.WebServiceCaller':
D 'Call')
D STATIC
D in like(Input)
D getReturnStat PR O EXTPROC(*JAVA:
D 'webService.Output':
D 'getReturnedStatus')
D CLASS(*JAVA:'java.lang.String')
D getBytes PR 65535A VARYING
D EXTPROC(*JAVA:
D 'java.lang.String':
D 'getBytes')
C *ENTRY PLIST
C PARM WebsercalInput
/free
jLogKey = new_String(LogKey);
jID = new_String(ID);
Input = new_Input(jLogKey:jID);
Output = Call(Input);
jString = getReturnStat(Output);
ReturnCode = getBytes(jString);
return;
/End-Free
The CLASSPATH is read only once for a given job, the first time you invoke the java command and the JVM starts. If your CLASSPATH changes after that, the JVM won't see or use the new CLASSPATH. Sign off and on (to start a new job), set the CLASSPATH (I do it in my signon program) and then try to use the class you're working with.
If the CLASSPATH is correct then the other thing to check is the Java prototype in your RPG program. It needs to exactly match the Java class definition.
First, make 100% certain that your jaxrpc.jar has all the classes you think it should. Start QShell, then java tf /JavaLib/jaxrpc.jar. Make sure you have at least these:
javax/xml/rpc/Call.class
javax/xml/rpc/ServiceFactory.class
javax/xml/rpc/ServiceException.class
Next, do a simple proof of concept program in pure Java to make sure all of the pieces work as you expect them to. Note: JAX-RPC is obsolete and goes away in Java 1.6 and up. It's been replaced by JAX-WS. If this is a brand new app, consider using the more current implementation. This 2006 DeveloperWorks article explains some of the differences.
Once you have a pure Java program written, it's time to take the Java classes that you used and prototype them in RPG. Assuming you've done all of that, could you edit your question to show the RPG *CLASS prototypes and the RPG code used to invoke them. Basically, see if someone reading this question can re-create the set-up on a different box.
I've used some Java in my RPG code and I found out that it's not enough to add the container folder to the CLASSPATH. I had to identify the individual jars in the CLASSPATH.
Related
I have a program using the Luaj 3.0 libraries and I found some lua scripts I want to include, but they all require lua file system and penlight and whenever I try to use those libraries, it gives an error.
Does anyone know how I am supposed to make use of those in Luaj?
Edit:
A little more information might help:
I have am Archlinux 64bit system with open-jdk8 Luaj, lua-filesystem, and lua-penlight installed. I found a set of libraries called Lua Java Utils which I want to include in my project. But it always gets this error:
#luaJavaUtils/import.lua:24 index expected, got nil
Line 24 for reference:
local function import_class (classname,packagename)
local res,class = pcall(luajava.bindClass,packagename)
if res then
_G[classname] = class
local mt = getmetatable(class)
mt.__call = call -- <----- Error Here
return class
end
end
It requires the penlight library which in turn requires lua filesystem which is why I installed the two. I found through testing that Lua filesystem wasn't loading by trying to run lfs.currentdir(). I tried globals.load("local lfs = require \"lfs\"").call(); but it also gave an error.
My Lfs library is located at /usr/lib/lua/5.2/lfs.so and penlight at /usr/share/lua/5.2/pl.
This Is an Issue in the Luaj 3.0 and Luaj 3.0 alpha 1.
The lua package.path is being ignored while requiring a module. Here's a workout for this.
You can override the require function:
local oldReq = require
function require(f)
local fi = io.open(f, "r")
local fs = f
if not fi then
fi = io.open(f .. ".lua", "r")
fs = f .. ".lua"
if not fi then
error("Invalid module " .. f)
return
end
end
local l = loadfile(fs)
if not l then
return oldReq(f)
end
return l()
end
I am trying to access a device through a COM object in a JAVA interface.
The particular call (as described by the manufacturer) is:
Name: ScanUSB
Parameters: [out] VARIANT* serialNumbers
Use: serialNumbers is a pointer to a VARIANT containing an array of BSTR.
The exact call doesn't matter, but I need to feed it a BSTR array through the Java interface. A VB demo for the COM interface simply does this with the commandlm_Co1.ScanUSB(snNum), with Dim snNum As Object = Nothing. The Items in snNum are then displayed in a dropdown menu.
I am trying to do this with JACOB, as I have had the most luck with communication. This is more or less what I am using:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
public JunoReader() {
Dispatch oOphirLink = new Dispatch("clsid:{--the id of the device here--}");
Variant snNum = new Variant();
Variant testing = Dispatch.call(oOphirLink,"ScanUSB", snNum);
println(testing);
}
}
When I run this, everything compiles properly and I can confirm that I am communicating with the device, but all I get back is the null Variant that I put in.
My question is: How can I feed a BSTR array to a COM object through a JAVA interface?
Thanks!
So, one month and zero free time later, I have an answer to my own question and that answer is "Use Python".
Python allows users to access COM objects with the comtypes module, effectively with a single command:
from comtypes.client import CreateObject
target_guid = CreateObject("{TARGET-COM-CLSID-HERE}")
This allows python to talk with whatever the COM object is, so there was none of the trouble that Java was giving me. The single line: target_guid.ScanUSB() produced (u'717610',), the serial number of the target device. Notice that Python has no trouble reading the Unicode produced by the COM object.
The second trick involves Python's COM server, generated with the win32com module. Because the COM servers can be registered to Windows, I don't have to worry about where the dll is located. All I need is the clsid. To build the python COM server, I followed the instructions for a "quick start to server side COM and Python". So what does it all look like?
Python code:
class OphirPyCOM:
_reg_clsid_ = "{PYTHON-COM-CLSID-HERE}"
_reg_desc_ = "Python COM server"
_reg_progid_ = "Python COM server"
_public_methods_ = [ 'Hello',
'ConnectOphir',
'ScanUSB', """More methods here"""
]
_public_attrs_ = ["""Some public attributes"""]
_readonly_attrs_ = ["""some read-only attributes"""]
def __init__(self):
"""some variables declared here"""
def Hello(self, who):
"""Verifies a connection"""
return "{PYTHON-COM-CLSID-HERE}" + str(who)
def ConnectOphir(self,clsid):
"""Connects to the target COM Object"""
from comtypes.client import CreateObject
self.target_guid = CreateObject(clsid)
return "OphirLMMeasurement object created."
def ScanUSB(self):
"""Communicates with the target device"""
self.connected_inst = self.target_guid.ScanUSB()
for i in range(0,len(self.connected_inst)):
self.inst_list.append(str(self.connected_inst[i]))
return self.inst_list
if __name__ == "__main__":
# use 'python com.py' to register the COM server
# use 'python com.py --unregister' to unregister it
print "Registering COM server..."
import win32com.server.register
win32com.server.register.UseCommandLine(OphirPyCOM)
We can run that with the command line and get it registered. Then we take the values over to Java with JACOB:
import com.jacob.com.Variant;
import com.jacob.com.Dispatch;
public class JunoReader {
String pyClsid = "{PYTHON-COM-CLSID-HERE}"; // This is where your python COM clsid goes
String opClsid = "{TARGET-COM-CLSID-HERE}"; // This is where your ultimate target clsid goes
public JunoReader() {
_pyClsid = "clsid:" + pyClsid
// This finds the COM object location:
Dispatch oOphirLink = new Dispatch(_pyClsid);
}
public String HandShake() {
String _talkBack = "is connected.";
Variant _handShake = Dispatch.call(oOphirLink,"Hello",_talkBack); // I am trying to look for the Juno...
return (_handShake.toString());
}
public String ConnectOphir() {
Variant _connectOphir = Dispatch.call(oOphirLink,"ConnectOphir", opClsid); // Connect to the target COM object
return (_connectOphir.toString());
}
public String ScanUSB() {
Variant _serialNumberList = Dispatch.call(oOphirLink,"ScanUSB"); // This scans the USB ports for devices
return (_serialNumberList.toString());
}
}
calling JunoReader.ScanUSB() produces: 717610, exactly like it is supposed to. Implementing the subsequent methods of the manufacturer dll allowed me to read data from this device into a Java applet. Problem solved.
A caveat: you may need to unregister the Python COM every time you change the change the source file and then re-register with a different clsid. Java was having a tough time establishing a connection to the updated code unless I used a new clsid every time I changed the file.
Why did I spend all this time typing this up? Because most of the advice related to reading native data types into Java involved some version of JNI and JNA. I spent weeks trying to get the tutorials to compile and didn't make any progress. On the other hand, I thought of this approach yesterday and can now communicate with my device through Java. The Python COM server provided a simple, straightforward way to interface Java with native applications. No UnsatisfiedLinkErrors, no Can't find librarys, no Classpath and JAVA_HOME issues. I didn't need to learn C or C++ and all the Python tutorials worked as described with no necessary modification.
To summarize, if you are having trouble reading native data types into Java, just set up a Python COM server and let Python's dynamic typing do the work for you.
I have the follow Java code that uses Rcaller.
RCaller caller = new RCaller();
RCode code = new RCode();
caller.setRscriptExecutable("/usr/bin/Rscript");
code.addRCode("install.packages(\"bbmle\")");
caller.redirectROutputToConsole();
caller.runOnly();
Essentially, I'm trying to run Java code that installs an R package (because later I will run R code within Java that requires this package).
When I run this code, I get the following output in Java
Error:Loading required package: Runiversal
However, I do have the Runiversal package on my Mac. Any ideas what this means, and why I'm not actually seeing any R output of the install.packages method, which is normally quite verbose?
UPDATE: I should note that even simple code such as the following results in the same error:
code.addRCode("x = c(1,2,3)");
code.addRCode("y = c(2,3,5");
code.addRCode("x+y");
caller.redirectROutputToConsole();
caller.runOnly();
UPDATE: I should also mention that the following works great:
StringBuffer allCode = readFile("temp.R");
code.setCode(allCode);
double[] xvector = new double[]{1,3,5,3,2,4,5,6,7,8,9,21,22,25,27,25,34,39,31};
double[] yvector = new double[]{6,7,5,6,5,6,6,7,6,8,9,21,20,19,23,24,29,38,30};
code.addDoubleArray("X",xvector);
code.addDoubleArray("Y",yvector);
code.addRCode("fun(X,Y)");
temp.R:
fun = function(x,y) {
return(lm(y~x))
}
Java output:
Output:
Output:Call:
Output:lm(formula = y ~ x)
Output:
Output:Coefficients:
Output:(Intercept) x
Output: 2.445 0.825
Output:
R loads package from the libraries. If the library that you installed the Runiversal package into is not being searched by the R process started under Java, that could result in the error message you're seeing.
So: what is the directory path (i.e., library) that the Runiversal package is installed in? Possibly related to this is what user installed the R package, and what user is running the Java code.
The 2.2 version of RCaller library does not require the R package Runiversal. A compact version of R to XML converters are implemented in the package. Try it out here
In past years, we created a program that uses X25 protocol. It was made in C language and works fine for a Sun-Fire machine with Solaris 5.9.
Recently, we are working with java 6 in same machine, and we are trying to adapt that old program in C for working with java via jni.
So I have done some modifications to the old C program and created a shared library named x25lib.so
But I have found a runtime problem using jni and X25: When the C function is invoked from java via jni, the C code does not work in a same way that when it is invoked from another C program.
Concrete, using jni, the C code in shared library works fine until is invoked the system call connect(), then returns -1,
But invoking the same C code of my shared library from another C program returns 0 (ok)
In both cases, the C code in shared library doesn´t receive external parameters so the conditions are the same, I don´t understand if loading my "x25lib.so" shared library from java have a little difference that induce connect() in C fails.
using "truss" command from java I have found the error:
/2: connect(5, 0xFD878B75, 112, 1) Err#22 EINVAL
the same, but invoking the shared lib from another C program:
connect(4, 0xFFBFE794, 114, 1) = 0
So it works ok only with pure C,
Is there another consideration for using jni and X25 for solaris 5.9?
IMPORTANT: C Code in shared library is identical in both cases.
COMPILATION TIME:
a. Creating x25lib.so
cc -w -fd -G -Kpic subs.o -L/opt/SUNWconn/lib -R/opt/SUNWconn/lib -lsockx25
-lsocket -lnsl -I"/SDK/jdk/include/" -I"/SDK/jdk/include/solaris/"
-o x25lib.so -h x25lib.so x25jni.c
b. Creating a test C program with that shared library:
cc -w x25lib.so -o x25test x25test.c
where `x25test.c` contains:
#include <stdio.h>
main()
{
java_x25();
}
c. Using java:
public class X25 {
static {
System.load("/home/x25lib.so");
}
public native void ejecutaComando();
}
public class TestX25 {
public static void main(String ... args) {
X25 x25 = new X25();
x25.ejecutaComando();
}
}
Then in C code shared library:
/*
* Class: X25
* Method: ejecutaComando
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_X25_ejecutaComando
(JNIEnv *env, jobject obj)
{
java_x25();
}
So finally both programs (java y C) call exactly the same C code in shared library:
java_x25()
Without parameters, so execute the same code.
Why works fine when is called from C, but fails when is called from java?
Thanks for any advice.
Thanks for your comments. I have found a solution while I was trying another approach: I decided not using jni, instead I adapted the old C program for listening for simple tcp connections from java and then could execute x25 code, but surprise, I got the same runtime error like using jni:
connect(5, 0xFD8789C5, 112, 1) Err#22 EINVAL
including a size of 112 instead 114, it was the same problem.
So I noticed that the problem was that I had compiled the new C program with "-lsocket" option before "-lsockx25", so that was a clue. Then I searched in google and I found a similar problem:
link to java X25 Bug ID:4077576
At the end of that article, it is mentioned the option LD_PRELOAD to force sockx25 library be loaded first. Finally the solution was at runtime:
bash$ export LD_PRELOAD=/opt/SUNWconn/lib/libsockx25.so
bash$ java TestX25
and then all is working fine using jni.
Reference for LD_PRELOAD: link to java tuning
Some observations (please post your code if you would like us to go deeper on this -- in particular the part that sets up the parameters to connect()):
Assuming X.25 over TCP(?):
From the man page EINVAL is returned from connect(3socket) "namelen is not the size of a valid address for the specified address family" where namelen is the sockaddr structure defined in <sys/socket_impl.h>. namelen is typically 16 (a 2-byte address family (I'd expect SOCK_STREAM) followed by 14 octets of address data). Your program returns namelen 112 or 114.
The address of name in your failing truss(1) output above 0xFD878B75 is odd (odd in the sense "not even"). Given Solaris' typical alignment requirements this seems strange. (SPARC or x86? What compiler and flags?). Perhaps a pointer or sizeof problem?
From your truss(1) output can see that threads are being used in the java invocation. Are your libraries thread-safe?
I have an application which is running on tomcat, one of the methods is, creating a simple thumbnail from an jpeg image. The functions works fine offline and a week ago also on tomcat. But now i get the following error:
java.lang.NoClassDefFoundError
java.lang.Class.forName0(Native Method)
java.lang.Class.forName(Class.java:164)
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(GraphicsEnvironment.java:68)
java.awt.image.BufferedImage.createGraphics(BufferedImage.java:1141)
eval.impl.ImageEval.getThumbnail(ImageEval.java:155)
eval.impl.ImageServlet.doGet(ImageServlet.java:79)
javax.servlet.http.HttpServlet.service(HttpServlet.java:690)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
I don't think that i have change anything what should influence this (actually i didn't change the function at all according to the svn repository), so it must be a library problem. But i can't figure out what is missing.
Here are the actual lines from the getThumbnail function, where the error occures:
BufferedImage thumbImage = new BufferedImage(thumbWidth,
thumbHeight, BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = thumbImage.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.drawImage(simage, 0, 0, thumbWidth, thumbHeight, null);
[edit] I decided to update the problem description a little.
Yes it seems that he can not find some class from java.awt or one related to that. But they do exist on the server in the jvm. Java headless mode doesn't solve the problem.
In another project the exact same code, but inside an axis2 webservice on this server is working fine.
[/edit]
It seems like you've change the configuration of Tomcat.
Either you've changed to a l{0,1}[iu]n[iu]x box or installed on a virtual machine with different security control than the one where you test it.
Apparently the
GraphicsEnvironment.getLocalGraphicsEnvironment()
Is trying to access the property: java.awt.graphicsenv
Which may return null or some non existing class name which is then loaded and throws the ClassNotFoundException. 1
The solution seems to be specifying the "java.awt.headless" property.
This is a similar question: java.awt.Color error
Try this search , it shows similar situations as your.
I remember there was something in the sun bugs database too.
Post the solution when you find it!
1.GraphicsEnvironment.java
EDIT
It is not eclipse!!
In my original post there is a link to the source code of the class which is throwing the exception.
Since I looks like you miss it, I'll post it here for you:
public static synchronized GraphicsEnvironment getLocalGraphicsEnvironment() {
if (localEnv == null) {
// Y O U R E R R O R O R I G I N A T E S H E R E !!!
String nm = (String) java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction
("java.awt.graphicsenv", null));
try {
// long t0 = System.currentTimeMillis();
localEnv =
(GraphicsEnvironment) Class.forName(nm).newInstance();
// long t1 = System.currentTimeMillis();
// System.out.println("GE creation took " + (t1-t0)+ "ms.");
if (isHeadless()) {
localEnv = new HeadlessGraphicsEnvironment(localEnv);
}
} catch (ClassNotFoundException e) {
throw new Error("Could not find class: "+nm);
} catch (InstantiationException e) {
throw new Error("Could not instantiate Graphics Environment: "
+ nm);
} catch (IllegalAccessException e) {
throw new Error ("Could not access Graphics Environment: "
+ nm);
}
}
return localEnv;
}
That's what gets executed.
And in the original post which you don't seem to have read, I said the code is accessing the property "java.awt.graphicsenv"
If that other project using axis doesn't have the same problem it may be because it may be running in a different tomcat configuration or the axis library allowed the access to that property. But we cannot be sure. That's pure speculation. So why don't you test the following and see what gets printed:
String nm = (String) java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction
("java.awt.graphicsenv", null));
System.out.println("java.awt.graphicsenv = " + nm );
It it prints null then you now what the problem is. You don't have that property in your system, or the security forbids you do use it.
It is very hard to tell you from here: "Go and edit file xyz and add : fail = false" So you have to do your work and try to figure out what's the real reason.
Start by researching what's the code being executed is ( which I have just posted ) and follow by understand what it does and how does all that "AccessController.doPrivileged" works. (You may use Google + StackOverflow for that).
We had a similar issue and after much trouble shooting it was identified to be related to the java.awt.headless property. The issue was resolved by explicitly setting the JVM option to
-Djava.awt.headless=true
It was running a week ago, and now it is not.
THEREFORE, YOU CHANGED SOMETHING BETWEEN "working" and "not working".
Go back to the working config (if you can), and rigorously track what you changed. If you don't have a backup of the working config, then meticulously go back through what you've done between working and non-working until you find what you changed.
It may not be code - it could be a config file, etc.
Best of luck,
-R
Is this server running java in server mode - I hear that doesn't load in the AWT classes.
If you are deploying this on *nix, and you don't have an X window system running anymore, that could explain it. Even if you do, if you aren't exporting the DISPLAY system variable to the process that starts the JVM, or if you are but it is not actually valid, it could cause such an issue.
That would at least explain why you didn't change any configuration in tomcat, but still have a problem.
If your NoClassDefFoundError has no message at all, then this means two things:
The JVM has already tried and failed to load a class. Usually, this means the JVM was unable to complete static initialization for that class, i.e. assign values to any static fields and run any static { } blocks. Often, this is because the classes necessary to do this static initialization are missing.
You're using Java 5, not Java 6. (In Java 6, you get a 'Could not initialize class xyz' message instead.)
The problem class appears to be the one whose name is the value of the system property java.awt.graphicsenv. I would start by finding out the value of this property. What happens when you try to instantiate this class?
Since you're getting NoClassDefFoundError from inside the AWT code, it looks like Java is failing to load the X Windows libraries. Note that even if you're running in headless mode ($DISPLAY not pointing to an X Windows server), AWT still needs some subset of the X11 libraries in order to render images. See, for example, this reference:
http://javatechniques.com/blog/linux-x11-libraries-for-headless-mode
If something stopped working and your Java code didn't change, it's possible that the X11 libraries got moved or uninstalled on your machine, or that for some other reason your LD_LIBRARY_PATH environment variable doesn't point to them anymore.