RMI NotSerializableException although it's a remote object - java

I'm writing a small RMI based Chat application.
The idea is: the Client registers himself on the Server, and everytime the server receives a message from a client, he pushes this message to all other clients.
But I receive a NotSerializableException although, the object, I'm passing as a method parameter implements the Remote interface.
Here is some code:
(The problematic part is the this parameter in this.chatServ.registriereClient(this); (ClientChat Implementation))
The (ClientChat)interface:
public interface ChatClient extends Remote
{
}
(ClientChat)Implementation:
public class ChatClientImpl implements ChatClient
{
ChatServer chatServ;
String clientName;
public ChatClientImpl(String clientName, ChatServer chatServ) {
this.chatServ = chatServ;
this.clientName = clientName;
try {
this.chatServ.registriereClient(this);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
(ServerChat) Interface
public interface ChatServer extends Remote
{
void registriereClient(ChatClient client) throws RemoteException;
}
(ServerChat) Implementation
public class LobbyChatServerImpl implements ChatServer
{
ArrayList<ChatClient> clientListe = null;
#Override
public void registriereClient(ChatClient client) {
System.out.println("Client registriert");
this.clientListe.add(client);
}
}
Client:
public static void main(String[] args) {
ChatServer lobbyChatServer = null;
try {
Registry registry = LocateRegistry.getRegistry(Server.RMI_PORT);
lobbyChatServer = (ChatServer) registry.lookup("LobbyChatServer");
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
}
ChatClient lobbyChat = new ChatClientImpl(name, lobbyChatServer);
}
Server:
public static void main(String[] args) {
try {
if (System.getSecurityManager() == null) {
System.setSecurityManager(new RMISecurityManager());
}
Registry registry = LocateRegistry.getRegistry(RMI_PORT);
ChatServer lobbyChatStub = (ChatServer)UnicastRemoteObject.exportObject(new LobbyChatServerImpl(), 0);
registry.bind("LobbyChatServer", lobbyChatStub);
} catch (RemoteException e) {
e.printStackTrace();
} catch (AlreadyBoundException e) {
e.printStackTrace();
}
}
Exception:
java.rmi.MarshalException: error marshalling arguments; nested exception is:
java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:156)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at $Proxy0.registriereClient(Unknown Source)
at de.XX.Chat.ChatClientImpl.<init>(ChatClientImpl.java:19)
at de.XX.Client.main(Client.java:49)
Caused by: java.io.NotSerializableException: de.XX.Chat.ChatClientImpl
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:292)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:151)
... 5 more
As already said, I wonder why i get this kind of Exception, although ChatClientImpl is already Remote.
Hope you can help me:)

Objects passed as parameters or results of remote methods must be either:
Serializable (or Externalizable), or
Exported remote objects.
Yours is neither. However as it implements a Remote interface clearly you intended (2).
Objects that extend UnicastRemoteObject are auto-exported on construction. Objects that don't must be exported explicitly, via UnicastRemoteObject.exportObject().

What you can do is setup a callback object. This is one which extends UnicastRemoteObject and when you pass this it becomes a callback.
http://www.cs.swan.ac.uk/~csneal/InternetComputing/RMIChat.html
Remote is not Serializable. You can't pass a proxy object this way. Even if you made it Serializable it would send a copy of the object which would exist on the server. The copy of the object on the client would not be called.
For your "server" to send messages to your "client" you have to create a service on the "client" to make it a server.
You may find that using a messaging solution such as JMS is better suited to this take. A JMS server has topics which you can publish to and subscribe from. A simple JMS server to use is Active MQ.

Looks like you might have forgotten to 'extends UnicastRemoteObject' on the interface implementations:
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient{
}
and
public class LobbyChatServerImpl extends UnicastRemoteObject implements ChatServer{
}

Related

How to design publish-subscribe pattern properly in grpc?

