You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Neil O'Toole <ne...@users.sourceforge.net> on 2003/07/21 08:57:46 UTC

[collections][submission] NotifyingCollections

This is a much updated submission of the event-based notifying
decorator mechanism for collections, as discussed on the list last
month.

The package is too big to be posted to this list. The source, javadoc,
and pre-built jar can be downloaded from:

 http://nettool.sourceforge.net/nc
 
The javadoc can be viewed online:
 
 http://nettool.sourceforge.net/nc/api
 
The best place to start is the package description for
o.a.c.collections.notifying. Either navigate from above, or directly
via:

http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifying/package-summary.html#package_description
 

This release provides notifying decorators for Collection, Set,
SortedSet, List, Bag and SortedBag. Map and SortedMap implementations
are present, but are not completed.

NotifyingCollections uses pluggable event factories to generate its
events. There are three such "event packages" included: 'simple',
'rich', and 'monolithic'. The 'simple' package is a bare-bones
implementation (one event class) that is fast and light. The 'rich'
package defines an event hierarchy (with AddEvent, RemoveEvent etc.)
that tracks all delta data necessary to reconstruct a collection's
entire history. In particular, RichCollectionEvent implements
ReplayableEvent (see below). The 'monolithic' event package is (like
'rich') a heavyweight package that implements ReplayableEvent, but has
only one event class (MonolithicCollectionEvent) instead of an
hierarchy. This package is an implementation of the Heuer/mailing-list
design that we discussed some time ago, and is basically intended as a
dis-proof-of-concept. I will discuss this in a follow-on email.

Probably the most interesting new feature is the "ReplayableEvent"
interface. This interface defines two methods, #replay and #undo (may
rename), and is implemented by the 'rich' and 'monolithic' package. An
example of usage is below.


#############################

class MyListener implements CollectionListener
{
	CollectionEvent event;

	public void collectionEventOccurred(CollectionEvent event)
	{
		this.event = event;
	}
}

NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
ArrayList());

MyListener listener = new MyListener();
nl.addCollectionListener(listener);

String s = "hello";

nl.add(s);
assertTrue(nl.size() == 1);

AddEvent event = (AddEvent) listener.event;
assertTrue(event.getAddedItem() == s);

// now for the fun part
event.undo(nl); // undoes the add action
assertTrue(nl.size() == 0);

// replay the action
event.replay(nl);
assertTrue(nl.size() == 1 && nl.contains(s));

// replay the action on a different target
List list = new ArrayList();

event.replay(list);
assertTrue(list.equals(nl));

############################

More comments in follow-on email.

Neil



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
Let me say that I don't find major flaws with either Neil's or
Stephen's approaches.  I think both will support my two use cases, as
follows

1.  Efficient and simple notification of changes in a Collection so that
user interface views may refresh.  Any detailed information about the
change, if necessary, can be calculated by the listener (the view in this
case) by comparing the new event source to an old(er) cached one.

2.  Enabling a listener to record changes made to a Collection (the
buzzword is "provenance" I guess), who made the change, timestamp, etc.
Again, detailed information about the change itself is not very
important.

I guess that means I'm backing out of the discussion, and will adapt to
whatever design comes out of this.  :)

   michael


On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> Been busy with [lang]....anyway
>
> There are various issues with designing an event system that bering the
> three approaches into conflict:
>
> 1) Listener methods -
> [neil] One Listener method, different event types
> [michael] Many Listener methods, one event type
> [stephen] Favour one method, but....
> What if the user doesn't want a listener?
>
> 2) Event classes -
> [neil] Very simple + Detail in OO hierarchy
> [michael] Standard, as detailed as possible
> [stephen] Standard, as detailed as possible, but....
> What if the user wants full detail to allow for undo?
>
> 3) OO/Patterns -
> [neil] Follow OO guidelines, type hierarchies, factories, etc.
> [michael] Simple solution to get job done
> [stephen] Basic solution, not much OO, but...
> What if the user want a more OO solution?
>
> Now you may think that #3 is a repeat of #2, but I added it as it is clear
> that there is a difference in programming approach between Neil and myself.
> I am not greatly in love with OO. It has its moments of convenience, but I
> do not really buy into it. (Many commons committers are like this, as
> commons libraries tend not to be terribly fancy OO designs). Thus #3 is
> included because I want to note that if I commit a final solution, it won't
> necessariily be overly OO, just practical.
>
> #1 is a straight choice, in theory. #2 is a choice too, simple or detailed.
> Except that too much constriction is placed by the NotifyingCollections
> design.
>
> What if I want to have events recieved without writing a Listener
> implementation and registering it. Can I? What if I want events that tell
> you as much as possible, but not enough to support undo?
>
> The design I posted before
> http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
> the event handling to another object. That object MIGHT be the standard one
> that calls Listeners. OR it might be one that logs calls directly. OR it
> might call a method on another object directly (no listener). This is much
> more flexible.
>
> The same handler also enables the factory behaviour from
> NotifyingCollections without being so explicit. The factory from
> NotifyingCollections limits the arguments that can be passed into the event
> object. The ObservedCollection handler creates the event object itself, so
> can do what it likes, allowing some very flexible possibilities. (eg.
> creating a handler that is linked to multiple lists and updates one based on
> changes to another while applying filtering....)
>
> The default ObservedCollection event stores as much data as possible for
> List, Collection (Map/Set/Bag can be added). It does not attempt to store
> absolute data about the change, so an undo facility is not possible. In
> other words, the single event class is not trying to compete with the
> hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
> Collections API in that it has UnsupportedOperationException. Typecasting is
> a pain however you try and look at it.
>
> The conflict between the rich hierarchy [neil] and the 'rich as possible
> monolithic' [stephen/michael] is most acute in defining which is the base
> event class for the listener. The solution is to not have the conflict -
> ObservedCollections allows one handler for monolithic that specifies one
> Listener that is passed a monolithic event, whereas for rich events a
> separate handler, with a separate Listener that is passed the rich event
> abstract base event type can be used. Two handlers, two listeners, one for
> each problem solution.
>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.
>
> Stephen
>
> ----- Original Message -----
> From: "Neil O'Toole" <ne...@users.sourceforge.net>
> > [stephen] > My goals for [collections] is to add something small and
> > simple that doesn't prevent a user adding something more complex.
> >
> > [michael] > I think I would prefer multiple listener interfaces and a
> > simple event to a single listener interface and either a hierarchy of
> > event classes or a typed-using-masks event.
> >
> > Obviously one of the concerns for the notifying package is that it be
> > small and easy to use, yet we also want it be flexible and powerful
> > (when required). This is why NotifyingCollections uses a pluggable
> > event system. And the simplest usage for NotifyingCollections is indeed
> > small and simple. The user need only know about one decorator (e.g.
> > NotifyingList), one listener (CollectionListener), and one event
> > (ModifyingEvent). The default 'simple' event package in
> > NotifyingCollections is just that, simple. The package can be used as
> > easily as this:
> >
> >  NotifyingCollection nc =
> >   NotifyingCollectionsUtils.notifyingCollection( c );
> >
> >  nc.addCollectionListener( myCollectionListener );
> >
> >  // do something
> >  nc.add( "hello world" )!
> >
> >  ModifyingEvent event = myCollectionListener.getEvent();
> >  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
> >
> > The 'simple' package has one event class, SimpleCollectionEvent. The
> > user does not even need to know of this class as it is simply a minimal
> > implementation of ModifyingEvent (which is abstract). The only data
> > provided is the size of the collection before and after the event. It
> > does not contain references to the arguments that caused the event to
> > be fired or references to the items added/removed etc. from the
> > collection by the event. That would be considered rich data.
> >
> > The 'rich' event package has an event hierarchy, which (I hope)
> > captures the semantics of collection manipulation quite well. There is
> > an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> > 9 events. I believe this is close to the minimum number of classes
> > necessary to richly model collection manipulation in a clean OO manner.
> > (Though if anyone can do better, they can just plug in their own event
> > package!).
> >
> > The third event package, 'monolithic', is an attempt to capture rich
> > data (like the 'rich' package) in a single event class, i.e. the design
> > idea that has been floated on the list. While a single event class
> > works fine for SimpleCollectionEvent, it does not work well with rich
> > data.
> >
> > Let's take three collection manipulations, for which we want to gather
> > rich data:
> >
> > a) remove several items from a list (e.g. #removeAll)
> > b) set a list element
> > c) put an entry into a map
> >
> > What data do we need to capture?
> >
> > a) The removed items, and the indices of each removed item (note that
> > they are not necessarily in sequence)
> > b) The value of the list element, the index, and the previous value at
> > that index
> > c) The key, the value associated with that key, and the previous value
> > associated with the key (if any)
> >
> > So, in this *one* monolithic rich event class, we need a method:
> >
> > 1) to access added/removed/set items (e.g. #getItems: Collection)
> > 2) to get indices (e.g. #getIndices: int[])
> > 3) to test if there was a former value associated with an index/key
> > (e.g. #hasPreviousValue: boolean)
> > 4) to get previous value if any (e.g. #getPreviousValue: Object)
> > 5) to get key associated with a Map put event (e.g. #getKey: Object -
> > though this could be possibly be shared with #getIndices)
> >
> > Those who already see what's wrong with this can skip this section ;)
> > For the unconvinced, let's say we add an item to a plain ol'
> > collection:
> >
> >  nc.add( "hello" );
> >  MonolithicEvent event = myListener.getEvent(); // grab the event
> >                                          // from a listener somewhere
> >
> > This monolithic event will have a method #getIndices, which has no
> > meaning in the context of a collection. Presumably #getIndices should
> > return null in this case? (as a zero-length indices array would violate
> > the invariant that the number of indices should be the same as the
> > number of added/removed items). Not pretty. There are a whole bunch of
> > similar methods in MonolithicEvent that are specific to the specialized
> > types in collections, and don't belong in a general type. This is a
> > textbook example of when to use subclassing.
> >
> > I don't argue that the included 'rich' event package is the only or the
> > best possible model of collections manipulation. Indeed I completely
> > redesigned the package at least once. What I do argue is that this
> > shows a) the need for a flexible event system and b) the difficulties
> > with trying to capture rich heterogeneous data in a single class.
> >
> > - Neil
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> <snip>
>
> The design I posted before
> http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
> the event handling to another object. That object MIGHT be the standard one
> that calls Listeners. OR it might be one that logs calls directly. OR it
> might call a method on another object directly (no listener). This is much
> more flexible.

Just for fun, here's a quick hack using aspects


import java.util.ArrayList;
import java.util.Collection;

import java.lang.reflect.Method;

import com.tirsen.nanning.AspectInstance;
import com.tirsen.nanning.MixinInstance;
import com.tirsen.nanning.MethodInterceptor;
import com.tirsen.nanning.Invocation;

import junit.framework.TestCase;

public class AspectCollectionTest
 extends TestCase
{

 private boolean heardAdd = false;

 public void testAdd()
 {
  try
  {
   AspectInstance instance = new AspectInstance();
   MixinInstance mixin = new MixinInstance(Collection.class,
                                           new ArrayList());
   Method addMethod = Collection.class.getMethod("add",
                                                 new Class[] { Object.class });

   mixin.addInterceptor(addMethod, new MethodInterceptor()
   {
    public Object invoke(Invocation invocation)
     throws Throwable
    {
     heardAdd = true;
     return invocation.invokeNext();
    }
   });

   instance.addMixin(mixin);
   Collection c = (Collection) instance.getProxy();

   assertTrue("before, heard add = " + heardAdd, heardAdd == false);
   c.add("hello");
   assertTrue("after, heard add = " + heardAdd, heardAdd);
  }
  catch (Exception e)
  {
   e.printStackTrace();
   fail(e.getMessage());
  }
 }
}


I'll address the rest of your email separately.

   michael


