I am trying to send an object in java over a physical network (not over localhost) but it seems I have something wrong.
The interface to the object (client and server have this):
public interface distributable extends Serializable {
public void test();
}
The Object I am trying to send (only server has this):
class ObjectToSend implements distributable {
public ObjectToSend() {
}
public void test() {
system.out.println("worked!");
}
}
Server:
private ObjectToSend obj = new ObjectToSend();
obj_out_stream.writeObject(obj);
obj_out_stream.flush();
Client:
private distributable ReceivedObj = null;
try {
ReceivedObj = (distributable) obj_in_steam,readObject();
} catch (ClassNotFoundException e) {
System.err.println("Error<w_console>: Couldn't recieve application code!");
}
ReceivedObj.test();
Everything was working when the ObjectToSend class implemented Serializable and I wasn't using an interface because all my classes were in one directory so the client 'knew' about the object. Now I want it to work across a physical network so the client only has the interface to the object. It seems that client can not receive the object as the exception is thrown every time.
As the other answers suggest, the Client also has to know the class of the object you want to send.
Usually, one creates three packages/projects for such a classic client-server example:
Common: Code that is used by client and server; the class definition of the objects you want to send from the server to the client belongs here
Client: All code only the client needs to know about
Server: All code only the server needs to know about
To be able to serialize and deserialize objects with objectinput/outputstream the classes must implement Serializable.
Also the deserializer must be able to find the classes on the classpath that you are trying to deserialize since this is embedded in the Serialized form.
If you want the client to have only the interface -- at compile time -- then you'll need to download the actual class from the server at run-time.
Jini (aka Apache River) makes this easy.
It's supposed to be like this. What can you do with a class whose code you don't have?
Have a look here: stackoverflow.com/questions/8175052/java-polymorphism-my-teacher-claims-you-can-distribute-an-executable-object-thr
Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Closed 9 years ago.
Improve this question
hi i have searched the internet for a long time trying to find some thing that talk about how to start rmi registry in windows 7 using cmd so if any one know how to do that pleas let me to know how to do it or if any one can provide us a good link for that... thx in advance
ok thanx for all how answered my question when i asked the question i was not fully understand the RMI system or how it work but know i have good idea i will summarized this for provide all with an idea for the RMI system and if i have any mistake please correct me
so
Remote Interface:
We need an interface that extends from the Remote class and defined the method that we would like to invoke remotely
note:
Remote is a "marker" interface that identifies interfaces whose methods may be invoked from a non-local virtual machine.
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.Calendar;
public interface CalendarTask extends Remote {
Calendar getDate() throws RemoteException;
}
The Remote Object:
We need class that create a Remote object's so we crate class object implement the Remote Interface to make the object's that created by this class object remote object's and we link this object's to the RMI System by extends from this class UnicastRemoteObjec so When a class extends from UnicastRemoteObject, it must provide a constructor declaring this constructor calls super(), it activates code in UnicastRemoteObject, which performs the RMI linking and remote object initialization.
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.Calendar;
public class CalendarImpl extends UnicastRemoteObject implements CalendarTask {
private int counter = 1;
public CalendarImpl() throws RemoteException {}
public Calendar getDate() throws RemoteException{
System.out.print("Method called on server:");
System.out.println("counter = " + counter++);
return Calendar.getInstance();
}
}
Writing the Server:
3.1 The server's job is to accept requests from a client, perform some service, and then send the results back to the client.
3.2 The server must specify an interface that defines the methods available to clients as a service. we do that above in the first step (Remote Interface)
3.3 The server creates the remote object, registers it under some arbitrary name, then waits for remote requests
3.4 so for register The remote object we use java.rmi.registry.LocateRegistry class allows the RMI registry service (provided as part of the JVM) to be started within the code by calling its createRegistry() method.
3.5 The java.rmi.registry.Registry class provides two methods for binding objects to the registry.
• Naming.bind("ArbitraryName", remoteObj);
throws an Exception if an object is already bound under the "ArbitrayName".
• Naming.rebind ("ArbitraryName", remoteObj);
binds the object under the "ArbitraryName" if it does not exist or overwrites the object that is bound.
3.6 The example on the following acts as a server that creates a CalendarImpl object and makes it available to clients by binding it under a name of "TheCalendar"
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class CalendarServer {
public static void main(String args[]) {
System.out.println("Starting server...");
// Start RMI registry service and bind
// object to the registry
try {
LocateRegistry.createRegistry(1099);
Naming.rebind("TheCalendar",
new CalendarImpl());
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
System.out.println("Server ready");
}
}
Writing the Client:
4.1 An RMI client is a program that accesses the services provided by a remote object
4.2 The java.rmi.registry.LocateRegistry class allows the RMI registry service to be located by a client by its getRegistry() method
4.3 The java.rmi.registry.Registry class provides a lookup() method that takes the "ArbitraryName" the remote object was bound to by the server.
Once the client obtains a reference to a remote object, it invokes methods as if the object were local
import java.rmi.registry.*;
import java.util.Calendar;
public class CalendarClient {
public static void main(String args[]) {
Calendar c = null;
CalendarTask remoteObj;
String host = "localhost";
if(args.length == 1)
host = args[0];
try {
Registry r =
LocateRegistry.getRegistry(host, 1099);
Object o = r.lookup("TheCalendar");
remoteObj = (CalendarTask) o;
c = remoteObj.getDate();
} catch (Exception e) {
e.printStackTrace();
}
System.out.printf("%tc", c);
}
}
The code you have written doesn't start a registry. LocateRegistry.getRegistry() doesn't do that. Check the Javadoc. It assumes the Registry is already running. LocateRegistry.getRegistry() just constructs a Registry stub according to the host and port you provide. It doesn't even do any network operations.
To start a Registry from within your JVM, use LocateRegistry.createRegistry(), as its Javadoc states.
EDIT: There's a lot of misinformation in your edit.
Remote is a "marker" interface that identifies interfaces whose methods may be invoked from a non-local virtual machine.
Only if implemented by an exported remote object whose stub has been transmitted to that VM. The remote interface itself doesn't have any such magical property. All methods defined in a remote interface must be declared to throw RemoteException, although the implementations of these methods generally don't need to be so declared (i.e. unless they perform remote operations themselves: the compiler will tell you).
We need class that create a Remote object's so we crate class object implement the Remote Interface to make the object's that created by this class object
Far too much confusion here. We need a class. The class must implement the remote interface. This is not an 'object' yet: it is a piece of code that must be compiled to a .class file. A class doesn't 'make objects'. An application does that, with the new operator.
we link this object's to the RMI System by extends from this class UnicastRemoteObjec so When a class extends from UnicastRemoteObject, it must provide a constructor declaring this constructor calls super(), it activates code in UnicastRemoteObject, which performs the RMI linking and remote object initialization
There is no 'link' step in RMI. There is an 'export' step. It is performed either by extending UnicastRemoteObject or by calling UnicastRemoteObject.exportObject(). If you don't extend UnicastRemoteObject you don't need the constructor you described.
The server's job is to accept requests from a client, perform some service, and then send the results back to the client.
The server's job is to implement the methods in the remote interface. RMI does all the rest for you.
The server creates the remote object, registers it under some arbitrary name, then waits for remote requests
Or else the server is the remote object and it registers itself.
for register The remote object we use java.rmi.registry.LocateRegistry class allows the RMI registry service (provided as part of the JVM) to be started within the code by calling its createRegistry() method.
Or you can use an external Registry via the rmiregistry command. Or you can use an LDAP server via JNDI.
LocateRegistry.createRegistry(1099);
Naming.rebind("TheCalendar",
new CalendarImpl());
This won't work unless you store the result of createRegistry() into a static variable. And having stored it, you may as well use it to do the bind, instead of using the Naming class. If you don't store it into a static variable it will be garbage-collected and so will the remote object.
The java.rmi.registry.LocateRegistry class allows the RMI registry service to be located by a client by its getRegistry() method
Or you can use the Naming class, see below.
The java.rmi.registry.Registry class provides a lookup() method that takes the "ArbitraryName" the remote object was bound to by the server.
So does the Naming class. It takes an rmi: URL which specifies the host and port and bind-name. You can omit the rmi:// part. If you omit the host it defaults to 'localhost', but this is only useful if the client is running in the same host as the server, which isn't itself very useful. If you omit the port it defaults to 1099.
I have a certain problem: I'm using RMI to communicate between server and client.
public class RemoteMap
extends java.rmi.server.UnicastRemoteObject
implements RemoteMapInterface {
private TreeMap<String, GeneralSprite> sprites;
...
This is my remote object. But I want the client to be able to change this object's content. And after the change the server can execute some operation based on this.
Example at the client side:
map = (RemoteMapInterface) (registry.lookup("map"));
map.getSprites.get("object1").setDx(-1);
I'm using serialiable on the GeneralSprite, but I guess it passed by value. So when I did some changes at the GeneralSprite, it wasn't transported to the server . Do I have to make GeneralSprite to an Remote object too? Or is it even possibly?
Thanks in advance, and sorry for my bad english, I hope you can understand.
Everything which does not implement the Remote interface, whether directly or indirectly, will get serialized for the remote method invocation. So it’s a “call-by-copy” behavior. You can implement a new Map which implements Remote, but you can also add a method like setDx(String spriteName, int value) to your RemoteMapInterface and implement it as sprites.get(spriteName) .setDx(value); on the server side.
I am creating a instant chat application using RMI. The server sends through certain objects which I need the client to handle.
For example the server will send a JoinedGroupOperation class. In my client application I need to recognise the class and let my handler take over (HandleJoinedGroupOperation). This class will do a bunch of stuff on the client side.
My question is how can I handle classes that come from the server so I don't need to do any if statements? ie
if(server.getResponse() instanceof JoinedGroupOperation){
HandleJoinedGroupOperation handle = new HandleJoinedGroupOperation();
handle.foo();
}
One of the possible option in your case is to use chain of responsibility design patern.
You should create some abstraction of your possible handlers(like HandleJoinedGroupOperation), then link those handlers(preferebly at start time). As a example, create an interface
interface OperationHandler {
void handle(Operation op);
}
where Operation is also a basic type for all possible operations. This type(Operation) can contain a field of enum type OperationType:
enum OperationType {
...
}
Then in the concrete handlers you can simply check this field(although it will contain if statement, but those statements will be encapsulated in each specific handler)
As a simple example, here is a default implementation of a handler
class SimpleHandler implements OperationHandler {
private OperationHandler next;
public void handle(Operation op) {
if (op.getType() == OperationType.SOMEYOURTYPE) {
//do some stuff
} else {
next.handle(op);
}
}
}
In this case your server.getResponse() method simply will return basic type of Operation hierarchy
Also read the article to get more information
I'm looking for a communication channel between two java programs running on the same machine. I've found a few options (RMI and XML-RCP) but none of the examples that I found show exchange of objects wich class it's non-primitive and not know on JDK (our own objects).
So, what's the easy technology to use when I want to do this (note that Utils.jar it's on the classpath of Server.jar and Client.jar):
Utils.jar:
class MyClassRequestParams { ... }
class MyClassReturnParams { ... }
Client.jar:
// Server creation
...
// Send request
MyClassRequestParams params = new MyClass...
MyClassReturnParams response = server.send("serverMethodName", params);
Server.jar:
MyClassRequestParams serverMethodName(MyClassRequestParams params)
{
MyClassReturnParams response = new MyC...
// do processing
return response;
}
Just make your transport classes implement the Serializable interface, and everything will be fine with RMI. Note that every object referenced bt the transport object should also be Serializable.
The RMI tutorial uses an example with a custom Task interface implemented by a Pi custom class that is not a "standard" JDK class.
You may also consider Versile Java (I am one of its developers). Follow the link for an example of making remote calls and defining remote interfaces. It implements a platform-independent standard for remote ORB interaction, currently also available for python.
I'm trying to pick up Java and wanted to test around with Java's client/server to make the client send a simple object of a self defined class(Message) over to the server. The problem was that I kept getting a ClassNotFoundException on the server side.
I think the rest of the codes seem to be alright because other objects such as String can go through without problems.
I had two different netbeans projects in different locations for client and server each.
Each of them have their own copy of Message class under their respective packages.
Message class implements Serializable.
On the client side, I attempt to send a Message object through.
On the server side, upon calling the readObject method, it seems to be finding Message class from the client's package instead of it's own. printStackTrace showed: "java.lang.ClassNotFoundException: client.Message" on the server side
I have not even tried to cast or store the object received yet. Is there something I left out?
The package name and classname must be exactly the same at the both sides. I.e. write once, compile once and then give the both sides the same copy. Don't have separate server.Message and client.Message classes, but a single shared.Message class or something like that.
If you can guarantee the same package/class name, but not always whenever it's exactly the same copy, then you need to add a serialVersionUID field with the same value to the class(es) in question.
package shared;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}
The reason is, that the readObject() in ObjectInputStream is practically implemented as:
String s = readClassName();
Class c = Class.forName(s); // Here your code breaks
Object o = c.newInstance();
...populate o...