Hello,
For those of you who are missing something akin to NSNotificationCenter
in J2SE, here is an "experimental" (aka "not tested very much") Java
implementation that somewhat mimics Apple's one.
If you are not sure what a notification center is about, you can check
Apple's documentation:
http://developer.apple.com/techpubs/webobjects/Reference/Javadoc/com/webobjects/
foundation/NSNotificationCenter.html
There are four elements in this Notification class:
[Notification]
Same thing as NSNotification. Here is how to create a notification:
new Notification( "ServiceAgent.WillProcessNotification",
anAccount, null )
The parameters are the same as in NSNotification: notification name,
object, and user info (a Map in that case).
[Notification.Observer]
This is the interface used by the observers to receive a notification.
public void notify(Notification aNotification);
[Notification.Center]
This class mimic NSNotificationCenter. Here is how to register an
observer:
Notification.Center.defaultCenter().addObserver( this,
"ServiceAgent.ExceptionNotification", null );
The parameters are the same as in NSNotificationCenter: observer,
notification name, and object. There is no NSSelector necessary as the
observer uses an interface (Notification.Observer) instead.
To create an "omniscient" observer, simply pass null for the
notification name and object.
An observer with a null notification name but an object will "listen" to
all notification "posted" by that object.
An observer with a null object but a notification name will "listen" to
all notification with that name irrespectively of the "poster".
Here is how to post a notification:
Notification.Center.defaultCenter().postNotification( new
Notification( "ServiceAgent.WillProcessNotification", anAccount,
null ) );
Of course you can create as many Notification.Center as you want in
addition to the default center:
new Notification.Center();
[Notification.Entry]
This is a private class that records an observer/notification
name/object tuple. This class also decides if an observer is
"interested" by a specific notification. Note the use of
java.lang.ref.Reference for referencing the observer and the object.
[Notification.Task]
This private java.lang.Runnable class will "dispatch" the
Notification.Observer.notify() method to a list of observers. This
action, triggered by postNotification, take place in a separate thread.
Source code attached.
Comments welcome.
PA.
//
// ===========================================================================
//
// Title: Notification.java
// Description: [Description]
// Author: Petite Abeille
// Creation Date: Fri 28-Jun-2002
// Legal: Copyright (C) 2001 Petite Abeille. All Rights Reserved.
// This class is hereby released for all uses.
// No warranties whatsoever.
//
// ---------------------------------------------------------------------------
//
import java.io.Externalizable;
import java.io.ObjectOutput;
import java.io.ObjectInput;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.Iterator;
public final class Notification extends Object implements Externalizable, Comparable
{
// ===========================================================================
// Constant(s)
// ---------------------------------------------------------------------------
// ===========================================================================
// Class variable(s)
// ---------------------------------------------------------------------------
// ===========================================================================
// Instance variable(s)
// ---------------------------------------------------------------------------
private String _name = null;
private Object _object = null;
private Map _userInfo = null;
// ===========================================================================
// Constructor method(s)
// ---------------------------------------------------------------------------
protected Notification()
{
super();
}
public Notification(String aName, Object anObject, Map anUserInfo)
{
this();
if ( aName != null )
{
this.setName( aName );
this.setObject( anObject );
this.setUserInfo( anUserInfo );
}
else
{
throw new IllegalArgumentException( "Notification: null name."
);
}
}
// ===========================================================================
// Class method(s)
// ---------------------------------------------------------------------------
// ===========================================================================
// Instance method(s)
// ---------------------------------------------------------------------------
public String name()
{
return _name;
}
private void setName(String aValue)
{
_name = aValue;
}
public Object object()
{
return _object;
}
private void setObject(Object aValue)
{
_object = aValue;
}
public Map userInfo()
{
return _userInfo;
}
private void setUserInfo(Map aValue)
{
_userInfo = aValue;
}
public int hashCode()
{
return this.name().hashCode();
}
public boolean equals(Object anObject)
{
if ( this == anObject )
{
return true;
}
if ( ( anObject instanceof Notification ) == true )
{
Notification anotherNotification = (Notification) anObject;
if ( this.name().equals( anotherNotification.name() ) == true )
{
Object aNotificationObject = this.object();
Object anotherNotificationObject =
anotherNotification.object();
Map anUserInfo = this.userInfo();
Map anotherUserInfo =
anotherNotification.userInfo();
if ( ( aNotificationObject != null ) &&
( aNotificationObject.equals(
anotherNotificationObject ) == false ) )
{
return false;
}
if ( ( anUserInfo != null ) &&
( anUserInfo.equals( anotherUserInfo ) ==
false ) )
{
return false;
}
return true;
}
}
return false;
}
public String toString()
{
return this.name();
}
// ===========================================================================
// Externalizable method(s)
// ---------------------------------------------------------------------------
public void writeExternal(ObjectOutput anOutputStream) throws IOException
{
anOutputStream.writeObject( this.name() );
anOutputStream.writeObject( this.object() );
anOutputStream.writeObject( this.userInfo() );
}
public void readExternal(ObjectInput anInputStream) throws IOException,
ClassNotFoundException
{
this.setName( (String) anInputStream.readObject() );
this.setObject( anInputStream.readObject() );
this.setUserInfo( (Map) anInputStream.readObject() );
}
// ===========================================================================
// Comparable method(s)
// ---------------------------------------------------------------------------
public int compareTo(Object anObject)
{
if ( anObject != null )
{
if ( ( anObject instanceof Notification ) == true )
{
return this.name().compareTo( ( (Notification)
anObject ).name() );
}
throw new IllegalArgumentException( "Notification.compareTo:
'" + anObject.getClass().getName() + "' not instance of '" + Notification.class + "'."
);
}
throw new IllegalArgumentException( "Notification.compareTo: null
object." );
}
// ===========================================================================
// Observer method(s)
// ---------------------------------------------------------------------------
public static interface Observer
{
public void notify(Notification aNotification);
}
// ===========================================================================
// Center method(s)
// ---------------------------------------------------------------------------
public static final class Center extends Object
{
private static final Center _defaultCenter = new Center();
private final Map _map = new WeakHashMap();
public Center()
{
super();
}
public static Center defaultCenter()
{
return _defaultCenter;
}
private synchronized void registerObserverWithKey(Observer anObserver,
Object aKey, String aName, Object anObject)
{
if ( anObserver != null )
{
if ( aKey != null )
{
Collection aCollection = (Collection)
_map.get( aKey );
if ( aCollection == null )
{
aCollection = new HashSet();
_map.put( aKey, aCollection );
}
aCollection.add( new Entry( anObserver, aName,
anObject ) );
return;
}
}
throw new IllegalArgumentException(
"Notification.Center.registerObserverForNotificationName: null observer." );
}
public void addObserver(Observer anObserver, String aName, Object
anObject)
{
if ( anObserver != null )
{
if ( aName != null )
{
this.registerObserverWithKey( anObserver,
aName, aName, anObject );
}
if ( anObject != null )
{
this.registerObserverWithKey( anObserver,
anObject, aName, anObject );
}
if ( ( aName == null ) && ( anObject == null ) )
{
this.registerObserverWithKey( anObserver,
Null.nullValue(), aName, anObject );
}
return;
}
throw new IllegalArgumentException(
"Notification.Center.addObserver: null observer." );
}
private synchronized void unregisterObserverWithKey(Observer
anObserver, Object aKey, String aName, Object anObject)
{
if ( anObserver != null )
{
if ( aKey != null )
{
Collection aCollection = (Collection)
_map.get( aKey );
if ( ( aCollection != null ) && (
aCollection.isEmpty() == false ) )
{
Collection someEntries = new
ArrayList();
for ( Iterator anIterator =
aCollection.iterator(); anIterator.hasNext(); )
{
Entry anEntry = (Entry)
anIterator.next();
if ( ( anEntry.isValid() ==
false ) || ( anEntry.accepts( aName, anObject ) != null ) )
{
someEntries.add(
anEntry );
}
}
if ( someEntries.isEmpty() == false )
{
aCollection.removeAll(
someEntries );
}
}
return;
}
}
throw new IllegalArgumentException(
"Notification.Center.registerObserverForNotificationName: null observer." );
}
public void removeObserver(Observer anObserver, String aName, Object
anObject)
{
if ( anObserver != null )
{
if ( aName != null )
{
this.unregisterObserverWithKey( anObserver,
aName, aName, anObject );
}
if ( anObject != null )
{
this.unregisterObserverWithKey( anObserver,
anObject, aName, anObject );
}
if ( ( aName == null ) && ( anObject == null ) )
{
this.unregisterObserverWithKey( anObserver,
Null.nullValue(), aName, anObject );
}
return;
}
throw new IllegalArgumentException(
"Notification.Center.removeObserver: null observer." );
}
private synchronized Collection observersForKey(Object aKey, String
aName, Object anObject)
{
if ( aKey != null )
{
Collection aCollection = (Collection) _map.get(
aKey );
if ( aCollection != null )
{
Collection someEntries = new ArrayList();
Collection someObservers = new
ArrayList();
for ( Iterator anIterator =
aCollection.iterator(); anIterator.hasNext(); )
{
Entry anEntry = (Entry)
anIterator.next();
if ( anEntry.isValid() == true )
{
Observer anObserver =
anEntry.accepts( aName, anObject );
if ( anObserver != null )
{
someObservers.add(
anObserver );
}
}
else
{
someEntries.add( anEntry );
}
}
if ( someEntries.isEmpty() == false )
{
aCollection.removeAll( someEntries );
}
if ( someObservers.isEmpty() == false )
{
return someObservers;
}
}
return null;
}
throw new IllegalArgumentException(
"Notification.Center.observersForKey: null observer." );
}
public void postNotification(Notification aNotification)
{
if ( aNotification != null )
{
String aName = aNotification.name();
Object anObject = aNotification.object();
Collection aCollection = new HashSet();
if ( aName != null )
{
Collection someObservers =
this.observersForKey( aName, aName, anObject );
if ( someObservers != null )
{
aCollection.addAll( someObservers );
}
}
if ( anObject != null )
{
Collection someObservers =
this.observersForKey( anObject, aName, anObject );
if ( someObservers != null )
{
aCollection.addAll( someObservers );
}
}
{
Collection someObservers =
this.observersForKey( Null.nullValue(), aName, anObject );
if ( someObservers != null )
{
aCollection.addAll( someObservers );
}
}
if ( aCollection.isEmpty() == false )
{
Task aTask = new Task( aCollection,
aNotification );
Thread aThread = new Thread( System.group(),
aTask, aTask.getClass().getName() );
aThread.setDaemon( true );
aThread.setPriority( Thread.MIN_PRIORITY );
aThread.start();
}
return;
}
throw new IllegalArgumentException(
"Notification.Center.postNotification: null notification." );
}
}
// ===========================================================================
// Entry method(s)
// ---------------------------------------------------------------------------
private static final class Entry extends Object
{
private Reference _observer = null;
private String _name = null;
private Reference _object = null;
private Entry(Observer anObserver, String aName, Object anObject)
{
super();
this.setObserver( anObserver );
this.setName( aName );
this.setObject( anObject );
}
private Observer observer()
{
if ( _observer != null )
{
return (Observer) _observer.get();
}
return null;
}
private void setObserver(Observer aValue)
{
if ( aValue != null )
{
_observer = new WeakReference( aValue );
}
}
private String name()
{
return _name;
}
private void setName(String aValue)
{
_name = aValue;
}
private Object object()
{
if ( _object != null )
{
return _object.get();
}
return null;
}
private void setObject(Object aValue)
{
if ( aValue != null )
{
_object = new WeakReference( aValue );
}
}
private boolean isValid()
{
Observer anObserver = this.observer();
if ( anObserver != null )
{
return true;
}
return false;
}
private Observer accepts(String aName, Object anObject)
{
Observer anObserver = this.observer();
if ( anObserver != null )
{
String anEntryName = this.name();
Object anEntryObject = this.object();
if ( ( anEntryName == null ) && ( anEntryObject ==
null ) )
{
return anObserver;
}
else
if ( ( anEntryName != null ) && ( anEntryObject !=
null ) )
{
if ( ( anEntryName.equals( aName ) == true ) &&
( anEntryObject.equals( anObject ) ==
true ) )
{
return anObserver;
}
}
else
if ( anEntryName != null )
{
if ( anEntryName.equals( aName ) == true )
{
return anObserver;
}
}
else
if ( anEntryObject != null )
{
if ( anEntryObject.equals( anObject ) == true )
{
return anObserver;
}
}
}
return null;
}
}
// ===========================================================================
// Task method(s)
// ---------------------------------------------------------------------------
private static final class Task extends Object implements Runnable
{
private Collection _observers = null;
private Notification _notification = null;
private Task(Collection someObservers, Notification aNotification)
{
super();
this.setObservers( someObservers );
this.setNotification( aNotification );
}
private Collection observers()
{
return _observers;
}
private void setObservers(Collection aValue)
{
_observers = aValue;
}
private Notification notification()
{
return _notification;
}
private void setNotification(Notification aValue)
{
_notification = aValue;
}
public void run()
{
Notification aNotification = this.notification();
for ( Iterator anIterator = this.observers().iterator();
anIterator.hasNext(); )
{
Observer anObserver = (Observer)
anIterator.next();
anObserver.notify( aNotification );
}
}
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>