>
> The same handler also enables the factory behaviour from
> NotifyingCollections without being so explicit. The factory from
> NotifyingCollections limits the arguments that can be passed into the event
> object. The ObservedCollection handler creates the event object itself, so
> can do what it likes, allowing some very flexible possibilities. (eg.
> creating a handler that is linked to multiple lists and updates one based on
> changes to another while applying filtering....)
>
> The default ObservedCollection event stores as much data as possible for
> List, Collection (Map/Set/Bag can be added). It does not attempt to store
> absolute data about the change, so an undo facility is not possible. In
> other words, the single event class is not trying to compete with the
> hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
> Collections API in that it has UnsupportedOperationException. Typecasting is
> a pain however you try and look at it.
>
> The conflict between the rich hierarchy [neil] and the 'rich as possible
> monolithic' [stephen/michael] is most acute in defining which is the base
> event class for the listener. The solution is to not have the conflict -
> ObservedCollections allows one handler for monolithic that specifies one
> Listener that is passed a monolithic event, whereas for rich events a
> separate handler, with a separate Listener that is passed the rich event
> abstract base event type can be used. Two handlers, two listeners, one for
> each problem solution.
>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.
>
> Stephen
>
> ----- Original Message -----
> From: "Neil O'Toole" <ne...@users.sourceforge.net>
> > [stephen] > My goals for [collections] is to add something small and
> > simple that doesn't prevent a user adding something more complex.
> >
> > [michael] > I think I would prefer multiple listener interfaces and a
> > simple event to a single listener interface and either a hierarchy of
> > event classes or a typed-using-masks event.
> >
> > Obviously one of the concerns for the notifying package is that it be
> > small and easy to use, yet we also want it be flexible and powerful
> > (when required). This is why NotifyingCollections uses a pluggable
> > event system. And the simplest usage for NotifyingCollections is indeed
> > small and simple. The user need only know about one decorator (e.g.
> > NotifyingList), one listener (CollectionListener), and one event
> > (ModifyingEvent). The default 'simple' event package in
> > NotifyingCollections is just that, simple. The package can be used as
> > easily as this:
> >
> >  NotifyingCollection nc =
> >   NotifyingCollectionsUtils.notifyingCollection( c );
> >
> >  nc.addCollectionListener( myCollectionListener );
> >
> >  // do something
> >  nc.add( "hello world" )!
> >
> >  ModifyingEvent event = myCollectionListener.getEvent();
> >  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
> >
> > The 'simple' package has one event class, SimpleCollectionEvent. The
> > user does not even need to know of this class as it is simply a minimal
> > implementation of ModifyingEvent (which is abstract). The only data
> > provided is the size of the collection before and after the event. It
> > does not contain references to the arguments that caused the event to
> > be fired or references to the items added/removed etc. from the
> > collection by the event. That would be considered rich data.
> >
> > The 'rich' event package has an event hierarchy, which (I hope)
> > captures the semantics of collection manipulation quite well. There is
> > an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> > 9 events. I believe this is close to the minimum number of classes
> > necessary to richly model collection manipulation in a clean OO manner.
> > (Though if anyone can do better, they can just plug in their own event
> > package!).
> >
> > The third event package, 'monolithic', is an attempt to capture rich
> > data (like the 'rich' package) in a single event class, i.e. the design
> > idea that has been floated on the list. While a single event class
> > works fine for SimpleCollectionEvent, it does not work well with rich
> > data.
> >
> > Let's take three collection manipulations, for which we want to gather
> > rich data:
> >
> > a) remove several items from a list (e.g. #removeAll)
> > b) set a list element
> > c) put an entry into a map
> >
> > What data do we need to capture?
> >
> > a) The removed items, and the indices of each removed item (note that
> > they are not necessarily in sequence)
> > b) The value of the list element, the index, and the previous value at
> > that index
> > c) The key, the value associated with that key, and the previous value
> > associated with the key (if any)
> >
> > So, in this *one* monolithic rich event class, we need a method:
> >
> > 1) to access added/removed/set items (e.g. #getItems: Collection)
> > 2) to get indices (e.g. #getIndices: int[])
> > 3) to test if there was a former value associated with an index/key
> > (e.g. #hasPreviousValue: boolean)
> > 4) to get previous value if any (e.g. #getPreviousValue: Object)
> > 5) to get key associated with a Map put event (e.g. #getKey: Object -
> > though this could be possibly be shared with #getIndices)
> >
> > Those who already see what's wrong with this can skip this section ;)
> > For the unconvinced, let's say we add an item to a plain ol'
> > collection:
> >
> >  nc.add( "hello" );
> >  MonolithicEvent event = myListener.getEvent(); // grab the event
> >                                          // from a listener somewhere
> >
> > This monolithic event will have a method #getIndices, which has no
> > meaning in the context of a collection. Presumably #getIndices should
> > return null in this case? (as a zero-length indices array would violate
> > the invariant that the number of indices should be the same as the
> > number of added/removed items). Not pretty. There are a whole bunch of
> > similar methods in MonolithicEvent that are specific to the specialized
> > types in collections, and don't belong in a general type. This is a
> > textbook example of when to use subclassing.
> >
> > I don't argue that the included 'rich' event package is the only or the
> > best possible model of collections manipulation. Indeed I completely
> > redesigned the package at least once. What I do argue is that this
> > shows a) the need for a flexible event system and b) the difficulties
> > with trying to capture rich heterogeneous data in a single class.
> >
> > - Neil
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> <snip>
>
> The design I posted before
> http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
> the event handling to another object. That object MIGHT be the standard one
> that calls Listeners. OR it might be one that logs calls directly. OR it
> might call a method on another object directly (no listener). This is much
> more flexible.

Just for fun, here's a quick hack using aspects


import java.util.ArrayList;
import java.util.Collection;

import java.lang.reflect.Method;

import com.tirsen.nanning.AspectInstance;
import com.tirsen.nanning.MixinInstance;
import com.tirsen.nanning.MethodInterceptor;
import com.tirsen.nanning.Invocation;

import junit.framework.TestCase;

public class AspectCollectionTest
 extends TestCase
{

 private boolean heardAdd = false;

 public void testAdd()
 {
  try
  {
   AspectInstance instance = new AspectInstance();
   MixinInstance mixin = new MixinInstance(Collection.class,
                                           new ArrayList());
   Method addMethod = Collection.class.getMethod("add",
                                                 new Class[] { Object.class });

   mixin.addInterceptor(addMethod, new MethodInterceptor()
   {
    public Object invoke(Invocation invocation)
     throws Throwable
    {
     heardAdd = true;
     return invocation.invokeNext();
    }
   });

   instance.addMixin(mixin);
   Collection c = (Collection) instance.getProxy();

   assertTrue("before, heard add = " + heardAdd, heardAdd == false);
   c.add("hello");
   assertTrue("after, heard add = " + heardAdd, heardAdd);
  }
  catch (Exception e)
  {
   e.printStackTrace();
   fail(e.getMessage());
  }
 }
}


I'll address the rest of your email separately.

   michael


>
> The same handler also enables the factory behaviour from
> NotifyingCollections without being so explicit. The factory from
> NotifyingCollections limits the arguments that can be passed into the event
> object. The ObservedCollection handler creates the event object itself, so
> can do what it likes, allowing some very flexible possibilities. (eg.
> creating a handler that is linked to multiple lists and updates one based on
> changes to another while applying filtering....)
>
> The default ObservedCollection event stores as much data as possible for
> List, Collection (Map/Set/Bag can be added). It does not attempt to store
> absolute data about the change, so an undo facility is not possible. In
> other words, the single event class is not trying to compete with the
> hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
> Collections API in that it has UnsupportedOperationException. Typecasting is
> a pain however you try and look at it.
>
> The conflict between the rich hierarchy [neil] and the 'rich as possible
> monolithic' [stephen/michael] is most acute in defining which is the base
> event class for the listener. The solution is to not have the conflict -
> ObservedCollections allows one handler for monolithic that specifies one
> Listener that is passed a monolithic event, whereas for rich events a
> separate handler, with a separate Listener that is passed the rich event
> abstract base event type can be used. Two handlers, two listeners, one for
> each problem solution.
>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.
>
> Stephen
>
> ----- Original Message -----
> From: "Neil O'Toole" <ne...@users.sourceforge.net>
> > [stephen] > My goals for [collections] is to add something small and
> > simple that doesn't prevent a user adding something more complex.
> >
> > [michael] > I think I would prefer multiple listener interfaces and a
> > simple event to a single listener interface and either a hierarchy of
> > event classes or a typed-using-masks event.
> >
> > Obviously one of the concerns for the notifying package is that it be
> > small and easy to use, yet we also want it be flexible and powerful
> > (when required). This is why NotifyingCollections uses a pluggable
> > event system. And the simplest usage for NotifyingCollections is indeed
> > small and simple. The user need only know about one decorator (e.g.
> > NotifyingList), one listener (CollectionListener), and one event
> > (ModifyingEvent). The default 'simple' event package in
> > NotifyingCollections is just that, simple. The package can be used as
> > easily as this:
> >
> >  NotifyingCollection nc =
> >   NotifyingCollectionsUtils.notifyingCollection( c );
> >
> >  nc.addCollectionListener( myCollectionListener );
> >
> >  // do something
> >  nc.add( "hello world" )!
> >
> >  ModifyingEvent event = myCollectionListener.getEvent();
> >  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
> >
> > The 'simple' package has one event class, SimpleCollectionEvent. The
> > user does not even need to know of this class as it is simply a minimal
> > implementation of ModifyingEvent (which is abstract). The only data
> > provided is the size of the collection before and after the event. It
> > does not contain references to the arguments that caused the event to
> > be fired or references to the items added/removed etc. from the
> > collection by the event. That would be considered rich data.
> >
> > The 'rich' event package has an event hierarchy, which (I hope)
> > captures the semantics of collection manipulation quite well. There is
> > an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> > 9 events. I believe this is close to the minimum number of classes
> > necessary to richly model collection manipulation in a clean OO manner.
> > (Though if anyone can do better, they can just plug in their own event
> > package!).
> >
> > The third event package, 'monolithic', is an attempt to capture rich
> > data (like the 'rich' package) in a single event class, i.e. the design
> > idea that has been floated on the list. While a single event class
> > works fine for SimpleCollectionEvent, it does not work well with rich
> > data.
> >
> > Let's take three collection manipulations, for which we want to gather
> > rich data:
> >
> > a) remove several items from a list (e.g. #removeAll)
> > b) set a list element
> > c) put an entry into a map
> >
> > What data do we need to capture?
> >
> > a) The removed items, and the indices of each removed item (note that
> > they are not necessarily in sequence)
> > b) The value of the list element, the index, and the previous value at
> > that index
> > c) The key, the value associated with that key, and the previous value
> > associated with the key (if any)
> >
> > So, in this *one* monolithic rich event class, we need a method:
> >
> > 1) to access added/removed/set items (e.g. #getItems: Collection)
> > 2) to get indices (e.g. #getIndices: int[])
> > 3) to test if there was a former value associated with an index/key
> > (e.g. #hasPreviousValue: boolean)
> > 4) to get previous value if any (e.g. #getPreviousValue: Object)
> > 5) to get key associated with a Map put event (e.g. #getKey: Object -
> > though this could be possibly be shared with #getIndices)
> >
> > Those who already see what's wrong with this can skip this section ;)
> > For the unconvinced, let's say we add an item to a plain ol'
> > collection:
> >
> >  nc.add( "hello" );
> >  MonolithicEvent event = myListener.getEvent(); // grab the event
> >                                          // from a listener somewhere
> >
> > This monolithic event will have a method #getIndices, which has no
> > meaning in the context of a collection. Presumably #getIndices should
> > return null in this case? (as a zero-length indices array would violate
> > the invariant that the number of indices should be the same as the
> > number of added/removed items). Not pretty. There are a whole bunch of
> > similar methods in MonolithicEvent that are specific to the specialized
> > types in collections, and don't belong in a general type. This is a
> > textbook example of when to use subclassing.
> >
> > I don't argue that the included 'rich' event package is the only or the
> > best possible model of collections manipulation. Indeed I completely
> > redesigned the package at least once. What I do argue is that this
> > shows a) the need for a flexible event system and b) the difficulties
> > with trying to capture rich heterogeneous data in a single class.
> >
> > - Neil
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Neil O'Toole <ne...@yahoo.com>.
Guys,

Sorry I haven't had a chance to read this thread - I've been on the
road since thursday. I'll be back in the real world tomorrow and i'll
get back to you all then.

- Neil


--- Stephen Colebourne <sc...@btopenworld.com> wrote:
> From: "Chuck Daniels" <cj...@yahoo.com>
> > >   sc.add("");
> > > Sends event OK - BUT eventCollection == oc.
> > > This is a problem, as if the listener then uses the collection,
> > > it will not
> > > be synchronized. Big problem.
> >
> > I don't think this will actually be a problem.  If calls to sc are
> > synchronized, then anything that the listener does to the backing
> collection
> > (oc in this case) is still within the context of the synchronized
> call on
> > sc.  Therefore, access to the backing collection is indirectly
> synchronized.
> > Or am I missing something here?
> 
> Intruiging. Yes, you are probably correct, so long as the listener
> operates
> in the same thread in a normal fashion. I was thinking of trying to
> spot if
> the ObservedCollection was being decorated and inform it, but maybe
> thats
> over zealous, and javadoc will do.
> 
> Stephen
> 
> 
> 
> 
> 
> > > ----- Original Message -----
> > > From: "Michael Heuer" <he...@acm.org>
> > > To: "Jakarta Commons Developers List"
> <co...@jakarta.apache.org>
> > > Cc: <ne...@users.sourceforge.net>
> > > Sent: Thursday, August 14, 2003 11:02 PM
> > > Subject: Re: [collections] NotifyingCollections - capturing rich
> > > non-uniform
> > > data
> > >
> > >
> > > >
> > > > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> > > >
> > > > > <snip>
> > > > >
> > > > > The biggest problem with all this is that the collection
> returned by
> > > > > getSource() on the event. If the observed collection is
> > > wrapped (eg. by
> > > a
> > > > > SyncronizedCollection) then getSource() SHOULD return the
> wrapped
> > > > > collection, but it can't as it doesn't know about it. This
> problem
> > > applies
> > > > > to all designs so far.
> > > >
> > > > Is this also a problem?  It's general to all of the delegation
> > > > implementations.
> > > >
> > > >
> > > >  private boolean heardChange = false;
> > > >
> > > >  public void testChangeToBackingCollection()
> > > >  {
> > > >   Collection c = new ArrayList();
> > > >   ObservableCollection oc =
> CollectionUtils.observableCollection(c);
> > > >   oc.addListener(new CollectionListener()
> > > >    {
> > > >     public void changed(CollectionEvent e) { heardChange =
> true; }
> > > >    });
> > > >
> > > >   c.add("hello");
> > > >
> > > >   assertTrue("heardChange == true", heardChange == true);
> > > >  }
> > > >
> > > >
> > > > I don't think it's possible to make this test pass -- just a
> > > > shortcoming of the wrapper design.  That's why I was looking
> into
> > > > aspect-based implementations.
> > > >
> > > >    michael
> > > >
> > > >
> > > >
> ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > > >
> > >
> > >
> > >
> ---------------------------------------------------------------------
> > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > >
> >
> >
> >
> >
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Neil O'Toole <ne...@yahoo.com>.
Guys,

Sorry I haven't had a chance to read this thread - I've been on the
road since thursday. I'll be back in the real world tomorrow and i'll
get back to you all then.

- Neil


