I created a simple Java RMI application in netbeans 7.0.1 ( win 7 + jdk 7u1). I have two separate projects:
RMI_Client contains:
MyClient class:
package rmi_client;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class MyClient
{
public static void main(String[] args)
{
String msg = "Hello RMI";
rmiInterface stub;
Registry reg;
try
{
reg = LocateRegistry.getRegistry("localhost");
stub = (rmiInterface) reg.lookup("Hello");
try
{
stub.hello(msg);
}
catch(Exception e)
{
System.out.println("Remote method exception thrown: " +e.getMessage());
}
}
catch(Exception e)
{
System.err.println("Client exception thrown: " + e.toString());
e.printStackTrace();
}
}
}
rmiInterface interface:
package rmi_client;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface rmiInterface extends Remote
{
void hello(String message) throws RemoteException;
}
RMI_Server contains:
rmiInterface interface - exactly the same as above
rmiImpl class:
package rmi_server;
import java.rmi.RemoteException;
public class rmiImpl implements rmiInterface
{
#Override
public void hello(String message) throws RemoteException
{
System.out.println("Server:" + message);
}
}
MyServer class:
package rmi_server;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MyServer
{
public static void main(String[] args)
{
try
{
rmiImpl robj = new rmiImpl();
rmiInterface stub = (rmiInterface) UnicastRemoteObject.exportObject(robj, 0);
Registry reg = LocateRegistry.createRegistry(1099);
reg.rebind("Hello", stub);
System.out.println("Server is ready to listen: ");
}
catch (Exception e)
{
System.err.println("Server exception thrown: " + e.toString());
}
}
}
If I'm doing something wrong above please let me know. First I start RMI_Server application, then when I run RMI_Client I get errors:
Client exception thrown: java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: rmi_server.rmiInterface (no security manager: RMI class loader disabled)
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: rmi_server.rmiInterface (no security manager: RMI class loader disabled)
at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
at rmi_client.MyClient.main(MyClient.java:28)
Caused by: java.lang.ClassNotFoundException: rmi_server.rmiInterface (no security manager: RMI class loader disabled)
at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:554)
at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:646)
at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:311)
at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStream.java:257)
at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1549)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1511)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
... 2 more
Where is the problem ?
RMI_Server contains:
rmiInterface interface - exactly the same as above
No it isn't. This message:
java.lang.ClassNotFoundException: rmi_server.rmiInterface
says that rmiinterface is in the rmi_server package, which isn't 'the same as above'.
It has to be exactly the same class. Not a similar class in a different package.
So what you need is three packages: server, client, and shared. The shared package needs to contain the remote interface and any application classes it relies on.
Related
my java version is: 1.8.0_282
this is client:
import java.rmi.registry.*;
import javax.naming.*;
public class RegistryClient {
public static void main(String[] args) throws Exception {
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
Context registry = new InitialContext();
registry.lookup("rmi://127.0.0.1:1099/Demo");
System.out.println("done");
}
}
this is server:
import java.rmi.registry.*;
import javax.naming.*;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
public class RegistryServer {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
Reference refObj = new Reference(
"xxx",
"RMIRegistryDemoRemote",
"http://127.0.0.1:8000/"
);
ReferenceWrapper hello = new ReferenceWrapper(refObj);
registry.bind("Demo", hello);
System.out.println("[!] server is ready");
}
}
this is the interface and implement of RMIRegistryDemo:
import java.rmi.*;
public interface RMIRegistryDemo extends Remote {
String sayHello(String name) throws Exception;
}
import java.rmi.server.*;
import java.rmi.*;
public class RMIRegistryDemoImpl extends UnicastRemoteObject implements RMIRegistryDemo {
public RMIRegistryDemoImpl() throws Exception {}
String id = "10";
#Override
public String sayHello(String name) {
System.out.println(id);
return "Hi, " + name;
}
}
this is the remote .class:
import java.io.IOException;
public class RMIRegistryDemoRemote {
public RMIRegistryDemoRemote() throws IOException {
final Process process = Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
}
}
after:
run RegistryServer
deployed a web server to send RMIRegistryDemoRemote.class
run RegistryClient
the client just prints "done", and no access log in my weblog:
# overflow in ~/Downloads/test [16:16:44]
» javac RegistryClient.java && java RegistryClient
done
# overflow in ~/Downloads/test/remote [16:20:05]
» python -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
what causes it?
i wrote a program in netbeans with RMI that client has error
error :
java.rmi.UnmarshalException: error unmarshalling return; nested
exception is: java.lang.ClassNotFoundException: rmiserver.Message
(no security manager: RMI class loader disabled) at
sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
but sever does not any error!
interfaace code:
package rmiclient;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Message extends Remote {
void sayHello(String name) throws RemoteException;
}
interface implementation is:
package rmiserver;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class MessageImpl extends UnicastRemoteObject implements Message {
public MessageImpl() throws RemoteException {
}
#Override
public void sayHello(String name) throws RemoteException {
System.out.println("hello "+name);
}
}
server code is:
package rmiserver;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Main {
private void startServer(){
try {
// create on port 1099
Registry registry = LocateRegistry.createRegistry(1099);
// create a new service named myMessage
registry.rebind("myMessage", new MessageImpl());
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("system is ready");
}
public static void main(String[] args) {
Main main = new Main();
main.startServer();
}
}
client code is:
package rmiclient;
import java.rmi.RMISecurityManager;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Main {
private void doTest(){
try {
// fire to localhost port 1099
Registry myRegistry = LocateRegistry.getRegistry("127.0.0.1", 1099);
// search for myMessage service
Message impl = (Message) myRegistry.lookup("myMessage");
// call server's method
impl.sayHello("edwin");
System.out.println("Message Sent");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Main main = new Main();
main.doTest();
}
}
thanks :).
In your stacktrace:
java.lang.ClassNotFoundException: rmiserver.Message
but as per data you have provided, your Message interface is declated with package package rmiclient; and You haven't created any rmiserver.Message class.
Correct the package name.
I have two package. rmiclient and rmiserver. that in rmiclient are "message" and "main" . in rmiserver are "message" and "main" and "messageimpl"
That's your problem. This doesn't satisfy the contract. You can't just copy Message to another package and expect to have it be treated the same as the original. The remote stub implements the same remote interfaces that the remote object does. Not another interface with the same name in another package.
You have to deploy rmiserver.Message to the client. Just like the error message says, really.
I have a java rmi server and a java rmi client in two separate and different machines.
The server is basically a fibonacy calculator. It receives a bunch of numbers and calculates a Fibonacci sequence based on them.
The client simply sends a bunch of numbers for the server to calculate.
The FiboServer project consists of three classes:
IFibonacci.java: an interface
Fibonacci.java: implements the previously defined interface
FibonacciServer.java: Has the main, and runs the server
FibonacciServer.java:
package fiboserver;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class FibonacciServer {
public static void main(String args[]){
if (System.getSecurityManager() == null) {
System.setProperty("java.security.policy", "server.policy");
System.setSecurityManager(new SecurityManager());
}
try{
IFibonacci fib = new Fibonacci();
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.createRegistry(1099);
registry.rebind("fibonacci", fib);
System.out.println("Fibonacci Server ready.");
}catch(RemoteException rex){
System.err.println("Exception in Fibonacci.main " + rex);
}
}
}
The client project merely has one class: FibonacciClient.java.
FibonacciClient.java:
package fiboclient;
import fiboserver.IFibonacci;
import java.math.BigInteger;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class FibonacciClient {
public static void main(String[] args) {
if (System.getSecurityManager() == null) {
System.setProperty("java.security.policy", "client.policy");
System.setSecurityManager(new SecurityManager());
}
try{
//args[0] = server Public IP
Registry registry = LocateRegistry.getRegistry(args[0]);
IFibonacci calculator = (IFibonacci) registry.lookup("fibonacci");
//the rest of the args are just numbers to calculate
for(int i = 1; i < args.length; i++){
try{
BigInteger index = new BigInteger(args[i]);
BigInteger f = calculator.getFibonacci(index);
System.out.println("The " + args[i] + "th Fibonacci number "
+ "is " + f);
}catch(NumberFormatException e){
System.err.println(args[i] + " is not an integer.");
}
}
}catch(RemoteException e){
System.err.println("Remote object threw exception " + e);
} catch (NotBoundException e) {
System.err.println("Could not find the requested remote object on "
+ "the server: " + e);
}
}
}
Both projects have a policy file, the server has a server.policy and the client has a client.policy file. Both files have the same content:
grant{
permission java.security.AllPermission;
};
I am launching the FiboServer in the server machine using java -jar FiboServer.jar -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=12.34.56.789
I am launching the client by using java -jar FiboClient.jar 12.34.56.789 1 2 3 4 5.
The server launches without a problem. But when I launch the client I get the error:
Remote object threw exception java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: fiboserver.IFibonacci
Searches on StackOverflow convinced me that this has to do with RMI registry errors or policy file errors. However I know the the policy files are being read correctly and I do not think they have any errors.
What am I doing wrong? Why is this not working?
EDIT:
IFibonacci.java:
package fiboserver;
import java.math.BigInteger;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface IFibonacci extends Remote{
public BigInteger getFibonacci(int n) throws RemoteException;
public BigInteger getFibonacci(BigInteger n) throws RemoteException;
}
JAR Files:
Contents of FibonacciClient.jar:
|META-INF
|----Manifest.mf
|fiboclient
|----FibonacciClient.class
Contents of FibonacciServer.jar:
|META-INF
|----manifest.mf
|fiboserver
|----IFibonacci.class
|----FibonacciServer.class
|----Fibonacci.class
The client doesn't have the class named in the exception available on its classpath. You need to deploy it, and any class it depends in, and so on recursively until closure.
Possibly you've renamed/copied the remote interface into another package for the client. You can't do that. It has to be the same at server and client. Same name, same methods, same package.
NB The message in your client 'remote object threw exception' isn't correct. It could be the lookup() throwing the exception. Don't confuse yourself by assuming things that may not be so. Just print the actual error message, exception, and stack trace.
import java.rmi.Naming;
import java.rmi.Remote;
import java.rmi.RMISecurityManager;
import java.rmi.server.RMIClassLoader;
import java.util.*;
import java.lang.reflect.Constructor;
public class DynamicClient {
public DynamicClient (String[] args) throws Exception {
Properties p = System.getProperties();
String url = p.getProperty("java.rmi.server.codebase");
Class ClasseClient = RMIClassLoader.loadClass(url,"ClientDistant");
Constructor [] C = ClasseClient.getConstructors();
C[0].newInstance( new Object[] {args} );
}
public static void main (String[] args) {
System.setSecurityManager( new RMISecurityManager() );
try {
DynamicClient cli = new DynamicClient(args);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
This code is supposed to dynamically charge the class ClientDistant from a web server and execute the treatment, however it displays an error message:
C:\Users\DELL\Desktop>java -Djava.security.policy=client.policy -Djava.rmi.serv
er.useCodebaseOnly=false -Djava.rmi.server.codebase=http://localhost:8080/RMI/
DynamicClient
java.lang.ArrayIndexOutOfBoundsException: 0
where RMI is a directory's in the java web application named RMI ( I m using GlassFish server).
Any solutions to load ClientDistant and execute its treatment?
I've spent almost five hours trying to resolve this, to no avail. I've created an application that uses RMI. It compiles fine, but I can't it get it to run.
All my class files are in C:\Users\Benji\Desktop\ass2\build (short for "assignment"; nothing dirty). All source files are in C:\Users\Benji\Desktop\ass2\src.
I've put everything in a single package to make things more comprehensible (and changed the import statements in the source to reflect this).
I have put a batch file in C:\Users\Benji\Desktop\ass2\ . Its contains the execution statement:
java -classpath ./build -Djava.rmi.server.codebase=file:/C:/Users/Benji/Desktop/ass2/build -Djava.security.policy=broker.policy BrokerReception Broker 16890
(The two args "Broker" and "16890" are needed by the program).
The file broker.policy is also in C:\Users\Benji\Desktop\ass2\ . Its contents are:
grant
{
permission java.security.AllPermission;
};
(and yes, I realise this isn't a good security policy. I'll work on this later).
There are actually three Main classes, one for a client, one for a broker (a mediator for the client) and a server. I am trying to start the Broker. Code for the Broker interface is as follows:
import java.io.FileNotFoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.util.ArrayList;
public interface Broker extends Remote
{
public boolean getAvailability(int startDate, int endDate) throws FileNotFoundException, RemoteException;
public ArrayList<CityInfo> getCities() throws FileNotFoundException, RemoteException;
public ArrayList<HotelInfo> getCityHotels(int cityNumber) throws FileNotFoundException, RemoteException;
public int getHotelRoomRate(int hotelNumber) throws FileNotFoundException, RemoteException;
public boolean makeBooking(String firstName, String lastName, String contact, String creditCardNo) throws FileNotFoundException, RemoteException;
}
And the implementation class:
import java.io.FileNotFoundException;
import java.util.ArrayList;
public class BrokerClientLiaison implements Broker
{
private BrokerDatabase directory;
private BrokerHotelsLiaison liaison;
public BrokerClientLiaison(BrokerDatabase directory, int activeHotelNumber)
{
this.liaison = new BrokerHotelsLiaison(activeHotelNumber);
this.directory = directory;
}
public boolean getAvailability(int startDate, int endDate) throws FileNotFoundException
{
return liaison.getAvailability(startDate, endDate);
}
public ArrayList<CityInfo> getCities() throws FileNotFoundException
{
return directory.getCities();
}
public ArrayList<HotelInfo> getCityHotels(int cityNumber) throws FileNotFoundException
{
return directory.getCityHotels(cityNumber);
}
public int getHotelRoomRate(int hotelNumber) throws FileNotFoundException
{
return liaison.getHotelRoomRate(hotelNumber);
}
public boolean makeBooking(String firstName, String lastName, String contact, String creditCardNo) throws FileNotFoundException
{
return liaison.makeBooking(firstName, lastName, contact, creditCardNo);
}
}
And finally, the main class to start the implementation class:
import java.io.FileNotFoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
public class BrokerReception
{
public static void main(String[] args)
{
System.out.println("Args are:");
for(String arg : args)
{
System.out.println(arg);
}
System.out.println();
try
{
BrokerDatabase directory = new BrokerDatabase();
directory.connect(args[0]);
int activeHotelNumber = Integer.parseInt(args[1]);
if(directory.checkActiveHotelExists(activeHotelNumber))
{
BrokerClientLiaison liaison = new BrokerClientLiaison(directory, activeHotelNumber);
Broker liaisonStub = (Broker) UnicastRemoteObject.exportObject(liaison, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind(Protocol.BROKER_INTERFACE_NAME, liaisonStub);
}
else
{
throw new FileNotFoundException();
}
}
catch(ArrayIndexOutOfBoundsException aioobe)
{
System.err.println("Args required:");
System.err.println("1. Name of database file");
System.err.println("2. Number of active hotel");
System.exit(1);
}
catch(ClassNotFoundException cnfe)
{
System.err.println("Couldn't load database driver");
System.exit(2);
}
catch(SQLException sqle)
{
System.err.println("Couldn't establish connection to database");
System.err.println("Check that the database has been properly registerd,");
System.err.println("and that you provided the correct name");
System.exit(3);
}
catch(NumberFormatException nfe)
{
System.err.println("Second argument must be an integer");
System.exit(4);
}
catch(FileNotFoundException fnfe)
{
System.err.println("The database contains no entries with that hotel number");
System.exit(5);
}
catch(RemoteException re)
{
System.err.println("Unable to bind as " + Protocol.BROKER_INTERFACE_NAME);
re.printStackTrace();
System.exit(6);
}
}
}
"Directory" in the above code is a class that accesses a database.
I don't know what other information I need to give. Can anybody tell me what I'm doing wrong?
Incidentally, I went back and did Oracle's RMI tutorial at http://download.oracle.com/javase/1.5.0/docs/guide/rmi/hello/hello-world.html, to see if I could figure out what's wrong. The tutorial makes no mention of codebase or security policy, but provides all the code and precise instructions for compilation and execution. I followed these instructions to the letter, and yet even this didn't work!
Stack trace:
java.rmi.ServerException: RemoteException occurred in server thread; nested exce
ption is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested excep
tion is:
java.lang.ClassNotFoundException: Broker
at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:396
)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:5
35)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:908)
at java.lang.Thread.run(Thread.java:662)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Stream
RemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:
233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:359)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at BrokerReception.main(BrokerReception.java:32)
Caused by: java.rmi.UnmarshalException: error unmarshalling arguments; nested ex
ception is:
java.lang.ClassNotFoundException: Broker
at sun.rmi.registry.RegistryImpl_Skel.dispatch(Unknown Source)
at sun.rmi.server.UnicastServerRef.oldDispatch(UnicastServerRef.java:386
)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:250)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:5
35)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTranspor
t.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport
.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExec
utor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor
.java:908)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.ClassNotFoundException: Broker
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:247)
at sun.rmi.server.LoaderHandler.loadProxyInterfaces(LoaderHandler.java:7
11)
at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:655)
at sun.rmi.server.LoaderHandler.loadProxyClass(LoaderHandler.java:592)
at java.rmi.server.RMIClassLoader$2.loadProxyClass(RMIClassLoader.java:6
28)
at java.rmi.server.RMIClassLoader.loadProxyClass(RMIClassLoader.java:294
)
at sun.rmi.server.MarshalInputStream.resolveProxyClass(MarshalInputStrea
m.java:238)
at java.io.ObjectInputStream.readProxyDesc(ObjectInputStream.java:1530)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1492)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1
731)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
... 12 more
if you are running your registry as a second process, it needs access to your remote classes. the easiest way to do this is to add the appropriate classpath argument to the commandline when starting the registry.
if you are trying to use remote class loading, i believe you need to setup an rmi security manager in your application, either on the commandline or in the main method. (personally, distributing the classes usually works for 99% of situations and is 100 times easier to get right).