i'm trying to implement pub sub pattern using grpc but i'm confusing a bit about how to do it properly.
my proto: rpc call (google.protobuf.Empty) returns (stream Data);
client:
asynStub.call(Empty.getDefaultInstance(), new StreamObserver<Data>() {
#Override
public void onNext(Data value) {
// process a data
#Override
public void onError(Throwable t) {
}
#Override
public void onCompleted() {
}
});
} catch (StatusRuntimeException e) {
LOG.warn("RPC failed: {}", e.getStatus());
}
Thread.currentThread().join();
server service:
public class Sender extends DataServiceGrpc.DataServiceImplBase implements Runnable {
private final BlockingQueue<Data> queue;
private final static HashSet<StreamObserver<Data>> observers = new LinkedHashSet<>();
public Sender(BlockingQueue<Data> queue) {
this.queue = queue;
}
#Override
public void data(Empty request, StreamObserver<Data> responseObserver) {
observers.add(responseObserver);
}
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
// waiting for first element
Data data = queue.take();
// send head element
observers.forEach(o -> o.onNext(data));
} catch (InterruptedException e) {
LOG.error("error: ", e);
Thread.currentThread().interrupt();
}
}
}
}
How to remove clients from global observers properly? How to received some sort of a signal when connection drops?
How to manage client-server reconnections? How to force client reconnect when connection drops?
Thanks in advance!
In the implementation of your service:
#Override
public void data(Empty request, StreamObserver<Data> responseObserver) {
observers.add(responseObserver);
}
You need to get the Context of the current request, and listen for cancellation. For single-request, multi-response calls (a.k.a. Server streaming) the gRPC generated code is simplified to pass in the the request directly. This means that you con't have direct access to the underlying ServerCall.Listener, which is how you would normally listen for clients disconnecting and cancelling.
Instead, every gRPC call has a Context associated with it, which carries the cancellation and other request-scoped signals. For your case, you just need to listen for cancellation by adding your own listener, which then safely removes the response observer from your linked hash set.
As for reconnects: gRPC clients will automatically reconnect if the connection is broken, but usually will not retry the RPC unless it is safe to do so. In the case of server streaming RPCs, it is usually not safe to do, so you'll need to retry the RPC on your client directly.

Access the object Inside Anonymous Handler function

I have a very basic question. I have just started with vertx Framework. There is one thing I am not able to understand like
vertx.createNetServer().connectHandler(new Handler<NetSocket>() {
#Override
public void handle(final NetSocket socket) {
socket.dataHandler(new Handler<Buffer>() {
public void handle(Buffer buffer) {
/* I can access the socket object inside this handler */
socket.write("Hello");
}
});
}
}).listen(1234);
but if I write the handler function separately like this
Handler<Message> socketHandler = new Handler<Buffer>() {
public void handle(Buffer buffer) {
/* How can i access the socket object now */
socket.write("Hello"); //this will give error as it does not recognize the socket object
}
};
vertx.createNetServer().connectHandler(new Handler<NetSocket>() {
#Override
public void handle(final NetSocket socket) {
socket.dataHandler(socketHandler);//now I write handler separately
}
}).listen(1234);
Handler can be anywhere in the same java class or other java class. Please help me me how I can write handler separately and still access the socket object.
In your second example, you're not passing socket to socketHandler, so you cannot expect socketHandler to know about it.
You could solve this by creating a method like createSocketHandler(final Socket socket) that returns a Handler<Message> and that replaces your socketHandler variable.
To learn more, and to find out why you need socket to be final, look up "anonymous inner classes"

Java RMI with SSL client authentication: obtain client x509Certificate

Is it possible to obtain a reference to connected client's x509Certificate object in Remote server implementation?
Rewrited RMISocketFactory:
RMISocketFactory.setSocketFactory(
new java.rmi.server.RMISocketFactory() {
...
#Override
public ServerSocket createServerSocket(int port)
throws IOException {
SSLServerSocket socket = ...
socket.setNeedClientAuth(true);
return socket;
}
});
Remote Object:
public class RMIServer extends UnicastRemoteObject implements IRMIServer {
public RMIServer() throws RemoteException {
super(0);
}
#Override
public String foo() throws RemoteException {
System.out.println(getClientCertificate().getSubjectDN().getName()); // something like this?
}
}
You've hit on a major design flaw in RMI. It's practically impossible for an RMI server to get hold of the client certificate, or vice versa, as it's practically impossible to know which SSLSocket is in use for the current call. They should have provided a way to attach something like a HandshakeCompletionListener.

RMI Server Stops?

