001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.context.event;
018:
019: import java.util.Collection;
020:
021: import org.springframework.beans.BeanUtils;
022: import org.springframework.context.ApplicationListener;
023: import org.springframework.core.CollectionFactory;
024:
025: /**
026: * Abstract implementation of the ApplicationEventMulticaster interface,
027: * providing the basic listener registration facility.
028: *
029: * <p>Doesn't permit multiple instances of the same listener by default,
030: * as it keeps listeners in a linked Set. The collection class used to hold
031: * ApplicationListener objects can be overridden through the "collectionClass"
032: * bean property.
033: *
034: * <p>Note that this class doesn't try to do anything clever to ensure thread
035: * safety if listeners are added or removed at runtime. A technique such as
036: * Copy-on-Write (Lea:137) could be used to ensure this, but the assumption in
037: * the basic version of the class is that listeners will be added at application
038: * configuration time and not added or removed as the application runs.
039: *
040: * <p>A custom collection class must be specified to allow for thread-safe
041: * runtime registration of listeners. A good candidate for this is Doug Lea's
042: * <code>java.util.concurrent.CopyOnWriteArraySet</code> or its non-JDK predecessor,
043: * <code>EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet</code> (or the
044: * respective CopyOnWriteArrayList version, allowing for registering the same
045: * listener multiple times). Those classes provide a thread-safe Iterator,
046: * optimized for read-mostly usage - matching this use case nicely.
047: *
048: * <p>Implementing ApplicationEventMulticaster's actual <code>multicastEvent</code>
049: * method is left to subclasses. SimpleApplicationEventMulticaster simply multicasts
050: * all events to all registered listeners, invoking them in the calling thread.
051: * Alternative implementations could be more sophisticated in those respects.
052: *
053: * @author Juergen Hoeller
054: * @since 1.2.3
055: * @see #setCollectionClass
056: * @see #getApplicationListeners()
057: * @see SimpleApplicationEventMulticaster
058: */
059: public abstract class AbstractApplicationEventMulticaster implements
060: ApplicationEventMulticaster {
061:
062: /** Collection of ApplicationListeners */
063: private Collection applicationListeners = CollectionFactory
064: .createLinkedSetIfPossible(16);
065:
066: /**
067: * Specify the collection class to use. Can be populated with a fully
068: * qualified class name when defined in a Spring application context.
069: * <p>Default is a linked HashSet, keeping the registration order.
070: * If no linked Set implementation is available, a plain HashSet will
071: * be used as fallback (not keeping the registration order).
072: * <p>Note that a Set class specified will not permit multiple instances
073: * of the same listener, while a List class will allow for registering
074: * the same listener multiple times.
075: * <p>Consider Doug Lea's <code>java.util.concurrent.CopyOnWriteArraySet</code> or its
076: * non-JDK predecessor, <code>EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet</code>
077: * (or the respective CopyOnWriteArrayList version). Those classes provide a thread-safe
078: * Iterator, optimized for read-mostly usage - matching this use case nicely.
079: * @see org.springframework.core.CollectionFactory#createLinkedSetIfPossible
080: * @see java.util.concurrent.CopyOnWriteArraySet
081: * @see EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArraySet
082: */
083: public void setCollectionClass(Class collectionClass) {
084: if (collectionClass == null) {
085: throw new IllegalArgumentException(
086: "collectionClass must not be null");
087: }
088: if (!Collection.class.isAssignableFrom(collectionClass)) {
089: throw new IllegalArgumentException(
090: "collectionClass must implement [java.util.Collection]");
091: }
092: // Create desired collection instance.
093: // Add all previously registered listeners (usually none).
094: Collection newColl = (Collection) BeanUtils
095: .instantiateClass(collectionClass);
096: newColl.addAll(this .applicationListeners);
097: this .applicationListeners = newColl;
098: }
099:
100: public void addApplicationListener(ApplicationListener listener) {
101: this .applicationListeners.add(listener);
102: }
103:
104: public void removeApplicationListener(ApplicationListener listener) {
105: this .applicationListeners.remove(listener);
106: }
107:
108: public void removeAllListeners() {
109: this .applicationListeners.clear();
110: }
111:
112: /**
113: * Return the current Collection of ApplicationListeners.
114: * <p>Note that this is the raw Collection of ApplicationListeners,
115: * potentially modified when new listeners get registered or
116: * existing ones get removed. This Collection is not a snapshot copy.
117: * @return a Collection of ApplicationListeners
118: * @see org.springframework.context.ApplicationListener
119: */
120: protected Collection getApplicationListeners() {
121: return applicationListeners;
122: }
123:
124: }
|