Come spegnere in remoto un server RMI Java
Domanda
Ho un Java RMI Server molto semplice che assomiglia al seguente:
import java.rmi.*;
import java.rmi.server.*;
public class CalculatorImpl extends UnicastRemoteObject implements Calculator {
private String mServerName;
public CalculatorImpl(String serverName) throws RemoteException
{
super();
mServerName = serverName;
}
public int calculate(int op1, int op2) throws RemoteException
{
return op1 + op2;
}
public void exit() throws RemoteException
{
try{
Naming.unbind(mServerName);
System.out.println("CalculatorServer exiting.");
}
catch(Exception e){}
System.exit(1);
}
public static void main(String args[]) throws Exception
{
System.out.println("Initializing CalculatorServer.");
String serverObjName = "rmi://localhost/Calculator";
Calculator calc = new CalculatorImpl(serverObjName);
Naming.rebind(serverObjName, calc);
System.out.println("CalculatorServer running.");
}
}
Quando chiamo il metodo exit, System.exit (1) genera la seguente eccezione:
CalculatorServer exiting.
java.rmi.UnmarshalException: Error unmarshaling return header; nested exception is:
java.io.EOFException
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:203)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
at CalculatorImpl_Stub.exit(Unknown Source)
at CalculatorClient.<init>(CalculatorClient.java:17)
at CalculatorClient.main(CalculatorClient.java:29)
Caused by: java.io.EOFException
at java.io.DataInputStream.readByte(DataInputStream.java:243)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:189)
... 4 more
[2]+ Exit 1 java CalculatorImpl
Cosa sto facendo di sbagliato in questo metodo?
Soluzione
Nel caso qualcuno abbia un problema simile, ho capito da solo la risposta. Ecco il mio metodo exit ():
public void exit() throws RemoteException
{
try{
// Unregister ourself
Naming.unbind(mServerName);
// Unexport; this will also remove us from the RMI runtime
UnicastRemoteObject.unexportObject(this, true);
System.out.println("CalculatorServer exiting.");
}
catch(Exception e){}
}
Altri suggerimenti
In realtà solo annullare la registrazione e chiamare immediatamente System.exit non si chiude in modo pulito. In pratica interrompe la connessione prima di informare il client che il messaggio è stato completato. Ciò che funziona è avviare un piccolo thread che arresta il sistema come:
public void quit() throws RemoteException {
System.out.println("quit");
Registry registry = LocateRegistry.getRegistry();
try {
registry.unbind(_SERVICENAME);
UnicastRemoteObject.unexportObject(this, false);
} catch (NotBoundException e) {
throw new RemoteException("Could not unregister service, quiting anyway", e);
}
new Thread() {
@Override
public void run() {
System.out.print("Shutting down...");
try {
sleep(2000);
} catch (InterruptedException e) {
// I don't care
}
System.out.println("done");
System.exit(0);
}
}.start();
}
Il thread è necessario per essere in grado di consentire che qualcosa accada in futuro, tornando comunque dal metodo quit.