RMI UnmarshalException - java

I'm currently developing a system that loads classes via rmi. This system uses a classloader that communicates with the server in order to get the classes. The code is as follows.
Server:
import rocks.squareRock;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends UnicastRemoteObject
implements RemInterface {
public Server() throws RemoteException {
super();
}
public static void main(String argv[]) {
try {
Server serv = new Server();
Naming.rebind("RockServer", serv);
} catch (Throwable t) {
t.printStackTrace();
}
}
public Class<?> getRockClass(String type) {
if (type.equals("squareRock"))
return squareRock.class;
else
return null;
}
}
Client:
import rocks.Rock;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
RemInterface reminterface = null;
RockLoader rl = null;
public Client() {
String strName = "rmi://127.0.0.1/RockServer";
try {
reminterface = (RemInterface) Naming.lookup(strName);
rl = new RockLoader(reminterface);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
loadRock("squareRock");
}
public Rock loadRock(String rock) {
try {
return (Rock) rl.loadClass(rock, false).newInstance();
} catch (Throwable t) {
return null;
}
}
}
Interface:
public interface RemInterface {
public Class<?> getRockClass(String type) throws RemoteException;
}
RockLoader:
import java.io.Serializable;
public class RockLoader extends ClassLoader implements Serializable {
private RemInterface reminterface = null;
public RockLoader(RemInterface reminterface) {
super();
this.reminterface = reminterface;
}
#Override
protected synchronized Class<?> loadClass(String className, boolean resolve)
throws ClassNotFoundException {
try {
return reminterface.getRockClass(className);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
The error I'm getting with this is (client-side):
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: SquareRock
This confuses me, as I'm not unmarshalling a SquareRock instance, but a Class. The only thought I have is that my classloader might be wrong.

It doesn't matter whether it's a Class or an object. The receiving JVM must have that class in its classpath, unless you are using the RMI codebase feature. What you are doing is basically trying to implement the codebase feature yourself. You can't do that.

Related

Tomcat WebSocket connection closed, Code: 1006 issue

I'm trying Tomcat server with websocket. This is what I do:
I created 3 java files, copied from Tomcat examples. Please see the code below.
Then I build a war file and put it in webapps. But then I got this error message:
Info: WebSocket connection closed, Code: 1006
Do I miss any step to make a websocket on Tomcat?
Thanks.
1. ExamplesConfig.java
import java.util.HashSet;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
public class ExamplesConfig implements ServerApplicationConfig
{
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> scanned)
{
Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
System.out.println("ExamplesConfig ==========> getEndpointConfigs");
if (scanned.contains(EchoEndpoint.class))
{
result.add(ServerEndpointConfig.Builder.create(EchoEndpoint.class, "/websocket/echoProgrammatic").build());
}
return result;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned)
{
// Deploy all WebSocket endpoints defined by annotations in the examples
// web application. Filter out all others to avoid issues when running
// tests on Gump
Set<Class<?>> results = new HashSet<Class<?>>();
for (Class<?> clazz : scanned)
{
if (clazz.getPackage().getName().startsWith("websocket."))
{
System.out.println("getAnnotatedEndpointClasses ===========>" + clazz);
results.add(clazz);
}
}
return results;
}
}
2. EchoEndpoint.java
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
public class EchoEndpoint extends Endpoint
{
#Override
public void onOpen(Session session, EndpointConfig endpointConfig) {
RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote();
session.addMessageHandler(new EchoMessageHandlerText(remoteEndpointBasic));
session.addMessageHandler(new EchoMessageHandlerBinary(remoteEndpointBasic));
}
private static class EchoMessageHandlerText
implements MessageHandler.Partial<String> {
private final RemoteEndpoint.Basic remoteEndpointBasic;
private EchoMessageHandlerText(RemoteEndpoint.Basic remoteEndpointBasic) {
this.remoteEndpointBasic = remoteEndpointBasic;
}
#Override
public void onMessage(String message, boolean last) {
try {
if (remoteEndpointBasic != null) {
remoteEndpointBasic.sendText(message, last);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static class EchoMessageHandlerBinary
implements MessageHandler.Partial<ByteBuffer> {
private final RemoteEndpoint.Basic remoteEndpointBasic;
private EchoMessageHandlerBinary(RemoteEndpoint.Basic remoteEndpointBasic) {
this.remoteEndpointBasic = remoteEndpointBasic;
}
#Override
public void onMessage(ByteBuffer message, boolean last) {
try {
if (remoteEndpointBasic != null) {
remoteEndpointBasic.sendBinary(message, last);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3. EchoAnnotation.java
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.OnMessage;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/websocket/echoAnnotation")
public class EchoAnnotation
{
#OnMessage
public void echoTextMessage(Session session, String msg, boolean last) {
try {
if (session.isOpen()) {
System.out.println("==========> this is my code");
session.getBasicRemote().sendText(msg, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
}
#OnMessage
public void echoBinaryMessage(Session session, ByteBuffer bb,
boolean last) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendBinary(bb, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
}
/**
* Process a received pong. This is a NO-OP.
*
* #param pm Ignored.
*/
#OnMessage
public void echoPongMessage(PongMessage pm) {
// NO-OP
}
}
This example work's fine with Tomcat 7.0.x if you are running JVM version 1.7 and your web.xml use Servlet Specification version 3.0 according to Tomcat documentation.
You web.xml file should look like this :
<web-app version="3.0" ... >

Java RMI has different instantiations on client variables from client itself and from remote calls from server

We are trying to create a system using Javas RMI. The problem is that a maintained list on the client cannot be accessed from the server using Java RMI. It seems that the RMI connection is handling a copy of the initialized list.
Below is a minimal example using an integer that the client increments every second until it equals 10. The server receives 0 all the time though.
Anyone have any idea what we are doing wrong?
Just run server and the client as a java application.
ServerDefaultImpl.java
package rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class ServerDefaultImpl implements EIServerRemote, Runnable {
ClientRemote client;
private boolean running = true;
public ServerDefaultImpl() {
try {
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
ServerDefaultImpl server = this;
EIServerRemote stub = (EIServerRemote) UnicastRemoteObject.exportObject(server, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("test", stub);
} catch (RemoteException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ServerDefaultImpl();
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
if (null != client) { //Client not connected yet.
int test = client.test();
System.out.println(test);
running = test <= 10;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void attachClientListener(ClientRemote client) throws RemoteException {
this.client = client;
}
}
EIServerRemote.java
package rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface EIServerRemote extends Remote {
void attachClientListener(ClientRemote client) throws RemoteException;
}
ClientRemote.java
package rmi;
import java.io.Serializable;
import java.rmi.Remote;
public interface ClientRemote extends Remote,Serializable {
int test();
}
ClientDefaultImpl.java
package rmi;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class ClientDefaultImpl implements Runnable,
ClientRemote {
private static final long serialVersionUID = 4846141863099303590L;
protected EIServerRemote server = null;
public int test;
public boolean running = true;
public ClientDefaultImpl(String serverName) {
test = 0;
try {
connect(serverName);
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ClientDefaultImpl("test");
}
public void connect(String serverName) throws RemoteException,
NotBoundException {
Registry registry = LocateRegistry.getRegistry();
EIServerRemote s = (EIServerRemote) registry.lookup(serverName);
server = s;
s.attachClientListener((ClientRemote) this);
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
System.out.println(test++);
running = test <= 10;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public int test() {
return test;
}
}
It seems that the RMI connection is handling a copy of the initialized list.
That's correct. The list isn't a remote object, so it is passed and returned via serialization.

SEVERE: Could not dispatch event: Eventbus com.google.common.eventbus.SubscriberExceptionContext

For EventBus, I merged the code inside my java Spring app and have full control of it but the result didn't change.
When I run The EventBus in spring sts (javaw), there is no issue but when I run in the server with java -jar project.jar it gives the same SEVERE: Could not dispatch event: error
The below didn't work for me..
package edu.uams.event;
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.Executor;
import org.apache.log4j.Logger;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventHandler;
import com.google.common.eventbus.SubscriberExceptionHandler;
import edu.uams.domain.TirEvent;
import edu.uams.pacs.IncomingFileMonitor;
public class AysncTraumaEventBus extends AsyncEventBus {
private final static Logger logger = Logger.getLogger(AysncTraumaEventBus.class);
private String name = null;
public AysncTraumaEventBus(Executor executor,
SubscriberExceptionHandler subscriberExceptionHandler) {
super(executor, subscriberExceptionHandler);
logger.info("AysncTraumaEventBus created.");
}
public AysncTraumaEventBus(String name, Executor executor) {
super(name,executor);
this.name=name;
logger.info("AysncTraumaEventBus created. Name:"+this.name);
}
#Override
public void register(Object object) {
super.register(object);
}
#Override
public void unregister(Object object) {
super.unregister(object);
}
#Override
public void dispatch(Object event, EventHandler wrapper) {
try {
logger.info("Let's dispatch Aysnchroneous Trauma Event:"+ ((TirEvent) event).getResultMessage());
wrapper.handleEvent(event);
} catch (InvocationTargetException e) {
// My logger
logger.error("Could not dispatch event: " + event + " to handler " + wrapper+" e:"+e.getMessage());
logger.info("Lets try to disptach again!");
super.post(new ExceptionEvent(event, e));
}
}
public static final class ExceptionEvent {
public final Object event;
public final InvocationTargetException exception;
public ExceptionEvent(final Object event, final InvocationTargetException exception) {
this.event = event;
this.exception = exception;
}
}
}
Somehow the EventHandler can't invoke the target event..
wrapper.handleEvent(event);
When you look the wrapper (EventHandler):
public void handleEvent(Object event) throws InvocationTargetException {
checkNotNull(event);
try {
method.invoke(target, new Object[] { event });
} catch (IllegalArgumentException e) {
throw new Error("Method rejected target/argument: " + event, e);
} catch (IllegalAccessException e) {
throw new Error("Method became inaccessible: " + event, e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof Error) {
throw (Error) e.getCause();
}
throw e;
}
}
You see that method.invoke(target, new Object[] { event }); throws the InvocationTargetException from the Method.class
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass(1);
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
Somehow it can't invoke.. But the most interesting part is that the same jar file along with EventBus can run fine in STS Run (javaw) but when I run java from commandline as java -jar project.jar it can't dispatch the event..
#Subscribe
#AllowConcurrentEvents
public void receivedDicomFile(TirEvent event){
try {
} catch (ClassNotFoundException e) {
logger.error(e.getMessage());
} catch (SQLException e) {
logger.error(e.getMessage());
} catch(Exception e){
logger.error(e.getMessage());
}
}
It always needs an try catch.. Thanks #dwnz for your help

RMI Exception RemoteException nested exception

Trying to run RMI example but facing the following exception:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: hejsan.RemoteBuffer
I have started the rmiregristry and it seems to be running fine. But the server is not running, it just builds and stops.
/Library/Java/JavaVirtualMachines/jdk1.7_45.jdk/Contents/Home/jre/bin/rmiregistry
Project name: hej
Package name: hejsan
Files: MyBuffer.java and RemoteBuffer.java
MyBuffer.java:
package hejsan;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.LinkedList;
#SuppressWarnings("serial")
public class MyBuffer extends UnicastRemoteObject implements RemoteBuffer {
LinkedList<Integer> list = new LinkedList<Integer>();
public MyBuffer() throws RemoteException, MalformedURLException {
super();
Naming.rebind("rmi://localhost/buffer", this);
}
public synchronized void put(Integer i) throws RemoteException {
list.addLast(i);
notifyAll();
}
public synchronized Integer get() throws RemoteException {
while (list.size() == 0) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return (Integer) list.removeFirst();
}
public static void main(String[] args) {
try {
new MyBuffer();
} catch (RemoteException re) {
System.out.println(re);
System.exit(1);
} catch (MalformedURLException me) {
System.out.println(me);
System.exit(1);
}
}
}
RemoteBuffer.java:
package hejsan;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RemoteBuffer extends Remote {
void put(Integer i) throws RemoteException;
Integer get() throws RemoteException;
}
I discovered that I had to be on netbeans project path: ~/build/classes and runs the rmiregistry from while on that path.
The rmiregistry path can be found under Tools-> Java Platforms in netbeans. Caution! Change to jre instead of jdk following this below example:
/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/bin/rmiregistry

RMI ClassNotFoundException

I've been building an RMI application over the past week and I've hit a roadblock that no amount of googling can seem to help with.
The following code is used to send an object from the server to the client via RMI:
Server code:
import rocks.Rock;
import rocks.squareRock;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends UnicastRemoteObject
implements RemInterface {
public Server() throws RemoteException {
super();
}
public static void main(String argv[]) {
try {
Server serv = new Server();
Naming.rebind("RockServer", serv);
} catch (Throwable t) {
t.printStackTrace();
}
}
public Rock getRock() {
return new squareRock();
}
}
Client code:
import rocks.Rock;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
RemInterface reminterface = null;
public Client() {
String strName = "rmi://127.0.0.1/RockServer";
try {
reminterface = (RemInterface) Naming.lookup(strName);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
public Rock loadRock() {
try {
return reminterface.getRock();
} catch (Throwable t) {
return null;
}
}
}
Interface:
public interface RemInterface {
public Rock getRock() throws RemoteException;
}
In this situation:
The "Rock" class is available in both the Client and Server classpath.
The "Rock" class implements serializable.
The "squareRock" extends class rock and is only available in the server's classpath.
The error I get when trying to call a method using a Rock from loadRock() on the client is as follows:
STDERR: java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: SquareRock
Any help would be appreciated.
You are returning an object of Type rocks.squareRock from the Server. During the de-serialization process at the client, this class will be required in order to create an instance of this class to represent the response from the server. As you've already indicated that the class is available only in the server's classpath, the failure to locate and load the said class causes the exception.
The resolution will be to make the rocks.squareRock class available in the client as well.

Categories

Resources