--- Stephen Colebourne <sc...@btopenworld.com> wrote:
> From: "Chuck Daniels" <cj...@yahoo.com>
> > >   sc.add("");
> > > Sends event OK - BUT eventCollection == oc.
> > > This is a problem, as if the listener then uses the collection,
> > > it will not
> > > be synchronized. Big problem.
> >
> > I don't think this will actually be a problem.  If calls to sc are
> > synchronized, then anything that the listener does to the backing
> collection
> > (oc in this case) is still within the context of the synchronized
> call on
> > sc.  Therefore, access to the backing collection is indirectly
> synchronized.
> > Or am I missing something here?
> 
> Intruiging. Yes, you are probably correct, so long as the listener
> operates
> in the same thread in a normal fashion. I was thinking of trying to
> spot if
> the ObservedCollection was being decorated and inform it, but maybe
> thats
> over zealous, and javadoc will do.
> 
> Stephen
> 
> 
> 
> 
> 
> > > ----- Original Message -----
> > > From: "Michael Heuer" <he...@acm.org>
> > > To: "Jakarta Commons Developers List"
> <co...@jakarta.apache.org>
> > > Cc: <ne...@users.sourceforge.net>
> > > Sent: Thursday, August 14, 2003 11:02 PM
> > > Subject: Re: [collections] NotifyingCollections - capturing rich
> > > non-uniform
> > > data
> > >
> > >
> > > >
> > > > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> > > >
> > > > > <snip>
> > > > >
> > > > > The biggest problem with all this is that the collection
> returned by
> > > > > getSource() on the event. If the observed collection is
> > > wrapped (eg. by
> > > a
> > > > > SyncronizedCollection) then getSource() SHOULD return the
> wrapped
> > > > > collection, but it can't as it doesn't know about it. This
> problem
> > > applies
> > > > > to all designs so far.
> > > >
> > > > Is this also a problem?  It's general to all of the delegation
> > > > implementations.
> > > >
> > > >
> > > >  private boolean heardChange = false;
> > > >
> > > >  public void testChangeToBackingCollection()
> > > >  {
> > > >   Collection c = new ArrayList();
> > > >   ObservableCollection oc =
> CollectionUtils.observableCollection(c);
> > > >   oc.addListener(new CollectionListener()
> > > >    {
> > > >     public void changed(CollectionEvent e) { heardChange =
> true; }
> > > >    });
> > > >
> > > >   c.add("hello");
> > > >
> > > >   assertTrue("heardChange == true", heardChange == true);
> > > >  }
> > > >
> > > >
> > > > I don't think it's possible to make this test pass -- just a
> > > > shortcoming of the wrapper design.  That's why I was looking
> into
> > > > aspect-based implementations.
> > > >
> > > >    michael
> > > >
> > > >
> > > >
> ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > > >
> > >
> > >
> > >
> ---------------------------------------------------------------------
> > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > >
> >
> >
> >
> >
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Stephen Colebourne <sc...@btopenworld.com>.
From: "Chuck Daniels" <cj...@yahoo.com>
> >   sc.add("");
> > Sends event OK - BUT eventCollection == oc.
> > This is a problem, as if the listener then uses the collection,
> > it will not
> > be synchronized. Big problem.
>
> I don't think this will actually be a problem.  If calls to sc are
> synchronized, then anything that the listener does to the backing
collection
> (oc in this case) is still within the context of the synchronized call on
> sc.  Therefore, access to the backing collection is indirectly
synchronized.
> Or am I missing something here?

Intruiging. Yes, you are probably correct, so long as the listener operates
in the same thread in a normal fashion. I was thinking of trying to spot if
the ObservedCollection was being decorated and inform it, but maybe thats
over zealous, and javadoc will do.

Stephen





