From 8a92b6e5556e3db9f033d7d9c77ddc8310884991 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 28 Aug 2003 18:31:13 +0000 Subject: [PATCH] Add ObservedCollection implementation with tests and event classes git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131118 13f79535-47bb-0310-9956-ffa450edef68 --- .../decorators/ObservedCollection.java | 365 ++++++++++ .../collections/decorators/ObservedList.java | 341 +++++++++ .../collections/decorators/ObservedSet.java | 220 ++++++ .../collections/event/ModificationEvent.java | 154 ++++ .../event/ModificationEventType.java | 183 +++++ .../event/ModificationHandler.java | 470 ++++++++++++ .../event/ModificationListener.java | 77 ++ .../event/ModificationVetoedException.java | 98 +++ .../event/StandardModificationAdaptor.java | 93 +++ .../event/StandardModificationEvent.java | 311 ++++++++ .../event/StandardModificationHandler.java | 379 ++++++++++ .../event/StandardModificationListener.java | 102 +++ .../decorators/ObservedTestHelper.java | 683 ++++++++++++++++++ .../decorators/TestObservedCollection.java | 204 ++++++ .../decorators/TestObservedList.java | 205 ++++++ .../decorators/TestObservedSet.java | 193 +++++ 16 files changed, 4078 insertions(+) create mode 100644 src/java/org/apache/commons/collections/decorators/ObservedCollection.java create mode 100644 src/java/org/apache/commons/collections/decorators/ObservedList.java create mode 100644 src/java/org/apache/commons/collections/decorators/ObservedSet.java create mode 100644 src/java/org/apache/commons/collections/event/ModificationEvent.java create mode 100644 src/java/org/apache/commons/collections/event/ModificationEventType.java create mode 100644 src/java/org/apache/commons/collections/event/ModificationHandler.java create mode 100644 src/java/org/apache/commons/collections/event/ModificationListener.java create mode 100644 src/java/org/apache/commons/collections/event/ModificationVetoedException.java create mode 100644 src/java/org/apache/commons/collections/event/StandardModificationAdaptor.java create mode 100644 src/java/org/apache/commons/collections/event/StandardModificationEvent.java create mode 100644 src/java/org/apache/commons/collections/event/StandardModificationHandler.java create mode 100644 src/java/org/apache/commons/collections/event/StandardModificationListener.java create mode 100644 src/test/org/apache/commons/collections/decorators/ObservedTestHelper.java create mode 100644 src/test/org/apache/commons/collections/decorators/TestObservedCollection.java create mode 100644 src/test/org/apache/commons/collections/decorators/TestObservedList.java create mode 100644 src/test/org/apache/commons/collections/decorators/TestObservedSet.java diff --git a/src/java/org/apache/commons/collections/decorators/ObservedCollection.java b/src/java/org/apache/commons/collections/decorators/ObservedCollection.java new file mode 100644 index 000000000..b774d1b60 --- /dev/null +++ b/src/java/org/apache/commons/collections/decorators/ObservedCollection.java @@ -0,0 +1,365 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/decorators/Attic/ObservedCollection.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.Collection; +import java.util.Iterator; + +import org.apache.commons.collections.event.ModificationHandler; +import org.apache.commons.collections.event.ModificationListener; +import org.apache.commons.collections.event.StandardModificationHandler; +import org.apache.commons.collections.event.StandardModificationListener; + +/** + * ObservedCollection decorates a Collection + * implementation to observe changes in the collection. + *

+ * Each modifying method call made on this Collection is forwarded to a + * {@link ModificationHandler}. + * The handler manages the event, notifying listeners and optionally vetoing changes. + * The default handler is {@link StandardModificationHandler}. + * See this class for details of configuration available. + *

+ * For convenience, add, remove and get listener methods are made available on + * this class. They accept a generic listener type, whereas handlers generally + * require a specific type. Thus a ClassCastException may be thrown from these + * methods. They may also throw UnsupportedOperationException if the handler + * uses a technique other than listeners to communicate events. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ObservedCollection extends AbstractCollectionDecorator { + + /** The handler to delegate event handling to */ + protected final ModificationHandler handler; + + // Factories + //----------------------------------------------------------------------- + /** + * Factory method to create an observable collection. + *

+ * A {@link StandardModificationHandler} will be created. + * This can be accessed by {@link #getHandler()} to add listeners. + * + * @param coll the collection to decorate, must not be null + * @return the observed collection + * @throws IllegalArgumentException if the collection is null + */ + public static ObservedCollection decorate(final Collection coll) { + return new ObservedCollection(coll, null); + } + + /** + * Factory method to create an observable collection and register one + * listener to receive all events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param coll the collection to decorate, must not be null + * @param listener collection listener, must not be null + * @return the observed collection + * @throws IllegalArgumentException if the collection or listener is null + */ + public static ObservedCollection decorate( + final Collection coll, + final StandardModificationListener listener) { + + return decorate(coll, listener, -1, -1); + } + + /** + * Factory method to create an observable collection and register one + * listener to receive all post events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param coll the collection to decorate, must not be null + * @param listener collection listener, must not be null + * @return the observed collection + * @throws IllegalArgumentException if the collection or listener is null + */ + public static ObservedCollection decoratePostEventsOnly( + final Collection coll, + final StandardModificationListener listener) { + + return decorate(coll, listener, 0, -1); + } + + /** + * Factory method to create an observable collection and + * register one listener using event masks. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * The masks are defined in + * {@link org.apache.commons.collections.event.ModificationEventType ModificationEventType}. + * + * @param coll the collection to decorate, must not be null + * @param listener collection listener, must not be null + * @param preEventMask mask for pre events (0 for none, -1 for all) + * @param postEventMask mask for post events (0 for none, -1 for all) + * @return the observed collection + * @throws IllegalArgumentException if the collection or listener is null + */ + public static ObservedCollection decorate( + final Collection coll, + final StandardModificationListener listener, + final int preEventMask, + final int postEventMask) { + + if (coll == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedCollection oc = new ObservedCollection(coll, handler); + handler.addModificationListener(listener, preEventMask, postEventMask); + return oc; + } + + /** + * Factory method to create an observable collection using a + * specific handler. + *

+ * The handler may be configured independently with listeners or other + * event recognition. + * + * @param coll the collection to decorate, must not be null + * @param handler observed handler, must not be null + * @return the observed collection + * @throws IllegalArgumentException if the collection or handler is null + */ + public static ObservedCollection decorate( + final Collection coll, + final ModificationHandler handler) { + + if (coll == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + if (handler == null) { + throw new IllegalArgumentException("Handler must not be null"); + } + return new ObservedCollection(coll, handler); + } + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies) and takes a handler. + *

+ * If a null handler is specified, an + * ObservedHandler is created. + * + * @param coll the collection to decorate, must not be null + * @param handler the observing handler, may be null + * @throws IllegalArgumentException if the collection is null + */ + protected ObservedCollection( + final Collection coll, + final ModificationHandler handler) { + super(coll); + this.handler = (handler == null ? new StandardModificationHandler() : handler); + this.handler.init(this); + } + + // Handler access + //----------------------------------------------------------------------- + /** + * Gets the handler that is observing this collection. + * + * @return the observing handler, never null + */ + public ModificationHandler getHandler() { + return handler; + } + + // Listener convenience methods + //---------------------------------------------------------------------- + /** + * Gets an array of all the listeners active in the handler. + * This method simply delegates to the handler. + * + * @return the listeners + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public ModificationListener[] getModificationListeners() { + return getHandler().getModificationListeners(); + } + + /** + * Adds a listener to the list held in the handler. + * This method simply delegates to the handler. + *

+ * No error occurs if the listener is null. + * + * @param listener the listener to add, may be null (ignored) + * @throws ClassCastException if the listener is not of the correct type + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public void addModificationListener(ModificationListener listener) { + getHandler().addModificationListener(listener); + } + + /** + * Removes a listener to the list held in the handler. + * This method simply delegates to the handler. + *

+ * No error occurs if the listener is not in the list or the type + * of the listener is incorrect. + *

+ * This implementation throws UnsupportedOperationException. + * + * @param listener the listener to remove, may be null (ignored) + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public void removeModificationListener(ModificationListener listener) { + getHandler().removeModificationListener(listener); + } + + // Collection + //----------------------------------------------------------------------- + public boolean add(Object object) { + boolean result = false; + if (handler.preAdd(object)) { + result = collection.add(object); + handler.postAdd(object, result); + } + return result; + } + + public boolean addAll(Collection coll) { + boolean result = false; + if (handler.preAddAll(coll)) { + result = collection.addAll(coll); + handler.postAddAll(coll, result); + } + return result; + } + + public void clear() { + if (handler.preClear()) { + collection.clear(); + handler.postClear(); + } + } + + public Iterator iterator() { + return new ObservedIterator(collection.iterator()); + } + + public boolean remove(Object object) { + boolean result = false; + if (handler.preRemove(object)) { + result = collection.remove(object); + handler.postRemove(object, result); + } + return result; + } + + public boolean removeAll(Collection coll) { + boolean result = false; + if (handler.preRemoveAll(coll)) { + result = collection.removeAll(coll); + handler.postRemoveAll(coll, result); + } + return result; + } + + public boolean retainAll(Collection coll) { + boolean result = false; + if (handler.preRetainAll(coll)) { + result = collection.retainAll(coll); + handler.postRetainAll(coll, result); + } + return result; + } + + // Iterator + //----------------------------------------------------------------------- + /** + * Inner class Iterator for the ObservedCollection. + */ + protected class ObservedIterator extends AbstractIteratorDecorator { + + protected Object last; + + protected ObservedIterator(Iterator iterator) { + super(iterator); + } + + public Object next() { + last = super.next(); + return last; + } + + public void remove() { + if (handler.preRemove(last)) { + iterator.remove(); + handler.postRemove(last, true); + } + } + } + +} diff --git a/src/java/org/apache/commons/collections/decorators/ObservedList.java b/src/java/org/apache/commons/collections/decorators/ObservedList.java new file mode 100644 index 000000000..bd3a6acb4 --- /dev/null +++ b/src/java/org/apache/commons/collections/decorators/ObservedList.java @@ -0,0 +1,341 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/decorators/Attic/ObservedList.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.Collection; +import java.util.List; +import java.util.ListIterator; + +import org.apache.commons.collections.event.ModificationHandler; +import org.apache.commons.collections.event.StandardModificationHandler; +import org.apache.commons.collections.event.StandardModificationListener; + +/** + * ObservedList decorates a List + * implementation to observe changes. + *

+ * Each modifying method call made on this List is forwarded to a + * {@link ModificationHandler}. + * The handler manages the event, notifying listeners and optionally vetoing changes. + * The default handler is {@link StandardModificationHandler}. + * See this class for details of configuration available. + *

+ * For convenience, add, remove and get listener methods are made available on + * this class. They accept a generic listener type, whereas handlers generally + * require a specific type. Thus a ClassCastException may be thrown from these + * methods. They may also throw UnsupportedOperationException if the handler + * uses a technique other than listeners to communicate events. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ObservedList extends ObservedCollection implements List { + + // Factories + //----------------------------------------------------------------------- + /** + * Factory method to create an observable list. + *

+ * A {@link StandardModificationHandler} will be created. + * This can be accessed by {@link #getHandler()} to add listeners. + * + * @param list the list to decorate, must not be null + * @return the observed List + * @throws IllegalArgumentException if the list is null + */ + public static ObservedList decorate(final List list) { + return new ObservedList(list, null); + } + + /** + * Factory method to create an observable list and register one + * listener to receive all events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param list the list to decorate, must not be null + * @param listener the listener, must not be null + * @return the observed list + * @throws IllegalArgumentException if the list or listener is null + */ + public static ObservedList decorate( + final List list, + final StandardModificationListener listener) { + + return decorate(list, listener, -1, -1); + } + + /** + * Factory method to create an observable list and register one + * listener to receive all post events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param list the list to decorate, must not be null + * @param listener the listener, must not be null + * @return the observed list + * @throws IllegalArgumentException if the list or listener is null + */ + public static ObservedList decoratePostEventsOnly( + final List list, + final StandardModificationListener listener) { + + return decorate(list, listener, 0, -1); + } + + /** + * Factory method to create an observable list and + * register one listener using event masks. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * The masks are defined in + * {@link org.apache.commons.collections.event.ModificationEventType ModificationEventType}. + * + * @param list the list to decorate, must not be null + * @param listener the listener, must not be null + * @param preEventMask mask for pre events (0 for none, -1 for all) + * @param postEventMask mask for post events (0 for none, -1 for all) + * @return the observed list + * @throws IllegalArgumentException if the list or listener is null + */ + public static ObservedList decorate( + final List list, + final StandardModificationListener listener, + final int preEventMask, + final int postEventMask) { + + if (list == null) { + throw new IllegalArgumentException("List must not be null"); + } + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedList oc = new ObservedList(list, handler); + handler.addModificationListener(listener, preEventMask, postEventMask); + return oc; + } + + /** + * Factory method to create an observable list using a + * specific handler. + *

+ * The handler may be configured independently with listeners or other + * event recognition. + * + * @param list the list to decorate, must not be null + * @param handler observed handler, must not be null + * @return the observed list + * @throws IllegalArgumentException if the list or handler is null + */ + public static ObservedList decorate( + final List list, + final ModificationHandler handler) { + + if (list == null) { + throw new IllegalArgumentException("List must not be null"); + } + if (handler == null) { + throw new IllegalArgumentException("Handler must not be null"); + } + return new ObservedList(list, handler); + } + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies) and takes a handler. + *

