aspose file tools*
The moose likes Distributed Java and the fly likes Add RMI Interface to Existing Application Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Distributed Java
Bookmark "Add RMI Interface to Existing Application" Watch "Add RMI Interface to Existing Application" New topic
Author

Add RMI Interface to Existing Application

David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
I'm a RMI novice. I've got an application that I need to make remotely accessible. It's my understanding that to do this via RMI I need to provide an interface object that implements the Remote interface and all the methods of the class that implement this interface must throw RemoteExceptions. Also, all the data members must be primative or Serializable. Is this correct to begin with?
My problem is that I have a central class which all clients currently instantiate (UPAWrapper). This class executes commands and returns results. The users will instantiate different "Command" objects and get a common "Result" object in response to running the various Commands.
How do I provide a remote interface to this application without modifying my current application such that clients that are not using this application remotely won't need to re-write their implementation.
Also, I'm concerned about providing another "RMI" implementation of my application which would required me to maintain 2 versions of my application (remote and non-remote versions).
Any guidance would be greatly appreciated.
David Sica
davidwsica@hotmail.com
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
I'm assuming that the problem is that you want to make your UPAWrapper an RMI object without modifying the clients which currently use it.
I can think of a solution inspired by Sun's BusinessDelegate and ServiceLocator J2EE patterns. It's difficult to explain, but I'll try
Lets say you create an RMI interface for your object called RemoteUPAWrapperInterface. Now create an RMI implementaton of your object by implementing this interface as well as extending UnicastRemoteObject. Lets call this class RemoteUPAWrapper. This would also have all the functionality of the original UPAWrapper.
Now, normally if your clients have to deal with RMI objects, they have to know how to do lookups as well as handle remote exceptions.
If you do not want to change any code in the clients, you could convert your existing object UPAWrapper into a delegate object, keeping the original interface. On every method call, the new UPAWrapper class simply looks up the RemoteUPAWrapper and delegates the method call to it. The UPAWrapper will also "swallow" all remote exceptions, converting them into already understood application exceptions.
Does this make any sense? Does this solve your problem?
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Thank you for the potential solution. I think I understand what you're proposing. I have a couple questions/comments:
1) Doesn't this mean that all calls to my application now will need to go through the remote interface regardless of whether they need to or not?
2) My first thought on a solution was to create a RemoteUPAWrapper class that extends UnicastRemoteObject and basically instantiates a UPAWrapper in it's constructor and then "wraps" all the methods in UPAWrapper (i.e. there will be duplicate methods in RemoteUPAWrapper that call the corresponding methods in UPAWrapper). This way users can call my application locally with UPAWrapper or remotely with RemoteUPAWrapper.
3) OK, I think maybe I see an advantage to your solution. Although it requires all calls to my application to go through the remote interface (RemoteUPAWrapper) all clients (local or remote) will use the same interface (UPAWrapper) to call my application rather than having to choose whether they call UPAWrapper or RemoteUPAWrapper depending on if they decide to run local or remote. Is this correct?
4) On a separate question regarding the RMI implementation. If I want to use dynamic class loading over the Internet (say by providing my application as a JAR file, upa.jar) can the clients instantiate objects provided in the JAR file which haven't extended Remote? In other words, the clients need to instantiate "Command" classes to pass to the UPAWrapper but I don't want them to be remotely instantiated on the RMI server. It seems that they should be able to instantiate them locally and them pass them into the appropriate methods in UPAWrapper (assuming they implement Serializable) Is this true, do you have comments?
Thank you VERY much for your thoughts and assistance!
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
We could have the best of both solutions:
UPAWrapper:
Interface declaring all methods of the original UPAWrapper.
LocalUPAWrapperImpl:
Implements UPAWrapper and provides all the functionality of the original UPAWrapper.
RemoteUPAWrapper:
Remote Interface declaring all methods of the original UPAWrapper but throwing remote exceptions.
RemoteUPAWrapperImpl:
Implements RemoteUPAWrapper and delegates all method calls to a LocalUPAWrapperImpl.
UPAWrapperDelegate:
Implements UPAWrapper. On every method call, the UPAWrapperDelegate simply looks up the RemoteUPAWrapper and delegates the method call to it. The UPAWrapperDelegate will also "swallow" all remote exceptions, converting them into already understood application exceptions.
UPAWrapperFactory:
Returns a UPAWrapper. Could be a LocalUPAWrapperImpl or a UPAWrapperDelegate, depending on whether the client requires a local or remote object.
All classes required for compilation have to be present in the local classpath, as they are loaded by the system default class loader. In the above case it would include only UPAWrapper and UPAWrapperFactory.
All other classes can be loaded by the RMIClassLoader, including the stub and skeleton classes of RemoteUPAWrapperImpl.
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
OK, I'm still digesting your solution. In the meantime, here's a couple questions that come to mind.
1) For my clients who are now just instantiating a UPAWrapper, how will this change their implementation? Will they now need to call the UPAWrapperFactory to get the UPAWrapper (or actually the LocalUPAWrapperImpl)?
2) Who should make the decision on whether the UPAWrapperFactory returns a LocalUPAWrapperImpl or a UPAWrapperDelagate, my application or the client? I'm assuming it should be my application. If so, how do I determine if they need the LocalUPAWrapperImpl or the UPAWrapperDelagate? In my situation any client calling from the server where the RMI Server will be running will be local and any client not calling from this server will be remote, but how do I implement this logic in code?
Thanks again!
David
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Here's another question not directly related to our evolving solution. A colleague of mine utilizing RMI for a similar solution advocates using a "SessionController" which dynamically binds a new RMI server to the registry everytime a request is made to his application. The client then makes a request to this dynamically bound server. According to him this guarantees that there will be no concurrency problems if multiple clients are requesting his RMI application simultaneously. What are you thoughts on this implementation and how does it affect our evolving solution?
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
1) For my clients who are now just instantiating a UPAWrapper, how will this change their implementation? Will they now need to call the UPAWrapperFactory to get the UPAWrapper (or actually the LocalUPAWrapperImpl)?

