How do I treat objects when having both RMI and Socket connections? - java

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.

Related

How to move objects by RMI?

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).

Dynamic Object Creation with RMI

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.

What exactly is the point of the codebase in Java RMI?

Im currently learning about RMI.
I dont really understand the concept of the codebase. Every paper i read suggests, that the client, which calls the Remote object can load the Method definitions from the codebase.
The Problem is now: Dont I need the descriptions/interfaces in my classpath anyway? How can i call methods on the remote object, if i only know them during Runtime? This Wouldnt even compile.
Am i completely missing the point here? What exactly is the point of the codebase then? It seems like a lot of extra work and requirements to provide a codebase
thanks
Well, let's say you provide to your client only interfaces, and the implementations will be located in a given code base. Then the client requests the server to send a given object, the client expects to receive an object that implements a given interface, but the actual implementation is unknown to the client, when it deserializes the sent object is when it has to go to the code base and download the corresponding implementing class for the actual object being passed.
This will make the client very thin, and you will very easily update your classes in the code base without having to resort to updating every single client.
EDIT
Let's say you have a RMI server with the following interface
public interface MiddleEarth {
public List<Creature> getAllCreatures();
}
The client will only have the interfaces for MiddleEarth and Creature, but none of the implementations in the class path.
Where the implementations of Creature are serializable objects of type Elf, Man, Dwarf and Hobbit. And these implementations are located in your code base, but not in your client's class path.
When you ask your RMI server to send you the list of all creatures in Middle Earth, it will send objects that implement Creature, that is, any of the classes listed above.
When the client receives the serialized objects it has to look for the class files in order to deserialized them, but these are not located in the local class path. Every object in this stream comes tagged with the given code base that can be used to look for missing classes. Therefore, the client resort to the code base to look for these classes. There it will find the actual creature classes being used.
The code base works in both directions, so it means that if you send your server a Creature (i.e. an Ent) it will look for it in the code base as well.
This means that when both, client and server need to publish new types of creatures all they have to do is to update the creaturesImpl.jar in the code base, and nothing in the server or client applications themselves.

Java RMI: Architecture for NOT passing an object, just exposing its methods to a client-side instance

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.

Java RMI, making an object serializeable AND remote

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.

Categories

Resources