I'm trying to learn RMI. Managed to launch a simple example but I can't achieve dynamic loading of classes.
Hello.java
package com.example;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String greet(String name) throws RemoteException;
}
HelloImpl.java
package com.example;
public class HelloImpl implements Hello {
public String greet(String name) {
System.out.println("Call from " + name);
return "Hello " + name + "!";
}
}
Server.java
package com.example;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends HelloImpl {
public Server() {}
public static void main(String args[]) {
System.setSecurityManager(new SecurityManager());
try {
HelloImpl greeter = new HelloImpl();
Hello stub = (Hello) UnicastRemoteObject.exportObject(greeter, 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Client.java
package com.example;
import java.rmi.Naming;
public class Client {
private Client() {}
public static void main(String[] args) {
System.setSecurityManager(new SecurityManager());
try {
Hello stub = (Hello) Naming.lookup("//localhost/Hello");
System.out.println(stub.greet(args[0]));
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
rmi.policy
grant {
permission java.security.AllPermission;
};
I started rmiregistry, web-server and executed java -Djava.security.policy=rmi.policy com.example.Server. When I try to start the client application with command
java -Djava.rmi.server.codebase=http://localhost:8000/ -Djava.security.policy=rmi.policy com.example.Client Hivemaster
web-server get request
127.0.0.1 - - [13/Dec/2017 14:06:45] "GET /com/example/Hello.class HTTP/1.1" 200
but program get exception
Exception in thread "main" java.lang.NoClassDefFoundError: com/example/Hello
at com.example.Client.main(Client.java:17)
Caused by: java.lang.ClassNotFoundException: com.example.Hello
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
Why?
If the client is using the Hello interface by name, it must be present on its classpath. Same as it does when compiling it.
The codebase feature is for classes derived from those mentioned in remote interfaces. In this case there is no apparent need to use the codebase feature at all: but if you do, the codebase property needs to be set at the JVM which is sending instances of those classes.
Related
I am using IntelliJ as my IDE and the code below runs alright if they are in the same src folder. However, what I want is to call the sayHello() method in another project. Is that possible? I thought this is possible since this is what RMI enables, but am I wrong?
I tried to create another project that contains a Main java class and has the same code as the Client Test Drive below, hoping to call the sayHello() method by utilizing Naming.lookup() but it doesn't work! If I try to run it, I was given a java.rmi.UnmarshalException: error unmarshalling return; exception. What am I missing?
How can I call the sayHello() method "remotely"?
Remote Interface:
package Remote;
import java.rmi.*;
public interface HelloRemote extends Remote {
String sayHello() throws RemoteException;
}
Remote Implementation
package Remote;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
public class HelloRemoteImpl extends UnicastRemoteObject implements HelloRemote{
public HelloRemoteImpl() throws RemoteException {};
#Override
public String sayHello() throws RemoteException {
return "Server says, \"Hello!\"";
}
public static void main(String[] args) {
try {
// 2.3 register the service
HelloRemote service = new HelloRemoteImpl();
final int PORT = 1888;
Registry registry = LocateRegistry.createRegistry(PORT);
registry.rebind("hello", service);
System.out.println("Service running on PORT: " + PORT);
} catch(Exception e) {
e.printStackTrace();
}
}
}
Client Test Drive
package Remote;
import java.rmi.Naming;
public class SayHelloTest {
public static void main(String[] args) {
try {
HelloRemote service = (HelloRemote) Naming.lookup("rmi://127.0.0.1:1888/hello");
String helloStr = service.sayHello();
System.out.println(helloStr);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I am learning RMI by myself now.I put all my files in the same directory and they are working well.But after I separate the server and client in different directory,there will be an error said
RemoteException
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: CalculatorImpl_Stub (no security manager: RMI class loader disabled).
I dont know how to fix it.and here is my code :
Server
import java.rmi.Naming;
public class CalculatorServer{
public CalculatorServer(){
try{
Calculator c = new CalculatorImpl();
Naming.rebind("rmi://localhost:1099/CalculatorService", c);
}catch(Exception e){
System.out.println("Trouble: "+ e);
}
}
public static void main(String args[]){
new CalculatorServer();
}
}
Client
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.net.MalformedURLException;
import java.rmi.NotBoundException;
public class CalculatorClient{
public static void main(String[] args){
try{
Calculator c = (Calculator)Naming.lookup("rmi://localhost/CalculatorService");
System.out.println(c.sub(4,3));
System.out.println(c.add(4,5));
System.out.println(c.mul(3,6));
System.out.println(c.div(9,3));
}catch(MalformedURLException murle){
System.out.println();
System.out.println("MalformedURLException");
System.out.println(murle);
}
....
}
You've over-separated. Some of the .class files are common to both the server and the client. The class mentioned in the exception is one of them, and so are any others that show up in subsequent such exceptions.
I am creating RMI program for my class assignment in Netbeans. It is a simple RMI program and The server side is working properly. But as I run my client side file. It ends up giving me error
Exception in thread "main" java.security.AccessControlException: access denied ("java.net.SocketPermission" "127.0.0.1:1099" "connect,resolve")
plus it is saying some error at line 26 at client code.
For clear understanding I am giving full code of all three files.
Interface.java :
package RMI;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface DemoInterface extends Remote {
public String SayDemo() throws RemoteException;
}
Server.java
package RMI;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class Server implements Interface{
public Server()
{
super();
}
private String message;
public Server(String msg) throws RemoteException
{
message = msg;
}
public static void main(String[] args) {
try {
DemoInterface h = new Server("Hello");
DemoInterface stub = (DemoInterface) UnicastRemoteObject.exportObject(h,0);
LocateRegistry.createRegistry(4096);
Registry registry = LocateRegistry.getRegistry("127.0.0.1",4096);
registry.rebind("Hello", stub);
System.out.println("Server is connected and ready to use");
}
catch(Exception e)
{
System.out.println("server not connected\n"+e);
}
}
#Override
public String SayDemo() throws RemoteException {
System.out.println("Server.saydemo override");
return message;
}
}
Client.java
package RMI;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
public static void main(String[] args) {
if(System.getSecurityManager() == null)
{
System.setSecurityManager(new SecurityManager());
}
try {
Registry reg = LocateRegistry.getRegistry("127.0.0.1", 4096);
System.out.println("in try after reg locate");
DemoInterface h = (DemoInterface) reg.lookup("Hello");//Error Showed on this line by netbeans
System.out.println(h.SayDemo());
}
catch(RemoteException | NotBoundException e)
{
System.out.println(""+e );
}
}
}
please guide me where I am wrong. Thank You in advance.
You set a SecurityManager in your client main method. Did you also provide a security policy file? The default policy is not very permissive, and denies, among other things, Socket operations.
You can specify a policy that allows all permissions to all code bases like so.
grant {
permission java.security.AllPermission;
};
add it to your command line for invoking java. Substitute mypolicy for your policy file and SomeApp for your main class. Note the two = characters in the second argument
java -Djava.security.manager -Djava.security.policy==mypolicy SomeApp
Note that this is not a safe policy to run for RMI in a production environment (RMI can load remote code bases).
Proper use of the SecurityManager class and policy configuration is a complex topic, for further reading I suggest Java SE 7 Security Documentation and in particular Default Policy Implementation and Policy File Syntax
I get a remote exception when I try to run my RMI example. I cannot understand why.
I run the program without any arguments to the program itself or to the JVM.
Please help me to get rid of the exception.
Thanks very much
This is the exception I get:
Server exception: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: hello.Hello
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.lang.ClassNotFoundException: hello.Hello
These are the classes I have:
The client class:
package hello;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class Client {
private Client() {}
public static void main(String[] args) {
String host = (args.length < 1) ? null : args[0];
try {
Registry registry = LocateRegistry.getRegistry(host);
Hello stub = (Hello) registry.lookup("Hello");
String response = stub.sayHello();
System.out.println("response: " + response);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
The remote interace:
package hello;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface Hello extends Remote {
String sayHello() throws RemoteException;
}
And finally the server:
package hello;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server implements Hello {
public Server() {}
public String sayHello() {
return "Hello, world!";
}
public static void main(String args[]) {
try {
Server obj = new Server();
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj, 0);
// Bind the remote object's stub in the registry
Registry registry = LocateRegistry.getRegistry("localhost");
registry.bind("Hello", stub);
System.err.println("Server ready");
} catch (Exception e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
}
Either the Registry or the client or both cannot find the class named in the exception. There are several possible solutions:
include that class in the classpath when executing the Registry and the client. And all the classes it depends on, recursively until closure.
Start the Registry from inside the server JVM, with LocateRegistry.createRegistry(), which solves that classpath problem, and provide the necessary classes on the client's classpath only.
Use the codebase feature to ensure all the system components can access the required server-side classes.
As outlined in the RMI trail
You may need to supply the java.rmi.server.codebase parameter that list all the jars that the RMI server needs to export the objects...
See Running the examples and look at the "Starting the server" section. Also be sure to check out the section on running the client program for additional suggested parameters
i am tying to serially invoke Java RMI from server to other server ?
RMI Client 1 >--(1)--->RMI Server 1 >---(2)-----> RMI Server 2
Means on RMI Client 1 will invoke method on RMI Server 1 and that RMI server 1 will invoke method on Other RMI Server 2 acting client..for RMI Server 2 in same execution program
Exception : java.lang.ClassCastException: rmiserver1_Stub cannot be cast to interfc2
Please Help..
Code Here :
rmiserver1.java
import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
import java.util.*;
class rmiserver1 extends UnicastRemoteObject implements interfc1
{
public rmiserver1() throws RemoteException
{
System.out.println("RMIServer 1 Constructor ");
}
public String remote1()
{
System.out.println("here Calling RMIServer2 method remote2 ");
try
{
//here is Exception
interfc2 obj2=(interfc2) Naming.lookup("rmi://localhost/rmiserver2");
String r2=obj2.remote2();
System.out.println("Result from rmiserver2 :"+r2);
}
catch(Exception e){e.printStackTrace();}
return "RMIServer1 remote 1 method return here....";
}
public static void main(String[] args)
{
System.out.println("RMIServer 1 Main method ");
try
{
rmiserver1 p1=new rmiserver1();
Naming.rebind("rmiserver1",p1);
System.out.println("RMIServer 1 rebinded ");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
interfc1.java
import java.rmi.*;
import java.io.*;
import java.util.*;
public interface interfc1 extends Remote
{
public String remote1() throws RemoteException;
}
interfc2.java
import java.rmi.*;
import java.io.*;
import java.util.*;
public interface interfc2 extends Remote
{
public String remote2() throws RemoteException;
}
rmiserver2.java
import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
import java.util.*;
class rmiserver2 extends UnicastRemoteObject implements interfc2
{
public rmiserver2() throws RemoteException
{
System.out.println("RMIServer 2 Constructor ");
}
public String remote2()
{
return "RMIServer2 remote 2 method return here....";
}
public static void main(String[] args)
{
System.out.println("RMIServer 2 Main method ");
try
{
rmiserver1 p1=new rmiserver1();
Naming.rebind("rmiserver2",p1);
System.out.println("RMIServer 2 rebinded ");
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
rmiclient1.java
import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
import java.util.*;
class rmiclient1
{
public static void main(String[] args)
{
System.out.println("RMIClient 1 Main method");
try
{
interfc1 obj1=(interfc1) Naming.lookup("rmi://localhost/rmiserver1");
String r1=obj1.remote1();
System.out.println("Result from rmiserver1 :"+r1);
}
catch(Exception e){e.printStackTrace();}
}
}
Exception on rmiserver1 prompt :
java.lang.ClassCastException: rmiserver1_Stub cannot be cast to interfc2
at rmiserver1.remote1(rmiserver1.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
sorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
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:619)
Please Help me.....
Your issue is in the main method of your class rmiserver2, you are binding rmiserver1 with the name "rmiserver2".
Your current code in the main method of rmiserver2
rmiserver1 p1=new rmiserver1();
Naming.rebind("rmiserver2",p1);
What you wanted was this :
rmiserver2 p2=new rmiserver2();
Naming.rebind("rmiserver2",p1);
Looks like a copy paste issue :)