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();
}
}
Related
I have create a simple plugin system that allows others upload their plugin's jar, and the plugin system will load it and execute some code in it.
the plugin system will get a subclass of Function<Input, Output> to execute the loaded plugin logic, but I do not want that Function to create new Thread or do some danger action like System.exit. how can I forbid this action?
I have found the AccessController or SecurityManager in Java, how to use it to implement my intent.
Like you said, you can add a security Manager. Something like below: You can put your code in try catch block and catch your custom security exception thrown. This code below runs in loop and keeps on calling System.exit(1);
import java.security.Permission;
public class TestPreventSystemExit {
public static void main(String[] args) {
forbidSystemExitCall();
while (true) {
try {
System.exit(1);
} catch (Exception ex) {
}
}
}
private static class PreventExitException extends SecurityException {
}
private static void forbidSystemExitCall() {
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission(Permission permission) {
if (permission.getName().indexOf("exitVM") >= 0) {
System.out.println("Why you did this to me? :)");
throw new PreventExitException();
}
}
};
System.setSecurityManager(securityManager);
}
}
For System.exit() - see the other answer.
For preventing the starting of threads: possible, but requires to extend the SecurityManager class - see here.
AccessController is more about how a client would write code that is potentially checked. It is not something that you, as the "owner" of the JVM can make usage of (see here). So it doesn't help with your problem.
I have set up a client/server project using Java RMI. Below I show parts of the implementation. I
launch the server using
ProcessBuilder processBuilder = new ProcessBuilder("cmd", "/C", "start /B java -jar myServer.jar --start);
this.myProcess = processBuilder.start();
I have added a main method to the server which handles the command line call.
The server starts and runs perfectly. The client is able to connect and perform as I expect it to.
My problems arise when I try to kill the server. This needs to be done from outside. The object which
previously started the process is not available anymore. To actually stop the server, the main method
of the server class calls a stop method (see below). This method now kills the RMI but it does not
the least stop the JVM from running. The process is still available and needs to be killed from the
task manager (on Windows).
Do I miss some fact in my implementation that yields this behavior. Why does the process not stop running?
public class MyServer {
// ...
public void startServer() throws RemoteException {
// the RMI registry
Registry registry;
try {
// find the registry
registry = LocateRegistry.createRegistry(portRMI);
} catch (Exception e) {
// if the registry does not yet exist, try to create a new registry
// entry or use an existing one
registry = LocateRegistry.getRegistry(MyConstants.HOST_NAME, portRMI);
}
// create the object
servantObject = new MyServant();
// bind the object to the server
registry.rebind(MyConstants.SERVER_NAME, servantObject);
}
public void stopServer() throws RemoteException {
try {
// access the service
Registry rmiRegistry = LocateRegistry.getRegistry(MyConstants.HOST_NAME, portRMI);
MyService myService = (MyService) rmiRegistry.lookup(MyConstants.SERVER_NAME);
rmiRegistry.unbind(MyConstants.SERVER_NAME);
// get rid of the service object
UnicastRemoteObject.unexportObject(myService, true);
// get rid of the rmi registry
UnicastRemoteObject.unexportObject(rmiRegistry, true);
} catch (NoSuchObjectException e) {
// ...
} catch (NotBoundException e) {
// ...
}
}
public static void main(String[] args) {
// handle arguments and call either startServer or stopServer
}
}
public class MyServant extends UnicastRemoteObject implements MyService {
// ...
}
public interface MyService extends Remote {
// ...
}
You should add a self writtem RMIService interface available in your RMIServer so that a program that wishes to stop the running server instructs it to stop.
Your app that tries to stop the server just unbinds some object, as it is not the running rmi server process itself it will not have a big effect.
if your rmi sever is process a, you should write an app (using rmi) running as process b to send a message to process a to stop it.
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{
}
Hi I have a class that is a remote object and I implemented methods.
Then I just wanted to test it in my local. So I added a main method on it.
Then in main, I called runtUtilApp method , that just executes notepad, after some sleep I finish the working of notepad and I called stop method. After the all execution I wait program to finish execution. But it is still working and not ending.
What is the reason of this ?
I am thinking wrong ?
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.*;
public class ClientImp extends UnicastRemoteObject implements Remote{
private static final long serialVersionUID = 227L;
private Process proc;
/**
* constructor
*/
public ClientImp() throws RemoteException {
super();
}
public boolean runApp() throws RemoteException {
try {
Runtime rt = Runtime.getRuntime();
proc = rt.exec("notepad");
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
public boolean stopCurrentUtilApp() throws RemoteException {
proc.destroy();
return true;
}
public static void main(String[] args) {
client;
try {
ClientImp client = new ClientImp();
client.runUtilApp();
Thread.sleep(10000);
client.stopCurrentUtilApp();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
(I know this is a old question, but as it is referenced by many other RMI related questions I want to complete / extend the answer that was already given)
As already stated, the JVM is not exiting because a non-daemon RMI thread is still executing. This thread started to execute when the constructor of UnicastRemoteObject has been executed.
This constructor itself calls the static method UnicastRemoteObject.exportObject(this, ...) which is starting the RMI thread.
To end the thread, one could either call System.exit() or unexport the Object using UnicastRemoteObject.unexportObject(everyObjectThatHasBeenExported). The later has the advantage of not shuting down the JVM.
This is usefull in case you are building a restartable server / network service.
In this case not calling unexportObject on old (no more used) objects clutters the rmi thread. Moreover, I assume the exportedObject won't get removed by garbage collection because the rmi thread is still holding a reference on it.
Because your class extends UnicastRemoteObject, which means that when you create a new instance of your class, the UnicastRemoteObject constructor is called, which exports this object as an RMI server object, which cause a non-daemon RMI thread to start.
Call System.exit() to exit from the JVM.
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.