java.rmi.RemoteException – How to solve RemoteException
In this example we are going to talk about java.rmi.RemoteException
. This the most general checked exception that may occur during the lookup or the execution of a Remote Procedure Call (RPC). As might you know, Java provides a very convenient API that enables you to create remote servers that can host Remote Procedure Cal services, as well as clients that can easily consumed these services. All of these infrastracture is provided by the Java RMI package.
If you are familiar with Web Services or the SOAP protocol, you should be already acquainted with the notion of Remote Method calls, as the follow the same principles. One could say that a Web Service is basically RPC over the Web.
1. A simple RMI Application
In this example were are not going to dive deep into the RMI package, but we are going to create a simple RMI application in order to demonstrate java.rmi.RemoteException
. This application will have a simple RMI server that provides an implementation of a remote method, as well as a client that can remotely call that method. Let’s go through the code.
First of all you need to create a remote interface. This is the interface that make the communication between the client and the server possible. The servers exposes concrete implementations of the methods in that interface. On the other side, the clients uses that interface to invoke the remote procedures provided by the server.
RemoteInterface .java:
package com.javacodegeeks.core.rmi.rminterface; import java.rmi.Remote; import java.rmi.RemoteException; public interface RemoteInterface extends Remote{ public String capitalize(String str) throws RemoteException; }
Here is also a configuration class (mostly for convenience) :
Configuration.java:
package com.javacodegeeks.core.rmi.rminterface; public class Configuration { public static final int REMOTE_PORT = 8888; public static final String REMOTE_ID = "RMI_EXAMPLE"; public static final String REMOTE_HOST = "localhost"; }
OK now let’s go to the server side. Remember that the server has to provide a concrete implementation of RemoteInterface
:
RMIImplementation.java:
package com.javacodegeeks.core.rmi.remoteserver; import java.rmi.RemoteException; import java.rmi.server.UnicastRemoteObject; import com.javacodegeeks.core.rmi.rminterface.RemoteInterface; public class RMIImplementation extends UnicastRemoteObject implements RemoteInterface{ protected RMIImplementation() throws RemoteException { super(); } private static final long serialVersionUID = 1L; @Override public String capitalize(String str) throws RemoteException { return str.toUpperCase(); } }
And now it has to expose this capitalize
implementation to the public:
RemoteServer.java :
package com.javacodegeeks.core.rmi.remoteserver; import java.rmi.AlreadyBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import com.javacodegeeks.core.rmi.rminterface.Configuration; public class RemoteServer { public static void main(String[] args) throws RemoteException, AlreadyBoundException { RMIImplementation rmiImplementation = new RMIImplementation(); Registry registry = LocateRegistry.createRegistry(Configuration.REMOTE_PORT); registry.bind(Configuration.REMOTE_ID, rmiImplementation); } }
On on the client side, the client has to connect to the server an simply look up the method it wants.
RemoteClient.java:
package com.javacodegeeks.core.rmi.remoteclient; import java.rmi.NotBoundException; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import com.javacodegeeks.core.rmi.rminterface.Configuration; import com.javacodegeeks.core.rmi.rminterface.RemoteInterface; public class RemoteClient { public static void main(String[] args) throws RemoteException, NotBoundException { Registry reg = LocateRegistry.getRegistry(Configuration.REMOTE_HOST, Configuration.REMOTE_PORT); RemoteInterface rmiInterface= (RemoteInterface) reg.lookup(Configuration.REMOTE_ID); String str = "javacodegeeks rock!"; System.out.println("RMI returns:"+rmiInterface.capitalize(str)); } }
To get an overview of the structure of the project that I’ve created, take a look at the following picture:
If you run RemoteServer
and then RemoteClient
, RemoteClient
will produce this output:
RMI returns:JAVACODEGEEKS ROCK!
2. An example of java.rmi.RemoteException
Now, imagine that as your remote methods is executed, suddenly something goes wrong and it throws an exception. A java.rmi.RemoteException
will be throw to the client.
So let’s change :
@Override public String capitalize(String str) throws RemoteException { return str.toUpperCase(); }
to :
@Override public String capitalize(String str) throws RemoteException { throw new UnexpectedException("Very unexpected"); //return str.toUpperCase(); }
Now, if you run the server first and then the client, here is the output:
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is: java.rmi.UnexpectedException: Very unexpected at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:353) at sun.rmi.transport.Transport$1.run(Transport.java:177) at sun.rmi.transport.Transport$1.run(Transport.java:174) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:173) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:275) at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:252) at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:161) at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194) at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148) at com.sun.proxy.$Proxy0.capitalize(Unknown Source) at com.javacodegeeks.core.rmi.remoteclient.RemoteClient.main(RemoteClient.java:21) Caused by: java.rmi.UnexpectedException: Very unexpected at com.javacodegeeks.core.rmi.remoteserver.RMIImplementation.capitalize(RMIImplementation.java:20) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322) at sun.rmi.transport.Transport$1.run(Transport.java:177) at sun.rmi.transport.Transport$1.run(Transport.java:174) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:173) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:556) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:811) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:670) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744)
3. How to solve RemoteException
As we’ve mentioned in the introduction, java.rmi.RemoteException
is the most general checked exception that may occur during the lookup or the execution of a Remote Procedure Call (RPC). It is important to note that it extends java.io.IOException
. But the most significant thing is that it is seldom found as a standalone exception in the wild. It mostly communicated along with its numerous sub classes. Some of them are : ConnectException
, ConnectIOException
, MarshalException
, NoSuchObjectException
, ServerError
, UnexpectedException
, UnmarshalException
. So as you can imagine each one of them is thrown for a variety of reasons. As always they are accompanied with a very explanatory message that will help you trace the root of the problem.
A good starting point when trying to debug this exception is to solve communication issues first. For example be sure that the client and server can communicate with each other. Then make sure that you load the correct remote ID in both sides. What you should mostly do then is try to debug the remote method implementation on the server side.
Note that RemoteException
also holds a reference to the most specific underlying exception that caused it. In the case of our example, that nested exception is a java.rmi.UnexpectedException
. This is quite helpful as you can trace the exception that caused the more general RemoteException
. That is important for debugging because, when an exception is thrown at the server, it usually reaches the client in the form of a RemoteException
. So it’s important to go deeper that that, and find out what truly cased the exception. So after solving communication and configuration issues, you can narrow down your work at debugging the remote method implementation, always following the nested exceptions.
Download the Source Code
This was an example on java.rmi.RemoteException
and how to solve RemoteException
. You can download the source code of this example here : RMIExample.zip