+ * If a null handler is specified, an + * ObservedHandler is created. + * + * @param list the list to decorate, must not be null + * @param handler the observing handler, may be null + * @throws IllegalArgumentException if the list is null + */ + protected ObservedList( + final List list, + final ModificationHandler handler) { + super(list, handler); + } + + /** + * Typecast the collection to a List. + * + * @return the wrapped collection as a List + */ + private List getList() { + return (List) getCollection(); + } + + // List API + //----------------------------------------------------------------------- + public Object get(int index) { + return getList().get(index); + } + + public int indexOf(Object object) { + return getList().indexOf(object); + } + + public int lastIndexOf(Object object) { + return getList().lastIndexOf(object); + } + + //----------------------------------------------------------------------- + public void add(int index, Object object) { + if (handler.preAdd(index, object)) { + getList().add(index, object); + handler.postAdd(index, object); + } + } + + public boolean addAll(int index, Collection coll) { + boolean result = false; + if (handler.preAddAll(index, coll)) { + result = getList().addAll(index, coll); + handler.postAddAll(index, coll, result); + } + return result; + } + + public Object remove(int index) { + Object result = null; + if (handler.preRemove(index)) { + result = getList().remove(index); + handler.postRemove(index, result); + } + return result; + } + + public Object set(int index, Object object) { + Object result = null; + if (handler.preSet(index, object)) { + result = getList().set(index, object); + handler.postSet(index, object, result); + } + return result; + } + + public ListIterator listIterator() { + return new ObservedListIterator(getList().listIterator()); + } + + public ListIterator listIterator(int index) { + return new ObservedListIterator(getList().listIterator(index)); + } + + public List subList(int fromIndex, int toIndex) { + // TODO: This list needs to be a special impl, as the index is offset + throw new UnsupportedOperationException(); + } + + // ListIterator + //----------------------------------------------------------------------- + /** + * Inner class ListIterator for the ObservedList. + */ + protected class ObservedListIterator extends AbstractListIteratorDecorator { + + protected Object last; + + protected ObservedListIterator(ListIterator iterator) { + super(iterator); + } + + public Object next() { + last = super.next(); + return last; + } + + public Object previous() { + last = iterator.previous(); + return last; + } + + public void remove() { + int index = iterator.previousIndex(); + if (handler.preRemove(index)) { + iterator.remove(); + handler.postRemove(index, last); + } + } + + public void add(Object object) { + int index = iterator.nextIndex(); + if (handler.preAdd(index, object)) { + iterator.add(object); + handler.postAdd(index, object); + } + } + + public void set(Object object) { + int index = iterator.previousIndex(); + if (handler.preSet(index, object)) { + iterator.set(object); + handler.postSet(index, object, last); + } + } + } + +} diff --git a/src/java/org/apache/commons/collections/decorators/ObservedSet.java b/src/java/org/apache/commons/collections/decorators/ObservedSet.java new file mode 100644 index 000000000..cdb250ff5 --- /dev/null +++ b/src/java/org/apache/commons/collections/decorators/ObservedSet.java @@ -0,0 +1,220 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/decorators/Attic/ObservedSet.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.Set; + +import org.apache.commons.collections.event.ModificationHandler; +import org.apache.commons.collections.event.StandardModificationHandler; +import org.apache.commons.collections.event.StandardModificationListener; + +/** + * ObservedSet decorates a Set + * implementation to observe changes. + *

+ * Each modifying method call made on this Set is forwarded to a + * {@link ModificationHandler}. + * The handler manages the event, notifying listeners and optionally vetoing changes. + * The default handler is {@link StandardModificationHandler}. + * See this class for details of configuration available. + *