> > ----- Original Message -----
> > From: "Michael Heuer" <he...@acm.org>
> > To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
> > Cc: <ne...@users.sourceforge.net>
> > Sent: Thursday, August 14, 2003 11:02 PM
> > Subject: Re: [collections] NotifyingCollections - capturing rich
> > non-uniform
> > data
> >
> >
> > >
> > > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> > >
> > > > <snip>
> > > >
> > > > The biggest problem with all this is that the collection returned by
> > > > getSource() on the event. If the observed collection is
> > wrapped (eg. by
> > a
> > > > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > > > collection, but it can't as it doesn't know about it. This problem
> > applies
> > > > to all designs so far.
> > >
> > > Is this also a problem?  It's general to all of the delegation
> > > implementations.
> > >
> > >
> > >  private boolean heardChange = false;
> > >
> > >  public void testChangeToBackingCollection()
> > >  {
> > >   Collection c = new ArrayList();
> > >   ObservableCollection oc = CollectionUtils.observableCollection(c);
> > >   oc.addListener(new CollectionListener()
> > >    {
> > >     public void changed(CollectionEvent e) { heardChange = true; }
> > >    });
> > >
> > >   c.add("hello");
> > >
> > >   assertTrue("heardChange == true", heardChange == true);
> > >  }
> > >
> > >
> > > I don't think it's possible to make this test pass -- just a
> > > shortcoming of the wrapper design.  That's why I was looking into
> > > aspect-based implementations.
> > >
> > >    michael
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Stephen Colebourne <sc...@btopenworld.com>.
From: "Chuck Daniels" <cj...@yahoo.com>
> >   sc.add("");
> > Sends event OK - BUT eventCollection == oc.
> > This is a problem, as if the listener then uses the collection,
> > it will not
> > be synchronized. Big problem.
>
> I don't think this will actually be a problem.  If calls to sc are
> synchronized, then anything that the listener does to the backing
collection
> (oc in this case) is still within the context of the synchronized call on
> sc.  Therefore, access to the backing collection is indirectly
synchronized.
> Or am I missing something here?

Intruiging. Yes, you are probably correct, so long as the listener operates
in the same thread in a normal fashion. I was thinking of trying to spot if
the ObservedCollection was being decorated and inform it, but maybe thats
over zealous, and javadoc will do.

Stephen





> > ----- Original Message -----
> > From: "Michael Heuer" <he...@acm.org>
> > To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
> > Cc: <ne...@users.sourceforge.net>
> > Sent: Thursday, August 14, 2003 11:02 PM
> > Subject: Re: [collections] NotifyingCollections - capturing rich
> > non-uniform
> > data
> >
> >
> > >
> > > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> > >
> > > > <snip>
> > > >
> > > > The biggest problem with all this is that the collection returned by
> > > > getSource() on the event. If the observed collection is
> > wrapped (eg. by
> > a
> > > > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > > > collection, but it can't as it doesn't know about it. This problem
> > applies
> > > > to all designs so far.
> > >
> > > Is this also a problem?  It's general to all of the delegation
> > > implementations.
> > >
> > >
> > >  private boolean heardChange = false;
> > >
> > >  public void testChangeToBackingCollection()
> > >  {
> > >   Collection c = new ArrayList();
> > >   ObservableCollection oc = CollectionUtils.observableCollection(c);
> > >   oc.addListener(new CollectionListener()
> > >    {
> > >     public void changed(CollectionEvent e) { heardChange = true; }
> > >    });
> > >
> > >   c.add("hello");
> > >
> > >   assertTrue("heardChange == true", heardChange == true);
> > >  }
> > >
> > >
> > > I don't think it's possible to make this test pass -- just a
> > > shortcoming of the wrapper design.  That's why I was looking into
> > > aspect-based implementations.
> > >
> > >    michael
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


RE: [collections] NotifyingCollections - the wrapping problem

Posted by Chuck Daniels <cj...@yahoo.com>.
> -----Original Message-----
> From: Stephen Colebourne [mailto:scolebourne@btopenworld.com]
> Sent: Saturday, August 16, 2003 8:01 AM
> To: Jakarta Commons Developers List
> Subject: Re: [collections] NotifyingCollections - the wrapping problem
>
>
> This isn't the problem case. Think about:
>
>   Collection c = new ArrayList();
>   ObservableCollection oc = CollectionUtils.observableCollection(c);
>   SynchronizedCollection sc = CollectionUtils.synchronizedCollection(oc);
>   oc.addListener(new CollectionListener() {
>     public void changed(CollectionEvent e) { Collection eventCollection =
> e.getCollection() }
>    });
>
>   c.add("");
> Fails - but all decorators ban this because c is decorated
>
>   oc.add("");
> Sends event OK - eventCollection == oc, but all decorators ban
> this because
> oc is decorated
>
>   sc.add("");
> Sends event OK - BUT eventCollection == oc.
> This is a problem, as if the listener then uses the collection,
> it will not
> be synchronized. Big problem.

I don't think this will actually be a problem.  If calls to sc are
synchronized, then anything that the listener does to the backing collection
(oc in this case) is still within the context of the synchronized call on
sc.  Therefore, access to the backing collection is indirectly synchronized.
Or am I missing something here?

>
> Stephen
>
> ----- Original Message -----
> From: "Michael Heuer" <he...@acm.org>
> To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
> Cc: <ne...@users.sourceforge.net>
> Sent: Thursday, August 14, 2003 11:02 PM
> Subject: Re: [collections] NotifyingCollections - capturing rich
> non-uniform
> data
>
>
> >
> > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> >
> > > <snip>
> > >
> > > The biggest problem with all this is that the collection returned by
> > > getSource() on the event. If the observed collection is
> wrapped (eg. by
> a
> > > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > > collection, but it can't as it doesn't know about it. This problem
> applies
> > > to all designs so far.
> >
> > Is this also a problem?  It's general to all of the delegation
> > implementations.
> >
> >
> >  private boolean heardChange = false;
> >
> >  public void testChangeToBackingCollection()
> >  {
> >   Collection c = new ArrayList();
> >   ObservableCollection oc = CollectionUtils.observableCollection(c);
> >   oc.addListener(new CollectionListener()
> >    {
> >     public void changed(CollectionEvent e) { heardChange = true; }
> >    });
> >
> >   c.add("hello");
> >
> >   assertTrue("heardChange == true", heardChange == true);
> >  }
> >
> >
> > I don't think it's possible to make this test pass -- just a
> > shortcoming of the wrapper design.  That's why I was looking into
> > aspect-based implementations.
> >
> >    michael
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>



RE: [collections] NotifyingCollections - the wrapping problem

Posted by Chuck Daniels <cj...@yahoo.com>.
> -----Original Message-----
> From: Stephen Colebourne [mailto:scolebourne@btopenworld.com]
> Sent: Saturday, August 16, 2003 8:01 AM
> To: Jakarta Commons Developers List
> Subject: Re: [collections] NotifyingCollections - the wrapping problem
>
>
> This isn't the problem case. Think about:
>
>   Collection c = new ArrayList();
>   ObservableCollection oc = CollectionUtils.observableCollection(c);
>   SynchronizedCollection sc = CollectionUtils.synchronizedCollection(oc);
>   oc.addListener(new CollectionListener() {
>     public void changed(CollectionEvent e) { Collection eventCollection =
> e.getCollection() }
>    });
>
>   c.add("");
> Fails - but all decorators ban this because c is decorated
>
>   oc.add("");
> Sends event OK - eventCollection == oc, but all decorators ban
> this because
> oc is decorated
>
>   sc.add("");
> Sends event OK - BUT eventCollection == oc.
> This is a problem, as if the listener then uses the collection,
> it will not
> be synchronized. Big problem.

I don't think this will actually be a problem.  If calls to sc are
synchronized, then anything that the listener does to the backing collection
(oc in this case) is still within the context of the synchronized call on
sc.  Therefore, access to the backing collection is indirectly synchronized.
Or am I missing something here?

>
> Stephen
>
> ----- Original Message -----
> From: "Michael Heuer" <he...@acm.org>
> To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
> Cc: <ne...@users.sourceforge.net>
> Sent: Thursday, August 14, 2003 11:02 PM
> Subject: Re: [collections] NotifyingCollections - capturing rich
> non-uniform
> data
>
>
> >
> > On Thu, 14 Aug 2003, Stephen Colebourne wrote:
> >
> > > <snip>
> > >
> > > The biggest problem with all this is that the collection returned by
> > > getSource() on the event. If the observed collection is
> wrapped (eg. by
> a
> > > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > > collection, but it can't as it doesn't know about it. This problem
> applies
> > > to all designs so far.
> >
> > Is this also a problem?  It's general to all of the delegation
> > implementations.
> >
> >
> >  private boolean heardChange = false;
> >
> >  public void testChangeToBackingCollection()
> >  {
> >   Collection c = new ArrayList();
> >   ObservableCollection oc = CollectionUtils.observableCollection(c);
> >   oc.addListener(new CollectionListener()
> >    {
> >     public void changed(CollectionEvent e) { heardChange = true; }
> >    });
> >
> >   c.add("hello");
> >
> >   assertTrue("heardChange == true", heardChange == true);
> >  }
> >
> >
> > I don't think it's possible to make this test pass -- just a
> > shortcoming of the wrapper design.  That's why I was looking into
> > aspect-based implementations.
> >
> >    michael
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Stephen Colebourne <sc...@btopenworld.com>.
This isn't the problem case. Think about:

  Collection c = new ArrayList();
  ObservableCollection oc = CollectionUtils.observableCollection(c);
  SynchronizedCollection sc = CollectionUtils.synchronizedCollection(oc);
  oc.addListener(new CollectionListener() {
    public void changed(CollectionEvent e) { Collection eventCollection =
e.getCollection() }
   });

  c.add("");
Fails - but all decorators ban this because c is decorated

  oc.add("");
Sends event OK - eventCollection == oc, but all decorators ban this because
oc is decorated

  sc.add("");
Sends event OK - BUT eventCollection == oc.
This is a problem, as if the listener then uses the collection, it will not
be synchronized. Big problem.

Stephen

----- Original Message -----
From: "Michael Heuer" <he...@acm.org>
To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
Cc: <ne...@users.sourceforge.net>
Sent: Thursday, August 14, 2003 11:02 PM
Subject: Re: [collections] NotifyingCollections - capturing rich non-uniform
data


>
> On Thu, 14 Aug 2003, Stephen Colebourne wrote:
>
> > <snip>
> >
> > The biggest problem with all this is that the collection returned by
> > getSource() on the event. If the observed collection is wrapped (eg. by
a
> > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > collection, but it can't as it doesn't know about it. This problem
applies
> > to all designs so far.
>
> Is this also a problem?  It's general to all of the delegation
> implementations.
>
>
>  private boolean heardChange = false;
>
>  public void testChangeToBackingCollection()
>  {
>   Collection c = new ArrayList();
>   ObservableCollection oc = CollectionUtils.observableCollection(c);
>   oc.addListener(new CollectionListener()
>    {
>     public void changed(CollectionEvent e) { heardChange = true; }
>    });
>
>   c.add("hello");
>
>   assertTrue("heardChange == true", heardChange == true);
>  }
>
>
> I don't think it's possible to make this test pass -- just a
> shortcoming of the wrapper design.  That's why I was looking into
> aspect-based implementations.
>
>    michael
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


Re: [collections] NotifyingCollections - the wrapping problem

Posted by Stephen Colebourne <sc...@btopenworld.com>.
This isn't the problem case. Think about:

  Collection c = new ArrayList();
  ObservableCollection oc = CollectionUtils.observableCollection(c);
  SynchronizedCollection sc = CollectionUtils.synchronizedCollection(oc);
  oc.addListener(new CollectionListener() {
    public void changed(CollectionEvent e) { Collection eventCollection =
e.getCollection() }
   });

  c.add("");
Fails - but all decorators ban this because c is decorated

  oc.add("");
Sends event OK - eventCollection == oc, but all decorators ban this because
oc is decorated

  sc.add("");
Sends event OK - BUT eventCollection == oc.
This is a problem, as if the listener then uses the collection, it will not
be synchronized. Big problem.

Stephen

----- Original Message -----
From: "Michael Heuer" <he...@acm.org>
To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
Cc: <ne...@users.sourceforge.net>
Sent: Thursday, August 14, 2003 11:02 PM
Subject: Re: [collections] NotifyingCollections - capturing rich non-uniform
data


>
> On Thu, 14 Aug 2003, Stephen Colebourne wrote:
>
> > <snip>
> >
> > The biggest problem with all this is that the collection returned by
> > getSource() on the event. If the observed collection is wrapped (eg. by
a
> > SyncronizedCollection) then getSource() SHOULD return the wrapped
> > collection, but it can't as it doesn't know about it. This problem
applies
> > to all designs so far.
>
> Is this also a problem?  It's general to all of the delegation
> implementations.
>
>
>  private boolean heardChange = false;
>
>  public void testChangeToBackingCollection()
>  {
>   Collection c = new ArrayList();
>   ObservableCollection oc = CollectionUtils.observableCollection(c);
>   oc.addListener(new CollectionListener()
>    {
>     public void changed(CollectionEvent e) { heardChange = true; }
>    });
>
>   c.add("hello");
>
>   assertTrue("heardChange == true", heardChange == true);
>  }
>
>
> I don't think it's possible to make this test pass -- just a
> shortcoming of the wrapper design.  That's why I was looking into
> aspect-based implementations.
>
>    michael
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> <snip>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.

Is this also a problem?  It's general to all of the delegation
implementations.


 private boolean heardChange = false;

 public void testChangeToBackingCollection()
 {
  Collection c = new ArrayList();
  ObservableCollection oc = CollectionUtils.observableCollection(c);
  oc.addListener(new CollectionListener()
   {
    public void changed(CollectionEvent e) { heardChange = true; }
   });

  c.add("hello");

  assertTrue("heardChange == true", heardChange == true);
 }


I don't think it's possible to make this test pass -- just a
shortcoming of the wrapper design.  That's why I was looking into
aspect-based implementations.

   michael


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
Let me say that I don't find major flaws with either Neil's or
Stephen's approaches.  I think both will support my two use cases, as
follows

1.  Efficient and simple notification of changes in a Collection so that
user interface views may refresh.  Any detailed information about the
change, if necessary, can be calculated by the listener (the view in this
case) by comparing the new event source to an old(er) cached one.

2.  Enabling a listener to record changes made to a Collection (the
buzzword is "provenance" I guess), who made the change, timestamp, etc.
Again, detailed information about the change itself is not very
important.

I guess that means I'm backing out of the discussion, and will adapt to
whatever design comes out of this.  :)

   michael


On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> Been busy with [lang]....anyway
>
> There are various issues with designing an event system that bering the
> three approaches into conflict:
>
> 1) Listener methods -
> [neil] One Listener method, different event types
> [michael] Many Listener methods, one event type
> [stephen] Favour one method, but....
> What if the user doesn't want a listener?
>
> 2) Event classes -
> [neil] Very simple + Detail in OO hierarchy
> [michael] Standard, as detailed as possible
> [stephen] Standard, as detailed as possible, but....
> What if the user wants full detail to allow for undo?
>
> 3) OO/Patterns -
> [neil] Follow OO guidelines, type hierarchies, factories, etc.
> [michael] Simple solution to get job done
> [stephen] Basic solution, not much OO, but...
> What if the user want a more OO solution?
>
> Now you may think that #3 is a repeat of #2, but I added it as it is clear
> that there is a difference in programming approach between Neil and myself.
> I am not greatly in love with OO. It has its moments of convenience, but I
> do not really buy into it. (Many commons committers are like this, as
> commons libraries tend not to be terribly fancy OO designs). Thus #3 is
> included because I want to note that if I commit a final solution, it won't
> necessariily be overly OO, just practical.
>
> #1 is a straight choice, in theory. #2 is a choice too, simple or detailed.
> Except that too much constriction is placed by the NotifyingCollections
> design.
>
> What if I want to have events recieved without writing a Listener
> implementation and registering it. Can I? What if I want events that tell
> you as much as possible, but not enough to support undo?
>
> The design I posted before
> http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
> the event handling to another object. That object MIGHT be the standard one
> that calls Listeners. OR it might be one that logs calls directly. OR it
> might call a method on another object directly (no listener). This is much
> more flexible.
>
> The same handler also enables the factory behaviour from
> NotifyingCollections without being so explicit. The factory from
> NotifyingCollections limits the arguments that can be passed into the event
> object. The ObservedCollection handler creates the event object itself, so
> can do what it likes, allowing some very flexible possibilities. (eg.
> creating a handler that is linked to multiple lists and updates one based on
> changes to another while applying filtering....)
>
> The default ObservedCollection event stores as much data as possible for
> List, Collection (Map/Set/Bag can be added). It does not attempt to store
> absolute data about the change, so an undo facility is not possible. In
> other words, the single event class is not trying to compete with the
> hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
> Collections API in that it has UnsupportedOperationException. Typecasting is
> a pain however you try and look at it.
>
> The conflict between the rich hierarchy [neil] and the 'rich as possible
> monolithic' [stephen/michael] is most acute in defining which is the base
> event class for the listener. The solution is to not have the conflict -
> ObservedCollections allows one handler for monolithic that specifies one
> Listener that is passed a monolithic event, whereas for rich events a
> separate handler, with a separate Listener that is passed the rich event
> abstract base event type can be used. Two handlers, two listeners, one for
> each problem solution.
>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.
>
> Stephen
>
> ----- Original Message -----
> From: "Neil O'Toole" <ne...@users.sourceforge.net>
> > [stephen] > My goals for [collections] is to add something small and
> > simple that doesn't prevent a user adding something more complex.
> >
> > [michael] > I think I would prefer multiple listener interfaces and a
> > simple event to a single listener interface and either a hierarchy of
> > event classes or a typed-using-masks event.
> >
> > Obviously one of the concerns for the notifying package is that it be
> > small and easy to use, yet we also want it be flexible and powerful
> > (when required). This is why NotifyingCollections uses a pluggable
> > event system. And the simplest usage for NotifyingCollections is indeed
> > small and simple. The user need only know about one decorator (e.g.
> > NotifyingList), one listener (CollectionListener), and one event
> > (ModifyingEvent). The default 'simple' event package in
> > NotifyingCollections is just that, simple. The package can be used as
> > easily as this:
> >
> >  NotifyingCollection nc =
> >   NotifyingCollectionsUtils.notifyingCollection( c );
> >
> >  nc.addCollectionListener( myCollectionListener );
> >
> >  // do something
> >  nc.add( "hello world" )!
> >
> >  ModifyingEvent event = myCollectionListener.getEvent();
> >  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
> >
> > The 'simple' package has one event class, SimpleCollectionEvent. The
> > user does not even need to know of this class as it is simply a minimal
> > implementation of ModifyingEvent (which is abstract). The only data
> > provided is the size of the collection before and after the event. It
> > does not contain references to the arguments that caused the event to
> > be fired or references to the items added/removed etc. from the
> > collection by the event. That would be considered rich data.
> >
> > The 'rich' event package has an event hierarchy, which (I hope)
> > captures the semantics of collection manipulation quite well. There is
> > an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> > 9 events. I believe this is close to the minimum number of classes
> > necessary to richly model collection manipulation in a clean OO manner.
> > (Though if anyone can do better, they can just plug in their own event
> > package!).
> >
> > The third event package, 'monolithic', is an attempt to capture rich
> > data (like the 'rich' package) in a single event class, i.e. the design
> > idea that has been floated on the list. While a single event class
> > works fine for SimpleCollectionEvent, it does not work well with rich
> > data.
> >
> > Let's take three collection manipulations, for which we want to gather
> > rich data:
> >
> > a) remove several items from a list (e.g. #removeAll)
> > b) set a list element
> > c) put an entry into a map
> >
> > What data do we need to capture?
> >
> > a) The removed items, and the indices of each removed item (note that
> > they are not necessarily in sequence)
> > b) The value of the list element, the index, and the previous value at
> > that index
> > c) The key, the value associated with that key, and the previous value
> > associated with the key (if any)
> >
> > So, in this *one* monolithic rich event class, we need a method:
> >
> > 1) to access added/removed/set items (e.g. #getItems: Collection)
> > 2) to get indices (e.g. #getIndices: int[])
> > 3) to test if there was a former value associated with an index/key
> > (e.g. #hasPreviousValue: boolean)
> > 4) to get previous value if any (e.g. #getPreviousValue: Object)
> > 5) to get key associated with a Map put event (e.g. #getKey: Object -
> > though this could be possibly be shared with #getIndices)
> >
> > Those who already see what's wrong with this can skip this section ;)
> > For the unconvinced, let's say we add an item to a plain ol'
> > collection:
> >
> >  nc.add( "hello" );
> >  MonolithicEvent event = myListener.getEvent(); // grab the event
> >                                          // from a listener somewhere
> >
> > This monolithic event will have a method #getIndices, which has no
> > meaning in the context of a collection. Presumably #getIndices should
> > return null in this case? (as a zero-length indices array would violate
> > the invariant that the number of indices should be the same as the
> > number of added/removed items). Not pretty. There are a whole bunch of
> > similar methods in MonolithicEvent that are specific to the specialized
> > types in collections, and don't belong in a general type. This is a
> > textbook example of when to use subclassing.
> >
> > I don't argue that the included 'rich' event package is the only or the
> > best possible model of collections manipulation. Indeed I completely
> > redesigned the package at least once. What I do argue is that this
> > shows a) the need for a flexible event system and b) the difficulties
> > with trying to capture rich heterogeneous data in a single class.
> >
> > - Neil
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Michael Heuer <he...@acm.org>.
On Thu, 14 Aug 2003, Stephen Colebourne wrote:

> <snip>
>
> The biggest problem with all this is that the collection returned by
> getSource() on the event. If the observed collection is wrapped (eg. by a
> SyncronizedCollection) then getSource() SHOULD return the wrapped
> collection, but it can't as it doesn't know about it. This problem applies
> to all designs so far.

Is this also a problem?  It's general to all of the delegation
implementations.


 private boolean heardChange = false;

 public void testChangeToBackingCollection()
 {
  Collection c = new ArrayList();
  ObservableCollection oc = CollectionUtils.observableCollection(c);
  oc.addListener(new CollectionListener()
   {
    public void changed(CollectionEvent e) { heardChange = true; }
   });

  c.add("hello");

  assertTrue("heardChange == true", heardChange == true);
 }


I don't think it's possible to make this test pass -- just a
shortcoming of the wrapper design.  That's why I was looking into
aspect-based implementations.

   michael


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Stephen Colebourne <sc...@btopenworld.com>.
Been busy with [lang]....anyway

There are various issues with designing an event system that bering the
three approaches into conflict:

1) Listener methods -
[neil] One Listener method, different event types
[michael] Many Listener methods, one event type
[stephen] Favour one method, but....
What if the user doesn't want a listener?

2) Event classes -
[neil] Very simple + Detail in OO hierarchy
[michael] Standard, as detailed as possible
[stephen] Standard, as detailed as possible, but....
What if the user wants full detail to allow for undo?

3) OO/Patterns -
[neil] Follow OO guidelines, type hierarchies, factories, etc.
[michael] Simple solution to get job done
[stephen] Basic solution, not much OO, but...
What if the user want a more OO solution?

Now you may think that #3 is a repeat of #2, but I added it as it is clear
that there is a difference in programming approach between Neil and myself.
I am not greatly in love with OO. It has its moments of convenience, but I
do not really buy into it. (Many commons committers are like this, as
commons libraries tend not to be terribly fancy OO designs). Thus #3 is
included because I want to note that if I commit a final solution, it won't
necessariily be overly OO, just practical.

#1 is a straight choice, in theory. #2 is a choice too, simple or detailed.
Except that too much constriction is placed by the NotifyingCollections
design.

What if I want to have events recieved without writing a Listener
implementation and registering it. Can I? What if I want events that tell
you as much as possible, but not enough to support undo?

The design I posted before
http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
the event handling to another object. That object MIGHT be the standard one
that calls Listeners. OR it might be one that logs calls directly. OR it
might call a method on another object directly (no listener). This is much
more flexible.

The same handler also enables the factory behaviour from
NotifyingCollections without being so explicit. The factory from
NotifyingCollections limits the arguments that can be passed into the event
object. The ObservedCollection handler creates the event object itself, so
can do what it likes, allowing some very flexible possibilities. (eg.
creating a handler that is linked to multiple lists and updates one based on
changes to another while applying filtering....)