The clients will never know about LocalUPAWrapperImpl, they will wil always call the UPAWrapperFactory.
2) Who should make the decision on whether the UPAWrapperFactory returns a LocalUPAWrapperImpl or a UPAWrapperDelagate, my application or the client? I'm assuming it should be my application. If so, how do I determine if they need the LocalUPAWrapperImpl or the UPAWrapperDelagate? In my situation any client calling from the server where the RMI Server will be running will be local and any client not calling from this server will be remote, but how do I implement this logic in code?

I think that the UPAWrapperFactory should know if the client needs a local or a remote UPAWrapper. The UPAWrapperFactory could read a properties file or something while inititalizing. The properties file will tell the UPAWrapperFactory if it resides on the same server as the RMI object, or otherwise.
Please tell me the final solution you choose to implement and why, because I think I definitely would need something similar down the road
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
Here's another question not directly related to our evolving solution. A colleague of mine utilizing RMI for a similar solution advocates using a "SessionController" which dynamically binds a new RMI server to the registry everytime a request is made to his application. The client then makes a request to this dynamically bound server. According to him this guarantees that there will be no concurrency problems if multiple clients are requesting his RMI application simultaneously. What are you thoughts on this implementation and how does it affect our evolving solution?

I'm not sure I fully understand the concept you just explained. How would you maintain the session? Would the client have to inform this Controller when it's done with the remote reference? Will the Controller have to maintain a pool of available and used references?
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Yes, this one is a little hard to explain. Really all that SessionController is doing is creating a uniquely named RMI Server instance and binding it to the RMI Registry for the remote object that is being requested. SessionController then passes this unique name to the client so they can then request this remote object from the RMI server.
The reasoning behind this was that there was concern that if 2 or more clients request the same RMI Server remote object there would be concurrency/synchronization issues. I'm a little confused by this solution so I'm sorry if I'm not explaining it properly.
This colleague was convinced that if 2 clients had a reference to a common RMI server remote object they could conceivably overwrite each other.
Can you confirm or deny any of these assumptions? Let me know if you need additional details, I'll try to provide more info.
I guess the basic question is when 2 or more clients make a request from the RMI server for a remote object do they receive a reference to a common instantiation of the object or do they receive references to unique instantiations of the object??
Thanks,
David
[ April 24, 2003: Message edited by: David Sica ]
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
I guess the basic question is when 2 or more clients make a request from the RMI server for a remote object do they receive a reference to a common instantiation of the object or do they receive references to unique instantiations of the object??

The clients will receive a reference to the same instance of the RMI object. If the clients call the UPAWrapper in a multithreaded environment, and the UPAWrapper is not thread safe, concurrency/synchronization will be an issue. You could either synchronize parts of the UPAWrapper that are not thread safe, or return references to unique intstances of the RMI object for every client request.
If you go that way, the SessionController would have to maintain Session IDs and a pool of used and unused references. The clients would have to inform the SessionController when they are done with their reference so that the SessionController can termintate the session and return the reference to the unused pool.
It almost sounds like you'll be creating your own SessionBean implementation!!!
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
OK, so I'm looking at implementing an object pool to handle the "Sessions". I can provide a method for the clients to "return" the session to the pool when they are done but what if the client neglects to call this returnSession method? Is there a way to determine from the my RMI Server (SessionController) whether a client is still using a reference to one of the sessions? Otherwise, I can see the object pool quickly reaching it's limit thinking that session objects are in use when if fact they are no longer being used by a client.
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
Is there a way to determine from the my RMI Server (SessionController) whether a client is still using a reference to one of the sessions?

