001: /*
002: * This software is released under a licence similar to the Apache Software Licence.
003: * See org.logicalcobwebs.proxool.package.html for details.
004: * The latest version is available at http://proxool.sourceforge.net
005: */
006: package org.logicalcobwebs.proxool.util;
007:
008: /**
009: * Implementation of {@link ListenerContainerIF} that uses a reads/write lock to handle concurrency in a safe and
010: * fast way.
011: * <p>
012: * The registered listeners are offered to subclasses through the protected {@link #getListeners} method. This
013: * method returns a reference to an array containing the registered listeners. A new array holding the listeners
014: * is created everytime a modification on the registration list is required (add/remove listener). Therefore,
015: * subclasses can safely iterate over the received array.
016: *
017: * Your code sould look like this:
018: * <code>
019: * <pre>
020: Object[] listeners = getListeners();
021: for(int i=0; i<listeners.length; i++) {
022: // do something
023: }
024: </pre>
025: </code>
026: * </p>
027: *
028: * @version $Revision: 1.8 $, $Date: 2004/03/16 08:48:33 $
029: * @author Christian Nedregaard (christian_nedregaard@email.com)
030: * @author $Author: brenuart $ (current maintainer)
031: * @since Proxool 0.7
032: */
033: public abstract class AbstractListenerContainer implements
034: ListenerContainerIF {
035:
036: private Object[] listeners = EMPTY_LISTENERS;
037: private static final Object[] EMPTY_LISTENERS = new Object[] {};
038:
039: /**
040: * @see ListenerContainerIF#addListener(Object)
041: */
042: public synchronized void addListener(Object listener) {
043: if (listener == null)
044: throw new NullPointerException(
045: "Unexpected NULL listener argument received");
046:
047: // create a new array
048: Object[] newListeners = new Object[listeners.length + 1];
049:
050: // copy listeners currently registered
051: System.arraycopy(listeners, 0, newListeners, 0,
052: listeners.length);
053:
054: // add the new one
055: newListeners[listeners.length] = listener;
056:
057: // commit changes
058: listeners = newListeners;
059: }
060:
061: /**
062: * @see ListenerContainerIF#removeListener(Object)
063: */
064: public synchronized boolean removeListener(Object listener) {
065: if (listener == null)
066: throw new NullPointerException(
067: "Unexpected NULL listener argument received");
068:
069: // find listener to remove in the list
070: int index = -1;
071: for (int i = 0; i < listeners.length; i++) {
072: if (listeners[i] == listener) {
073: index = i;
074: break;
075: }
076: }
077:
078: // not found ?
079: if (index == -1)
080: return false;
081:
082: // create a new array of the right size
083: Object[] newListeners = new Object[listeners.length - 1];
084:
085: // copy registered listeners minus the one to remove
086: if (index > 0)
087: System.arraycopy(listeners, 0, newListeners, 0, index);
088:
089: if (index < listeners.length - 1)
090: System.arraycopy(listeners, index + 1, newListeners, index,
091: listeners.length - index - 1);
092:
093: // commit
094: listeners = newListeners;
095: return true;
096: }
097:
098: /**
099: * Get a reference to the array of registered listeners.
100: *
101: * @return reference to the array containing registered listeners (always not NULL)
102: */
103: protected Object[] getListeners() {
104: return listeners;
105: }
106:
107: /**
108: * @see ListenerContainerIF#isEmpty()
109: */
110: public boolean isEmpty() {
111: return listeners.length == 0;
112: }
113: }
114:
115: /*
116: Revision history:
117: $Log: AbstractListenerContainer.java,v $
118: Revision 1.8 2004/03/16 08:48:33 brenuart
119: Changes in the AbstractListenerContainer:
120: - provide more efficient concurrent handling;
121: - better handling of RuntimeException thrown by external listeners.
122:
123: Revision 1.7 2003/03/11 00:12:11 billhorsman
124: switch to concurrent package
125:
126: Revision 1.6 2003/03/10 15:26:55 billhorsman
127: refactoringn of concurrency stuff (and some import
128: optimisation)
129:
130: Revision 1.5 2003/03/03 11:12:01 billhorsman
131: fixed licence
132:
133: Revision 1.4 2003/02/19 19:35:21 chr32
134: Formated code in javadoc.
135:
136: Revision 1.3 2003/02/07 17:20:18 billhorsman
137: checkstyle
138:
139: Revision 1.2 2003/02/07 15:06:43 billhorsman
140: fixed isEmpty bug
141:
142: Revision 1.1 2003/02/07 01:46:31 chr32
143: Initial revition.
144:
145: */
|