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.
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.
I have an object on a server which clients can retrieve in a distributed system. This all happens on a local machine and the clients call the server object through RMI lookup. The point is that the server object is supposed to be one single object which clients can modify. However after it's deserialized at the clients, they all have a different object ID. That is, they seem to get a new object, even though they are all supposed to retrieve the same object from the server. This makes sense, considering the objects are supposed to be on separate machines (per client).
I have tried to implement the hashcode and equals methods on the server object, but the clients still get a different object id. When the clients perform actions on the deserialized server object, the original server object does not receive the changes. I know this because any subsequent lookups retrieve the server object in its original state.
Basically my question is: How can I let my clients update the original server object by performing client operations on the respective deserialized objects? When another client looks at the getters of its deserialized object, it must see all the changes performed by other clients. To clarify further, despite that the objects are deserialized over different machines, I want them to behave as if they were one and the same object on the same machine.
The point is that the server object is supposed to be one single object which clients can modify. However after it's deserialized at the clients, they all have a different object ID
The point is that this isn't a remote object, so it gets serialized, which you don't want.
I want them to behave as if they were one and the same object on the same machine.
Exactly. You need to:
Have it implement a remote interface
Export it, either by having it extend UnicastRemoteObject (preferred) or calling UnicastRemoteObject.exportObject() on construction.
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 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.
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.