• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

RMI client/server JVM

 
Ranch Hand
Posts: 59
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When a remote object creates a new object - is it created in the JVM it (remote object) came from or the JVM that currently has a hold on it? Does CORBA work differently?


example : I wrote some native c++ code to access our calendar system... I wanted to put that on the server, than each client can log in and get an object that can handle the job. However , the clients seem to want to create the objects locally - or at least run the code locally ( calendar system isn't on client machines ).

I also did run the program successfully using one calendar-obj that was created before any clients logged in - they used that pre-created object instead of creating individual ones, and than made calls to the calendar software from their machines. So it seems the code only wants to run locally if I create it from a client machine vs getting it already created.

One last thing - the calendar object is serializable - but thats it. I don't try to export it or set it up to be remote.

Would the serializable-only be causing my problem? or would reworking this with CORBA work? ( dont know anything about corba) Thanks.

Rich
 
Bartender
Posts: 4121
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When a remote object creates another object it is created in the JVM that the remote object is actually running in - not in the JVM of the client that called the remote object. I'm not as familiar with CORBA, but as I understand it, it works the pretty much the same way.

The only way the client JVM can get a reference to the object on the server is for the server to send it as a return value of a remote method. (Yes... you could also do some other things like bind a new remote service and tell the client to look it up, but the usual case is just to return the object as a return value from a remote method.)

If the object being returned is Serializable, the client recieves a *copy* of the object from the server. Serialiazable classes should basically be the "data" classes in your application. There shouldn't be much "code to be run" in their methods. If the object being returned is Remote the client recieves a *stub* to the object on the server. Remote classes basically offer methods for the client to call that actually run on the server.
 
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Nate,

Maybe you can help me see this problem a little more clearly.

I'm working on a "server" to access QuickBooks, which requires sdkjcalls.dll to be in the PATH. No problem on the server. My client is getting an error that one of the methods can't be found, and I'm thinking that the dll needs to be on the client also. This is obviously not what I want.

Based on your post, it's likely because Naming.lookup() returns the interface that will be doing the QB access. I don't have the code in front of me, but this is basically how it looks:

On the server:
QBServer.java
main()
{
Naming.rebind("QBServer", new QBAccessor());
}

QBAccessor.java
public boolean connect()
{
// requestProcessor is from the QBSDK
requestProcessor.connectToQB();
}

QBAccessorIntf.java
public boolean connect();

On the client:
QBClient.java
main()
{
QBAccessorIntf qbAccessor = (QBAccessorIntf) Naming.lookup("//server/QBServer");
if (qbAccessor.connect()) // blows up here
{
// do something
}
...
}

QBAccessorIntf.java
// just like the server copy


I'm using netBeans 4.1 on both the client and the server, and I can set break points and see execution hit the server, but the error is always raised on the client, which is what led me to think that the client is wanting the dll.

If I understand your post correctly, my problem is the result of returning the actual worker bee in Naming.lookup. If I return something else, something that can create the worker bee, then my problem should be resolved?

Thanks for you insight,
Phillip
[ June 22, 2005: Message edited by: Phillip Koebbe ]
 
Phillip Koebbe
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Well, I gave my idea a shot and I'm still facing the same error, which is:



This is a very simple application, so I will post the code for you to see.

First, the server project:
QBServer.java


QBServerLinkIntf.java


QBServerLink.java


QBAccessor.java


RequestProcessor.java
This file was supplied by Intuit and is the wrapper around their native calls in the dll. I've removed comments to short this post.


Now, the client project:
QBClient.java


QBServerLink.java
Same as in server project.

For each project, I'm using the default package. I know that is discouraged, and I don't intend to do that for production, but I'm just trying to get a working test case right now. I know that I can query into QuickBooks because I've got another "tester" that works. It's just not client/server like I am needing.

I apologize for the lengthy post. I do appreciate all the help I can get.

Peace,
Phillip

[ June 22, 2005: Message edited by: Phillip Koebbe ]
[ June 22, 2005: Message edited by: Phillip Koebbe ]
 
Nathan Pruett
Bartender
Posts: 4121
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


QBServerLink.java
Same as in server project.



Shouldn't this be QBServerLinkIntf? Still... that's not causing the error you are seeing...

Here's what I think the issue is - The server isn't finding the "sdkjcalls" DLL (or another DLL sdkjcalls is using). Move it somewhere the JVM can find it - the windows/system32 directory, the Java/bin directory, add the directory to the system path, or specify the path using the "java.library.path" property. Strange that it worked in your earlier test program, though... maybe it got moved around?

The error that you are getting is not being wrapped in a RemoteException because you are catching all *Exceptions* and rethrowing them as RemoteExceptions - but you're getting a java.lang.UnsatisfiedLinkError - which is an *Error* - higher up the chain than Exception - try catching "Throwable" instead. Also, in several places you are constructing a RemoteException, but never throw it... so the program just silently fails with no indication that anything went wrong.
[ June 23, 2005: Message edited by: Nathan Pruett ]
 
Phillip Koebbe
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Nathan Pruett:


Shouldn't this be QBServerLinkIntf? Still... that's not causing the error you are seeing...



Sorry. I miss-typed. It's the interface.


Here's what I think the issue is - The server isn't finding the "sdkjcalls" DLL (or another DLL sdkjcalls is using). Move it somewhere the JVM can find it - the windows/system32 directory, the Java/bin directory, add the directory to the system path, or specify the path using the "java.library.path" property. Strange that it worked in your earlier test program, though... maybe it got moved around?



Surprisingly, it didn't get moved around. I put it in WINNT\system32 and the other program works fine. There are some differences with the other program, namely it's not client/server and it has all QuickBooks-related code in one procedure. I'm trying to split it out and make it actually usefule to my application.


The error that you are getting is not being wrapped in a RemoteException because you are catching all *Exceptions* and rethrowing them as RemoteExceptions - but you're getting a java.lang.UnsatisfiedLinkError - which is an *Error* - higher up the chain than Exception - try catching "Throwable" instead. Also, in several places you are constructing a RemoteException, but never throw it... so the program just silently fails with no indication that anything went wrong.



Please forgive my horrid use (or lack thereof) catching and rethrowing these things. I've been doing Java development for only a few months, and this is my first foray into RMI. I have not yet had ocassion to throw my own exceptions, and I was copying and pasting someone else's code.

I see your point, though. Since the error was actually an *error* instead of an *exception*, there was no handler for it and it got passed back to the caller, which didn't have a proper handler, so it all just blew up.

I very much appreciate your help. I've been scouring the internet for help on various issues, and I just haven't been able to find very many resources of solid, complete examples of how to do things. I've been taking the basic "Hello World" type of examples and trying to turn them into something I could use in production. Finding Java Ranch was a treat, that's for sure!

I'll get on this and let you know how it goes.

Peace,
Phillip
 
Phillip Koebbe
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I am confused. I removed sdkjcalls.dll from WINNT\system32 and ran the "other" program (tester), and it failed. I put the dll back in system32 and ran tester again, and it worked correctly. Ok, great. The JVM can locate and use the dll.

Run QBServer. No dice. Still getting the UnsatisfiedLinkError. Although, now, I can see that it is happening on the server. I've experimented with putting the dll in different places, such as <java>\jre\bin, and attempting to set the java.library.path property, though I'm not sure that I did that correctly. In netBeans IDE 4.1, I added -Djava.library.path=file://k/source/QBSERVER/dlls/ to the VM Options text box in Run of Project->Properties. That may not be correct. But since the JVM found and used the dll in system32, it seems that the library path shouldn't be necessary.

Peace,
Phillip
 
Phillip Koebbe
Greenhorn
Posts: 27
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, I figured out my problem, except that I don't understand the solution. I started thinking about what was different between the project that worked and the one that didn't, and I then began to change things about the one that didn't to make it as much like the one that did as I could. I still didn't get it to work. So then I started changing the one that did work to be like the one that didn't work, and guess what...I made it stop working. I was getting the exact same error. The problem?

The tester program that I have came from Intuit's developer network, and I'm pretty sure that it was someone with Intuit that wrote it. They originally had the RequestProcessor class in a package called com.intuit.publicdomain. Because I was working in the default package, I removed the package statement from RequestProcessor.java and moved the file. I also removed the import statement from tester.java, the only other class file in the project. It compiled just fine. However, when it executed, it generated the UnsatisfiedLinkError. Solution? Put it back into com.intuit.publicdomain. I don't understand how the dll could know what package the RequestProcessor was in, nor do I see why it would care, but somehow it does.

So, I made similar changes in my client/server RMI project and it is working now. Two days spent on this. *sigh* My "hourly rate" for this project continues to shrink.

Thanks for the insight Nate. I'm sure I'll be back with more questions. Maybe I'll learn how to write shorter posts between now and then.

Peace,
Phillip
 
Nathan Pruett
Bartender
Posts: 4121
IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Ah... it was really a JNI problem then.

Inside the native code part of the JNI the full name of the java class is prepended to the function name. The package is part of the "full name" - so if you change the package in the java portion, you have to change the code in the native portion. Since you just changed code on the Java side the native calls couldn't find the appropriate function in the DLL and blew up.

Glad you finally got it all to work, though!
[ June 24, 2005: Message edited by: Nathan Pruett ]
 
Author and all-around good cowpoke
Posts: 13078
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Using the "default" package in any sort of server environment is dangerous. The JVM tries to find the class in the "current" directory - which you may have no control over. This trips up a LOT of Tomcat beginners.
Much safer to just always use packages for any serious work.
Bill
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic