I would like to make a project with RMI, but I would like to know this. Is it possible to create new remote objects on demand while the server is operating? If so, is there anything special needed?
The short answer is, yes.
There are some caverts though.
The object begin returned to the client must implement a interface that the client has access to
The object begin returned must implement the Remote interface (or implement an interface that extends from Remote)
Basically, the object the is "exported" to the RMI server would act as a factory that the client would be able to call and it would then create what ever new remote objects it required.
Related
I am in the process of creating a game using Java. It is requested of me that the player of the game can choose to connect either through a RMI connection or a Socket one. Until now I have created all the necessary components for the game, but when it comes to creating the RMI connection, i'm having a bit of problem. From what I have read in regards of RMI all the objects used to create the connection need to be declared Remote (for example implement the Serializable interface). Seeing that I have to create both types of connections, I don't see it reasonable to serialize all the objects created so far. At this point I can think of two possible solutions:
Create a remote version of the necessary objects for the connection(for example by creating a class that extends said object and implements Serializable interface to make the object remote). After doing that, I can define the methods applicable to the remote objects that can be invoked by the clients.
Create this new type of remote objects that are just messages that take the requests from the client and "translate" them to the non remote objects and then proceed to do what was requested.
I am new to Java and I would appreciate your time and patience on this question.
From what I have read in regards of RMI all the objects used to create the connection need to be declared Remote (for example implement the Serializable interface).
You didn't read that anywhere. It doesn't even makes sense. Implementing Remote doesn't make an object Serializable. You have to
Design a remote interface that extends Remote.
Ensure that every object that will be passed or returned via this interface implements Serializable or, in rare cases, a remote interface.
Write an implementation of the interface, that typically extends UnicastRemoteObject.
If you have any remote objects at (2), repeat.
Seeing that I have to create both types of connections, I don't see it reasonable to serialize all the objects created so far.
You don't have any choice about (2), although that is unlikely to include all the objects created so far. In any case you would already have had to do it for objects you were planning to send over a socket.
At this point I can think of two possible solutions:
Create a remote version of the necessary objects for the connection(for example by creating a class that extends said object and implements Serializable interface to make the object remote).
Again this is just nonsense.
After doing that, I can define the methods applicable to the remote objects that can be invoked by the clients.
That corresponds to my step 1.
Create this new type of remote objects that are just messages that take the requests from the client and "translate" them to the non remote objects and then proceed to do what was requested.
This also is nonsense.
Is there an easy, elegant and clever way to move objects between different RMI instances?
At the moment I would perform this task by cloning the object in the receiving RMI server and then destroying the original in the sending RMI client (or other way around when moving from RMI server A to RMI server B).
I guess, I will also have to clone and destroy all objects of the object?
If your object implements "Remote" interface, it is passed by reference.
If your object doesn't implements "Remote" interface, it is passed by value.
You have to take a decision depending on type of the object.
Java documentation
Passing Objects in RMI
Arguments to or return values from remote methods can be of almost any type, including local objects, remote objects, and primitive data types.
The rules governing how arguments and return values are passed are as follows:
Remote objects are essentially passed by reference. A remote object reference is a stub, which is a client-side proxy that implements the complete set of remote interfaces that the remote object implements.
Local objects are passed by copy, using object serialization. By default, all fields are copied except fields that are marked static or transient. Default serialization behavior can be overridden on a class-by-class basis.
It is not necessary to clone the received object.
It is enough to create a reference to it.
The received object is already a copy (in the server b) of the original object used in the rmi call (in the server a).
I've got a large Java-based API and for security reasons I'm trying to divide it into a client-to-application server architecture. I've already determined that there are no so-called "Java Application Servers" (frameworks) extant that can help me here, but if I'm wrong, please point me at one that's not restricted to web-oriented applications. That is, I'm "rolling my own" application server.
The existing API is already accessed via method calls to an instantiated instance of a single "object" that implements what needs to be done.
IIUC (If I understand correctly), I can set up an RMI server that instantiates individual instances of the API object - maybe instantiate a pool of them - and then "hand them" as object instances to inbound RMI calls from clients who ask for an instance. They can then call any methods of that instance, and all the actual processing of those methods happens on the server's side, with any results returned through the RMI mechanism.
So far so good, I think. Now for the tricky part I'd like clarification on, please:
If I've got it right, I further understand that either all the methods and attributes are exposed (via "extends UnicastRemoteObject" or I can restrict the attributes and methods I'd like to have available remotely by creating an intermediary class definition whose methods are all defined in an interface.
Am I correct in understanding that using this approach I can then have my original API as-was, and only need to create this one "encapsulating class" which exposes what needs to be exposed?
And moving to a more advanced design, as instantiation is expensive, I'd like to have a pool of pre-instantiated instances; would I need yet another class that instantiates a bunch of these exposable objects and then "returns" them to a calling client? Or, can I do that somehow within the existing RMI machinery - or within my encapsulating API-Server class itself?
When you extend UnicastRemoteObject (or export a Remote object) and implement an interface that extends Remote, the methods declared in that Remote interface are exposed for remote invocation. When these methods are invoked by a client, the execution of the method takes place on the server. Only data contained in the method result, if any, is exposed to the client.
If you want multiple instances of the remote object, you can bind them in a registry under distinct names, or you can create another remote type that returns instances of your Remote service. Here is a simple sketch:
interface MyService extends Remote {
void doStuff() throws RemoteException;
}
interface MyServiceManager extends Remote {
MyService getService() throws RemoteException;
}
You would then bind a single MyServiceManager instance in an RMI registry so that clients can find it. The MyService instances should not be bound in the registry; anonymous instances will be returned via MyServiceManager. Since these objects are also Remote, only a stub will be returned to the client, and when the client invokes a method on it, the method will be executed on the server.
You might be thinking why would you want to have an object both Remote AND serializeable. Well let me give you some context.
I'm building an air traffic control system (school project), it's distributed so that each control zone runs on it's own server and communicates with other control zones. Each control zone keeps track of its own aiplanes.
When an airplane (flying in controlzone A) is 100km near its border, it is passed as a remote object to the controlzone (controlzone B) it's near to. This way controlzone B can see where the aiplane is (by periodical asking its position) while it's still controlled by controlzone A.
But when an airplane crosses the border between controlzone A and B, controlzone B should keep track of the airplane instead of controlzone A. So we we want to serialize the airplane and pass it to controlZone B. This is where our problem lies.
Can I make the airplane remote AND serializeable?
EDIT: Also, I could use remote methods to copy the needed fields for the airplane, but I prefer serializing it.
If a remote object isn't exported at the time it is sent as a remote method parameter or result, it is serialized instead of being passed as a remote reference, provided that it implements Serializable as well as Remote. It is then exported at the receiver. UnicastRemoteObject does this for example, and therefore so does any remote object derived from it. This can be used for mobile remote agents.
You don't have to make your object subclass UnicastRemoteObject.
Take your class, define it to implement Serializable and your RMI api interface, which itself should implement Remote. It doesn't need to subclass anything other than java.lang.Object.
When you are ready for your object to be called remotely, call the static UnicastRemoteObject.exportObject() method on it. From that point on, any reference you return over RMI to that object will be remotely callable.
When you want to pass the object off to another server, call UnicastRemoteObject.unexportObject() on your object. Then when you pass it over an RMI call, you'll be passing the serialized representation of that object.
The downside to this is once you pass it off, the object on your server will no longer accept RMI calls. unexportObject() turns it off completely as an RMI call recipient.
If you want to be able to maintain an object as an RMI target and concurrently pass it around over RMI as a serializable object, you'll need to make it serializable and interpose a proxy object that exports the Remote interface and which can talk to the non-exported, serializable object on the caller's behalf.
When you want to pass the underlying object with serialization, you pass it directly. When you want to pass a remotely callable reference to it, you pass the proxy.
Take a look at UnicastRemoteObject class. It is normally used for callback driven programming in RMI and hence implements both Remote and Serializable. Though you might want to revisit your logic since you now have an entity (airplane) which acts like a "remote server".
Turns out this solution was not correct. See #EJP's answer below for the only way to do this with a single instance.
i understand that ,once, developing remote proxy included generating stub/skeleton , though today this is no longer needed thanks to reflection. (dynamic proxy)
i want to get a clear explanation as to why and how reflection replaces this need.
for example i understood the stub was suppose to handle the communication over the network (in case the the remote object is on a different computer) , plus in charge of serialization/deserialization , etc... who's in charge of that now ?
maybe i got the concept of dynamic proxy all wrong.
in addition i read about that subject regarding Java and Rmi, how would i implement remote proxy in C++,
i probably can use DCOM, is there another, maybe easier, way ? (and do i need stub/skeleton in DCom or like java no more ? )
thanks
say you have an interface A, and class B implements A.
the server VM has one instance of B; it's associated with a name; the server listens on a TCP port for client communication. something like this:
Server server = new Server(localhost, port);
server.bind("bbbb", new B() );
on the client VM, you want to access that B object residing on the server VM. You need to obtain a reference (of type A) to it
A bb = lookup(serverIp, port, "bbbb");
bb is a subclass of A, created with java.lang.reflect.Proxy. any method call on bb is handled by an InvocationHandler, which encodes the invocation in whichever way, and send it to ther server over the wire. the server receives a request of "calling this method of this name [with these arguments] on the objected named bbbb", and the server has no problem performing that task with reflection. then the return value is sent back to client in the similar way.
So it is really not hard to do this by yourself. Sun's RMI is probably doing the same thing (RMI has some other features, like remote garbage collection). see http://java.sun.com/j2se/1.5.0/docs/guide/rmi/relnotes.html
If I'm not mistaking, the stub/skeleton was statically created by the rmic tool while now the whole process is dynamic.
Its not that its necessarily 'better', but just removes the hassle of compiling a stub and skeleton. In both cases, the request parameters and response is serialized in the same way pretty much at the same level.
As for question #1: Some implementation of RMI uses Corba, so if the code is available, you may want to look at that.
All you would need is to interface your C++ code with the Corba layer as the stub/skeleton did.