The default ObservedCollection event stores as much data as possible for
List, Collection (Map/Set/Bag can be added). It does not attempt to store
absolute data about the change, so an undo facility is not possible. In
other words, the single event class is not trying to compete with the
hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
Collections API in that it has UnsupportedOperationException. Typecasting is
a pain however you try and look at it.

The conflict between the rich hierarchy [neil] and the 'rich as possible
monolithic' [stephen/michael] is most acute in defining which is the base
event class for the listener. The solution is to not have the conflict -
ObservedCollections allows one handler for monolithic that specifies one
Listener that is passed a monolithic event, whereas for rich events a
separate handler, with a separate Listener that is passed the rich event
abstract base event type can be used. Two handlers, two listeners, one for
each problem solution.


The biggest problem with all this is that the collection returned by
getSource() on the event. If the observed collection is wrapped (eg. by a
SyncronizedCollection) then getSource() SHOULD return the wrapped
collection, but it can't as it doesn't know about it. This problem applies
to all designs so far.

Stephen

----- Original Message -----
From: "Neil O'Toole" <ne...@users.sourceforge.net>
> [stephen] > My goals for [collections] is to add something small and
> simple that doesn't prevent a user adding something more complex.
>
> [michael] > I think I would prefer multiple listener interfaces and a
> simple event to a single listener interface and either a hierarchy of
> event classes or a typed-using-masks event.
>
> Obviously one of the concerns for the notifying package is that it be
> small and easy to use, yet we also want it be flexible and powerful
> (when required). This is why NotifyingCollections uses a pluggable
> event system. And the simplest usage for NotifyingCollections is indeed
> small and simple. The user need only know about one decorator (e.g.
> NotifyingList), one listener (CollectionListener), and one event
> (ModifyingEvent). The default 'simple' event package in
> NotifyingCollections is just that, simple. The package can be used as
> easily as this:
>
>  NotifyingCollection nc =
>   NotifyingCollectionsUtils.notifyingCollection( c );
>
>  nc.addCollectionListener( myCollectionListener );
>
>  // do something
>  nc.add( "hello world" )!
>
>  ModifyingEvent event = myCollectionListener.getEvent();
>  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
>
> The 'simple' package has one event class, SimpleCollectionEvent. The
> user does not even need to know of this class as it is simply a minimal
> implementation of ModifyingEvent (which is abstract). The only data
> provided is the size of the collection before and after the event. It
> does not contain references to the arguments that caused the event to
> be fired or references to the items added/removed etc. from the
> collection by the event. That would be considered rich data.
>
> The 'rich' event package has an event hierarchy, which (I hope)
> captures the semantics of collection manipulation quite well. There is
> an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> 9 events. I believe this is close to the minimum number of classes
> necessary to richly model collection manipulation in a clean OO manner.
> (Though if anyone can do better, they can just plug in their own event
> package!).
>
> The third event package, 'monolithic', is an attempt to capture rich
> data (like the 'rich' package) in a single event class, i.e. the design
> idea that has been floated on the list. While a single event class
> works fine for SimpleCollectionEvent, it does not work well with rich
> data.
>
> Let's take three collection manipulations, for which we want to gather
> rich data:
>
> a) remove several items from a list (e.g. #removeAll)
> b) set a list element
> c) put an entry into a map
>
> What data do we need to capture?
>
> a) The removed items, and the indices of each removed item (note that
> they are not necessarily in sequence)
> b) The value of the list element, the index, and the previous value at
> that index
> c) The key, the value associated with that key, and the previous value
> associated with the key (if any)
>
> So, in this *one* monolithic rich event class, we need a method:
>
> 1) to access added/removed/set items (e.g. #getItems: Collection)
> 2) to get indices (e.g. #getIndices: int[])
> 3) to test if there was a former value associated with an index/key
> (e.g. #hasPreviousValue: boolean)
> 4) to get previous value if any (e.g. #getPreviousValue: Object)
> 5) to get key associated with a Map put event (e.g. #getKey: Object -
> though this could be possibly be shared with #getIndices)
>
> Those who already see what's wrong with this can skip this section ;)
> For the unconvinced, let's say we add an item to a plain ol'
> collection:
>
>  nc.add( "hello" );
>  MonolithicEvent event = myListener.getEvent(); // grab the event
>                                          // from a listener somewhere
>
> This monolithic event will have a method #getIndices, which has no
> meaning in the context of a collection. Presumably #getIndices should
> return null in this case? (as a zero-length indices array would violate
> the invariant that the number of indices should be the same as the
> number of added/removed items). Not pretty. There are a whole bunch of
> similar methods in MonolithicEvent that are specific to the specialized
> types in collections, and don't belong in a general type. This is a
> textbook example of when to use subclassing.
>
> I don't argue that the included 'rich' event package is the only or the
> best possible model of collections manipulation. Indeed I completely
> redesigned the package at least once. What I do argue is that this
> shows a) the need for a flexible event system and b) the difficulties
> with trying to capture rich heterogeneous data in a single class.
>
> - Neil
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


Re: [collections] NotifyingCollections - capturing rich non-uniform data

Posted by Stephen Colebourne <sc...@btopenworld.com>.
Been busy with [lang]....anyway

There are various issues with designing an event system that bering the
three approaches into conflict:

1) Listener methods -
[neil] One Listener method, different event types
[michael] Many Listener methods, one event type
[stephen] Favour one method, but....
What if the user doesn't want a listener?

2) Event classes -
[neil] Very simple + Detail in OO hierarchy
[michael] Standard, as detailed as possible
[stephen] Standard, as detailed as possible, but....
What if the user wants full detail to allow for undo?

3) OO/Patterns -
[neil] Follow OO guidelines, type hierarchies, factories, etc.
[michael] Simple solution to get job done
[stephen] Basic solution, not much OO, but...
What if the user want a more OO solution?

Now you may think that #3 is a repeat of #2, but I added it as it is clear
that there is a difference in programming approach between Neil and myself.
I am not greatly in love with OO. It has its moments of convenience, but I
do not really buy into it. (Many commons committers are like this, as
commons libraries tend not to be terribly fancy OO designs). Thus #3 is
included because I want to note that if I commit a final solution, it won't
necessariily be overly OO, just practical.

#1 is a straight choice, in theory. #2 is a choice too, simple or detailed.
Except that too much constriction is placed by the NotifyingCollections
design.

What if I want to have events recieved without writing a Listener
implementation and registering it. Can I? What if I want events that tell
you as much as possible, but not enough to support undo?

The design I posted before
http://www.scolebourne.eurobell.co.uk/Observed2.zip delegates ALL aspects of
the event handling to another object. That object MIGHT be the standard one
that calls Listeners. OR it might be one that logs calls directly. OR it
might call a method on another object directly (no listener). This is much
more flexible.

The same handler also enables the factory behaviour from
NotifyingCollections without being so explicit. The factory from
NotifyingCollections limits the arguments that can be passed into the event
object. The ObservedCollection handler creates the event object itself, so
can do what it likes, allowing some very flexible possibilities. (eg.
creating a handler that is linked to multiple lists and updates one based on
changes to another while applying filtering....)

The default ObservedCollection event stores as much data as possible for
List, Collection (Map/Set/Bag can be added). It does not attempt to store
absolute data about the change, so an undo facility is not possible. In
other words, the single event class is not trying to compete with the
hierarchy like for like. Is this anti-OO. Yes, I expect so. But so is the
Collections API in that it has UnsupportedOperationException. Typecasting is
a pain however you try and look at it.

The conflict between the rich hierarchy [neil] and the 'rich as possible
monolithic' [stephen/michael] is most acute in defining which is the base
event class for the listener. The solution is to not have the conflict -
ObservedCollections allows one handler for monolithic that specifies one
Listener that is passed a monolithic event, whereas for rich events a
separate handler, with a separate Listener that is passed the rich event
abstract base event type can be used. Two handlers, two listeners, one for
each problem solution.


The biggest problem with all this is that the collection returned by
getSource() on the event. If the observed collection is wrapped (eg. by a
SyncronizedCollection) then getSource() SHOULD return the wrapped
collection, but it can't as it doesn't know about it. This problem applies
to all designs so far.

Stephen

----- Original Message -----
From: "Neil O'Toole" <ne...@users.sourceforge.net>
> [stephen] > My goals for [collections] is to add something small and
> simple that doesn't prevent a user adding something more complex.
>
> [michael] > I think I would prefer multiple listener interfaces and a
> simple event to a single listener interface and either a hierarchy of
> event classes or a typed-using-masks event.
>
> Obviously one of the concerns for the notifying package is that it be
> small and easy to use, yet we also want it be flexible and powerful
> (when required). This is why NotifyingCollections uses a pluggable
> event system. And the simplest usage for NotifyingCollections is indeed
> small and simple. The user need only know about one decorator (e.g.
> NotifyingList), one listener (CollectionListener), and one event
> (ModifyingEvent). The default 'simple' event package in
> NotifyingCollections is just that, simple. The package can be used as
> easily as this:
>
>  NotifyingCollection nc =
>   NotifyingCollectionsUtils.notifyingCollection( c );
>
>  nc.addCollectionListener( myCollectionListener );
>
>  // do something
>  nc.add( "hello world" )!
>
>  ModifyingEvent event = myCollectionListener.getEvent();
>  assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);
>
> The 'simple' package has one event class, SimpleCollectionEvent. The
> user does not even need to know of this class as it is simply a minimal
> implementation of ModifyingEvent (which is abstract). The only data
> provided is the size of the collection before and after the event. It
> does not contain references to the arguments that caused the event to
> be fired or references to the items added/removed etc. from the
> collection by the event. That would be considered rich data.
>
> The 'rich' event package has an event hierarchy, which (I hope)
> captures the semantics of collection manipulation quite well. There is
> an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
> 9 events. I believe this is close to the minimum number of classes
> necessary to richly model collection manipulation in a clean OO manner.
> (Though if anyone can do better, they can just plug in their own event
> package!).
>
> The third event package, 'monolithic', is an attempt to capture rich
> data (like the 'rich' package) in a single event class, i.e. the design
> idea that has been floated on the list. While a single event class
> works fine for SimpleCollectionEvent, it does not work well with rich
> data.
>
> Let's take three collection manipulations, for which we want to gather
> rich data:
>
> a) remove several items from a list (e.g. #removeAll)
> b) set a list element
> c) put an entry into a map
>
> What data do we need to capture?
>
> a) The removed items, and the indices of each removed item (note that
> they are not necessarily in sequence)
> b) The value of the list element, the index, and the previous value at
> that index
> c) The key, the value associated with that key, and the previous value
> associated with the key (if any)
>
> So, in this *one* monolithic rich event class, we need a method:
>
> 1) to access added/removed/set items (e.g. #getItems: Collection)
> 2) to get indices (e.g. #getIndices: int[])
> 3) to test if there was a former value associated with an index/key
> (e.g. #hasPreviousValue: boolean)
> 4) to get previous value if any (e.g. #getPreviousValue: Object)
> 5) to get key associated with a Map put event (e.g. #getKey: Object -
> though this could be possibly be shared with #getIndices)
>
> Those who already see what's wrong with this can skip this section ;)
> For the unconvinced, let's say we add an item to a plain ol'
> collection:
>
>  nc.add( "hello" );
>  MonolithicEvent event = myListener.getEvent(); // grab the event
>                                          // from a listener somewhere
>
> This monolithic event will have a method #getIndices, which has no
> meaning in the context of a collection. Presumably #getIndices should
> return null in this case? (as a zero-length indices array would violate
> the invariant that the number of indices should be the same as the
> number of added/removed items). Not pretty. There are a whole bunch of
> similar methods in MonolithicEvent that are specific to the specialized
> types in collections, and don't belong in a general type. This is a
> textbook example of when to use subclassing.
>
> I don't argue that the included 'rich' event package is the only or the
> best possible model of collections manipulation. Indeed I completely
> redesigned the package at least once. What I do argue is that this
> shows a) the need for a flexible event system and b) the difficulties
> with trying to capture rich heterogeneous data in a single class.
>
> - Neil
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


[collections] NotifyingCollections - capturing rich non-uniform data

Posted by Neil O'Toole <ne...@users.sourceforge.net>.
[stephen] > My goals for [collections] is to add something small and
simple that doesn't prevent a user adding something more complex.

[michael] > I think I would prefer multiple listener interfaces and a
simple event to a single listener interface and either a hierarchy of
event classes or a typed-using-masks event.

Obviously one of the concerns for the notifying package is that it be
small and easy to use, yet we also want it be flexible and powerful
(when required). This is why NotifyingCollections uses a pluggable
event system. And the simplest usage for NotifyingCollections is indeed
small and simple. The user need only know about one decorator (e.g.
NotifyingList), one listener (CollectionListener), and one event
(ModifyingEvent). The default 'simple' event package in
NotifyingCollections is just that, simple. The package can be used as
easily as this:

 NotifyingCollection nc = 
  NotifyingCollectionsUtils.notifyingCollection( c );
 
 nc.addCollectionListener( myCollectionListener );

 // do something
 nc.add( "hello world" )!

 ModifyingEvent event = myCollectionListener.getEvent();
 assertTrue( event.getPreEventSize() == event.getPostEventSize() -1);

The 'simple' package has one event class, SimpleCollectionEvent. The
user does not even need to know of this class as it is simply a minimal
implementation of ModifyingEvent (which is abstract). The only data
provided is the size of the collection before and after the event. It
does not contain references to the arguments that caused the event to
be fired or references to the items added/removed etc. from the
collection by the event. That would be considered rich data.

The 'rich' event package has an event hierarchy, which (I hope)
captures the semantics of collection manipulation quite well. There is
an AddEvent, a RemoveEvent, a ListAddEvent, a MapPutEvent... a total of
9 events. I believe this is close to the minimum number of classes
necessary to richly model collection manipulation in a clean OO manner.
(Though if anyone can do better, they can just plug in their own event
package!).

