/* * RemoteServer.java * * Created on October 22, 2003, 9:01 PM */ package hep.aida.ref.remote; import hep.aida.dev.IDevTree; import hep.aida.ref.event.AIDAListener; import hep.aida.ref.event.IsObservable; import hep.aida.ref.event.TreeEvent; 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 java.util.Hashtable; import java.util.Map; import java.util.Set; import java.util.logging.Logger; /** * This is implementation of the AidaTreeServer. * This class does not have any remote transport layer (RMI, CORBA, etc.), * so special adapter classes, like RmiRemoteServer, are used to provide * such functionality. * Default is to support duplex mode. * * @author serbo */ public class RemoteServer implements AidaTreeServer, AIDAListener { private IDevTree tree; private String treeName; private boolean duplex; protected boolean blocking; private boolean useValidation; private boolean appendAxisType; private Map servantHash; private boolean acceptNewConnections; private long timeOut; protected Logger remoteLogger; /** Creates a new instance of RemoteServer */ public RemoteServer(IDevTree tree) { this(tree, true); } public RemoteServer(IDevTree tree, boolean duplex) { this(tree, duplex, false); } public RemoteServer(IDevTree tree, boolean duplex, boolean appendAxisType) { this.tree = tree; this.duplex = duplex; blocking = false; this.appendAxisType = appendAxisType; useValidation = true; treeName = tree.storeName(); servantHash = new Hashtable(); acceptNewConnections = true; remoteLogger = Logger.getLogger("hep.aida.ref.remote"); timeOut = 5000; if (tree instanceof IsObservable) ((IsObservable) tree).addListener(this); } // Service methods public void setBlocking(boolean b) { blocking = b; } public boolean isBlocking() { return blocking; } public void setTimeout(long t) { timeOut = t; } public long getTimeout() { return timeOut; } /** * 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; } private AidaTreeServant connect(java.lang.Object clientRef) { remoteLogger.info("New connection from Client: "+clientRef+", acceptNewConnections="+acceptNewConnections); if (clientRef == null) { throw new RemoteConnectionException("Can not connect with NULL Client Reference."); } AidaTreeServant servant = null; if (!acceptNewConnections) return servant; synchronized ( servantHash ) { servant = (AidaTreeServant) servantHash.get(clientRef); if (servant != null) { throw new RemoteConnectionException("This client is already connected. Please disconnect first.\nClient: "+clientRef.toString()); } else { if (clientRef instanceof String) { servant = new RemoteServant(tree, (String) clientRef); boolean tmpBlocking = blocking; if (((String) clientRef).indexOf("blocking") >= 0) tmpBlocking = true; ((RemoteServant) servant).setBlocking(tmpBlocking); } else if (clientRef instanceof AidaTreeClient) servant = new RemoteServant(tree, (AidaTreeClient) clientRef); ((RemoteServant) servant).setAppendAxisType(appendAxisType); ((RemoteServant) servant).setUseValidation(useValidation); servantHash.put(clientRef, servant); } } return servant; } /** * Disconnect servant for a particular client. * RemoteServer remains functional after that */ private boolean disconnect (java.lang.Object clientRef) { remoteLogger.info("\tDisconnecting Client: "+clientRef+", acceptNewConnections="+acceptNewConnections); AidaTreeServant servant = (AidaTreeServant) servantHash.get(clientRef); try { if (servant instanceof RemoteServant) ((RemoteServant) servant).close(); servantHash.remove(clientRef); return true; } catch (Exception e) { e.printStackTrace(); } return false; } /** * Disconnect servants for all client. * RemoteServer remains functional after that */ private void disconnectAll() { synchronized ( servantHash ) { if (!servantHash.isEmpty()) { Set keySet = servantHash.keySet(); int size = keySet.size(); Object[] a = new Object[size]; keySet.toArray(a); for (int i=0; i<size; i++) { Object clientRef = a[i]; disconnect(clientRef); } servantHash.clear(); } } } /** * Disconnect servants for all client, server and release all * allocated resources. RemoteServer does not function after that */ public void close() { acceptNewConnections = false; try { if (tree instanceof IsObservable) ((IsObservable) tree).removeListener(this); } catch (Exception e) { e.printStackTrace(); } disconnectAll(); servantHash.clear(); servantHash = null; tree = null; } // AidaTreeServer methods public AidaTreeServant connectDuplex(AidaTreeClient client) { return connect(client); } public AidaTreeServant connectNonDuplex(String clientID) { return connect(clientID); } public boolean disconnectDuplex(AidaTreeClient client) { return disconnect(client); } public boolean disconnectNonDuplex(String clientID) { return disconnect(clientID); } public boolean supportDuplexMode() { return duplex; } public String treeName() { return treeName; } // AIDAListener method public void stateChanged(java.util.EventObject event) { boolean closeTree = false; if (event instanceof TreeEvent) { if (((TreeEvent) event).getID() == TreeEvent.TREE_CLOSED) { closeTree = true; } } else if (event instanceof AidaUpdateEvent) { if (((AidaUpdateEvent) event).id() == AidaUpdateEvent.TREE_CLOSED) { closeTree = true; } } if (!closeTree) return; acceptNewConnections = false; remoteLogger.info("Got TREE_CLOSED event. Closing this RemoteServer after delay: "+timeOut); Thread t = new Thread( new Runnable() { public void run() { // Give Servants time to disconnect, then close everything try { Thread.sleep(timeOut); close(); remoteLogger.info("Server is closed"); } catch (Exception e) { e.printStackTrace(); } } } ); t.start(); } }