Yes, there is, though I have never used it. I think the RMI object will need to implement the java.rmi.server.Unreferenced interface. The RMI runtime calls the unreferenced() method when there are no more clients referencing the object.
I think it treats the RMI registry as a client too, so you won't be able to bind the references to it.
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
OK, then 2 questions:
1) How do I programmatically (from my object pool) determine if the unreferenced() method has been called for a particular remote object?
2) If it's true I can't bind it to the registry how do I make it available for remote access? It seems like it's not very useful if you can't bind it to the rmiregistry.
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
1) How do I programmatically (from my object pool) determine if the unreferenced() method has been called for a particular remote object?

The RMI runtime calls the unreferenced() method on your RMI object when it's no longer referenced by any clients. It's then upto your object to transfer itself from the used pool to the available pool.
2) If it's true I can't bind it to the registry how do I make it available for remote access? It seems like it's not very useful if you can't bind it to the rmiregistry.

Well, you won't need to bind the individual instances of RemoteUPAWrapper to the registry. You will need to make the SessionController a Remote object, and bind it to the registry. The factory will then only lookup the SessionController, and the SessionController will return a RemoteUPAWrapper reference from the available pool.
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Originally posted by Nilesh Pereira:

Well, you won't need to bind the individual instances of RemoteUPAWrapper to the registry. You will need to make the SessionController a Remote object, and bind it to the registry. The factory will then only lookup the SessionController, and the SessionController will return a RemoteUPAWrapper reference from the available pool.

Exactly! I just thought of this as you posted your reply. I guess I don't NEED to bind my new RemoteUPAWrapper to the registry as I previously thought. Passing a reference to the RemoteUPAWrapper gives the client the same access to the remote object as having them look up the remote object via the registry, right?
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
Right. And if you add thread pooling and transaction support you will have implemented an EJB 1.0 container! Are you sure this solution is not an overkill for your problem? Could you not just make your object a Stateful Session EJB and use an off-the-shelf EJB container? I must admit, though, that this would be fun to implement yourself...
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Originally posted by Nilesh Pereira:
Right. And if you add thread pooling and transaction support you will have implemented an EJB 1.0 container! Are you sure this solution is not an overkill for your problem? Could you not just make your object a Stateful Session EJB and use an off-the-shelf EJB container? I must admit, though, that this would be fun to implement yourself...

In fact, I was wondering if it would be more appropriate to go down the EJB road. However, we don't have an EJB container running on the server I need this running on. I actually do have a little experience with JBoss but not much with EJB. I'm scheduled to attend a week-long EJB course in May so I may implement this solution now and then refactor to an EJB solution down the road.
David Sica
Ranch Hand

Joined: Jan 09, 2002
Posts: 39
Does each RemoteUPAWrapper that I instantiate from the Controller run in it's own JVM? In other words, if I have some code in RemoteUPAWrapper to call System.setProperty() will that property only be set for this particular RemoteUPAWrapper instance?
Why I ask this is that I want each RemoteUPAWrapper to be able to write to it's own unique log file using an implementation of JDK1.4 logging but I'm not sure how to specify the logging.properties uniquely for each RemoteUPAWrapper instance.
Any thoughts?
David
Nilesh Pereira
Ranch Hand

Joined: Apr 14, 2003
Posts: 53
Usually, all the RemoteUPAWrapper instances will reside in the JVM they were instantiated. If you need separate JVMs for each instance you can do that by making your RMI object an Activatable RMI object. You need to implement the java.rmi.activation.Activatable interface, as well as register it with the RMI daemon (rmid) I think. You can then choose whether to activate the RMI object in the same JVM or a new one. Making the RMI object Activatable gives several other advantages including some sort of pooling and wake up capabilities. You'll have to look it up for more detailed information.
I haven't used JDK 1.4 or it's new logging mechanisms yet, so I can help you with that. But I'm sure there are plenty of other ranchers who are up to speed with the latest and greatest JDK.
BTW I found a pretty good collection of RMI links including one for using a Factory with RMI objects! Check http://www.dickbaldwin.com/javalinks/jaxarmi.htm out.
 
 
subject: Add RMI Interface to Existing Application