The third event package, 'monolithic', is an attempt to capture rich
data (like the 'rich' package) in a single event class, i.e. the design
idea that has been floated on the list. While a single event class
works fine for SimpleCollectionEvent, it does not work well with rich
data.

Let's take three collection manipulations, for which we want to gather
rich data:

a) remove several items from a list (e.g. #removeAll)
b) set a list element
c) put an entry into a map

What data do we need to capture?

a) The removed items, and the indices of each removed item (note that
they are not necessarily in sequence)
b) The value of the list element, the index, and the previous value at
that index
c) The key, the value associated with that key, and the previous value
associated with the key (if any)

So, in this *one* monolithic rich event class, we need a method:

1) to access added/removed/set items (e.g. #getItems: Collection)
2) to get indices (e.g. #getIndices: int[])
3) to test if there was a former value associated with an index/key
(e.g. #hasPreviousValue: boolean)
4) to get previous value if any (e.g. #getPreviousValue: Object)
5) to get key associated with a Map put event (e.g. #getKey: Object -
though this could be possibly be shared with #getIndices)

Those who already see what's wrong with this can skip this section ;)
For the unconvinced, let's say we add an item to a plain ol'
collection:

 nc.add( "hello" );
 MonolithicEvent event = myListener.getEvent(); // grab the event
                                         // from a listener somewhere

This monolithic event will have a method #getIndices, which has no
meaning in the context of a collection. Presumably #getIndices should
return null in this case? (as a zero-length indices array would violate
the invariant that the number of indices should be the same as the
number of added/removed items). Not pretty. There are a whole bunch of
similar methods in MonolithicEvent that are specific to the specialized
types in collections, and don't belong in a general type. This is a
textbook example of when to use subclassing.

I don't argue that the included 'rich' event package is the only or the
best possible model of collections manipulation. Indeed I completely
redesigned the package at least once. What I do argue is that this
shows a) the need for a flexible event system and b) the difficulties
with trying to capture rich heterogeneous data in a single class.

- Neil


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections] NotifyingCollections update

Posted by Neil O'Toole <ne...@users.sourceforge.net>.
--- Neil O'Toole <ne...@yahoo.com> wrote:
> Latest build and docs for NotifyingCollections available from:
> 
>  http://nettool.sourceforge.net/nc/
> 
> The significant update is that NotifyingList no longer performs
> explicit range checks (and thus should now be suitable for use with
> LazyList - an informal indicates that it does indeed work).


Last line should read "an informal test indicates that..."

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


[collections] NotifyingCollections update

Posted by Neil O'Toole <ne...@yahoo.com>.
Latest build and docs for NotifyingCollections available from:

 http://nettool.sourceforge.net/nc/

The significant update is that NotifyingList no longer performs
explicit range checks (and thus should now be suitable for use with
LazyList - an informal indicates that it does indeed work).

- Neil

 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


[collections] NotifyingCollections design

Posted by Neil O'Toole <ne...@users.sourceforge.net>.
This email gives an overview of the design of NotifyingCollections, and
addresses all of the points raised by Stephen in earlier emails.

The NotifyingCollections code is too large to post to the list, but can
be accessed at http://nettool.sourceforge.net/nc/


Design Overview
---------------

NotifyingCollections is a decorator package that provides event-based
notification functionality for the collections api. Decorators are
provided for Collection, List, Set, SortedSet, Bag, SortedBag, Map and
SortedMap. The iterators and sub-views (e.g. List#subList) are also
first class decorators (and are fail-fast). All of the decorator
classes implement the NotifyingDecorator interface, which provides
common functionality for managing listeners (adding, removing, etc.). 

A collection is decorated using the usual static method pattern, e.g.:

 NotifyingCollection nc =
    NotifyingCollectionsUtils.notifyingCollection( c );

There are two types of listeners. A 'post-listener' implements the
CollectionListener interface, and it receives a CollectionEvent *after*
the actual modification has occurred (as you might expect). 

public interface CollectionListener extends EventListener
{
   void collectionEventOccurred(CollectionEvent event);
}


A 'pre-listener' implements the VetoingCollectionListener interface,
and it receives the event *before* the modification takes place. This
gives the pre-listener a chance to veto the proposed modification
before it occurs.

public interface VetoingCollectionListener extends EventListener
{
 /**
  * @throws ModificationVetoException to indicate that the
  *  proposed event should be vetoed.
  */

   void vetoableModificationOccurring( ModifyingEvent event );
}


A notifying decorator can be configured to support either or both of
these listener mechanisms.

The base event type fired by NotifyingCollections is CollectionEvent.
This has two subclasses, ModifyingEvent and NonModifyingEvent.
NonModifyingEvents are only fired in exceptional circumstances, i.e.
when a listener vetoes a modification (ModificationVetoEvent), or when
an exception occurs during an operation on the decorated collection
(CollectionExceptionEvent). All normal collection operations result in
instances of ModifyingEvent being fired.

ModifyingEvent provides limited information about the event (actually
just the size of the collection before and after the modification).
Subclasses of ModifyingEvent (which is an abstract class) can choose to
provide as much or as little detail as desired. This capability is
provided through the use of a pluggable "event package". The author of
an event package implements one or many of the event factory interfaces
defined by NotifyingCollections (one for each main collection type),
and passes an instance of such an event factory to the decorator
factory methods in NotifyingCollectionsUtils.

NotifyingCollections includes two** event package implementations,
'simple' and 'rich'. SimpleCollectionEvent is fast and light, and does
not provide additional functionality above and beyond that specified by
ModifyingEvent. RichCollectionEvent is a heavyweight implementation. It
has an event hierarchy (i.e. AddEvent, RemoveEvent etc.), and
significant additional functionality. In particular,
RichCollectionEvent implements the ReplayableEvent interface. This
interface defines two operations, #replay and #undo, which permit the
event's actions to be replayed (or undone) on the decorated collection,
*or* on any arbitrary target collection. In effect, RichCollectionEvent
can be used to capture the entire history of a collection, and can be
used to roll back a collection to any previous state. This is a very
powerful facility.

** The current build includes a third event package 'monolithic', which
illustrates some of the limitations of dispensing with an event
hierarchy and using a single event class to capture rich mixed-type
data.


FAQ, comments, and responses
----------------------------

>> How much information about the collection modification can an event
capture?

Just about everything. For any given method, the fired event can
access:

- the entire state of the collection before and after the modification,
- the signature of the invoked method,
- the arguments to the method,
- the return value,
- any exceptions that occur,
- the state of the decorator (i.e. access to the listeners).


>> 2) The event dispatch sometimes assumes too much. For example the
List addAll() method validates the index as being in range, but the
LazyList implementation expects out of range indices. The modCount in
the iterators could face the same problem.

This issue didn't occur to me earlier in development as I had not
considered the case of contract violators such as LazyList. And in fact
the explicit range checks by NotifyingList are superfluous as the
decorated list will eventually throw an IndexOutOfBoundsException
anyway. The offending code has been removed and LazyList should work
fine now (though I have not tested against it).


>> 3) Similar to (2), the boolean result flag cannot be relied on to
give accurate results as to whether the collection has changed.

Quite correct. The result flag is no longer relied upon - the event is
fired regardless of the result value. Again thank you for the pointer.


>> 1) I dislike that a new instance of the event factory has to be
created for each collection. The factory should be capable of being
shared. This can be done by passing the init() parameters to each of
the other methods.

This is one point on which I disagree with Stephen. Indeed a new
instance of the appropriate event factory is referenced by each
decorator instance. This instance is initialized with references to the
decorator and the decorated collection. I do not consider this to be
significant in terms of storage (in the context of the number of
objects/events likely to be generated by the decorator). The
alternative (as suggested above) is to pass these instances with each
call to the factory, i.e. one call per event. This means that a method
like this:

 public ModifyingEvent createAddEvent(Object addItem);

becomes

 public ModifyingEvent createAddEvent(
	NotifyingCollection decorator,
	Collection backing,
	Object addItem);

or maybe even something like this:

 public ModifyingEvent createAddEvent(
	NotifyingList decorator,
	List backing,
	Object addItem,
	int index);
	

This essentially returns us to the days of procedural programming, in
the name of unproven optimization. Though I have not run any
comparative tests, it's questionable if in an intensive session (where
thousands or millions of events are produced in seconds) the saving in
storage (two object references) is worth the additional overhead of
pushing the same two object references onto the stack each time an
event occurs. The optimization to rid ourselves of those superflous
stack operations is to cache the two references in an object instance,
i.e. the current implementation. And of course the existing
implementation is cleaner and easier to understand and to code to, the
usual benefits of object-oriented programming.

Also, some event factory implementations may have reasons to maintain
state. For example, the 'rich' event package's ListEventFactory keeps a
member "indexOffset" which is used to calculate the indices of sub-list
elements relative to the master list. If the factory instance is shared
it means that the indexOffset parameter would have to be passed in each
time an event occurs (stack ops again), and it would also mean that
ListEventFactory could not inherit from CollectionEventFactory as the
indexOffset parameter would require changing the signatures of the
methods inherited from CollectionEventFactory.



>> 4) What if I want vetoes to have no effect, rather than throw an
exception.

While it would be very simple to provide a mechanism to disable veto
exception throwing, to do so would result in a violation of the
Collections API. Let's say we have an empty NotifyingCollection and we
attempt to add an element 'a' as below, but this addition gets vetoed
by a VetoingCollectionListener.

 boolean result = nc.add( "a" ); // gets vetoed

The *only* thing we can do here is throw an exception, as the API is
quite specific:

Collection#add: ... If a collection refuses to add a particular element
for any reason other than that it already contains the element, it must
throw an exception (rather than returning false). This preserves the
invariant that a collection always contains the specified element after
this call returns.


>> 6) There are a lot of classes to get your head around - its very OO.

The number of event classes is dependent upon the event package. The
'simple' event package has only one event class. I will agree that in
the earlier releases of NotifyingCollections, the main event package
was bloated and didn't even have the most useful semantics. It's been
entirely rewritten, and is smaller and hopefully much improved now.
Also, the factory classes are hidden away in subpackages to reduce the
clutter (most users will never need to know anything about the
factories). I hope you'll find that the latest releases are much leaner
and cleaner. 


>> 5) It is quite hard to get info out about events. Typecasting is
always needed.

The typecasting is an inevitable consequence of the flexible event
system. Either we tie ourselves to one set of events, or there must be
typecasting. I don't see this as a major problem - it is fair to say
that users of the Collections API are well used to typecasting. Also,
it should be easier to 'get info' now, as the ModifyingEvent class
(which is in the main package) now includes the most basic event info,
i.e. the change in size caused by the event. Previously one had to
typecast to a specific event package implementation to find out
anything about the event, so this concern certainly was valid.


>> Event data is theoretically flexible, but limited in practice. In
particular, the post-event cannot contain a copy of the state of the
collection, or the size before the change occurred.

