/* * RemoteServant.java * * Created on October 22, 2003, 9:20 PM */ package hep.aida.ref.remote; import hep.aida.IAnnotation; import hep.aida.IBaseHistogram; import hep.aida.IDataPointSet; import hep.aida.IManagedObject; import hep.aida.ITree; import hep.aida.dev.IDevTree; import hep.aida.ref.Annotation; import hep.aida.ref.ManagedObject; import hep.aida.ref.event.AIDAListener; import hep.aida.ref.event.DataPointSetEvent; import hep.aida.ref.event.HistogramEvent; 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.AidaUpdateEvent; import hep.aida.ref.tree.Tree; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; /** * This is implementation of the AidaTreeServant. It mainly deals with the * Tree and Tree Objects - change in Tree structure, updates of Tree Objects' * Data, etc. * This class does not have any remote transport layer (RMI, CORBA, etc.), * so special adapter classes, like RmiRemoteServant, are used to provide * such functionality. * The default for useValidation = true; * * @author serbo */ public class RemoteServant implements AidaTreeServant, AIDAListener { private IDevTree tree; private AidaTreeClient client; private String clientID; private boolean duplex; protected boolean blocking = false; private boolean appendAxisType; private boolean keepRunning; private Vector sources; private Hashtable hash; private RemoteServerQueue eventQueue; protected boolean useValidation; protected Logger remoteLogger; /** Creates a new instance of RemoteServant */ public RemoteServant(IDevTree tree, String clientID) { this.tree = tree; this.clientID = clientID; this.duplex = false; this.appendAxisType = false; eventQueue = new RemoteServerQueue(); remoteLogger = Logger.getLogger("hep.aida.ref.remote"); init(); } public RemoteServant(IDevTree tree, AidaTreeClient client) { this.tree = tree; this.client = client; this.duplex = true; this.appendAxisType = false; eventQueue = new RemoteServerQueue(client); remoteLogger = Logger.getLogger("hep.aida.ref.remote"); init(); } // Service methods // If "true", append ":date" or ":double" to the object type public void setAppendAxisType(boolean a) { appendAxisType = a; } public boolean getAppendAxisType() { return appendAxisType; } public void setBlocking(boolean b) { blocking = b; eventQueue.setBlocking(b); } public boolean isBlocking() { return blocking; } protected void init() { sources = new Vector(); hash = new Hashtable(); useValidation = true; keepRunning = duplex; Object lock = tree.getLock(); if (lock != null) { //synchronized (lock) { if (tree instanceof IsObservable) { ((IsObservable) tree).addListener(this); sources.add(tree); ((IsObservable) tree).setValid(this); } if (tree instanceof Tree) ((Tree) tree).setFolderIsWatched("/", true); //} } else { if (tree instanceof IsObservable) { ((IsObservable) tree).addListener(this); sources.add(tree); ((IsObservable) tree).setValid(this); } if (tree instanceof Tree) ((Tree) tree).setFolderIsWatched("/", true); } } /** * 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; } /** * Close all connections and release all allocated resources. */ public void close() { synchronized ( this ) { remoteLogger.fine("\n\tClosing RemoteServant ... "); keepRunning = false; if (eventQueue != null) eventQueue.close(); Object lock = null; if (tree != null) tree.getLock(); if (lock != null) { //synchronized (lock) { if (tree instanceof IsObservable) { try { ((IsObservable) tree).removeListener(this); } catch (Exception e) { e.printStackTrace(); } } if (sources != null) for (int i=0; i<sources.size(); i++) { try { IsObservable o = (IsObservable) sources.get(i); if (o != null) o.removeListener(this); } catch (Exception e) { e.printStackTrace(); } } //} } else { if (tree instanceof IsObservable) { try { ((IsObservable) tree).removeListener(this); } catch (Exception e) { e.printStackTrace(); } } if (sources != null) for (int i=0; i<sources.size(); i++) { try { IsObservable o = (IsObservable) sources.get(i); if (o != null) o.removeListener(this); } catch (Exception e) { e.printStackTrace(); } } } } if (sources != null) sources.clear(); if (hash != null) hash.clear(); sources = null; hash = null; tree = null; client = null; eventQueue = null; remoteLogger.fine(" ... RemoteServant is closed\n"); } public void setValid(String path) { remoteLogger.finest("RemoteServant.setValid for path="+path); if (path == null || path.equals("") || path.equals("/") ) { if (tree instanceof IsObservable) ((IsObservable) tree).setValid(this); } else { IManagedObject mo = tree.find(path); if (!sources.contains(mo) && mo instanceof IsObservable) { ((IsObservable) mo).addListener(this); sources.add(mo); } if (mo instanceof IsObservable) { ((IsObservable) mo).setValid(this); } } } // AidaTreeServant methods /** * Just return an IManagedObject itself. Later the transport layer class * (like RmiRemoteServant) will have to extract the data from the IManagedObject * and send the data over the network. */ public java.lang.Object find(String path) { remoteLogger.finest("RemoteServant.find for path="+path); IManagedObject mo = tree.find(path); if (mo instanceof IsObservable) { if (!sources.contains((IsObservable) mo)) { ((IsObservable) mo).addListener(this); sources.add((IsObservable) mo); hash.put(path, mo); if (!useValidation) ((IsObservable) mo).setValid(this); } } remoteLogger.finest("RemoteServant.find for path="+path+", found MO="+mo.toString()); return mo; } public String[] listObjectNames(String path, boolean recursive) { remoteLogger.finest("RemoteServant.listObjectNames for path="+path); if (tree instanceof Tree) ((Tree) tree).setFolderIsWatched(path, true); String[] list = tree.listObjectNames(path, recursive); /* if (list == null || list.length == 0) return list; if (tree instanceof Tree) { Tree tTree = (Tree) tree; for (int i=0; i<list.length; i++) { String objPath = list[i]; if (!useValidation) { IManagedObject mo = tTree.findObject(objPath); if (mo instanceof IsObservable) { ((IsObservable) mo).setValid(this); } } } } */ return list; } public String[] listObjectTypes(String path, boolean recursive) { remoteLogger.finest("RemoteServant.listObjectTypes for path="+path+", appendAxisType="+appendAxisType); if (tree instanceof Tree) ((Tree) tree).setFolderIsWatched(path, true); String[] names = tree.listObjectNames(path, recursive); String[] list = tree.listObjectTypes(path, recursive); if (list == null || list.length == 0) return list; if (tree instanceof Tree) { Tree tTree = (Tree) tree; for (int i=0; i<names.length; i++) { String objPath = names[i]; IManagedObject mo = tTree.findObject(objPath); if (appendAxisType && !list[i].equalsIgnoreCase("dir")) { String xType = "double"; String tmp = null; if (mo instanceof ManagedObject) { synchronized (mo) { boolean isFillable = false; boolean isAnnotationFillable = false; Annotation an = null; isFillable = ((ManagedObject) mo).isFillable(); if (!isFillable) ((ManagedObject) mo).setFillable(true); if (mo instanceof IBaseHistogram) an = (Annotation) ((IBaseHistogram) mo).annotation(); else if (mo instanceof IDataPointSet) an = (Annotation) ((IDataPointSet) mo).annotation(); if (an != null) { isAnnotationFillable = an.isFillable(); if (!isAnnotationFillable) an.setFillable(true); try { tmp = an.value("xAxisType"); } catch (IllegalArgumentException e) {} an.setFillable(isAnnotationFillable); } ((ManagedObject) mo).setFillable(isFillable); } } else if (mo != null) { IAnnotation an = null; if (mo instanceof IBaseHistogram) an = (IAnnotation) ((IBaseHistogram) mo).annotation(); else if (mo instanceof IDataPointSet) an = (IAnnotation) ((IDataPointSet) mo).annotation(); try { tmp = an.value("xAxisType"); } catch (Exception e) {} } if (tmp != null && !tmp.trim().equals("")) { xType = tmp; list[i] = list[i]+":"+xType; } } //if (!useValidation && mo instanceof IsObservable) { // ((IsObservable) mo).setValid(this); //} } } return list; } public void setValid(String[] path) { if (path != null && path.length != 0) { for (int i=0; i<path.length; i++) { //System.out.println("RemoteServant.setValid: path["+i+"] = "+path[i]); setValid(path[i]); } } } public AidaUpdateEvent[] updates() { remoteLogger.finest("RemoteServant.updates"); AidaUpdateEvent[] events = new AidaUpdateEvent[0]; if (eventQueue != null) events = eventQueue.getEvents(); remoteLogger.finest("RemoteServant.updates gotEvents="+events.length); return events; } // AIDAListener methods /** * Mainly this method translates Tree, DataPointSet, Histogram, etc. * event into AidaUpdateEvent. Also add event to the queue. */ public void stateChanged(java.util.EventObject ev) { remoteLogger.finest("RemoteServant: got Event: "+ev.toString()); AidaUpdateEvent event = null; int id = -1; String pathString = ""; String nodeType = "null"; String xAxisType = "double"; IManagedObject mo = null; if (ev instanceof AidaUpdateEvent) { AidaUpdateEvent aev = (AidaUpdateEvent) ev; id = aev.id(); pathString = aev.path(); String nodeTypeString = aev.nodeType(); nodeType = nodeTypeString; xAxisType = "double"; // Parce out possible X Axis type int indexT = nodeTypeString.lastIndexOf(":"); if (indexT > 0) { nodeType = nodeTypeString.substring(0, indexT); String tmpType = nodeTypeString.substring(indexT+1); if (tmpType != null && !tmpType.equals("")) xAxisType = tmpType; } else if (event instanceof RemoteUpdateEvent) { String tmp = ((RemoteUpdateEvent) event).getXAxisType(); if (tmp != null) xAxisType = tmp; } } else if (ev instanceof TreeEvent) { //TreeEvent TreeEvent tev = (TreeEvent) ev; if (tev.getType() != null) nodeType = tev.getType().getName(); if (tev.getFlags() == TreeEvent.FOLDER_MASK) { nodeType = "dir"; } String[] path = tev.getPath(); if (path != null) for (int i=0; i<path.length; i++) { pathString += "/" + path[i]; } if (tev.getID() == TreeEvent.NODE_ADDED) { id = AidaUpdateEvent.NODE_ADDED; try { if (!nodeType.equalsIgnoreCase("dir")) { IManagedObject tmpMo = ((ITree) ev.getSource()).find(pathString); nodeType = tmpMo.type(); } } catch (Exception ex) { remoteLogger.log(Level.INFO, "RemoteServant.stateChanged: Exception while setting type:"+nodeType+ " \n\t"+ex.getMessage()); remoteLogger.log(Level.FINEST, "", ex); } } else if (tev.getID() == TreeEvent.NODE_DELETED) { id = AidaUpdateEvent.NODE_DELETED; } else if (tev.getID() == TreeEvent.TREE_CLOSED) { id = AidaUpdateEvent.TREE_CLOSED; nodeType = "dir"; } } else if (ev instanceof HistogramEvent) { mo = (IManagedObject) ev.getSource(); } else if (ev instanceof DataPointSetEvent) { mo = (IManagedObject) ev.getSource(); } else { // Unknown Event remoteLogger.fine("RemoteServant.stateChanged Unknown Event: "+ev); return; } if (mo != null) { pathString = tree.findPath((IManagedObject) mo); id = AidaUpdateEvent.NODE_UPDATED; nodeType = ((IManagedObject)mo).type(); //if (!useValidation && mo instanceof IsObservable) ((IsObservable) mo).setValid(this); } if (!nodeType.equalsIgnoreCase("dir") && pathString.endsWith("/")) pathString = pathString.substring(0, pathString.length()-1); if (nodeType.equalsIgnoreCase("dir") && !pathString.endsWith("/")) pathString += "/"; if (id == AidaUpdateEvent.NODE_ADDED) { if (nodeType.equalsIgnoreCase("dir")) { // nothing to do here } else if (mo != null) { String tmp = null; if (mo instanceof ManagedObject) { synchronized (mo) { boolean isFillable = false; boolean isAnnotationFillable = false; Annotation an = null; isFillable = ((ManagedObject) mo).isFillable(); if (!isFillable) ((ManagedObject) mo).setFillable(true); if (mo instanceof IBaseHistogram) an = (Annotation) ((IBaseHistogram) mo).annotation(); else if (mo instanceof IDataPointSet) an = (Annotation) ((IDataPointSet) mo).annotation(); if (an != null) { isAnnotationFillable = an.isFillable(); if (!isAnnotationFillable) an.setFillable(true); try { tmp = an.value("xAxisType"); } catch (IllegalArgumentException e) {} an.setFillable(isAnnotationFillable); } ((ManagedObject) mo).setFillable(isFillable); } } else if (mo != null) { IAnnotation an = null; if (mo instanceof IBaseHistogram) an = (IAnnotation) ((IBaseHistogram) mo).annotation(); else if (mo instanceof IDataPointSet) an = (IAnnotation) ((IDataPointSet) mo).annotation(); try { tmp = an.value("xAxisType"); } catch (Exception e) {} } if (tmp != null && !tmp.trim().equals("")) xAxisType = tmp; } } else if (id == AidaUpdateEvent.NODE_DELETED) { if (nodeType.equalsIgnoreCase("dir")) { Enumeration en = hash.keys(); while (en.hasMoreElements()) { String tmpPath = (String) en.nextElement(); if (tmpPath.startsWith(pathString)) { IsObservable o = (IsObservable) hash.remove(pathString); if (mo != null) { ((IsObservable) o).removeListener(this); sources.remove(o); } } } } else { IsObservable o = (IsObservable) hash.remove(pathString); if (mo != null) { ((IsObservable) o).removeListener(this); sources.remove(o); } } } if (id < 0) { remoteLogger.fine("RemoteServant.stateChanged wrong event ID="+id); return; } if (!useValidation && tree instanceof IsObservable) ((IsObservable) tree).setValid(this); remoteLogger.finest("RemoteServant: process Event: id = "+id+", path = "+pathString+ ", type = "+nodeType+", xAxisType="+xAxisType); event = new RemoteUpdateEvent(id, pathString, nodeType, xAxisType); eventQueue.schedule(event); } }