From 40a9d99496e098562f090fb7ffce9e749011b131 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 20 May 2024 17:58:16 -0400 Subject: Formatting pass --- .../net/wotonomy/control/EOObserverCenter.java | 727 +++++++++------------ 1 file changed, 318 insertions(+), 409 deletions(-) (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java') diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java index d42130c..a8710ef 100644 --- a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java +++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/control/EOObserverCenter.java @@ -34,514 +34,423 @@ import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSMutableArray; /** -* EOObserverCenter is a static singleton-like class -* that manages EOObservings that want to be notified -* of changes to those objects that call -* notifyObserversObjectWillChange() before their -* properties change.

-* -* Implementation note: Because Java implements the -* Observer pattern in java.util.Observable, this -* class knows how to register itself as an Observer -* with Observables as well. However, users should -* note that Observables only notify their Observers -* of changes after their property has changed. -* EODelayedObservers would see no difference because -* they always receive their notification after all -* changes have taken place.

-* -* This implementation uses weak references for observers -* and observables. The advantage to this approach is -* that you do not need to explicitly unregister observers -* or observables; they will be unregistered when they are -* garbage-collected. Note that you will need to retain -* a reference to any objects you register or they may -* become unregistered if no other object references them. -* -* @author michael@mpowers.net -* @author $Author: cgruber $ -* @version $Revision: 894 $ -*/ -public class EOObserverCenter implements Observer -{ - /** - * Would much rather use a WeakHashMap, but that class - * compares by value, and we need to compare by reference. - * This means we need to recreate a weak hashmap with - * the ReferenceKey class below. Using hashtable for - * thread safety. - */ + * EOObserverCenter is a static singleton-like class that manages EOObservings + * that want to be notified of changes to those objects that call + * notifyObserversObjectWillChange() before their properties change.
+ *
+ * + * Implementation note: Because Java implements the Observer pattern in + * java.util.Observable, this class knows how to register itself as an Observer + * with Observables as well. However, users should note that Observables only + * notify their Observers of changes after their property has changed. + * EODelayedObservers would see no difference because they always receive their + * notification after all changes have taken place.
+ *
+ * + * This implementation uses weak references for observers and observables. The + * advantage to this approach is that you do not need to explicitly unregister + * observers or observables; they will be unregistered when they are + * garbage-collected. Note that you will need to retain a reference to any + * objects you register or they may become unregistered if no other object + * references them. + * + * @author michael@mpowers.net + * @author $Author: cgruber $ + * @version $Revision: 894 $ + */ +public class EOObserverCenter implements Observer { + /** + * Would much rather use a WeakHashMap, but that class compares by value, and we + * need to compare by reference. This means we need to recreate a weak hashmap + * with the ReferenceKey class below. Using hashtable for thread safety. + */ private static Map observableToObservers = new Hashtable(); - + private static List omniscients = new LinkedList(); - + // suppression count private static int suppressions = 0; - + // singleton instance - needed for Observer private static EOObserverCenter instance = null; - - // optimization: remember last request and result - private static Object lastRequest; - private static NSArray lastResult; - + + // optimization: remember last request and result + private static Object lastRequest; + private static NSArray lastResult; + /** - * Registers the specified EOObserving for - * notifications from the specified object. - * An EOObserving can only be registered - * once for a given object. - */ - public static void addObserver( - EOObserving anObserver, Object anObject ) - { + * Registers the specified EOObserving for notifications from the specified + * object. An EOObserving can only be registered once for a given object. + */ + public static void addObserver(EOObserving anObserver, Object anObject) { // atomic operation - synchronized ( instance() ) - { + synchronized (instance()) { // find observer list - List observers = (List) - observableToObservers.get( new ReferenceKey( anObject ) ); - + List observers = (List) observableToObservers.get(new ReferenceKey(anObject)); + // if observer list not found, create and add item - if ( observers == null ) - { + if (observers == null) { observers = new ArrayList(); - observers.add( new WeakReference( anObserver ) ); - processQueue(); - observableToObservers.put( new ReferenceKey( anObject, queue ), observers ); + observers.add(new WeakReference(anObserver)); + processQueue(); + observableToObservers.put(new ReferenceKey(anObject, queue), observers); // support for java.util.Observable - if ( anObject instanceof Observable ) - { - ((Observable)anObject).addObserver( instance() ); + if (anObject instanceof Observable) { + ((Observable) anObject).addObserver(instance()); } - } - else // observer list found - scan for observer - if ( indexOf( observers, anObserver ) < 0 ) - { + } else // observer list found - scan for observer + if (indexOf(observers, anObserver) < 0) { // observer not found, register it - observers.add( new WeakReference( anObserver ) ); + observers.add(new WeakReference(anObserver)); } - - lastRequest = null; - lastResult = null; + + lastRequest = null; + lastResult = null; } } /** - * Registers the specified EOObserving for notifications - * on all object changes. An EOObserving can be - * registered as an omniscient observer at most once. - * Use omniscient observers with caution. - */ - public static void addOmniscientObserver( - EOObserving anObserver ) - { - if ( indexOf( omniscients, anObserver ) < 0 ) - { - omniscients.add( anObserver ); + * Registers the specified EOObserving for notifications on all object changes. + * An EOObserving can be registered as an omniscient observer at most once. Use + * omniscient observers with caution. + */ + public static void addOmniscientObserver(EOObserving anObserver) { + if (indexOf(omniscients, anObserver) < 0) { + omniscients.add(anObserver); } } /** - * Notifies all EOObservings registered for - * notifications for the specified object. - * This method is typically called by objects - * that wish to broadcast a notification before - * a property change takes place, passing itself - * as the argument. - */ - public static void notifyObserversObjectWillChange( - Object anObject ) - { - if ( observerNotificationSuppressCount() == 0 ) - { - List observers = observersForObject( anObject ); + * Notifies all EOObservings registered for notifications for the specified + * object. This method is typically called by objects that wish to broadcast a + * notification before a property change takes place, passing itself as the + * argument. + */ + public static void notifyObserversObjectWillChange(Object anObject) { + if (observerNotificationSuppressCount() == 0) { + List observers = observersForObject(anObject); EOObserving o; Iterator it = observers.iterator(); - while ( it.hasNext() ) - { + while (it.hasNext()) { o = (EOObserving) it.next(); - o.objectWillChange( anObject ); + o.objectWillChange(anObject); } } } /** - * Returns an observer that is an instance of - * the specified class and - * that is registered for notifications about - * the specified object. If more than one - * such observer exists, which observer is - * returned is undetermined - use - * observersForObject instead. If no observer - * exists, returns null. - */ - public static EOObserving observerForObject( - Object anObject, Class aClass ) - { - List result = observersForObject( anObject ); - if ( result.size() == 0 ) return null; - + * Returns an observer that is an instance of the specified class and that is + * registered for notifications about the specified object. If more than one + * such observer exists, which observer is returned is undetermined - use + * observersForObject instead. If no observer exists, returns null. + */ + public static EOObserving observerForObject(Object anObject, Class aClass) { + List result = observersForObject(anObject); + if (result.size() == 0) + return null; + Object o; Iterator it = result.iterator(); - while ( it.hasNext() ) - { + while (it.hasNext()) { o = it.next(); - if ( aClass.isAssignableFrom( o.getClass() ) ) - { - return (EOObserving) o; + if (aClass.isAssignableFrom(o.getClass())) { + return (EOObserving) o; } } return null; } /** - * Returns the number of times that notifications - * have been suppressed. This is also the number - * of times that enableObserverNotification must - * be called to allow notifications to take place. - */ - public static int observerNotificationSuppressCount() - { + * Returns the number of times that notifications have been suppressed. This is + * also the number of times that enableObserverNotification must be called to + * allow notifications to take place. + */ + public static int observerNotificationSuppressCount() { return suppressions; } /** - * Returns a List of observers for the - * specified object. Returns an empty List - * if no observer has registered for that - * object. - */ - public static NSArray observersForObject( - Object anObject ) - { - synchronized ( instance() ) - { - // optimization: this is called very frequently - // from the same object calling willChange() a - // number of times in a row as it is updating. - if ( lastRequest == anObject ) - { - return lastResult; - } - - NSArray result; - - List references = observerListForObject( anObject ); - if ( references == null ) - { - result = NSArray.EmptyArray; - } - else - { - result = new NSMutableArray(); - Object observer; - Iterator it = references.iterator(); - while ( it.hasNext() ) - { - observer = ((Reference)it.next()).get(); - if ( observer != null ) - { - result.add( observer ); - } - else // reference has expired - { - processQueue(); - it.remove(); // remove from list - // if last observer, unregister observable - if ( references.size() == 0 ) - { - observableToObservers.remove( new ReferenceKey( anObject ) ); - } - } - } - } - - lastRequest = anObject; - lastResult = result; - - return result; - } - + * Returns a List of observers for the specified object. Returns an empty List + * if no observer has registered for that object. + */ + public static NSArray observersForObject(Object anObject) { + synchronized (instance()) { + // optimization: this is called very frequently + // from the same object calling willChange() a + // number of times in a row as it is updating. + if (lastRequest == anObject) { + return lastResult; + } + + NSArray result; + + List references = observerListForObject(anObject); + if (references == null) { + result = NSArray.EmptyArray; + } else { + result = new NSMutableArray(); + Object observer; + Iterator it = references.iterator(); + while (it.hasNext()) { + observer = ((Reference) it.next()).get(); + if (observer != null) { + result.add(observer); + } else // reference has expired + { + processQueue(); + it.remove(); // remove from list + // if last observer, unregister observable + if (references.size() == 0) { + observableToObservers.remove(new ReferenceKey(anObject)); + } + } + } + } + + lastRequest = anObject; + lastResult = result; + + return result; + } + } - + /** - * Returns a reference to the actual list of - * observers for the given object, or null if it - * doesn't exist. - */ - private static List observerListForObject( Object anObject ) - { - return (List) observableToObservers.get( new ReferenceKey( anObject ) ); + * Returns a reference to the actual list of observers for the given object, or + * null if it doesn't exist. + */ + private static List observerListForObject(Object anObject) { + return (List) observableToObservers.get(new ReferenceKey(anObject)); } /** - * Unregisters the specified observer for - * notifications from the specified object. - */ - public static void removeObserver( - EOObserving anObserver, Object anObject ) - { + * Unregisters the specified observer for notifications from the specified + * object. + */ + public static void removeObserver(EOObserving anObserver, Object anObject) { // atomic operation - synchronized ( instance() ) - { - lastRequest = null; - lastResult = null; - - List result = observerListForObject( anObject ); - if ( result == null ) return; - int index = indexOf( result, anObserver ); - if ( index == -1 ) return; - + synchronized (instance()) { + lastRequest = null; + lastResult = null; + + List result = observerListForObject(anObject); + if (result == null) + return; + int index = indexOf(result, anObserver); + if (index == -1) + return; + // remove observer from list - result.remove( index ); - + result.remove(index); + // if last observer, unregister observable - if ( result.size() == 0 ) - { - processQueue(); - observableToObservers.remove( new ReferenceKey( anObject ) ); + if (result.size() == 0) { + processQueue(); + observableToObservers.remove(new ReferenceKey(anObject)); } } } /** - * Unregisters the specified omniscient observer. - */ - public static void removeOmniscientObserver( - EOObserving anObserver ) - { - int index = indexOf( omniscients, anObserver ); - if ( index != -1 ) - { - omniscients.remove( index ); + * Unregisters the specified omniscient observer. + */ + public static void removeOmniscientObserver(EOObserving anObserver) { + int index = indexOf(omniscients, anObserver); + if (index != -1) { + omniscients.remove(index); } } /** - * Enables notifications after they have been - * suppressed by suppressObserverNotification. - * If notifications have been suppressed - * multiple times, this method must be called - * an equal number of times to resume notifications. - * If notifications are not currently suppressed, - * this method does nothing. - */ - public static void enableObserverNotification() - { - if ( suppressions > 0 ) suppressions--; + * Enables notifications after they have been suppressed by + * suppressObserverNotification. If notifications have been suppressed multiple + * times, this method must be called an equal number of times to resume + * notifications. If notifications are not currently suppressed, this method + * does nothing. + */ + public static void enableObserverNotification() { + if (suppressions > 0) + suppressions--; } /** - * Causes notifications to be suppressed until - * the next matching call to enableObserverNotification. - * If this method is called more than once, - * enableObserverNotification must be called an - * equal number of times for notifications to resume. - * This method always causes notifications to cease - * immediately. - */ - public static void suppressObserverNotification() - { + * Causes notifications to be suppressed until the next matching call to + * enableObserverNotification. If this method is called more than once, + * enableObserverNotification must be called an equal number of times for + * notifications to resume. This method always causes notifications to cease + * immediately. + */ + public static void suppressObserverNotification() { suppressions++; } - + /** - * Because we're comparing by reference, we need to - * test for the existence of the object directly. - * @return the index or -1 if not found. - */ - private static int indexOf( List aList, Object anObject ) - { - if ( anObject == null ) return -1; - - synchronized ( aList ) - { + * Because we're comparing by reference, we need to test for the existence of + * the object directly. + * + * @return the index or -1 if not found. + */ + private static int indexOf(List aList, Object anObject) { + if (anObject == null) + return -1; + + synchronized (aList) { int len = aList.size(); - for ( int i = 0; i < len; i++ ) - { + for (int i = 0; i < len; i++) { // compare by reference - if ( anObject == ((Reference)aList.get(i)).get() ) - { + if (anObject == ((Reference) aList.get(i)).get()) { return i; } } } return -1; } - + /** - * Private singleton instance, so we can be an observer. - */ - private static EOObserverCenter instance() - { - if ( instance == null ) - { + * Private singleton instance, so we can be an observer. + */ + private static EOObserverCenter instance() { + if (instance == null) { instance = new EOObserverCenter(); } return instance; } - + + /** + * Interface Observer + */ + public void update(Observable o, Object arg) { + notifyObserversObjectWillChange(o); + } + + /* Reference queue for cleared WeakKeys */ + private static ReferenceQueue queue = new ReferenceQueue(); + + /* + * Remove all invalidated entries from the map, that is, remove all entries + * whose keys have been discarded. This method should be invoked once by each + * public mutator in this class. We don't invoke this method in public accessors + * because that can lead to surprising ConcurrentModificationExceptions. + */ + private static void processQueue() { + synchronized (instance()) { + ReferenceKey rk; + while ((rk = (ReferenceKey) queue.poll()) != null) { + // System.out.println( "EOObserverCenter.processQueue: removing object" ); + observableToObservers.remove(rk); + } + } + } + /** - * Interface Observer - */ - public void update( Observable o, Object arg ) - { - notifyObserversObjectWillChange( o ); + * Private class used to force a hashmap to perform key comparisons by + * reference. Retains a weak reference just like WeakHashMap. + */ + static private class ReferenceKey extends WeakReference { + private int hashCode; + + /** + * Called to create a disposable reference key, used for retrieving values from + * the hashtable. + */ + public ReferenceKey(Object anObject) { + super(anObject); + hashCode = anObject.hashCode(); + } + + /** + * Called to create a reference key that will be used as a key in the hashtable, + * so we need the reference queue to later remove the key from the table when + * referred object is no longer in use. + */ + public ReferenceKey(Object anObject, ReferenceQueue aQueue) { + super(anObject, aQueue); + hashCode = anObject.hashCode(); + } + + /** + * Passes through to actual key's hash code. + */ + public int hashCode() { + return hashCode; + } + + /** + * Compares by reference. + */ + public boolean equals(Object anObject) { + if (!(anObject instanceof ReferenceKey)) + return false; + Object key = get(); + if (key == null) + return false; + return (key == ((ReferenceKey) anObject).get()); + } } - - /* Reference queue for cleared WeakKeys */ - private static ReferenceQueue queue = new ReferenceQueue(); - - /* Remove all invalidated entries from the map, that is, remove all entries - whose keys have been discarded. This method should be invoked once by - each public mutator in this class. We don't invoke this method in - public accessors because that can lead to surprising - ConcurrentModificationExceptions. */ - private static void processQueue() - { - synchronized ( instance() ) - { - ReferenceKey rk; - while ((rk = (ReferenceKey)queue.poll()) != null) - { - //System.out.println( "EOObserverCenter.processQueue: removing object" ); - observableToObservers.remove(rk); - } - } - } - - /** - * Private class used to force a hashmap to - * perform key comparisons by reference. - * Retains a weak reference just like WeakHashMap. - */ - static private class ReferenceKey extends WeakReference - { - private int hashCode; - - /** - * Called to create a disposable reference key, - * used for retrieving values from the hashtable. - */ - public ReferenceKey( Object anObject ) - { - super( anObject ); - hashCode = anObject.hashCode(); - } - - /** - * Called to create a reference key that will be - * used as a key in the hashtable, so we need the - * reference queue to later remove the key from the - * table when referred object is no longer in use. - */ - public ReferenceKey( Object anObject, ReferenceQueue aQueue ) - { - super( anObject, aQueue ); - hashCode = anObject.hashCode(); - } - - /** - * Passes through to actual key's hash code. - */ - public int hashCode() - { - return hashCode; - } - - /** - * Compares by reference. - */ - public boolean equals( Object anObject ) - { - if ( ! ( anObject instanceof ReferenceKey ) ) return false; - Object key = get(); - if ( key == null ) return false; - return ( key == ((ReferenceKey)anObject).get() ); - } - } - - private static String debugString() - { - String result = ""; - int count = 0; - synchronized ( instance() ) - { - Object anObject; - Iterator it = observableToObservers.keySet().iterator(); - while ( it.hasNext() ) - { - result += ((Reference)it.next()).get() + " : "; - count++; - /* - Iterator values = ((List)it.next()).iterator(); - while ( values.hasNext() ) - { - anObject = ((Reference)values.next()).get(); - if ( anObject != null ) - { -// if ( anObject instanceof net.wotonomy.ui.MasterDetailAssociation ) - result += anObject.getClass().toString() + " : "; - count++; - } - } - */ - } - result += "["+count+"]"; + + private static String debugString() { + String result = ""; + int count = 0; + synchronized (instance()) { + Object anObject; + Iterator it = observableToObservers.keySet().iterator(); + while (it.hasNext()) { + result += ((Reference) it.next()).get() + " : "; + count++; + /* + * Iterator values = ((List)it.next()).iterator(); while ( values.hasNext() ) { + * anObject = ((Reference)values.next()).get(); if ( anObject != null ) { // if + * ( anObject instanceof net.wotonomy.ui.MasterDetailAssociation ) result += + * anObject.getClass().toString() + " : "; count++; } } + */ + } + result += "[" + count + "]"; } - return result; - } - + return result; + } + } /* - * $Log$ - * Revision 1.2 2006/02/16 16:47:14 cgruber - * Move some classes in to "internal" packages and re-work imports, etc. + * $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. + * 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.1 2006/02/16 13:19:57 cgruber Check in all sources in + * eclipse-friendly maven-enabled packages. * - * Revision 1.9 2002/10/24 18:18:12 mpowers - * NSArray's are now considered read-only, so we can return our internal - * representation to reduce unnecessary object allocation. + * Revision 1.9 2002/10/24 18:18:12 mpowers NSArray's are now considered + * read-only, so we can return our internal representation to reduce unnecessary + * object allocation. * - * Revision 1.8 2001/02/21 21:17:32 mpowers - * Now retaining a reference to the recent changes observer. - * Better documented need to retain reference. - * Started implementing notifications. + * Revision 1.8 2001/02/21 21:17:32 mpowers Now retaining a reference to the + * recent changes observer. Better documented need to retain reference. Started + * implementing notifications. * - * Revision 1.7 2001/02/17 16:52:05 mpowers - * Changes in imports to support building with jdk1.1 collections. + * Revision 1.7 2001/02/17 16:52:05 mpowers Changes in imports to support + * building with jdk1.1 collections. * - * Revision 1.6 2001/02/05 18:45:45 mpowers - * Reduced access back to private for utility methods. + * Revision 1.6 2001/02/05 18:45:45 mpowers Reduced access back to private for + * utility methods. * - * Revision 1.5 2001/02/05 18:42:32 mpowers - * Updated documentation throughout project. + * Revision 1.5 2001/02/05 18:42:32 mpowers Updated documentation throughout + * project. * - * Revision 1.4 2001/01/18 16:57:47 mpowers - * Added debug facility. + * Revision 1.4 2001/01/18 16:57:47 mpowers Added debug facility. * - * Revision 1.3 2001/01/10 16:28:53 mpowers - * Implemented a compare-by-reference weak hashtable - * because WeakHashMap compared by value and we can't - * assume that display groups won't contain objects - * whose values are equivalent. + * Revision 1.3 2001/01/10 16:28:53 mpowers Implemented a compare-by-reference + * weak hashtable because WeakHashMap compared by value and we can't assume that + * display groups won't contain objects whose values are equivalent. * - * Revision 1.2 2001/01/09 20:10:19 mpowers - * Now using weak references to track observables and their observers. + * Revision 1.2 2001/01/09 20:10:19 mpowers Now using weak references to track + * observables and their observers. * - * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers - * Contributing wotonomy. + * Revision 1.1.1.1 2000/12/21 15:46:44 mpowers Contributing wotonomy. * - * Revision 1.8 2000/12/20 16:25:35 michael - * Added log to all files. + * Revision 1.8 2000/12/20 16:25:35 michael Added log to all files. * * */ - - -- cgit v1.2.3