/*
* RmiServerImpl.java
*
* Created on October 15, 2003, 7:02 PM
*/
package hep.aida.ref.remote.rmi.server;
// For the tests in main
import java.io.*;
import java.util.*;
import hep.aida.*;
import hep.aida.dev.*;
import hep.aida.ref.remote.*;
import hep.aida.ref.remote.rmi.*;
import hep.aida.ref.remote.rmi.client.*;
import hep.aida.ref.remote.rmi.converters.*;
import hep.aida.ref.remote.rmi.data.*;
import hep.aida.ref.remote.rmi.interfaces.*;
import org.freehep.util.FreeHEPLookup;
//
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.rmi.ConnectException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.text.DateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import java.util.logging.Level;
import hep.aida.ref.remote.RemoteConnectionException;
import hep.aida.ref.remote.RemoteServer;
import hep.aida.ref.remote.interfaces.AidaTreeClient;
import hep.aida.ref.remote.interfaces.AidaTreeServant;
import hep.aida.ref.remote.interfaces.AidaTreeServer;
import hep.aida.ref.remote.interfaces.AidaUpdateEvent;
import hep.aida.ref.remote.rmi.RmiRemoteUtils;
import hep.aida.ref.remote.rmi.interfaces.RmiClient;
import hep.aida.ref.remote.rmi.interfaces.RmiServant;
import hep.aida.ref.remote.rmi.interfaces.RmiServer;
/**
*
* @author serbo
*/
public class RmiServerImpl extends UnicastRemoteObject implements RmiServer {
static final long serialVersionUID = 5979753791192166996L;
private AidaTreeServer aidaServer;
private int port;
private String currentHost = null;
private String bindName;
private boolean useValidation;
private Map servants;
private transient Logger remoteLogger;
/** Creates a new instance of RmiClientImpl */
public RmiServerImpl(AidaTreeServer aidaServer) throws MalformedURLException, RemoteException, UnknownHostException {
this(aidaServer, null);
}
public RmiServerImpl(AidaTreeServer aidaServer, String bindName) throws MalformedURLException, RemoteException, UnknownHostException {
super();
port = RmiRemoteUtils.port;
this.aidaServer = aidaServer;
this.bindName = bindName;
remoteLogger = Logger.getLogger("hep.aida.ref.remote");
remoteLogger.setLevel(Level.SEVERE);
this.servants = new Hashtable();
this.currentHost = InetAddress.getLocalHost().getHostName();
this.port = RmiRemoteUtils.port;
useValidation = true;
connect();
}
// Service methods
/**
* If useValidation = true, client has to call "setValid" method after
* receiving update from the ManagedObject in order to reseive next update.
* If useValidation = false, client receives all updates.
*/
public synchronized void setUseValidation(boolean state) { useValidation = state; }
public void connect() throws MalformedURLException, RemoteException, UnknownHostException {
if (bindName == null) bindName = createBindName();
else {
int index = bindName.indexOf(":");
if (index >0) {
String portString = bindName.substring(index+1);
int index2 = portString.indexOf("/");
if (index2 > 0) { portString = portString.substring(0, index2); }
try {
int tmpPort = Integer.parseInt(portString);
port = tmpPort;
} catch (NumberFormatException nfe) {
//throw new RuntimeException("Bind Name is not formatted correctly: "+bindName, nfe);
}
}
}
remoteLogger.fine("RmiServer: Binding in Registry: "+bindName+", port="+port);
try {
Naming.rebind(bindName, this);
} catch (ConnectException co) {
//co.printStackTrace();
remoteLogger.fine("RmiServer: No RMI Registry is currently available for port="+port+". Starting new RMI Registry.");
LocateRegistry.createRegistry(port);
Naming.rebind(bindName, this);
}
remoteLogger.info("RmiServer ready at rmi:"+bindName);
}
public void unbind() {
try {
remoteLogger.fine("RmiServer: unbinding server from Registry: "+bindName+", port="+port);
Naming.unbind(bindName);
} catch (Exception e) { e.printStackTrace(); }
}
public void disconnect() {
remoteLogger.fine("RmiServer.disconnect: Start");
unbind();
synchronized ( servants ) {
try {
if (!servants.isEmpty()) {
Set s = servants.keySet();
Object[] arr = new Object[s.size()];
s.toArray(arr);
for (int i=0; i<arr.length; i++) {
Object clientRef = arr[i];
try {
unRegisterServant(clientRef);
} catch (Exception e3) { e3.printStackTrace(); }
}
s.clear();
servants.clear();
}
unexportObject(this, true);
} catch (Exception e2) { e2.printStackTrace(); }
}
remoteLogger.finest("RmiServer.disconnect: Finish");
servants = null;
aidaServer = null;
}
private String createBindName() {
String name = "/RmiAidaServer";
String dateString = RmiRemoteUtils.getCurrentDateString();
name = "//"+currentHost+":"+port+name+"/"+dateString;
return name;
}
private boolean checkServant(java.lang.Object key) throws RemoteException {
boolean ok = false;
if (servants.containsKey(key)) { ok = true; }
return ok;
}
private void registerServant(java.lang.Object key, RmiServantImpl rmiServant) throws RemoteException {
servants.put(key, rmiServant);
}
private boolean unRegisterServant(java.lang.Object key) throws RemoteException {
RmiServantImpl rmiServant = (RmiServantImpl) servants.remove(key);
if (rmiServant == null) return false;
rmiServant.disconnect();
return true;
}
// RmiServer methods
public String getBindName() throws RemoteException { return bindName; }
public RmiServant connectDuplex(RmiClient client) throws RemoteException {
RmiServantImpl rmiServant = null;
if (checkServant(client)) {
String clientRef = client.toString();
if (client instanceof RmiClient) clientRef = ((RmiClient) client).getBindName();
throw new RemoteConnectionException("This client is already connected. Please disconnect first.\nClient: "+clientRef);
}
rmiServant = new RmiServantImpl(client);
rmiServant.setUseValidation(useValidation);
AidaTreeServant aidaServant = aidaServer.connectDuplex(rmiServant);
if (aidaServant == null) throw new RemoteConnectionException("Can not connect to Server: "+aidaServer.treeName());
rmiServant.setAidaTreeServant(aidaServant);
registerServant(client, rmiServant);
return rmiServant;
}
public RmiServant connectNonDuplex(String clientID) throws RemoteException {
if (checkServant(clientID)) {
throw new RemoteConnectionException("This client is already connected. Please disconnect first.\nClient: "+clientID);
}
AidaTreeServant aidaServant = aidaServer.connectNonDuplex(clientID);
if (aidaServant == null) throw new RemoteConnectionException("Can not connect to Server: "+aidaServer.treeName());
RmiServantImpl rmiServant = new RmiServantImpl();
rmiServant.setUseValidation(useValidation);
rmiServant.setAidaTreeServant(aidaServant);
registerServant(clientID, rmiServant);
return rmiServant;
}
public boolean disconnectDuplex(RmiClient client) throws RemoteException {
if (!checkServant(client)) {
String clientRef = client.toString();
if (client instanceof RmiClient) clientRef = ((RmiClient) client).getBindName();
throw new RemoteConnectionException("This client is not connected.\nClient: "+clientRef);
}
RmiServantImpl rmiServant = (RmiServantImpl) servants.get(client);
boolean ok = aidaServer.disconnectDuplex(rmiServant);
return unRegisterServant(client) && ok;
}
public boolean disconnectNonDuplex(String clientID) throws RemoteException {
if (!checkServant(clientID)) {
throw new RemoteConnectionException("This client is not connected.\nClient: "+clientID);
}
boolean ok = aidaServer.disconnectNonDuplex(clientID);
return unRegisterServant(clientID) && ok;
}
public boolean supportDuplexMode() throws RemoteException {
return aidaServer.supportDuplexMode();
}
public String treeName() throws RemoteException {
return aidaServer.treeName();
}
// Do some tests here
public static void main(String[] args) throws Exception {
// Create RmiStoreFactory and register it in lookup
RmiStoreFactory rsf = new RmiStoreFactory();
// Create an AIDA tree
System.out.println("Creating AIDA server tree");
IAnalysisFactory anf = IAnalysisFactory.create();
ITreeFactory tf = anf.createTreeFactory();
IDevTree tree = (IDevTree) tf.create();
// Populate tree
System.out.println("Populating AIDA server tree");
Vector hist1D = new Vector();
tree.mkdirs("/dir1-1");
tree.mkdirs("/dir1-2");
tree.mkdirs("/dir1-1/dir2-1/dir3-1");
tree.mkdirs("/dir1-1/dir2-2");
tree.mkdirs("/dir1-2/dir2-1");
IHistogramFactory hf = anf.createHistogramFactory(tree);
tree.cd("/dir1-1");
hist1D.add(hf.createHistogram1D("Hist1D 1", "Flat Histogram 1", 50, 0, 0.9));
tree.cd("/dir1-2/dir2-1");
hist1D.add(hf.createHistogram1D("Hist1D 2", "Flat Histogram 2", 50, 0.1, 1));
hist1D.add(hf.createHistogram1D("Hist1D 3", "Gauss Histogram 3", 50, -3, 3));
tree.cd("/dir1-1/dir2-1/dir3-1");
hist1D.add(hf.createHistogram1D("Hist1D 4", "Gauss Histogram 4", 50, -3, 3));
tree.cd("/dir1-1/dir2-2");
// Update histograms
System.out.println("Updating histograms in AIDA server tree");
Random r = new Random();
for (int k=0; k<hist1D.size(); k++) {
for (int i = 0; i < 1000; i++ ) {
IHistogram1D h1D = (IHistogram1D) hist1D.get(k);
h1D.fill(r.nextDouble());
}
}
System.out.println("Creating RemoteServer");
RemoteServer treeServer = new RemoteServer(tree);
treeServer.setBlocking(true);
System.out.println("Creating RmiServer");
RmiServerImpl rmiTreeServer = new RmiServerImpl(treeServer);
String clientName = "RmiClientTree";
String bindName = rmiTreeServer.getBindName();
String options = "duplex=\"false\",RmiServerName=\""+bindName+"\"";
/*
System.out.println("Creating Client Tree: bindName="+bindName+", options="+options);
ITree clientTree = tf.create(clientName, RmiStoreFactory.storeType, true, false, options);
// Open all client Directories
String[] dirs = clientTree.listObjectNames("/");
String[] types = clientTree.listObjectTypes("/");
for (int i=0; i<dirs.length; i++) {
if (types[i].equalsIgnoreCase("dir")) {
String[] dirs1 = clientTree.listObjectNames("/"+dirs[i]);
String[] types1 = clientTree.listObjectTypes("/"+dirs[i]);
for (int ii=0; ii<dirs1.length; ii++) {
if (types1[ii].equalsIgnoreCase("dir")) {
String[] dirs2 = clientTree.listObjectNames(dirs1[ii]);
String[] types2 = clientTree.listObjectTypes(dirs1[ii]);
for (int iii=0; iii<dirs2.length; iii++) {
if (types2[iii].equalsIgnoreCase("dir")) {
String[] dirs3 = clientTree.listObjectNames(dirs2[iii]);
String[] types3 = clientTree.listObjectTypes(dirs2[iii]);
}
}
}
}
}
}
*/
// Wait for user input
System.out.println("\n\nInput: u - update histograms, a - add histogram to a tree, d - delete last added histogram, e - exit");
System.out.print("> ");
BufferedReader console = new BufferedReader( new InputStreamReader(System.in));
String input = null;
while ((input = console.readLine()) != null ) {
try {
if (input.equalsIgnoreCase("e")) System.exit(1);
else if (input.equalsIgnoreCase("u")) { // update existing histograms
for (int k=0; k<hist1D.size(); k++) {
for (int i = 0; i < 1000; i++ ) {
IHistogram1D h1D = (IHistogram1D) hist1D.get(k);
h1D.fill(r.nextDouble());
}
}
} else if (input.equalsIgnoreCase("a")) { // Add new histogram
int id = hist1D.size() + 1;
hist1D.add(hf.createHistogram1D("Extra Hist1D "+id, "Extra Flat Histogram id="+id, 50, 0.1, 0.9));
} else if (input.equalsIgnoreCase("d")) { // Delete histogram that was added last
int id = hist1D.size() - 1;
IManagedObject h1D = (IManagedObject) hist1D.remove(id);
String path = tree.findPath(h1D);
tree.rm(path);
} else {
System.out.println("Wrong input: "+input);
System.out.println("\n\nInput: u - update histograms, a - add histogram to a tree, d - delete last added histogram, e - exit");
}
System.out.print("> ");
} catch (Exception e) {
e.printStackTrace();
System.out.println("\n\nInput: u - update histograms, a - add histogram to a tree, d - delete last added histogram, e - exit");
System.out.print("> ");
}
}
}
}