This is true for earlier versions, but the design has been corrected
(once again thanks for your assistance). Event data is now flexible and
complete. (In particular see the #finalizeState mechanism).


>> [NotifyingCollections is] Unsuited to certain collections (e.g.
LazyList)

This was because of explicit range checks in NotifyingList which turned
out to be superflous, and have been removed. Thank you for pointing
this out.


>> Should give reasonable performance.

Performance depends upon the chosen event package. The default 'simple'
package is lightning fast.


- Neil












---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Neil O'Toole <ne...@yahoo.com>.
> I can't access your server at present, so I can't compare.

Sourceforge was down for a while. It's back up now.

 http://nettool.sourceforge.net/nc

> > My goals for [collections] is to add something small and simple
that
> doesn't
> prevent a user adding something more complex.

NotifyingCollections includes a 'simple' event package that is small
and fast, as well as a 'rich' package that provides a great deal of
functionality. In fact, the build of NotifyingCollections available
from the link above addresses most (if not all) of the concerns you
raised in your previous emails. I will address these issues point by
point in my next email.

Neil

--- Stephen Colebourne <sc...@btopenworld.com> wrote:
> See http://www.scolebourne.eurobell.co.uk/Observed2.zip
> This contains a simple observing collections decorator.
> 
> My goals for [collections] is to add something small and simple that
> doesn't
> prevent a user adding something more complex.
> 
> There are relatively few classes involved here, and no tests.
> 
> - ObservedCollection  is the decorator. It calls ObservedHandler
> before and
> after each method call.
> 
> - ObservedHandler has two methods for each Collection method, one to
> be
> called before and one after. (It will also have methods for
> List/Bag/Set/...
> The standard implementation in the handler forwards all the methods
> to a
> single point where the event is sent. Event filtering (from notifying
> colls)
> is used on a per method basis.
> 
> - ObservedEvent is the standard event class that stores values for
> all the
> data that is available 'for free' from the method call.
> 
> Positives:
> Simple
> Extendable by subclassing Handler/Event
> Can swallow method calls without an exception if desired
> Can cope with invalid boolean 'collection changed' flags if desired
> 
> Negatives:
> One Handler created per decorator
> Event instance not shared between pre and post event
> Listener process may not be quite right yet
> 
> I can't access your server at present, so I can't compare.
> Stephen
> 
> From: "Neil O'Toole" <ne...@yahoo.com>
> > --- Stephen Colebourne <sc...@btopenworld.com> wrote:
> > > I haven't forgotten this, and will release some code I've been
> > > working on
> > > for comparison soon.
> > > Stephen
> >
> > Great, do you have a rough idea when you'll have that code out?
> >
> > N.
> >
> >
> > > ----- Original Message -----
> > > From: "Neil O'Toole" <ne...@yahoo.com>
> > > To: "Jakarta Commons Developers List"
> > > <co...@jakarta.apache.org>;
> > > <ne...@users.sourceforge.net>
> > > Sent: Monday, July 21, 2003 9:01 PM
> > > Subject: Re: [collections][submission] NotifyingCollections
> > >
> > >
> > > > More updates: the source, jar, and javadoc have all been
> updated.
> > > >
> > > >  http://nettool.sourceforge.net/nc
> > > >
> > > > Neil
> > > >
> > > >
> > > > --- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> > > > > This is a much updated submission of the event-based
> notifying
> > > > > decorator mechanism for collections, as discussed on the list
> > > last
> > > > > month.
> > > > >
> > > > > The package is too big to be posted to this list. The source,
> > > > > javadoc,
> > > > > and pre-built jar can be downloaded from:
> > > > >
> > > > >  http://nettool.sourceforge.net/nc
> > > > >
> > > > > The javadoc can be viewed online:
> > > > >
> > > > >  http://nettool.sourceforge.net/nc/api
> > > > >
> > > > > The best place to start is the package description for
> > > > > o.a.c.collections.notifying. Either navigate from above, or
> > > directly
> > > > > via:
> > > > >
> > > > >
> > > >
> > >
> >
>
http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifyi
> > > ng/package-summary.html#package_description
> > > > >
> > > > >
> > > > > This release provides notifying decorators for Collection,
> Set,
> > > > > SortedSet, List, Bag and SortedBag. Map and SortedMap
> > > implementations
> > > > > are present, but are not completed.
> > > > >
> > > > > NotifyingCollections uses pluggable event factories to
> generate
> > > its
> > > > > events. There are three such "event packages" included:
> 'simple',
> > > > > 'rich', and 'monolithic'. The 'simple' package is a
> bare-bones
> > > > > implementation (one event class) that is fast and light. The
> > > 'rich'
> > > > > package defines an event hierarchy (with AddEvent,
> RemoveEvent
> > > etc.)
> > > > > that tracks all delta data necessary to reconstruct a
> > > collection's
> > > > > entire history. In particular, RichCollectionEvent implements
> > > > > ReplayableEvent (see below). The 'monolithic' event package
> is
> > > (like
> > > > > 'rich') a heavyweight package that implements
> ReplayableEvent,
> > > but
> > > > > has
> > > > > only one event class (MonolithicCollectionEvent) instead of
> an
> > > > > hierarchy. This package is an implementation of the
> > > > > Heuer/mailing-list
> > > > > design that we discussed some time ago, and is basically
> intended
> > > as
> > > > > a
> > > > > dis-proof-of-concept. I will discuss this in a follow-on
> email.
> > > > >
> > > > > Probably the most interesting new feature is the
> > > "ReplayableEvent"
> > > > > interface. This interface defines two methods, #replay and
> #undo
> > > (may
> > > > > rename), and is implemented by the 'rich' and 'monolithic'
> > > package.
> > > > > An
> > > > > example of usage is below.
> > > > >
> > > > >
> > > > > #############################
> > > > >
> > > > > class MyListener implements CollectionListener
> > > > > {
> > > > > CollectionEvent event;
> > > > >
> > > > > public void collectionEventOccurred(CollectionEvent event)
> > > > > {
> > > > > this.event = event;
> > > > > }
> > > > > }
> > > > >
> > > > > NotifyingList nl =
> NotifyingCollectionsUtils.notifyingList(new
> > > > > ArrayList());
> > > > >
> > > > > MyListener listener = new MyListener();
> > > > > nl.addCollectionListener(listener);
> > > > >
> > > > > String s = "hello";
> > > > >
> > > > > nl.add(s);
> > > > > assertTrue(nl.size() == 1);
> > > > >
> > > > > AddEvent event = (AddEvent) listener.event;
> > > > > assertTrue(event.getAddedItem() == s);
> > > > >
> > > > > // now for the fun part
> > > > > event.undo(nl); // undoes the add action
> > > > > assertTrue(nl.size() == 0);
> > > > >
> > > > > // replay the action
> > > > > event.replay(nl);
> > > > > assertTrue(nl.size() == 1 && nl.contains(s));
> > > > >
> > > > > // replay the action on a different target
> > > > > List list = new ArrayList();
> > > > >
> > > > > event.replay(list);
> > > > > assertTrue(list.equals(nl));
> > > > >
> > > > > ############################
> > > > >
> > > > > More comments in follow-on email.
> > > > >
> > > > > Neil
> > > > >
> > > > >
> > > > >
> > > > >
> > >
> ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail:
> > > commons-dev-unsubscribe@jakarta.apache.org
> > > > > For additional commands, e-mail:
> > > commons-dev-help@jakarta.apache.org
> > > > >
> > > >
> > > >
> > > >
> > >
> ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> > > commons-dev-help@jakarta.apache.org
> > > >
> > >
> > >
> > >
> ---------------------------------------------------------------------
> > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > >
> >
> >
> >
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Michael Heuer <he...@acm.org>.
Regarding both Neil's and Stephen's recent submissions on the topic of
event support for collections,

I think I would prefer multiple listener interfaces and a simple event to
a single listener interface and either a hierarchy of event classes or a
typed-using-masks event.  Information about the type of change is provided
to the listener through the method that is called.

I would also prefer different interfaces for simple and veto-able event
notification, e.g. CollectionListener and VetoableCollectionListener.

This leads to more interfaces than the current designs on the table

CollectionListener
VetoableCollectionListener
ListListener
VetoableListListener
...

but feels better to me from a client point of view.

   michael


On Thu, 24 Jul 2003, Stephen Colebourne wrote:

> See http://www.scolebourne.eurobell.co.uk/Observed2.zip
> This contains a simple observing collections decorator.
>
> My goals for [collections] is to add something small and simple that doesn't
> prevent a user adding something more complex.
>
> There are relatively few classes involved here, and no tests.
>
> - ObservedCollection  is the decorator. It calls ObservedHandler before and
> after each method call.
>
> - ObservedHandler has two methods for each Collection method, one to be
> called before and one after. (It will also have methods for List/Bag/Set/...
> The standard implementation in the handler forwards all the methods to a
> single point where the event is sent. Event filtering (from notifying colls)
> is used on a per method basis.
>
> - ObservedEvent is the standard event class that stores values for all the
> data that is available 'for free' from the method call.
>
> Positives:
> Simple
> Extendable by subclassing Handler/Event
> Can swallow method calls without an exception if desired
> Can cope with invalid boolean 'collection changed' flags if desired
>
> Negatives:
> One Handler created per decorator
> Event instance not shared between pre and post event
> Listener process may not be quite right yet
>
> I can't access your server at present, so I can't compare.
> Stephen
>
> From: "Neil O'Toole" <ne...@yahoo.com>
> > --- Stephen Colebourne <sc...@btopenworld.com> wrote:
> > > I haven't forgotten this, and will release some code I've been
> > > working on
> > > for comparison soon.
> > > Stephen
> >
> > Great, do you have a rough idea when you'll have that code out?
> >
> > N.
> >
> >
> > > ----- Original Message -----
> > > From: "Neil O'Toole" <ne...@yahoo.com>
> > > To: "Jakarta Commons Developers List"
> > > <co...@jakarta.apache.org>;
> > > <ne...@users.sourceforge.net>
> > > Sent: Monday, July 21, 2003 9:01 PM
> > > Subject: Re: [collections][submission] NotifyingCollections
> > >
> > >
> > > > More updates: the source, jar, and javadoc have all been updated.
> > > >
> > > >  http://nettool.sourceforge.net/nc
> > > >
> > > > Neil
> > > >
> > > >
> > > > --- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> > > > > This is a much updated submission of the event-based notifying
> > > > > decorator mechanism for collections, as discussed on the list
> > > last
> > > > > month.
> > > > >
> > > > > The package is too big to be posted to this list. The source,
> > > > > javadoc,
> > > > > and pre-built jar can be downloaded from:
> > > > >
> > > > >  http://nettool.sourceforge.net/nc
> > > > >
> > > > > The javadoc can be viewed online:
> > > > >
> > > > >  http://nettool.sourceforge.net/nc/api
> > > > >
> > > > > The best place to start is the package description for
> > > > > o.a.c.collections.notifying. Either navigate from above, or
> > > directly
> > > > > via:
> > > > >
> > > > >
> > > >
> > >
> >
> http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifyi
> > > ng/package-summary.html#package_description
> > > > >
> > > > >
> > > > > This release provides notifying decorators for Collection, Set,
> > > > > SortedSet, List, Bag and SortedBag. Map and SortedMap
> > > implementations
> > > > > are present, but are not completed.
> > > > >
> > > > > NotifyingCollections uses pluggable event factories to generate
> > > its
> > > > > events. There are three such "event packages" included: 'simple',
> > > > > 'rich', and 'monolithic'. The 'simple' package is a bare-bones
> > > > > implementation (one event class) that is fast and light. The
> > > 'rich'
> > > > > package defines an event hierarchy (with AddEvent, RemoveEvent
> > > etc.)
> > > > > that tracks all delta data necessary to reconstruct a
> > > collection's
> > > > > entire history. In particular, RichCollectionEvent implements
> > > > > ReplayableEvent (see below). The 'monolithic' event package is
> > > (like
> > > > > 'rich') a heavyweight package that implements ReplayableEvent,
> > > but
> > > > > has
> > > > > only one event class (MonolithicCollectionEvent) instead of an
> > > > > hierarchy. This package is an implementation of the
> > > > > Heuer/mailing-list
> > > > > design that we discussed some time ago, and is basically intended
> > > as
> > > > > a
> > > > > dis-proof-of-concept. I will discuss this in a follow-on email.
> > > > >
> > > > > Probably the most interesting new feature is the
> > > "ReplayableEvent"
> > > > > interface. This interface defines two methods, #replay and #undo
> > > (may
> > > > > rename), and is implemented by the 'rich' and 'monolithic'
> > > package.
> > > > > An
> > > > > example of usage is below.
> > > > >
> > > > >
> > > > > #############################
> > > > >
> > > > > class MyListener implements CollectionListener
> > > > > {
> > > > > CollectionEvent event;
> > > > >
> > > > > public void collectionEventOccurred(CollectionEvent event)
> > > > > {
> > > > > this.event = event;
> > > > > }
> > > > > }
> > > > >
> > > > > NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
> > > > > ArrayList());
> > > > >
> > > > > MyListener listener = new MyListener();
> > > > > nl.addCollectionListener(listener);
> > > > >
> > > > > String s = "hello";
> > > > >
> > > > > nl.add(s);
> > > > > assertTrue(nl.size() == 1);
> > > > >
> > > > > AddEvent event = (AddEvent) listener.event;
> > > > > assertTrue(event.getAddedItem() == s);
> > > > >
> > > > > // now for the fun part
> > > > > event.undo(nl); // undoes the add action
> > > > > assertTrue(nl.size() == 0);
> > > > >
> > > > > // replay the action
> > > > > event.replay(nl);
> > > > > assertTrue(nl.size() == 1 && nl.contains(s));
> > > > >
> > > > > // replay the action on a different target
> > > > > List list = new ArrayList();
> > > > >
> > > > > event.replay(list);
> > > > > assertTrue(list.equals(nl));
> > > > >
> > > > > ############################
> > > > >
> > > > > More comments in follow-on email.
> > > > >
> > > > > Neil
> > > > >
> > > > >
> > > > >
> > > > >
> > > ---------------------------------------------------------------------
> > > > > To unsubscribe, e-mail:
> > > commons-dev-unsubscribe@jakarta.apache.org
> > > > > For additional commands, e-mail:
> > > commons-dev-help@jakarta.apache.org
> > > > >
> > > >
> > > >
> > > >
> > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> > > commons-dev-help@jakarta.apache.org
> > > >
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Stephen Colebourne <sc...@btopenworld.com>.
See http://www.scolebourne.eurobell.co.uk/Observed2.zip
This contains a simple observing collections decorator.

My goals for [collections] is to add something small and simple that doesn't
prevent a user adding something more complex.

There are relatively few classes involved here, and no tests.

- ObservedCollection  is the decorator. It calls ObservedHandler before and
after each method call.

- ObservedHandler has two methods for each Collection method, one to be
called before and one after. (It will also have methods for List/Bag/Set/...
The standard implementation in the handler forwards all the methods to a
single point where the event is sent. Event filtering (from notifying colls)
is used on a per method basis.

- ObservedEvent is the standard event class that stores values for all the
data that is available 'for free' from the method call.

Positives:
Simple
Extendable by subclassing Handler/Event
Can swallow method calls without an exception if desired
Can cope with invalid boolean 'collection changed' flags if desired

Negatives:
One Handler created per decorator
Event instance not shared between pre and post event
Listener process may not be quite right yet

I can't access your server at present, so I can't compare.
Stephen

From: "Neil O'Toole" <ne...@yahoo.com>
> --- Stephen Colebourne <sc...@btopenworld.com> wrote:
> > I haven't forgotten this, and will release some code I've been
> > working on
> > for comparison soon.
> > Stephen
>
> Great, do you have a rough idea when you'll have that code out?
>
> N.
>
>
> > ----- Original Message -----
> > From: "Neil O'Toole" <ne...@yahoo.com>
> > To: "Jakarta Commons Developers List"
> > <co...@jakarta.apache.org>;
> > <ne...@users.sourceforge.net>
> > Sent: Monday, July 21, 2003 9:01 PM
> > Subject: Re: [collections][submission] NotifyingCollections
> >
> >
> > > More updates: the source, jar, and javadoc have all been updated.
> > >
> > >  http://nettool.sourceforge.net/nc
> > >
> > > Neil
> > >
> > >
> > > --- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> > > > This is a much updated submission of the event-based notifying
> > > > decorator mechanism for collections, as discussed on the list
> > last
> > > > month.
> > > >
> > > > The package is too big to be posted to this list. The source,
> > > > javadoc,
> > > > and pre-built jar can be downloaded from:
> > > >
> > > >  http://nettool.sourceforge.net/nc
> > > >
> > > > The javadoc can be viewed online:
> > > >
> > > >  http://nettool.sourceforge.net/nc/api
> > > >
> > > > The best place to start is the package description for
> > > > o.a.c.collections.notifying. Either navigate from above, or
> > directly
> > > > via:
> > > >
> > > >
> > >
> >
>
http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifyi
> > ng/package-summary.html#package_description
> > > >
> > > >
> > > > This release provides notifying decorators for Collection, Set,
> > > > SortedSet, List, Bag and SortedBag. Map and SortedMap
> > implementations
> > > > are present, but are not completed.
> > > >
> > > > NotifyingCollections uses pluggable event factories to generate
> > its
> > > > events. There are three such "event packages" included: 'simple',
> > > > 'rich', and 'monolithic'. The 'simple' package is a bare-bones
> > > > implementation (one event class) that is fast and light. The
> > 'rich'
> > > > package defines an event hierarchy (with AddEvent, RemoveEvent
> > etc.)
> > > > that tracks all delta data necessary to reconstruct a
> > collection's
> > > > entire history. In particular, RichCollectionEvent implements
> > > > ReplayableEvent (see below). The 'monolithic' event package is
> > (like
> > > > 'rich') a heavyweight package that implements ReplayableEvent,
> > but
> > > > has
> > > > only one event class (MonolithicCollectionEvent) instead of an
> > > > hierarchy. This package is an implementation of the
> > > > Heuer/mailing-list
> > > > design that we discussed some time ago, and is basically intended
> > as
> > > > a
> > > > dis-proof-of-concept. I will discuss this in a follow-on email.
> > > >
> > > > Probably the most interesting new feature is the
> > "ReplayableEvent"
> > > > interface. This interface defines two methods, #replay and #undo
> > (may
> > > > rename), and is implemented by the 'rich' and 'monolithic'
> > package.
> > > > An
> > > > example of usage is below.
> > > >
> > > >
> > > > #############################
> > > >
> > > > class MyListener implements CollectionListener
> > > > {
> > > > CollectionEvent event;
> > > >
> > > > public void collectionEventOccurred(CollectionEvent event)
> > > > {
> > > > this.event = event;
> > > > }
> > > > }
> > > >
> > > > NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
> > > > ArrayList());
> > > >
> > > > MyListener listener = new MyListener();
> > > > nl.addCollectionListener(listener);
> > > >
> > > > String s = "hello";
> > > >
> > > > nl.add(s);
> > > > assertTrue(nl.size() == 1);
> > > >
> > > > AddEvent event = (AddEvent) listener.event;
> > > > assertTrue(event.getAddedItem() == s);
> > > >
> > > > // now for the fun part
> > > > event.undo(nl); // undoes the add action
> > > > assertTrue(nl.size() == 0);
> > > >
> > > > // replay the action
> > > > event.replay(nl);
> > > > assertTrue(nl.size() == 1 && nl.contains(s));
> > > >
> > > > // replay the action on a different target
> > > > List list = new ArrayList();
> > > >
> > > > event.replay(list);
> > > > assertTrue(list.equals(nl));
> > > >
> > > > ############################
> > > >
> > > > More comments in follow-on email.
> > > >
> > > > Neil
> > > >
> > > >
> > > >
> > > >
> > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail:
> > commons-dev-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail:
> > commons-dev-help@jakarta.apache.org
> > > >
> > >
> > >
> > >
> > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail:
> > commons-dev-help@jakarta.apache.org
> > >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Neil O'Toole <ne...@yahoo.com>.

--- Stephen Colebourne <sc...@btopenworld.com> wrote:
> I haven't forgotten this, and will release some code I've been
> working on
> for comparison soon.
> Stephen

Great, do you have a rough idea when you'll have that code out?

N.


> ----- Original Message -----
> From: "Neil O'Toole" <ne...@yahoo.com>
> To: "Jakarta Commons Developers List"
> <co...@jakarta.apache.org>;
> <ne...@users.sourceforge.net>
> Sent: Monday, July 21, 2003 9:01 PM
> Subject: Re: [collections][submission] NotifyingCollections
> 
> 
> > More updates: the source, jar, and javadoc have all been updated.
> >
> >  http://nettool.sourceforge.net/nc
> >
> > Neil
> >
> >
> > --- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> > > This is a much updated submission of the event-based notifying
> > > decorator mechanism for collections, as discussed on the list
> last
> > > month.
> > >
> > > The package is too big to be posted to this list. The source,
> > > javadoc,
> > > and pre-built jar can be downloaded from:
> > >
> > >  http://nettool.sourceforge.net/nc
> > >
> > > The javadoc can be viewed online:
> > >
> > >  http://nettool.sourceforge.net/nc/api
> > >
> > > The best place to start is the package description for
> > > o.a.c.collections.notifying. Either navigate from above, or
> directly
> > > via:
> > >
> > >
> >
>
http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifyi
> ng/package-summary.html#package_description
> > >
> > >
> > > This release provides notifying decorators for Collection, Set,
> > > SortedSet, List, Bag and SortedBag. Map and SortedMap
> implementations
> > > are present, but are not completed.
> > >
> > > NotifyingCollections uses pluggable event factories to generate
> its
> > > events. There are three such "event packages" included: 'simple',
> > > 'rich', and 'monolithic'. The 'simple' package is a bare-bones
> > > implementation (one event class) that is fast and light. The
> 'rich'
> > > package defines an event hierarchy (with AddEvent, RemoveEvent
> etc.)
> > > that tracks all delta data necessary to reconstruct a
> collection's
> > > entire history. In particular, RichCollectionEvent implements
> > > ReplayableEvent (see below). The 'monolithic' event package is
> (like
> > > 'rich') a heavyweight package that implements ReplayableEvent,
> but
> > > has
> > > only one event class (MonolithicCollectionEvent) instead of an
> > > hierarchy. This package is an implementation of the
> > > Heuer/mailing-list
> > > design that we discussed some time ago, and is basically intended
> as
> > > a
> > > dis-proof-of-concept. I will discuss this in a follow-on email.
> > >
> > > Probably the most interesting new feature is the
> "ReplayableEvent"
> > > interface. This interface defines two methods, #replay and #undo
> (may
> > > rename), and is implemented by the 'rich' and 'monolithic'
> package.
> > > An
> > > example of usage is below.
> > >
> > >
> > > #############################
> > >
> > > class MyListener implements CollectionListener
> > > {
> > > CollectionEvent event;
> > >
> > > public void collectionEventOccurred(CollectionEvent event)
> > > {
> > > this.event = event;
> > > }
> > > }
> > >
> > > NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
> > > ArrayList());
> > >
> > > MyListener listener = new MyListener();
> > > nl.addCollectionListener(listener);
> > >
> > > String s = "hello";
> > >
> > > nl.add(s);
> > > assertTrue(nl.size() == 1);
> > >
> > > AddEvent event = (AddEvent) listener.event;
> > > assertTrue(event.getAddedItem() == s);
> > >
> > > // now for the fun part
> > > event.undo(nl); // undoes the add action
> > > assertTrue(nl.size() == 0);
> > >
> > > // replay the action
> > > event.replay(nl);
> > > assertTrue(nl.size() == 1 && nl.contains(s));
> > >
> > > // replay the action on a different target
> > > List list = new ArrayList();
> > >
> > > event.replay(list);
> > > assertTrue(list.equals(nl));
> > >
> > > ############################
> > >
> > > More comments in follow-on email.
> > >
> > > Neil
> > >
> > >
> > >
> > >
> ---------------------------------------------------------------------
> > > To unsubscribe, e-mail:
> commons-dev-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> > >
> >
> >
> >
> ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail:
> commons-dev-help@jakarta.apache.org
> >
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Stephen Colebourne <sc...@btopenworld.com>.
I haven't forgotten this, and will release some code I've been working on
for comparison soon.
Stephen
----- Original Message -----
From: "Neil O'Toole" <ne...@yahoo.com>
To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>;
<ne...@users.sourceforge.net>
Sent: Monday, July 21, 2003 9:01 PM
Subject: Re: [collections][submission] NotifyingCollections


> More updates: the source, jar, and javadoc have all been updated.
>
>  http://nettool.sourceforge.net/nc
>
> Neil
>
>
> --- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> > This is a much updated submission of the event-based notifying
> > decorator mechanism for collections, as discussed on the list last
> > month.
> >
> > The package is too big to be posted to this list. The source,
> > javadoc,
> > and pre-built jar can be downloaded from:
> >
> >  http://nettool.sourceforge.net/nc
> >
> > The javadoc can be viewed online:
> >
> >  http://nettool.sourceforge.net/nc/api
> >
> > The best place to start is the package description for
> > o.a.c.collections.notifying. Either navigate from above, or directly
> > via:
> >
> >
>
http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifyi
ng/package-summary.html#package_description
> >
> >
> > This release provides notifying decorators for Collection, Set,
> > SortedSet, List, Bag and SortedBag. Map and SortedMap implementations
> > are present, but are not completed.
> >
> > NotifyingCollections uses pluggable event factories to generate its
> > events. There are three such "event packages" included: 'simple',
> > 'rich', and 'monolithic'. The 'simple' package is a bare-bones
> > implementation (one event class) that is fast and light. The 'rich'
> > package defines an event hierarchy (with AddEvent, RemoveEvent etc.)
> > that tracks all delta data necessary to reconstruct a collection's
> > entire history. In particular, RichCollectionEvent implements
> > ReplayableEvent (see below). The 'monolithic' event package is (like
> > 'rich') a heavyweight package that implements ReplayableEvent, but
> > has
> > only one event class (MonolithicCollectionEvent) instead of an
> > hierarchy. This package is an implementation of the
> > Heuer/mailing-list
> > design that we discussed some time ago, and is basically intended as
> > a
> > dis-proof-of-concept. I will discuss this in a follow-on email.
> >
> > Probably the most interesting new feature is the "ReplayableEvent"
> > interface. This interface defines two methods, #replay and #undo (may
> > rename), and is implemented by the 'rich' and 'monolithic' package.
> > An
> > example of usage is below.
> >
> >
> > #############################
> >
> > class MyListener implements CollectionListener
> > {
> > CollectionEvent event;
> >
> > public void collectionEventOccurred(CollectionEvent event)
> > {
> > this.event = event;
> > }
> > }
> >
> > NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
> > ArrayList());
> >
> > MyListener listener = new MyListener();
> > nl.addCollectionListener(listener);
> >
> > String s = "hello";
> >
> > nl.add(s);
> > assertTrue(nl.size() == 1);
> >
> > AddEvent event = (AddEvent) listener.event;
> > assertTrue(event.getAddedItem() == s);
> >
> > // now for the fun part
> > event.undo(nl); // undoes the add action
> > assertTrue(nl.size() == 0);
> >
> > // replay the action
> > event.replay(nl);
> > assertTrue(nl.size() == 1 && nl.contains(s));
> >
> > // replay the action on a different target
> > List list = new ArrayList();
> >
> > event.replay(list);
> > assertTrue(list.equals(nl));
> >
> > ############################
> >
> > More comments in follow-on email.
> >
> > Neil
> >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: [collections][submission] NotifyingCollections