+ * For convenience, add, remove and get listener methods are made available on + * this class. They accept a generic listener type, whereas handlers generally + * require a specific type. Thus a ClassCastException may be thrown from these + * methods. They may also throw UnsupportedOperationException if the handler + * uses a technique other than listeners to communicate events. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ObservedSet extends ObservedCollection implements Set { + + // Factories + //----------------------------------------------------------------------- + /** + * Factory method to create an observable set. + *

+ * A {@link StandardModificationHandler} will be created. + * This can be accessed by {@link #getHandler()} to add listeners. + * + * @param set the set to decorate, must not be null + * @return the observed Set + * @throws IllegalArgumentException if the collection is null + */ + public static ObservedSet decorate(final Set set) { + return new ObservedSet(set, null); + } + + /** + * Factory method to create an observable set and register one + * listener to receive all events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param set the set to decorate, must not be null + * @param listener the listener, must not be null + * @return the observed set + * @throws IllegalArgumentException if the set or listener is null + */ + public static ObservedSet decorate( + final Set set, + final StandardModificationListener listener) { + + return decorate(set, listener, -1, -1); + } + + /** + * Factory method to create an observable set and register one + * listener to receive all post events. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * + * @param set the set to decorate, must not be null + * @param listener the listener, must not be null + * @return the observed set + * @throws IllegalArgumentException if the set or listener is null + */ + public static ObservedSet decoratePostEventsOnly( + final Set set, + final StandardModificationListener listener) { + + return decorate(set, listener, 0, -1); + } + + /** + * Factory method to create an observable set and + * register one listener using event masks. + *

+ * A {@link StandardModificationHandler} will be created. + * The listener will be added to the handler. + * The masks are defined in + * {@link org.apache.commons.collections.event.ModificationEventType ModificationEventType}. + * + * @param set the set to decorate, must not be null + * @param listener the listener, must not be null + * @param preEventMask mask for pre events (0 for none, -1 for all) + * @param postEventMask mask for post events (0 for none, -1 for all) + * @return the observed set + * @throws IllegalArgumentException if the set or listener is null + */ + public static ObservedSet decorate( + final Set set, + final StandardModificationListener listener, + final int preEventMask, + final int postEventMask) { + + if (set == null) { + throw new IllegalArgumentException("Set must not be null"); + } + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedSet oc = new ObservedSet(set, handler); + handler.addModificationListener(listener, preEventMask, postEventMask); + return oc; + } + + /** + * Factory method to create an observable set using a + * specific handler. + *

+ * The handler may be configured independently with listeners or other + * event recognition. + * + * @param set the set to decorate, must not be null + * @param handler observed handler, must not be null + * @return the observed set + * @throws IllegalArgumentException if the set or handler is null + */ + public static ObservedSet decorate( + final Set set, + final ModificationHandler handler) { + + if (set == null) { + throw new IllegalArgumentException("Set must not be null"); + } + if (handler == null) { + throw new IllegalArgumentException("Handler must not be null"); + } + return new ObservedSet(set, handler); + } + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructor that wraps (not copies) and takes a handler. + *

+ * If a null handler is specified, an + * ObservedHandler is created. + * + * @param set the set to decorate, must not be null + * @param handler the observing handler, may be null + * @throws IllegalArgumentException if the collection is null + */ + protected ObservedSet( + final Set set, + final ModificationHandler handler) { + super(set, handler); + } + +} diff --git a/src/java/org/apache/commons/collections/event/ModificationEvent.java b/src/java/org/apache/commons/collections/event/ModificationEvent.java new file mode 100644 index 000000000..50f6d83c5 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/ModificationEvent.java @@ -0,0 +1,154 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/ModificationEvent.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +import java.util.Collection; +import java.util.EventObject; + +/** + * Base event class extended by each class that encapsulates event information. + *

+ * This class can be used as is, but generally it is subclassed. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ModificationEvent extends EventObject { + + /** The source collection */ + protected final Collection collection; + /** The handler */ + protected final ModificationHandler handler; + /** The event code */ + protected final int type; + + // Constructor + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param collection the event source + * @param handler the handler + * @param type the event type + */ + public ModificationEvent( + final Collection collection, + final ModificationHandler handler, + final int type) { + + super(collection); + this.collection = collection; + this.handler = handler; + this.type = type; + } + + // Basic info + //----------------------------------------------------------------------- + /** + * Gets the collection the event is reporting on. + *

+ * This method returns the ObservedCollection instance. + * If this collection is wrapped, by a synchronized wrapper for example, + * changing this collection will bypass the wrapper. For the synchronized + * example, this will be OK so long as the event is processed in the same + * thread and program stack as the modification was made in. + * + * @return the collection + */ + public Collection getSourceCollection() { + return collection; + } + + /** + * Gets the handler of the events. + * + * @return the handler + */ + public ModificationHandler getHandler() { + return handler; + } + + /** + * Gets the event type constant. + *

+ * This is one of the method constants from {@link ModificationEventType}. + * + * @return the method event type constant + */ + public int getType() { + return type; + } + + // toString + //----------------------------------------------------------------------- + /** + * Gets a debugging string version of the event. + * + * @return a debugging string + */ + public String toString() { + StringBuffer buf = new StringBuffer(64); + buf.append("ObservedEvent[type="); + buf.append(ModificationEventType.toString(type)); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/src/java/org/apache/commons/collections/event/ModificationEventType.java b/src/java/org/apache/commons/collections/event/ModificationEventType.java new file mode 100644 index 000000000..72f87fa7b --- /dev/null +++ b/src/java/org/apache/commons/collections/event/ModificationEventType.java @@ -0,0 +1,183 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/ModificationEventType.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +/** + * Defines event constants for event handling and matching. + *

+ * The constants in this class are of two types: + *

    + *
  1. Methods - the base definitions (unique bits) + *
  2. Groups - combination definitions (method bits combined) + *
+ *

+ * Only a method constant may be compared using == to an event type. + * This can include use in a switch statement + *

+ * Any constant may be used for filtering. + * They may combined using the bitwise OR, |. + * They may negated using the bitwise NOT, ~. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ModificationEventType { + + /** The method add(Object) */ + public static final int ADD = 0x00000001; + /** The method add(int,Object) */ + public static final int ADD_INDEXED = 0x00000002; + /** The method addAll(Collection) */ + public static final int ADD_ALL = 0x00000004; + /** The method addAll(int,Collection) */ + public static final int ADD_ALL_INDEXED=0x00000008; + /** The method remove(Object) */ + public static final int REMOVE = 0x00000010; + /** The method remove(int) */ + public static final int REMOVE_INDEXED =0x00000020; + /** The method removeAll(Collection) */ + public static final int REMOVE_ALL = 0x00000040; + /** The method retainAll(Collection) */ + public static final int RETAIN_ALL = 0x00000080; + /** The method clear() */ + public static final int CLEAR = 0x00000100; + /** The method set(int,Object) */ + public static final int SET_INDEXED = 0x00000200; + + /** All add methods */ + public static final int GROUP_ADD = ADD | ADD_INDEXED | ADD_ALL | ADD_ALL_INDEXED; + /** All methods that change without structure modification */ + public static final int GROUP_CHANGE = SET_INDEXED; + /** All remove methods */ + public static final int GROUP_REMOVE = REMOVE | REMOVE_INDEXED | REMOVE_ALL; + /** All retain methods */ + public static final int GROUP_RETAIN = RETAIN_ALL; + /** All clear methods */ + public static final int GROUP_CLEAR = CLEAR; + /** All reducing methods (remove, retain and clear) */ + public static final int GROUP_REDUCE = GROUP_REMOVE | GROUP_CLEAR | GROUP_RETAIN; + + /** All indexed methods */ + public static final int GROUP_INDEXED = ADD_INDEXED | ADD_ALL_INDEXED | REMOVE_INDEXED | SET_INDEXED; + /** All non indexed methods */ + public static final int GROUP_NON_INDEXED = ADD | ADD_ALL | REMOVE | REMOVE_ALL | RETAIN_ALL | CLEAR; + /** All bulk methods (xxxAll and clear) */ + public static final int GROUP_BULK = ADD_ALL | ADD_ALL_INDEXED | REMOVE_ALL | RETAIN_ALL | CLEAR; + /** All non bulk methods */ + public static final int GROUP_NON_BULK = ADD | ADD_INDEXED | REMOVE | REMOVE_INDEXED | SET_INDEXED; + /** All methods that modify the structure */ + public static final int GROUP_STRUCTURE_MODIFIED = + ADD | ADD_INDEXED | ADD_ALL | ADD_ALL_INDEXED | REMOVE | REMOVE_INDEXED | REMOVE_ALL | RETAIN_ALL | CLEAR; + /** All non structure modifying methods */ + public static final int GROUP_NON_STRUCTURE_MODIFIED = SET_INDEXED; + + /** All methods sent by a Collection */ + public static final int GROUP_FROM_COLLECTION = ADD | ADD_ALL | REMOVE | REMOVE_ALL | RETAIN_ALL | CLEAR; + /** All methods sent by a Set */ + public static final int GROUP_FROM_SET = GROUP_FROM_COLLECTION; + /** All methods sent by a List */ + public static final int GROUP_FROM_LIST = GROUP_FROM_COLLECTION | ADD_INDEXED | ADD_ALL_INDEXED | REMOVE_INDEXED | SET_INDEXED; + + /** No methods */ + public static final int GROUP_NONE = 0x00000000; + /** All methods */ + public static final int GROUP_ALL = 0xFFFFFFFF; + + /** + * Constructor. + */ + protected ModificationEventType() { + super(); + } + + /** + * Gets a string version of a method event type. + * + * @param methodType the method event type constant + * @return a string description + */ + public static String toString(final int methodType) { + switch (methodType) { + case ADD: + return "Add"; + case ADD_INDEXED: + return "AddIndexed"; + case ADD_ALL: + return "AddAll"; + case ADD_ALL_INDEXED: + return "AddAllIndexed"; + case REMOVE: + return "Remove"; + case REMOVE_INDEXED: + return "RemoveIndexed"; + case REMOVE_ALL: + return "RemoveAll"; + case RETAIN_ALL: + return "RetainAll"; + case CLEAR: + return "Clear"; + case SET_INDEXED: + return "SetIndexed"; + default: + return "Unknown"; + } + } + +} diff --git a/src/java/org/apache/commons/collections/event/ModificationHandler.java b/src/java/org/apache/commons/collections/event/ModificationHandler.java new file mode 100644 index 000000000..49fd1a4e2 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/ModificationHandler.java @@ -0,0 +1,470 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/ModificationHandler.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +import java.util.Collection; + +import org.apache.commons.collections.decorators.ObservedCollection; + +/** + * Abstract base implementation of a handler for collection modification. + *

+ * All data storage and event sending is performed by a subclass. + * This class provides a default implementation for the event handling methods + * that forwards to single points. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public abstract class ModificationHandler { + + /** The collection being observed */ + private ObservedCollection collection = null; + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructor. + */ + protected ModificationHandler() { + super(); + } + + /** + * Initialize the handler. + *

+ * The handler cannot be used until this method is called. + * However, the handler's setup methods can be called. + * All other methods will throw NullPointerException until then. + * + * @param coll the observed collection, must not be null + * @throws IllegalArgumentException if the collection is null + * @throws IllegalStateException if init has already been called + */ + public void init(final ObservedCollection coll) { + if (coll == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + if (this.collection != null) { + throw new IllegalArgumentException("init() has already been called"); + } + this.collection = coll; + } + + // Collection access + //----------------------------------------------------------------------- + /** + * Gets the observed collection. + * + * @return the observed collection + */ + public Collection getCollection() { + return collection; + } + + // Listeners + //---------------------------------------------------------------------- + /** + * Gets an array of all the listeners active in the handler. + *

+ * This implementation throws UnsupportedOperationException. + * + * @return the listeners + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public ModificationListener[] getModificationListeners() { + throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName()); + } + + /** + * Adds a listener to the list held in the handler. + *

+ * No error occurs if the listener is null. + *

+ * This implementation throws UnsupportedOperationException. + * + * @param listener the listener to add, may be null (ignored) + * @throws ClassCastException if the listener is not of the correct type + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public void addModificationListener(ModificationListener listener) { + throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName()); + } + + /** + * Removes a listener to the list held in the handler. + *

+ * No error occurs if the listener is not in the list or the type + * of the listener is incorrect. + *

+ * This implementation throws UnsupportedOperationException. + * + * @param listener the listener to remove, may be null (ignored) + * @throws UnsupportedOperationException if the handler does not support listeners + */ + public void removeModificationListener(ModificationListener listener) { + throw new UnsupportedOperationException("Listeners not supported by " + getClass().getName()); + } + + // Event sending + //----------------------------------------------------------------------- + /** + * Handles the pre event. + * + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + */ + protected abstract boolean preEvent(int type, int index, Object object, int repeat); + + /** + * Handles the post event. + * + * @param success true if the method succeeded in changing the collection + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + */ + protected abstract void postEvent(boolean success, int type, int index, Object object, int repeat); + + /** + * Handles the post event. + * + * @param success true if the method succeeded in changing the collection + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + * @param result the result of the method + */ + protected abstract void postEvent(boolean success, int type, int index, Object object, int repeat, Object result); + + // Event handling + //----------------------------------------------------------------------- + /** + * Store data and send event before add(obj) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param object the object being added + * @return true + */ + public boolean preAdd(Object object) { + return preEvent(ModificationEventType.ADD, -1, object, 1); + } + + /** + * Send an event after add(obj) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param object the object being added + * @param result the result from the add method + */ + public void postAdd(Object object, boolean result) { + postEvent(result, ModificationEventType.ADD, -1, object, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before add(int,obj) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param index the index to add at + * @param object the object being added + * @return true + */ + public boolean preAdd(int index, Object object) { + return preEvent(ModificationEventType.ADD_INDEXED, index, object, 1); + } + + /** + * Send an event after add(int,obj) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int, Object)}. + * + * @param index the index to add at + * @param object the object being added + */ + public void postAdd(int index, Object object) { + postEvent(true, ModificationEventType.ADD_INDEXED, index, object, 1, null); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before addAll(coll) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param coll the collection being added + * @return true + */ + public boolean preAddAll(Collection coll) { + return preEvent(ModificationEventType.ADD_ALL, -1, coll, 1); + } + + /** + * Send an event after addAll(coll) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param coll the collection being added + * @param result the result from the addAll method + */ + public void postAddAll(Collection coll, boolean result) { + postEvent(result, ModificationEventType.ADD_ALL, -1, coll, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before addAll(int,coll) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param index the index to addAll at + * @param coll the collection being added + * @return true + */ + public boolean preAddAll(int index, Collection coll) { + return preEvent(ModificationEventType.ADD_ALL_INDEXED, index, coll, 1); + } + + /** + * Send an event after addAll(int,coll) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param index the index to addAll at + * @param coll the collection being added + * @param result the result from the addAll method + */ + public void postAddAll(int index, Collection coll, boolean result) { + postEvent(result, ModificationEventType.ADD_ALL_INDEXED, index, coll, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before clear() is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @return true + */ + public boolean preClear() { + return preEvent(ModificationEventType.CLEAR, -1, null, 1); + } + + /** + * Send an event after clear() is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + */ + public void postClear() { + // assumes a modification occurred + postEvent(true, ModificationEventType.CLEAR, -1, null, 1, null); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before remove(obj) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param object the object being removed + * @return true + */ + public boolean preRemove(Object object) { + return preEvent(ModificationEventType.REMOVE, -1, object, 1); + } + + /** + * Send an event after remove(obj) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param object the object being removed + * @param result the result from the remove method + */ + public void postRemove(Object object, boolean result) { + postEvent(result, ModificationEventType.REMOVE, -1, object, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before remove(int) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param index the index to remove at + * @return true + */ + public boolean preRemove(int index) { + return preEvent(ModificationEventType.REMOVE_INDEXED, index, null, 1); + } + + /** + * Send an event after remove(int) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int, Object)}. + * + * @param index the index to remove at + * @param result the result from the remove method + */ + public void postRemove(int index, Object result) { + postEvent(true, ModificationEventType.REMOVE_INDEXED, index, null, 1, result); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before removeAll(coll) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param coll the collection being removed + * @return true + */ + public boolean preRemoveAll(Collection coll) { + return preEvent(ModificationEventType.REMOVE_ALL, -1, coll, 1); + } + + /** + * Send an event after removeAll(coll) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param coll the collection being removed + * @param result the result from the removeAll method + */ + public void postRemoveAll(Collection coll, boolean result) { + postEvent(result, ModificationEventType.REMOVE_ALL, -1, coll, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before retainAll(coll) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param coll the collection being retained + * @return true + */ + public boolean preRetainAll(Collection coll) { + return preEvent(ModificationEventType.RETAIN_ALL, -1, coll, 1); + } + + /** + * Send an event after retainAll(coll) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int)}. + * + * @param coll the collection being retained + * @param result the result from the retainAll method + */ + public void postRetainAll(Collection coll, boolean result) { + postEvent(result, ModificationEventType.RETAIN_ALL, -1, coll, 1); + } + + //----------------------------------------------------------------------- + /** + * Store data and send event before set(int,obj) is called. + *

+ * This implementation forwards to {@link #preEvent(int, int, Object, int)}. + * + * @param index the index to add at + * @param object the object being added + * @return true + */ + public boolean preSet(int index, Object object) { + return preEvent(ModificationEventType.SET_INDEXED, index, object, 1); + } + + /** + * Send an event after set(int,obj) is called. + *

+ * This implementation forwards to {@link #postEvent(boolean, int, int, Object, int, Object)}. + * + * @param index the index to add at + * @param object the object being added + * @param result the result from the set method + */ + public void postSet(int index, Object object, Object result) { + postEvent(true, ModificationEventType.SET_INDEXED, index, object, 1, result); + } + + // toString + //----------------------------------------------------------------------- + /** + * Gets a debugging string version of this object. + * + * @return a debugging string + */ + public String toString() { + String name = getClass().getName(); + int pos = name.lastIndexOf('.'); + if (pos != -1) { + name = name.substring(pos + 1); + } + return name + '[' + (collection == null ? "" : "initialised") + ']'; + } + +} diff --git a/src/java/org/apache/commons/collections/event/ModificationListener.java b/src/java/org/apache/commons/collections/event/ModificationListener.java new file mode 100644 index 000000000..3f81dcf28 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/ModificationListener.java @@ -0,0 +1,77 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/ModificationListener.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +import java.util.EventListener; + +/** + * An empty listener designed to be subclassed. + *

+ * This interface exists to mark independent subclasses as fulfilling the + * role of an event listener for collection modification events. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public interface ModificationListener extends EventListener { + + // no methods - subinterfaces define them + +} diff --git a/src/java/org/apache/commons/collections/event/ModificationVetoedException.java b/src/java/org/apache/commons/collections/event/ModificationVetoedException.java new file mode 100644 index 000000000..5f6d94540 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/ModificationVetoedException.java @@ -0,0 +1,98 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/ModificationVetoedException.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +/** + * Exception thrown when a modifcation to a collection is vetoed. + * It extends IllegalArgumentException for compatability with the collections API. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ModificationVetoedException extends IllegalArgumentException { + + /** The source event */ + protected final ModificationEvent event; + + // Constructor + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param message the text message, may be null + * @param event the observed event, should not be null + */ + public ModificationVetoedException(final String message, final ModificationEvent event) { + super((message == null ? "Modification vetoed" : message)); + this.event = event; + } + + // Event access + //----------------------------------------------------------------------- + /** + * Gets the event that caused the veto. + * + * @return the event + */ + public ModificationEvent getEvent() { + return event; + } + +} diff --git a/src/java/org/apache/commons/collections/event/StandardModificationAdaptor.java b/src/java/org/apache/commons/collections/event/StandardModificationAdaptor.java new file mode 100644 index 000000000..3607ea24b --- /dev/null +++ b/src/java/org/apache/commons/collections/event/StandardModificationAdaptor.java @@ -0,0 +1,93 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/StandardModificationAdaptor.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +/** + * An adaptor for StandardModificationListener that provides no-op + * implementations of both methods. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class StandardModificationAdaptor implements StandardModificationListener { + + /** + * A collection modification is occurring and may be vetoed. + *

+ * This implementation does nothing. + * + * @param event the event detail + * @throws ModicationVetoedException to veto + */ + public void modificationOccurring(StandardModificationEvent event) { + // do nothing + } + + /** + * A collection modification occurred. + *

+ * This implementation does nothing. + * + * @param event the event detail + */ + public void modificationOccurred(StandardModificationEvent event) { + // do nothing + } +} diff --git a/src/java/org/apache/commons/collections/event/StandardModificationEvent.java b/src/java/org/apache/commons/collections/event/StandardModificationEvent.java new file mode 100644 index 000000000..8d5d76f1d --- /dev/null +++ b/src/java/org/apache/commons/collections/event/StandardModificationEvent.java @@ -0,0 +1,311 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/StandardModificationEvent.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.collections.Bag; + +/** + * Event class that encapsulates all the event information for a + * standard collection event. + *

+ * The information stored in this event is all that is available as + * parameters or return values. + * In addition, the size method is used on the collection. + * All objects used are the real objects from the method calls, not clones. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class StandardModificationEvent extends ModificationEvent { + + /** The size before the event */ + protected final int preSize; + /** The size after the event */ + protected final int postSize; + /** The index of the change */ + protected final int index; + /** The object of the change */ + protected final Object object; + /** The number of changes */ + protected final int repeat; + /** The result of the method call */ + protected final Object result; + + // Constructor + //----------------------------------------------------------------------- + /** + * Constructor. + * + * @param collection the event source + * @param handler the handler + * @param type the event type + * @param preSize the size before the change + * @param index the index that changed + * @param object the value that changed + * @param repeat the number of repeats + * @param result the method result + */ + public StandardModificationEvent( + final Collection collection, + final ModificationHandler handler, + final int type, + final int preSize, + final int index, + final Object object, + final int repeat, + final Object result) { + + super(collection, handler, type); + this.preSize = preSize; + this.postSize = collection.size(); + this.index = index; + this.object = object; + this.repeat = repeat; + this.result = result; + } + + // Change info + //----------------------------------------------------------------------- + /** + * Gets the index of the change. + *

+ * This is -1 when not applicable. Typically only used + * for {@link java.util.List} events. + * + * @return the change index + */ + public int getChangeIndex() { + return index; + } + + /** + * Gets the object that was added/removed/set. + *

+ * This is null when not applicable, such as for clear(). + * + * @return the changing object + */ + public Object getChangeObject() { + return object; + } + + /** + * Gets the collection of changed objects. + *

+ * For clear, it is an empty list. + * For bulk operations, it is the collection. + * For non-bulk operations, it is a size one list. + * + * @return the changing collection, never null + */ + public Collection getChangeCollection() { + if (object == null) { + return Collections.EMPTY_LIST; + } else if (isType(ModificationEventType.GROUP_BULK)) { + if (object instanceof Collection) { + return (Collection) object; + } else { + throw new IllegalStateException( + "Bulk operations must involve a Collection, but was " + object.getClass().getName()); + } + } else { + return Collections.singletonList(object); + } + } + + /** + * Gets the number of times the object was added/removed. + *

+ * This is normally 1, but will be used for + * {@link org.apache.commons.collections.Bag Bag} events. + * + * @return the repeat + */ + public int getChangeRepeat() { + return repeat; + } + + /** + * Gets the result of the method call. + *

+ * For set(int) and remove(int) this will be the previous value + * being replaced. + *

+ * If there is no result yet, null will be returned. + * If the result was a boolean, a Boolean is returned. + * If the result was void, null will be returned. + * + * @return the repeat + */ + public Object getResult() { + return result; + } + + // Size info + //----------------------------------------------------------------------- + /** + * Gets the size before the change. + * + * @return the size before the change + */ + public int getPreSize() { + return preSize; + } + + /** + * Gets the size after the change. + *

+ * This method will return the same as getPreSzie if + * called when handling a pre event. + * + * @return the size before the change + */ + public int getPostSize() { + return postSize; + } + + /** + * Gets the size change, negative for remove/clear. + *

+ * This method will return zero if called when handling a pre event. + * + * @return the size before the change + */ + public int getSizeChange() { + return postSize - preSize; + } + + /** + * Returns true if the size of the collection changed. + *

+ * This method will return false if called when handling a pre event. + * + * @return true is the size changed + */ + public boolean isSizeChanged() { + return (preSize != postSize); + } + + // Event type + //----------------------------------------------------------------------- + /** + * Checks to see if the event is of the specified type. + *

+ * This is any combination of constants from {@link ObservedEventType}. + * + * @param eventType an event type constant + * @return true if of the specified type + */ + public boolean isType(final int eventType) { + return (type & eventType) > 0; + } + + // toString + //----------------------------------------------------------------------- + /** + * Gets a debugging string version of the event. + * + * @return a debugging string + */ + public String toString() { + StringBuffer buf = new StringBuffer(64); + buf.append("ObservedEvent[type="); + buf.append(ModificationEventType.toString(type)); + if (index >= 0) { + buf.append(",index="); + buf.append(index); + } + if (type != ModificationEventType.CLEAR) { + buf.append(",object="); + if (object instanceof List) { + buf.append("List:size:"); + buf.append(((List) object).size()); + } else if (object instanceof Set) { + buf.append("Set:size:"); + buf.append(((Set) object).size()); + } else if (object instanceof Bag) { + buf.append("Bag:size:"); + buf.append(((Bag) object).size()); + } else if (object instanceof Collection) { + buf.append("Collection:size:"); + buf.append(((Collection) object).size()); + } else if (object instanceof Map) { + buf.append("Map:size:"); + buf.append(((Map) object).size()); + } else if (object instanceof Object[]) { + buf.append("Array:size:"); + buf.append(((Object[]) object).length); + } else if (object == null) { + buf.append("null"); + } else { + buf.append(object.toString()); + } + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/src/java/org/apache/commons/collections/event/StandardModificationHandler.java b/src/java/org/apache/commons/collections/event/StandardModificationHandler.java new file mode 100644 index 000000000..6fc70a932 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/StandardModificationHandler.java @@ -0,0 +1,379 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/StandardModificationHandler.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +/** + * The standard implementation of a ModificationHandler that + * sends standard JavaBean style events to listeners. + *

+ * The information gathered by this implementation is all that is available + * as parameters or return values. + * In addition, the size method is used on the collection. + * All objects used are the real objects from the method calls, not clones. + *

+ * Each listener can be filtered. There are separate filters for pre events + * (modificationOccurring) and post events (modificationOccurred). + *

+ * This implementation is the standard one. Most listeners will probably be + * content with the events generated from here. However, if you need something + * extra then this class can be subclassed or replaced as required. For example: + *

+ * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class StandardModificationHandler extends ModificationHandler { + + /** A reusable empty holders array. */ + protected static final Holder[] EMPTY_HOLDERS = new Holder[0]; + + /** The event mask as to which event types to send on pre events. */ + protected int preMask = ModificationEventType.GROUP_NONE; + /** The event mask as to which event types to send on post events. */ + protected int postMask = ModificationEventType.GROUP_NONE; + /** The event listeners. */ + protected Holder[] holders = EMPTY_HOLDERS; + /** + * Temporary store for the size. + * This makes the class thread-unsafe, but you should sync collections anyway. + */ + protected int preSize; + + // Constructors + //----------------------------------------------------------------------- + /** + * Constructor the creates the handler but leaves it invalid. + *

+ * The handler can only be used after {@link #init(ObservedCollection)} is + * called. This is normally done automatically by + * {@link ObservedCollection#decorate(Collection, ModificationHandler)}. + */ + public StandardModificationHandler() { + super(); + } + + // Listeners + //---------------------------------------------------------------------- + /** + * Gets an array of all the listeners active in the handler. + *

+ * All listeners will be instances of StandardModificationListener. + * + * @return the listeners + */ + public synchronized ModificationListener[] getModificationListeners() { + ModificationListener[] lnrs = new ModificationListener[holders.length]; + for (int i = 0; i < holders.length; i++) { + lnrs[i] = holders[i].listener; + } + return lnrs; + } + + /** + * Adds a listener to the list held in the handler. + *

+ * No error occurs if the listener is null. + * + * @param listener the listener to add, may be null (ignored) + * @throws ClassCastException if the listener is not a StandardModificationListener + */ + public void addModificationListener(ModificationListener listener) { + addModificationListener(listener, -1, -1); + } + + /** + * Adds a listener to the list held in the handler. + *

+ * No error occurs if the listener is null. + * + * @param listener the listener to add, may be null (ignored) + * @param preMask the mask for pre events (0 for none, -1 for all) + * @param postMask the mask for post events (0 for none, -1 for all) + * @throws ClassCastException if the listener is not a StandardModificationListener + */ + public synchronized void addModificationListener(ModificationListener listener, int preMask, int postMask) { + if (listener != null) { + int oldSize = holders.length; + Holder[] array = new Holder[oldSize + 1]; + System.arraycopy(holders, 0, array, 0, oldSize); + array[oldSize] = new Holder((StandardModificationListener) listener, preMask, postMask); + holders = array; + calculateMasks(); + } + } + + /** + * Removes a listener to the list held in the handler. + *

+ * No error occurs if the listener is not in the list or the type + * of the listener is incorrect. + * The listener is matched using ==. + * + * @param listener the listener to remove, may be null (ignored) + */ + public synchronized void removeModificationListener(ModificationListener listener) { + if (listener != null) { + switch (holders.length) { + case 0: + return; + + case 1: + if (holders[0].listener == listener) { + holders = EMPTY_HOLDERS; + calculateMasks(); + } + return; + + default: + Holder[] array = new Holder[holders.length - 1]; + boolean match = false; + for (int i = 0; i < holders.length; i++) { + if (match) { + array[i - 1] = holders[i]; + } else if (holders[i].listener == listener) { + match = true; + } else { + array[i] = holders[i]; + } + } + holders = array; + calculateMasks(); + return; + } + } + } + + /** + * Sets the masks of a listener. + *

+ * No error occurs if the listener is not in the list. + * The listener is matched using ==. + * + * @return a non-null array of listeners + */ + public synchronized void setModificationListenerMasks(StandardModificationListener listener, int preMask, int postMask) { + if (listener != null) { + for (int i = 0; i < holders.length; i++) { + if (holders[i].listener == listener) { + holders[i].preMask = preMask; + holders[i].postMask = postMask; + calculateMasks(); + break; + } + } + } + } + + // Holder for listener and masks + //----------------------------------------------------------------------- + protected static class Holder { + StandardModificationListener listener; + int preMask; + int postMask; + + Holder(StandardModificationListener listener, int preMask, int postMask) { + this.listener = listener; + this.preMask = preMask; + this.postMask = postMask; + } + + public String toString() { + return "[" + listener + "," + + ModificationEventType.toString(preMask) + "," + + ModificationEventType.toString(postMask) + "]"; + } + + } + + // Masks + //----------------------------------------------------------------------- + /** + * Calculate the combined masks. + */ + protected void calculateMasks() { + preMask = ModificationEventType.GROUP_NONE; + postMask = ModificationEventType.GROUP_NONE; + for (int i = 0; i < holders.length; i++) { + preMask |= holders[i].preMask; + postMask |= holders[i].postMask; + } + } + + // Pre event sending + //----------------------------------------------------------------------- + /** + * Handles the pre event. + * + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + * @return true to call the decorated collection + */ + protected boolean preEvent(int type, int index, Object object, int repeat) { + preSize = getCollection().size(); + return firePreEvent(type, index, object, repeat); + } + + /** + * Sends the pre event to the listeners. + * + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + * @return true to call the decorated collection + */ + protected boolean firePreEvent(int type, int index, Object object, int repeat) { + if ((preMask & type) > 0) { + StandardModificationEvent event = null; + synchronized (this) { + for (int i = 0; i < holders.length; i++) { + Holder holder = holders[i]; + if ((holder.preMask & type) > 0) { + if (event == null) { + event = new StandardModificationEvent( + getCollection(), this, type, preSize, index, object, repeat, null); + } + holder.listener.modificationOccurring(event); + } + } + } + } + return true; + } + + // Post event sending + //----------------------------------------------------------------------- + /** + * Handles the post event. + * + * @param success true if the method succeeded in changing the collection + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + */ + protected void postEvent(boolean success, int type, int index, Object object, int repeat) { + if (success) { + firePostEvent(type, index, object, repeat, (success ? Boolean.TRUE : Boolean.FALSE)); + } + } + + /** + * Handles the post event. + * + * @param success true if the method succeeded in changing the collection + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + * @param result the method result + */ + protected void postEvent(boolean success, int type, int index, Object object, int repeat, Object result) { + if (success) { + firePostEvent(type, index, object, repeat, result); + } + } + + /** + * Sends the post event to the listeners. + * + * @param type the event type to send + * @param index the index where the change starts + * @param object the object that was added/removed + * @param repeat the number of repeats of the add/remove + * @param result the method result + */ + protected void firePostEvent(int type, int index, Object object, int repeat, Object result) { + if ((postMask & type) > 0) { + StandardModificationEvent event = null; + synchronized (this) { + for (int i = 0; i < holders.length; i++) { + Holder holder = holders[i]; + if ((holder.postMask & type) > 0) { + if (event == null) { + event = new StandardModificationEvent( + getCollection(), this, type, preSize, index, object, repeat, result); + } + holder.listener.modificationOccurred(event); + } + } + } + } + } + + // Event handling + //----------------------------------------------------------------------- + /** + * Send an event after clear() is called. + *

+ * Override to only send event if something actually cleared. + */ + public void postClear() { + postEvent(preSize > 0, ModificationEventType.CLEAR, -1, null, 1, null); + } + +} diff --git a/src/java/org/apache/commons/collections/event/StandardModificationListener.java b/src/java/org/apache/commons/collections/event/StandardModificationListener.java new file mode 100644 index 000000000..1ccae0ee9 --- /dev/null +++ b/src/java/org/apache/commons/collections/event/StandardModificationListener.java @@ -0,0 +1,102 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/event/Attic/StandardModificationListener.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.event; + +/** + * A listener that receives events from the StandardModificationHandler. + *

+ * This listener has two methods. + *

    + *
  1. modificationOccurring - called before the modification + * occurs and can veto the change. + *
  2. modificationOccurred - called after the change and is + * for information. + *
+ * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public interface StandardModificationListener extends ModificationListener { + + /** + * A collection modification is occurring. + *

+ * To veto the change, throw ModicationVetoedException. + *

+ * This method should be processed quickly, as with all event handling. + * It should also avoid modifying the event source (the collection). + * + * @param event the event detail + * @throws ModicationVetoedException to veto + */ + public void modificationOccurring(StandardModificationEvent event); + + /** + * A collection modification occurred. + *

+ * This method should be processed quickly, as with all event handling. + * It should also avoid modifying the event source (the collection). + * Finally it should avoid throwing an exception. + * + * @param event the event detail + */ + public void modificationOccurred(StandardModificationEvent event); + +} diff --git a/src/test/org/apache/commons/collections/decorators/ObservedTestHelper.java b/src/test/org/apache/commons/collections/decorators/ObservedTestHelper.java new file mode 100644 index 000000000..c567858bc --- /dev/null +++ b/src/test/org/apache/commons/collections/decorators/ObservedTestHelper.java @@ -0,0 +1,683 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/decorators/Attic/ObservedTestHelper.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import junit.framework.Assert; + +import org.apache.commons.collections.event.ModificationEventType; +import org.apache.commons.collections.event.ModificationListener; +import org.apache.commons.collections.event.StandardModificationEvent; +import org.apache.commons.collections.event.StandardModificationHandler; +import org.apache.commons.collections.event.StandardModificationListener; + +/** + * Helper for testing + * {@link ObservedCollection} implementations. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class ObservedTestHelper { + + public static Integer SIX = new Integer(6); + public static Integer SEVEN = new Integer(7); + public static Integer EIGHT = new Integer(8); + public static List SIX_SEVEN_LIST = new ArrayList(); + static { + SIX_SEVEN_LIST.add(SIX); + SIX_SEVEN_LIST.add(SEVEN); + } + + public static class Listener implements StandardModificationListener { + public StandardModificationEvent preEvent = null; + public StandardModificationEvent postEvent = null; + + public void modificationOccurring(StandardModificationEvent event) { + this.preEvent = event; + } + + public void modificationOccurred(StandardModificationEvent event) { + this.postEvent = event; + } + } + + public static final Listener LISTENER = new Listener(); + public static final Listener LISTENER2 = new Listener(); + + public ObservedTestHelper() { + super(); + } + + //----------------------------------------------------------------------- + public static void doTestFactoryPlain(ObservedCollection coll) { + Assert.assertEquals(StandardModificationHandler.class, coll.getHandler().getClass()); + Assert.assertEquals(0, coll.getModificationListeners().length); + } + + public static void doTestFactoryWithListener(ObservedCollection coll) { + Assert.assertEquals(StandardModificationHandler.class, coll.getHandler().getClass()); + Assert.assertEquals(1, coll.getModificationListeners().length); + Assert.assertSame(LISTENER, coll.getModificationListeners()[0]); + } + + public static void doTestFactoryPostEvents(ObservedCollection coll) { + Assert.assertEquals(StandardModificationHandler.class, coll.getHandler().getClass()); + Assert.assertEquals(1, coll.getModificationListeners().length); + Assert.assertSame(LISTENER, coll.getModificationListeners()[0]); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + Assert.assertTrue(LISTENER.preEvent == null); + Assert.assertTrue(LISTENER.postEvent != null); + } + + //----------------------------------------------------------------------- + public static void doTestAddRemoveGetListeners(ObservedCollection coll) { + Assert.assertEquals(0, coll.getModificationListeners().length); + coll.addModificationListener(LISTENER); + Assert.assertEquals(1, coll.getModificationListeners().length); + Assert.assertSame(LISTENER, coll.getModificationListeners()[0]); + + coll.addModificationListener(LISTENER2); + Assert.assertEquals(2, coll.getModificationListeners().length); + Assert.assertSame(LISTENER, coll.getModificationListeners()[0]); + Assert.assertSame(LISTENER2, coll.getModificationListeners()[1]); + + coll.removeModificationListener(LISTENER); + Assert.assertEquals(1, coll.getModificationListeners().length); + Assert.assertSame(LISTENER2, coll.getModificationListeners()[0]); + + coll.removeModificationListener(LISTENER); // check no error if not present + Assert.assertEquals(1, coll.getModificationListeners().length); + Assert.assertSame(LISTENER2, coll.getModificationListeners()[0]); + + coll.removeModificationListener(LISTENER2); + Assert.assertEquals(0, coll.getModificationListeners().length); + + try { + coll.addModificationListener(new ModificationListener() {}); + Assert.fail(); + } catch (ClassCastException ex) { + } + } + + //----------------------------------------------------------------------- + public static void doTestAdd(ObservedCollection coll) { + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(0, coll.size()); + coll.add(SIX); + Assert.assertEquals(1, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX, LISTENER.preEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SIX, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(0, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(0, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeCollection().size()); + Assert.assertSame(SIX, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(0, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(1, coll.size()); + coll.add(SEVEN); + Assert.assertEquals(2, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(1, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(1, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.add(SIX_SEVEN_LIST); + Assert.assertEquals(3, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeCollection().size()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(3, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + } + + //----------------------------------------------------------------------- + public static void doTestAddIndexed(ObservedList coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.add(1, EIGHT); + Assert.assertEquals(3, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_INDEXED, LISTENER.preEvent.getType()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(EIGHT, LISTENER.preEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(EIGHT, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_INDEXED, LISTENER.postEvent.getType()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeCollection().size()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(3, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + } + + //----------------------------------------------------------------------- + public static void doTestAddAll(ObservedCollection coll) { + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(0, coll.size()); + coll.addAll(SIX_SEVEN_LIST); + Assert.assertEquals(2, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_ALL, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(0, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(0, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_ALL, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(0, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(2, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + } + + //----------------------------------------------------------------------- + public static void doTestAddAllIndexed(ObservedList coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.addAll(1, SIX_SEVEN_LIST); + Assert.assertEquals(4, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_ALL_INDEXED, LISTENER.preEvent.getType()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.preEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.ADD_ALL_INDEXED, LISTENER.postEvent.getType()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(4, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(2, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + } + + //----------------------------------------------------------------------- + public static void doTestClear(ObservedCollection coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.clear(); + Assert.assertEquals(0, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.CLEAR, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(null, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.CLEAR, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(null, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(0, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-2, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(0, coll.size()); + coll.clear(); // already done this + Assert.assertEquals(0, coll.size()); + Assert.assertTrue(LISTENER.preEvent != null); + Assert.assertTrue(LISTENER.postEvent == null); + } + + //----------------------------------------------------------------------- + public static void doTestRemove(ObservedCollection coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.remove(SEVEN); + Assert.assertEquals(1, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(1, coll.size()); + coll.remove(SEVEN); // already removed + Assert.assertEquals(1, coll.size()); + Assert.assertTrue(LISTENER.preEvent != null); + Assert.assertTrue(LISTENER.postEvent == null); + } + + //----------------------------------------------------------------------- + public static void doTestRemoveIndexed(ObservedList coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.remove(0); + Assert.assertEquals(1, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE_INDEXED, LISTENER.preEvent.getType()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(null, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE_INDEXED, LISTENER.postEvent.getType()); + Assert.assertEquals(0, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(null, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(SIX, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + } + + //----------------------------------------------------------------------- + public static void doTestRemoveAll(ObservedCollection coll) { + coll.add(EIGHT); + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(3, coll.size()); + coll.removeAll(SIX_SEVEN_LIST); + Assert.assertEquals(1, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE_ALL, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(3, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(3, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE_ALL, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(3, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-2, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(1, coll.size()); + coll.removeAll(SIX_SEVEN_LIST); // already done this + Assert.assertEquals(1, coll.size()); + Assert.assertTrue(LISTENER.preEvent != null); + Assert.assertTrue(LISTENER.postEvent == null); + } + + //----------------------------------------------------------------------- + public static void doTestRetainAll(ObservedCollection coll) { + coll.add(EIGHT); + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(3, coll.size()); + coll.retainAll(SIX_SEVEN_LIST); + Assert.assertEquals(2, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.RETAIN_ALL, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(3, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(3, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.RETAIN_ALL, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeObject()); + Assert.assertSame(SIX_SEVEN_LIST, LISTENER.postEvent.getChangeCollection()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(3, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.retainAll(SIX_SEVEN_LIST); // already done this + Assert.assertEquals(2, coll.size()); + Assert.assertTrue(LISTENER.preEvent != null); + Assert.assertTrue(LISTENER.postEvent == null); + } + + //----------------------------------------------------------------------- + public static void doTestIteratorRemove(ObservedCollection coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + Iterator it = coll.iterator(); + it.next(); + it.next(); + it.remove(); + Assert.assertEquals(1, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE, LISTENER.preEvent.getType()); + Assert.assertEquals(-1, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.REMOVE, LISTENER.postEvent.getType()); + Assert.assertEquals(-1, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(SEVEN, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(SEVEN, LISTENER.preEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(Boolean.TRUE, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(1, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(-1, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(true, LISTENER.postEvent.isSizeChanged()); + + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(1, coll.size()); + coll.remove(SEVEN); // already removed + Assert.assertEquals(1, coll.size()); + Assert.assertTrue(LISTENER.preEvent != null); + Assert.assertTrue(LISTENER.postEvent == null); + } + + //----------------------------------------------------------------------- + public static void doTestSetIndexed(ObservedList coll) { + coll.addAll(SIX_SEVEN_LIST); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + Assert.assertEquals(2, coll.size()); + coll.set(0, EIGHT); + Assert.assertEquals(2, coll.size()); + // pre + Assert.assertSame(coll, LISTENER.preEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.preEvent.getHandler()); + Assert.assertEquals(ModificationEventType.SET_INDEXED, LISTENER.preEvent.getType()); + Assert.assertEquals(0, LISTENER.preEvent.getChangeIndex()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeRepeat()); + Assert.assertSame(null, LISTENER.preEvent.getResult()); + Assert.assertEquals(2, LISTENER.preEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.preEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.preEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.preEvent.isSizeChanged()); + // post + Assert.assertSame(coll, LISTENER.postEvent.getSourceCollection()); + Assert.assertSame(coll.getHandler(), LISTENER.postEvent.getHandler()); + Assert.assertEquals(ModificationEventType.SET_INDEXED, LISTENER.postEvent.getType()); + Assert.assertEquals(0, LISTENER.postEvent.getChangeIndex()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeObject()); + Assert.assertEquals(1, LISTENER.preEvent.getChangeCollection().size()); + Assert.assertSame(EIGHT, LISTENER.postEvent.getChangeCollection().iterator().next()); + Assert.assertEquals(1, LISTENER.postEvent.getChangeRepeat()); + Assert.assertSame(SIX, LISTENER.postEvent.getResult()); + Assert.assertEquals(2, LISTENER.postEvent.getPreSize()); + Assert.assertEquals(2, LISTENER.postEvent.getPostSize()); + Assert.assertEquals(0, LISTENER.postEvent.getSizeChange()); + Assert.assertEquals(false, LISTENER.postEvent.isSizeChanged()); + } + +} diff --git a/src/test/org/apache/commons/collections/decorators/TestObservedCollection.java b/src/test/org/apache/commons/collections/decorators/TestObservedCollection.java new file mode 100644 index 000000000..0d48503d8 --- /dev/null +++ b/src/test/org/apache/commons/collections/decorators/TestObservedCollection.java @@ -0,0 +1,204 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/decorators/Attic/TestObservedCollection.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.commons.collections.TestCollection; +import org.apache.commons.collections.event.ModificationEventType; +import org.apache.commons.collections.event.StandardModificationHandler; + +/** + * Extension of {@link TestCollection} for exercising the + * {@link ObservedCollection} implementation. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class TestObservedCollection extends TestCollection { + + private static Integer SIX = new Integer(6); + private static Integer SEVEN = new Integer(7); + private static Integer EIGHT = new Integer(8); + private static final ObservedTestHelper.Listener LISTENER = ObservedTestHelper.LISTENER; + + public TestObservedCollection(String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(TestObservedCollection.class); + } + + public static void main(String args[]) { + String[] testCaseName = { TestObservedCollection.class.getName()}; + junit.textui.TestRunner.main(testCaseName); + } + + //----------------------------------------------------------------------- + public Collection makeConfirmedCollection() { + return new ArrayList(); + } + + protected Collection makeConfirmedFullCollection() { + List list = new ArrayList(); + list.addAll(Arrays.asList(getFullElements())); + return list; + } + + public Collection makeCollection() { + return ObservedCollection.decorate(new ArrayList(), LISTENER); + } + + protected Collection makeFullCollection() { + List list = new ArrayList(); + list.addAll(Arrays.asList(getFullElements())); + return ObservedCollection.decorate(list, LISTENER); + } + + //----------------------------------------------------------------------- + public void testObservedCollection() { + ObservedCollection coll = ObservedCollection.decorate(new ArrayList()); + ObservedTestHelper.doTestFactoryPlain(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestFactoryWithListener(coll); + + coll = ObservedCollection.decoratePostEventsOnly(new ArrayList(), LISTENER); + ObservedTestHelper.doTestFactoryPostEvents(coll); + + coll = ObservedCollection.decorate(new ArrayList()); + ObservedTestHelper.doTestAddRemoveGetListeners(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAdd(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAddAll(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestClear(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRemove(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRemoveAll(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRetainAll(coll); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestIteratorRemove(coll); + } + + //----------------------------------------------------------------------- + public void testFactoryWithHandler() { + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedCollection coll = ObservedCollection.decorate(new ArrayList(), handler); + + assertSame(handler, coll.getHandler()); + assertEquals(0, coll.getModificationListeners().length); + } + + public void testFactoryWithMasks() { + ObservedCollection coll = ObservedCollection.decorate(new ArrayList(), LISTENER, -1, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER, 0, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER, -1, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER, 0, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedCollection.decorate(new ArrayList(), LISTENER, ModificationEventType.ADD, ModificationEventType.ADD_ALL); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + } + +} diff --git a/src/test/org/apache/commons/collections/decorators/TestObservedList.java b/src/test/org/apache/commons/collections/decorators/TestObservedList.java new file mode 100644 index 000000000..7932d472a --- /dev/null +++ b/src/test/org/apache/commons/collections/decorators/TestObservedList.java @@ -0,0 +1,205 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/decorators/Attic/TestObservedList.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.commons.collections.TestList; +import org.apache.commons.collections.event.ModificationEventType; +import org.apache.commons.collections.event.StandardModificationHandler; + +/** + * Extension of {@link TestList} for exercising the + * {@link ObservedList} implementation. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class TestObservedList extends TestList { + + private static Integer SIX = new Integer(6); + private static Integer SEVEN = new Integer(7); + private static Integer EIGHT = new Integer(8); + private static final ObservedTestHelper.Listener LISTENER = ObservedTestHelper.LISTENER; + + public TestObservedList(String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(TestObservedList.class); + } + + public static void main(String args[]) { + String[] testCaseName = { TestObservedList.class.getName()}; + junit.textui.TestRunner.main(testCaseName); + } + + //----------------------------------------------------------------------- + public List makeEmptyList() { + return ObservedList.decorate(new ArrayList(), LISTENER); + } + + protected List makeFullList() { + List set = new ArrayList(); + set.addAll(Arrays.asList(getFullElements())); + return ObservedList.decorate(set, LISTENER); + } + + //----------------------------------------------------------------------- + public void testObservedList() { + ObservedList coll = ObservedList.decorate(new ArrayList()); + ObservedTestHelper.doTestFactoryPlain(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestFactoryWithListener(coll); + + coll = ObservedList.decoratePostEventsOnly(new ArrayList(), LISTENER); + ObservedTestHelper.doTestFactoryPostEvents(coll); + + coll = ObservedList.decorate(new ArrayList()); + ObservedTestHelper.doTestAddRemoveGetListeners(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAdd(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAddIndexed(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAddAll(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestAddAllIndexed(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestClear(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRemove(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRemoveIndexed(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRemoveAll(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestRetainAll(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestIteratorRemove(coll); + + coll = ObservedList.decorate(new ArrayList(), LISTENER); + ObservedTestHelper.doTestSetIndexed(coll); + } + + //----------------------------------------------------------------------- + public void testFactoryWithHandler() { + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedList coll = ObservedList.decorate(new ArrayList(), handler); + + assertSame(handler, coll.getHandler()); + assertEquals(0, coll.getModificationListeners().length); + } + + public void testFactoryWithMasks() { + ObservedList coll = ObservedList.decorate(new ArrayList(), LISTENER, -1, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedList.decorate(new ArrayList(), LISTENER, 0, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedList.decorate(new ArrayList(), LISTENER, -1, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedList.decorate(new ArrayList(), LISTENER, 0, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedList.decorate(new ArrayList(), LISTENER, ModificationEventType.ADD, ModificationEventType.ADD_ALL); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + } + +} diff --git a/src/test/org/apache/commons/collections/decorators/TestObservedSet.java b/src/test/org/apache/commons/collections/decorators/TestObservedSet.java new file mode 100644 index 000000000..5f0c5b0dc --- /dev/null +++ b/src/test/org/apache/commons/collections/decorators/TestObservedSet.java @@ -0,0 +1,193 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/decorators/Attic/TestObservedSet.java,v 1.1 2003/08/28 18:31:13 scolebourne Exp $ + * ==================================================================== + * + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "The Jakarta Project", "Commons", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.commons.collections.decorators; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import org.apache.commons.collections.TestSet; +import org.apache.commons.collections.event.ModificationEventType; +import org.apache.commons.collections.event.StandardModificationHandler; + +/** + * Extension of {@link TestSet} for exercising the + * {@link ObservedSet} implementation. + * + * @since Commons Collections 3.0 + * @version $Revision: 1.1 $ $Date: 2003/08/28 18:31:13 $ + * + * @author Stephen Colebourne + */ +public class TestObservedSet extends TestSet { + + private static Integer SIX = new Integer(6); + private static Integer SEVEN = new Integer(7); + private static Integer EIGHT = new Integer(8); + private static final ObservedTestHelper.Listener LISTENER = ObservedTestHelper.LISTENER; + + public TestObservedSet(String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(TestObservedSet.class); + } + + public static void main(String args[]) { + String[] testCaseName = { TestObservedSet.class.getName()}; + junit.textui.TestRunner.main(testCaseName); + } + + //----------------------------------------------------------------------- + public Set makeEmptySet() { + return ObservedSet.decorate(new HashSet(), LISTENER); + } + + protected Set makeFullSet() { + Set set = new HashSet(); + set.addAll(Arrays.asList(getFullElements())); + return ObservedSet.decorate(set, LISTENER); + } + + //----------------------------------------------------------------------- + public void testObservedSet() { + ObservedSet coll = ObservedSet.decorate(new HashSet()); + ObservedTestHelper.doTestFactoryPlain(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestFactoryWithListener(coll); + + coll = ObservedSet.decoratePostEventsOnly(new HashSet(), LISTENER); + ObservedTestHelper.doTestFactoryPostEvents(coll); + + coll = ObservedSet.decorate(new HashSet()); + ObservedTestHelper.doTestAddRemoveGetListeners(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestAdd(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestAddAll(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestClear(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestRemove(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestRemoveAll(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestRetainAll(coll); + + coll = ObservedSet.decorate(new HashSet(), LISTENER); + ObservedTestHelper.doTestIteratorRemove(coll); + } + + //----------------------------------------------------------------------- + public void testFactoryWithHandler() { + StandardModificationHandler handler = new StandardModificationHandler(); + ObservedSet coll = ObservedSet.decorate(new HashSet(), handler); + + assertSame(handler, coll.getHandler()); + assertEquals(0, coll.getModificationListeners().length); + } + + public void testFactoryWithMasks() { + ObservedSet coll = ObservedSet.decorate(new HashSet(), LISTENER, -1, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedSet.decorate(new HashSet(), LISTENER, 0, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedSet.decorate(new HashSet(), LISTENER, -1, -1); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent != null); + + coll = ObservedSet.decorate(new HashSet(), LISTENER, 0, 0); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent == null); + assertTrue(LISTENER.postEvent == null); + + coll = ObservedSet.decorate(new HashSet(), LISTENER, ModificationEventType.ADD, ModificationEventType.ADD_ALL); + LISTENER.preEvent = null; + LISTENER.postEvent = null; + coll.add(SIX); + assertTrue(LISTENER.preEvent != null); + assertTrue(LISTENER.postEvent == null); + } + +}