summaryrefslogtreecommitdiff
path: root/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
diff options
context:
space:
mode:
authorBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
committerBenjamin Culkin <scorpress@gmail.com>2024-05-19 17:56:33 -0400
commitaedc34d55462a75e329bbf342251ff6504cd117e (patch)
treebcc8f1f2352582717b484df302aeea6696b8f000 /projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
Initial import from SVN
Diffstat (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java')
-rw-r--r--projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java323
1 files changed, 323 insertions, 0 deletions
diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
new file mode 100644
index 0000000..6b9b9c3
--- /dev/null
+++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EODelayedObserverQueue.java
@@ -0,0 +1,323 @@
+/*
+Wotonomy: OpenStep design patterns for pure Java applications.
+Copyright (C) 2000 Intersect Software Corporation
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, see http://www.gnu.org
+*/
+
+package net.wotonomy.control;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import net.wotonomy.foundation.NSRunLoop;
+import net.wotonomy.foundation.NSSelector;
+
+/**
+* EODelayedObserverQueue allows EODelayedObservers
+* to receive only one subjectChanged() message
+* after numerous willChange() messages have
+* been sent. Observers are then notified in order
+* of their priority property,
+* so that certain observers can be notified before
+* others for whatever application-specific purpose.
+* This class is not thread-safe and should be used
+* only for single-threaded GUI clients (AWT and Swing).
+* <br><br>
+*
+* Important note: because AWT's event queue does
+* not allow for priority-based scheduling, this
+* class installs a custom event queue, replacing
+* the existing queue on the AWT dispatch thread.
+* We know of no way around this problem.
+* <br><br>
+*
+* Implementation note: this queue relies on the
+* result of equals() for maintaining a set of
+* objects on the queue. If two EODelayedObservers
+* evaluate to the same value using equals(), only
+* one of them will exist on the queue. If this,
+* starts to suck, we can change it.
+*
+* @author michael@mpowers.net
+* @author $Author: cgruber $
+* @version $Revision: 894 $
+*/
+
+public class EODelayedObserverQueue
+{
+ /**
+ * The default run loop ordering flushes the delayed observers
+ * up to ObserverPrioritySixth before dispatching the AWT event
+ * queue. ObserverPriorityLater is run last.
+ */
+ public static int FlushDelayedObserversRunLoopOrdering = 400000;
+
+ private static EODelayedObserverQueue
+ defaultObserverQueue = null;
+
+ private static NSSelector runLaterSelector =
+ new NSSelector( "flushObserverQueue",
+ new Class[] { Object.class } );
+
+ private boolean willRunLater;
+ private LinkedList priorityQueue;
+
+ /**
+ * Default constructor.
+ */
+ public EODelayedObserverQueue ()
+ {
+ willRunLater = false;
+ priorityQueue = new LinkedList();
+ }
+
+ /**
+ * Returns the system default observer queue.
+ */
+ public static EODelayedObserverQueue defaultObserverQueue ()
+ {
+ if ( defaultObserverQueue == null )
+ {
+ defaultObserverQueue = new EODelayedObserverQueue();
+ }
+ return defaultObserverQueue;
+ }
+
+ /**
+ * Removes the specified observer from the queue.
+ */
+ public void dequeueObserver (
+ EODelayedObserver anObserver )
+ {
+//System.out.println( "dequeueObserver: " + anObserver );
+ //synchronized ( priorityQueue )
+ //{
+ priorityQueue.remove( anObserver );
+ //}
+ }
+
+ /**
+ * Adds the specified observer to the queue.
+ * An already enqueued observer will not be
+ * added again.
+ * If the observer's priority is
+ * ObserverPriorityImmediate, it will be
+ * notified immediately and not added to the
+ * queue.
+ * Otherwise, the queue sets itself up to
+ * call notifyObserversUpToPriority during the
+ * run loop as specified by
+ * FlushDelayedObserversRunLoopOrdering.
+ */
+ public void enqueueObserver (
+ EODelayedObserver anObserver )
+ {
+ // syntactic glue for Runnables
+ final EODelayedObserver observer = anObserver;
+
+ if ( observer.priority() ==
+ EODelayedObserver.ObserverPriorityImmediate )
+ {
+ // invoke immediately
+ observer.subjectChanged();
+ }
+ else
+ {
+ // place in the delayed observer queue
+
+ //synchronized ( priorityQueue )
+ //{
+ int i = 0;
+ int priority = observer.priority();
+ Object o;
+
+ Iterator iterator = priorityQueue.iterator();
+
+ // scan entire list to ensure we're not already queued
+ while ( iterator.hasNext() )
+ {
+ o = iterator.next();
+ if ( o == observer )
+ {
+ // already queued
+ return;
+ }
+ if ( ((EODelayedObserver)o).priority() > priority )
+ {
+ // insert at this index: break now
+ break;
+ }
+ i++;
+ }
+
+ // if we broke early, we found a threshhold:
+ // continue scanning to ensure we're not already queued
+ while ( iterator.hasNext() )
+ {
+ if ( iterator.next() == observer )
+ {
+ // already queued
+ return;
+ }
+ }
+
+ // insert before items of lower priority,
+ // otherwise insert at end of list.
+ priorityQueue.add( i, observer );
+
+ //}
+ runLater();
+ }
+//System.out.println( "enqueueObserver: " + anObserver + " : " + priorityQueue );
+ }
+
+ /**
+ * Notifies all observers with priority equal to
+ * or greater than the specified priority.
+ */
+ public void notifyObserversUpToPriority ( int priority )
+ {
+//System.out.println( "notifyObserversUpToPriority: priorityQueue size = " + priorityQueue.size() );
+ EODelayedObserver o;
+ while ( ! priorityQueue.isEmpty() )
+ {
+ o = (EODelayedObserver) priorityQueue.getFirst();
+ if ( o.priority() > priority ) break;
+ priorityQueue.removeFirst();
+
+ try
+ {
+ o.subjectChanged();
+ }
+ catch ( Exception exc )
+ {
+ System.out.println( "Error notifying observer: " + o );
+ exc.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Called to ensure that notifyObserversUpToPriority
+ * will be called on the next event loop.
+ */
+ private void runLater()
+ {
+ if ( ! willRunLater )
+ {
+ willRunLater = true;
+ NSRunLoop.currentRunLoop().performSelectorWithOrder(
+ runLaterSelector, this, null, FlushDelayedObserversRunLoopOrdering, null );
+ }
+ }
+
+ /**
+ * This method is called by the event queue run loop
+ * and calls notifyObserversUpToPriority with
+ * ObserverPriorityLater.
+ * NOTE: This method is not part of the specification.
+ */
+ public void flushObserverQueue( Object anObject )
+ {
+//System.out.println( "EODelayedObserverQueue: running" );
+ notifyObserversUpToPriority( EODelayedObserver.ObserverPrioritySixth );
+ if ( ! priorityQueue.isEmpty() )
+ {
+ // assumes all remaining on queue are ObserverPriorityLater
+ NSRunLoop.invokeLater(
+ new PriorityLaterRunnable( new LinkedList( priorityQueue ) ) );
+ priorityQueue.clear();
+ }
+ willRunLater = false;
+ }
+
+ /**
+ * A runnable for dispatching remaining observers running at ObserverPriorityLater.
+ */
+ class PriorityLaterRunnable implements Runnable
+ {
+ List observers;
+
+ public PriorityLaterRunnable( List anObserverList )
+ {
+ observers = anObserverList;
+ }
+
+ public void run()
+ {
+ EODelayedObserver o = null;
+ Iterator i = observers.iterator();
+ while ( i.hasNext() )
+ {
+ try
+ {
+ o = (EODelayedObserver) i.next();
+ o.subjectChanged();
+ }
+ catch ( Exception exc )
+ {
+ System.out.println( "Error notifying observer: " + o );
+ exc.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
+
+/*
+ * $Log$
+ * Revision 1.2 2006/02/16 16:47:14 cgruber
+ * Move some classes in to "internal" packages and re-work imports, etc.
+ *
+ * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
+ *
+ * Revision 1.1 2006/02/16 13:19:57 cgruber
+ * Check in all sources in eclipse-friendly maven-enabled packages.
+ *
+ * Revision 1.8 2003/08/19 01:53:12 chochos
+ * EOObjectStore had some incompatible return types (Object instead of EOEnterpriseObject, in fault methods mostly). It's internally consistent but I hope it doesn't break anything based on this, even though fault methods mostly throw exceptions for now.
+ *
+ * Revision 1.7 2002/05/20 15:08:35 mpowers
+ * Optimization for enqueueObserver: we were scanning the entire list anyway;
+ * now we compare priorities and ensure we're not double-queued on same pass.
+ *
+ * Revision 1.6 2002/05/15 13:45:57 mpowers
+ * RunLater now appropriately runs later: at the end of the current awt queue.
+ *
+ * Revision 1.5 2002/03/11 03:18:39 mpowers
+ * Now properly handling ObserverChangesLater.
+ *
+ * Revision 1.4 2001/10/26 18:37:15 mpowers
+ * Now using NSRunLoop instead of AWT EventQueue.
+ *
+ * Revision 1.3 2001/10/22 21:54:16 mpowers
+ * Removed swing dependency in favor of jdk1.3 event queue.
+ * Optimized priority queue population.
+ *
+ * Revision 1.2 2001/10/12 18:01:59 mpowers
+ * Now catching exceptions before they disrupt the awt event queue.
+ *
+ * Revision 1.1.1.1 2000/12/21 15:46:42 mpowers
+ * Contributing wotonomy.
+ *
+ * Revision 1.5 2000/12/20 16:25:35 michael
+ * Added log to all files.
+ *
+ *
+ */
+
+