How do I keep an RMI server running? It currently, just binds and object, then exits..
public class WutServer {
public static void main(String[] args) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(1099);
try {
registry.bind("WutManager", new WutManager());
System.out.println("Ready..");
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am simply running this class. I didn't run rmic or anything..
How do I force it to stay running?
Try this:
Remote stub = UnicastRemoteObject.exportObject(new WutManager(), 0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("WutManager", stub);
Note: WutManager should implement java.rmi.Remote.
Your server is being DGC'd and then GC'd, which causes it to be unexported, which eventually causes the JVM to exit if it has nothing else to do. To stop that, if you are creating the Registry via LocateRegistry.createRegistry(), keep the return value of that method in a static variable. Otherwise keep a static reference to your server object.
This is an old question, but here is a new answer.
On OSX, using latest Java 9.0.4 I find that the program exits. If I use latest Java 1.8.0.162 then it does not exit and the server remains running.
You need to make WutServer implement the interface that clients will access it by, which in turn should inherit from the marker interface Remote. You also probably want to make the WutServer class inherit from UnicastRemoteObject; while there are other ways to build the remoting support, inheriting from UnicastRemoteObject is definitely the easiest way to get something going.
Try this instead (though you should probably separate the remote interface into another file and have it be redistributed separately):
public class WutServer extends UnicastRemoteObject implements WutServer.Wut {
interface Wut extends Remote {
String wut() throws RemoteException;
}
// Because of the exception...
public WutServer() throws RemoteException {}
public String wut() { return "wut"; }
public static void main(String[] args) throws RemoteException {
LocateRegistry.createRegistry(1099).rebind("WutManager",new WutServer());
System.out.println("Ready...");
}
}
Create an object and call wait of the object at the end of the main function. That is;
public static void main(String[] args) throws RemoteException {
Registry registry = LocateRegistry.createRegistry(1099);
//your object to wait
Object lockObject=new Object();
try {
registry.bind("WutManager", new WutManager());
System.out.println("Ready..");
//here makes your rmi server non-stop
synchronized(lockObject){
lockObject.wait();
}
}catch (Exception e) {
e.printStackTrace();
}
}

How Polling mechanism can be realized with RMI?

Following the design/architecture i created for multiuser/network turn-based game with RMI server callbacks, I have tried to create a distributed animation in which my model(Ball) is remote object and it updates the clients via callback mechanism from server.
The current situation of code is :
The model remote object, which is iterating client list and calling update method of them,
public class BallImpl extends UnicastRemoteObject implements Ball,Runnable {
private List<ICallback> clients = new ArrayList<ICallback>();
protected static ServerServices chatServer;
static ServerServices si;
BallImpl() throws RemoteException {
super();
}
....
public synchronized void move() throws RemoteException {
loc.translate((int) changeInX, (int) changeInY);
}
public void start() throws RemoteException {
if (gameThread.isAlive()==false )
if (run==false){
gameThread.start();
}
}
/** Start the ball bouncing. */
// Run the game logic in its own thread.
public void run() {
while (true) {
run=true;
// Execute one game step
try {
updateClients();
} catch (RemoteException e) {
e.printStackTrace();
}
try {
Thread.sleep(50);
} catch (InterruptedException ex) {
}
}
}
public void updateClients() throws RemoteException {
si = new ServerServicesImpl();
List<ICallback> j = si.getClientNames();
System.out.println("in messimpl " + j.size());
if (j != null) {
System.out.println("in ballimpl" + j.size());
for (ICallback aClient : j) {
aClient.updateClients(this);
}
} else
System.err.println("Clientlist is empty");
}
}
The client which is implementing callback interface and has update method implementation :
public final class thenewBallWhatIwant implements Runnable, ICallback {
.....
#Override
public void updateClients(final Ball ball) throws RemoteException {
try {
ball.move();
try {
Thread.sleep(50);
} catch (Exception e) {
System.exit(0);
}
} catch (Exception e) {
System.out.println("Exception: " + e);
}
}
.....
}
My general perception is that i m implementing pushing mechanism with RMI and in that scenario i need to implement polling)
if that is the case how can i implement the polling mechanism with RMI?
thanks for any feedback.
jibbylala
Polling is independent of the protocol you use to implement the client and server.
A client polls by looping endlessly. Inside the loop there's a request to the server for information. The server sends either the desired information or a "not ready" message back. The client does its thing and waits until the next request needs to be sent.
If you happen to choose RMI, it means an RMI client and server. But the polling mechanism is the same regardless.
Break the problem into pieces - it'll be easier to think about and solve that way.
Forget about polling to start. Can you write an RMI server, start it up, and create a separate client to make a single request? If you can do that, then you put it inside a loop with a sleep to implement the delay and you're done.
I don't belive you can implement a callback via Java RMI. You need to either setup polling as you have suggested, or make your "client" RMI servers can you can send message to them directly.
How could you do this differently? I would suggest using JMS messaging to send command objects to the clients, this would handle all the distribution for you.

Categories