lcsim/src/org/lcsim/contrib/onoprien/util/job
diff -u -r1.1 -r1.2
--- JobManager.java 25 Nov 2008 21:02:58 -0000 1.1
+++ JobManager.java 2 Dec 2008 23:56:10 -0000 1.2
@@ -1,39 +1,58 @@
package org.lcsim.contrib.onoprien.util.job;
-import java.lang.ref.WeakReference;
import java.util.*;
import org.lcsim.conditions.ConditionsListener;
import org.lcsim.conditions.ConditionsEvent;
import org.lcsim.conditions.ConditionsManager;
import org.lcsim.conditions.ConditionsManager.ConditionsSetNotFoundException;
-import org.lcsim.contrib.onoprien.crux.geom.CalGeometry;
-import org.lcsim.event.CalorimeterHit;
import org.lcsim.event.EventHeader;
import org.lcsim.geometry.Detector;
import org.lcsim.util.aida.AIDA;
-import org.lcsim.contrib.onoprien.util.Driver;
-
/**
* Driver that provides miscellaneous services to other classes.
* <p>
* Current functionality:
* <ul>
+ *
* <li>Accepts listener registration and dispatch events that trigger geometry dependent
- * initialization in client classes.
+ * initialization in client classes. Listeners can be registered along with
+ * dependencies among them - <tt>JobMamager</tt> guaranties that the listeners
+ * specified as "prerequisites" for come other listener will receive the event first.
+ *
+ * <li>Allows registration and retrieval of singleton objects of any type.
+ *
* <li>Provides access to the default AIDA object that can be used for histogramming, plotting, etc.
* </ul>
*
* @author D. Onoprienko
- * @version $Id: JobManager.java,v 1.1 2008/11/25 21:02:58 onoprien Exp $
+ * @version $Id: JobManager.java,v 1.2 2008/12/02 23:56:10 onoprien Exp $
*/
-public class JobManager extends Driver implements ConditionsListener {
+public class JobManager extends org.lcsim.util.Driver implements ConditionsListener {
+
+// -- Private parts : ---------------------------------------------------------
+
+ static private JobManager _defInstance;
+
+ private JobEvent _lastEvent;
+ private ArrayList<Node> _listeners;
+
+ private HashMap<Class, Object> _singletons;
+
+ private AIDA _aida;
+
// -- Constructors and initialization : ---------------------------------------
private JobManager() {
+
+ _listeners = new ArrayList<Node>(1);
+
+ _singletons = new HashMap<Class, Object>();
+
_aida = AIDA.defaultInstance();
+
getConditionsManager().addConditionsListener(this);
}
@@ -43,6 +62,18 @@
*/
private void detectorChanged(JobEvent jobEvent) {
}
+
+
+// -- Event processing : ------------------------------------------------------
+
+ /** Called by the framework to process event. */
+ public void process(EventHeader event) {
+ if (_lastEvent == null) {
+ _lastEvent = new JobEvent(this, event.getDetector());
+ fireJobEvent(_lastEvent);
+ }
+ }
+
// -- Getters : ---------------------------------------------------------------
@@ -60,22 +91,28 @@
}
-// -- Event processing : ------------------------------------------------------
+// -- Registering/retrieving singletons : -------------------------------------
- /** Called by the framework to process event. */
- public void process(EventHeader event) {
-
- // Let the listeners know they have to re-validate themselves
-
- if (_lastEvent == null) {
- _lastEvent = new JobEvent(this, event.getDetector());
- fireJobEvent(_lastEvent);
- }
-
- // Run daughter Drivers :
-
- super.process(event);
+ /**
+ * Retrieve a singleton of the specified type.
+ * If a singleton of the given type has not been registered with this <tt>JobManager</tt>,
+ * <tt>IllegalArgumentException</tt> is thrown.
+ */
+ public <T> T get(Class<T> singletonType) {
+ T singleton = (T) _singletons.get(singletonType);
+ if (singleton == null) throw new IllegalArgumentException("Singleton of this type is not registered");
+ return singleton;
+ }
+
+ /**
+ * Register a singleton of the specified type.
+ * If the given object is not an instance of the specified type, <tt>IllegalArgumentException</tt> is thrown.
+ */
+ public void put(Object singleton, Class type) {
+ if (! type.isInstance(singleton)) throw new IllegalArgumentException();
+ _singletons.put(type, singleton);
}
+
// -- Handling of event listeners : -------------------------------------------
@@ -89,9 +126,8 @@
private void fireJobEvent(JobEvent jEvent) {
detectorChanged(jEvent);
ArrayList<JobEventListener> listeners = new ArrayList<JobEventListener>(_listeners.size());
- for (WeakReference<JobEventListener> ref : _listeners) {
- JobEventListener listener = ref.get();
- if (listener != null) listeners.add(listener);
+ for (Node node : _listeners) {
+ listeners.add(node.listener);
}
for (JobEventListener listener : listeners) {
listener.detectorChanged(jEvent);
@@ -103,61 +139,150 @@
* <p>
* If the <tt>JobManager</tt> has valid detector information when a new listener is
* added, <tt>JobEvent</tt> is dispatched to that listener immediately.
- * <p>
- * Listeners are kept through weak references, so being registered with
- * JobManager as a listener does not prevent objects from being garbage-collected.
*
* @param listener Listener to be added.
* @param prerequisite Zero or more listeners that should receive the event before the listener
- * specified by the first parameter. Prerequisite listeners that have not been
- * registered earlier will be added now (in order in which they are listed).
- * If the listener specified by the first parameter is already registered,
- * neither it nor its prerequisite will be added.
+ * specified by the first parameter, in arbitrary order. Prerequisite
+ * listeners that have not been registered earlier will be added now.
+ * @throws IllegalArgumentException - if the specified list of prerequisites is inconsistent with
+ * previously registered dependencies between listeners (introduces
+ * cyclic dependencies).
*/
public void addListener(JobEventListener listener, JobEventListener... prerequisite) {
-
- LinkedList<JobEventListener> prereq = new LinkedList<JobEventListener>(Arrays.asList(prerequisite));
-
- Iterator<WeakReference<JobEventListener>> it = _listeners.iterator();
- boolean newListener = true;
- while (it.hasNext()) {
- JobEventListener lstnr = it.next().get();
- if (lstnr == null) {
- it.remove();
- } else if (lstnr == listener) {
- newListener = false;
- } else {
- prereq.remove(lstnr);
+ if (listener == null) throw new IllegalArgumentException();
+ Node newNode = new Node(listener);
+ if (prerequisite.length == 0) {
+ for (Node node : _listeners) {
+ if (node.listener == listener) return;
}
- }
- if (newListener) {
- for (JobEventListener preListener : prereq) {
- _listeners.add(new WeakReference<JobEventListener>(preListener));
- if (_lastEvent != null) preListener.detectorChanged(_lastEvent);
+ _listeners.add(0, newNode);
+ } else {
+ LinkedHashSet<JobEventListener> prereq = new LinkedHashSet<JobEventListener>(Arrays.asList(prerequisite));
+ if (prereq.contains(listener)) throw new IllegalArgumentException();
+ newNode.parents = new ArrayList<Node>(prereq.size());
+ Node oldNode = null;
+ for (Node node : _listeners) {
+ JobEventListener lstnr = node.listener;
+ boolean old = prereq.remove(lstnr);
+ if (old) {
+ newNode.parents.add(node);
+ } else if (lstnr == listener) {
+ oldNode = node;
+ }
+ }
+ if (!prereq.isEmpty()) {
+ for (JobEventListener lstnr : prereq) {
+ if (_lastEvent != null) lstnr.detectorChanged(_lastEvent);
+ Node node = new Node(lstnr);
+ _listeners.add(0, node);
+ newNode.parents.add(node);
+ }
+ }
+ if (oldNode == null) {
+ if (_lastEvent != null) listener.detectorChanged(_lastEvent);
+ _listeners.add(newNode);
+ for (Node node : newNode.parents) {
+ if (node.daughters == null) node.daughters = new ArrayList<Node>(1);
+ node.daughters.add(newNode);
+ if (node.depth >= newNode.depth) newNode.depth = node.depth + 1;
+ }
+ } else {
+ if (oldNode.parents == null) oldNode.parents = new ArrayList<Node>(newNode.parents);
+ HashSet<Node> newParents = new HashSet<Node>(newNode.parents);
+ newParents.removeAll(oldNode.parents);
+ oldNode.parents.addAll(newParents);
+ for (Node node : newParents) {
+ if (node.daughters == null) node.daughters = new ArrayList<Node>(1);
+ node.daughters.add(oldNode);
+ }
+ oldNode.setDepth();
}
- _listeners.add(new WeakReference<JobEventListener>(listener));
- if (_lastEvent != null) listener.detectorChanged(_lastEvent);
+ Collections.sort(_listeners);
}
- _listeners.trimToSize();
}
- /** Remove a listener. */
- public void removeListener(JobEventListener listener) {
- Iterator<WeakReference<JobEventListener>> it = _listeners.iterator();
+ /**
+ * Remove a listener.
+ * Throws <tt>IllegalArgumentException</tt> if the specified listener is a
+ * prerequisite for other registered listeners.
+ *
+ * @return <tt>true</tt> if the list of listeners changed as a result of the call.
+ */
+ public boolean removeListener(JobEventListener listener) {
+ ListIterator<Node> it = _listeners.listIterator();
while (it.hasNext()) {
- JobEventListener lstnr = it.next().get();
- if (lstnr == null || lstnr == listener) {
- it.remove();
+ Node node = it.next();
+ if (node.listener == listener) {
+ if (node.daughters == null || node.daughters.isEmpty()) {
+ if (node.parents != null) {
+ for (Node p : node.parents) {
+ p.daughters.remove(node);
+ if (p.daughters.isEmpty()) p.daughters = null;
+ }
+ }
+ it.remove();
+ return true;
+ } else {
+ throw new IllegalArgumentException();
+ }
}
}
+ return false;
}
-// -- Private parts : ---------------------------------------------------------
-
- static private JobManager _defInstance;
-
- private JobEvent _lastEvent;
- private ArrayList<WeakReference<JobEventListener>> _listeners = new ArrayList<WeakReference<JobEventListener>>(1);
-
- private AIDA _aida;
+ /**
+ * Replaces a listener while keeping its dependencies.
+ * Throws <tt>IllegalArgumentException</tt> if any of the specified listeners is <tt>null</tt>.
+ *
+ * @return <tt>true</tt> if the list of listeners changed as a result of the call.
+ */
+ public boolean replaceListener(JobEventListener oldListener, JobEventListener newListener) {
+ if (oldListener == null || newListener == null) throw new IllegalArgumentException();
+ if (oldListener == newListener) return false;
+ boolean changed = false;
+ for (Node node : _listeners) {
+ if (node.listener == oldListener) {
+ node.listener = newListener;
+ changed = true;
+ } else if (node.listener == newListener) {
+ throw new IllegalArgumentException();
+ }
+ }
+ return changed;
+ }
+
+ /** Node in the collection of JobEventListeners. */
+ private class Node implements Comparable<Node> {
+ JobEventListener listener;
+ ArrayList<Node> parents;
+ ArrayList<Node> daughters;
+ int depth;
+ Node(JobEventListener listener) {this.listener = listener;}
+ public int compareTo(Node that) {return depth - that.depth;}
+ void setDepth() {
+ depth = calculateDepth(this, false);
+ adjustDaughters(this);
+ }
+ int calculateDepth(Node node, boolean check) {
+ if (check && node == this) throw new IllegalArgumentException();
+ if (node.parents == null) return 0;
+ int dep = 0;
+ for (Node n : node.parents) {
+ int pdep = calculateDepth(n, true);
+ if (pdep >= dep) dep = pdep + 1;
+ }
+ return dep;
+ }
+ void adjustDaughters(Node node) {
+ if (node.daughters == null) return;
+ for (Node d : node.daughters) {
+ if (d.depth > node.depth) {
+ continue;
+ } else {
+ d.depth = node.depth + 1;
+ adjustDaughters(d);
+ }
+ }
+ }
+ }
}