Posted by Neil O'Toole <ne...@yahoo.com>.
More updates: the source, jar, and javadoc have all been updated.

 http://nettool.sourceforge.net/nc

Neil


--- Neil O'Toole <ne...@users.sourceforge.net> wrote:
> This is a much updated submission of the event-based notifying
> decorator mechanism for collections, as discussed on the list last
> month.
> 
> The package is too big to be posted to this list. The source,
> javadoc,
> and pre-built jar can be downloaded from:
> 
>  http://nettool.sourceforge.net/nc
>  
> The javadoc can be viewed online:
>  
>  http://nettool.sourceforge.net/nc/api
>  
> The best place to start is the package description for
> o.a.c.collections.notifying. Either navigate from above, or directly
> via:
> 
>
http://nettool.sourceforge.net/nc/api/org/apache/commons/collections/notifying/package-summary.html#package_description
>  
> 
> This release provides notifying decorators for Collection, Set,
> SortedSet, List, Bag and SortedBag. Map and SortedMap implementations
> are present, but are not completed.
> 
> NotifyingCollections uses pluggable event factories to generate its
> events. There are three such "event packages" included: 'simple',
> 'rich', and 'monolithic'. The 'simple' package is a bare-bones
> implementation (one event class) that is fast and light. The 'rich'
> package defines an event hierarchy (with AddEvent, RemoveEvent etc.)
> that tracks all delta data necessary to reconstruct a collection's
> entire history. In particular, RichCollectionEvent implements
> ReplayableEvent (see below). The 'monolithic' event package is (like
> 'rich') a heavyweight package that implements ReplayableEvent, but
> has
> only one event class (MonolithicCollectionEvent) instead of an
> hierarchy. This package is an implementation of the
> Heuer/mailing-list
> design that we discussed some time ago, and is basically intended as
> a
> dis-proof-of-concept. I will discuss this in a follow-on email.
> 
> Probably the most interesting new feature is the "ReplayableEvent"
> interface. This interface defines two methods, #replay and #undo (may
> rename), and is implemented by the 'rich' and 'monolithic' package.
> An
> example of usage is below.
> 
> 
> #############################
> 
> class MyListener implements CollectionListener
> {
> 	CollectionEvent event;
> 
> 	public void collectionEventOccurred(CollectionEvent event)
> 	{
> 		this.event = event;
> 	}
> }
> 
> NotifyingList nl = NotifyingCollectionsUtils.notifyingList(new
> ArrayList());
> 
> MyListener listener = new MyListener();
> nl.addCollectionListener(listener);
> 
> String s = "hello";
> 
> nl.add(s);
> assertTrue(nl.size() == 1);
> 
> AddEvent event = (AddEvent) listener.event;
> assertTrue(event.getAddedItem() == s);
> 
> // now for the fun part
> event.undo(nl); // undoes the add action
> assertTrue(nl.size() == 0);
> 
> // replay the action
> event.replay(nl);
> assertTrue(nl.size() == 1 && nl.contains(s));
> 
> // replay the action on a different target
> List list = new ArrayList();
> 
> event.replay(list);
> assertTrue(list.equals(nl));
> 
> ############################
> 
> More comments in follow-on email.
> 
> Neil
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org