001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.lib.util.concurrent;
020:
021: import java.io.Serializable;
022: import java.util.Collection;
023: import java.util.Collections;
024: import java.util.Iterator;
025: import java.util.LinkedList;
026: import java.util.List;
027:
028: import org.apache.openjpa.lib.util.EventManager;
029:
030: /**
031: * Base event manager that handles adding/removing listeners
032: * and firing events. Meant for high concurrency. This class is
033: * reentrant-safe; listeners can be added and removed by other listeners when
034: * they receive events. The changes will not be visible until the event fire
035: * that initiated the recursive sequence of calls completes, however.
036: *
037: * @author Abe White
038: */
039: public abstract class AbstractConcurrentEventManager implements
040: EventManager, Serializable {
041:
042: private static Exception[] EMPTY_EXCEPTIONS = new Exception[0];
043:
044: protected final Collection _listeners;
045: private boolean _failFast = false;
046:
047: /**
048: * Default constructor.
049: */
050: public AbstractConcurrentEventManager() {
051: _listeners = newListenerCollection();
052: }
053:
054: /**
055: * Whether to fail after the first exception thrown by any listener.
056: */
057: public boolean isFailFast() {
058: return _failFast;
059: }
060:
061: /**
062: * Whether to fail after the first exception thrown by any listener.
063: */
064: public void setFailFast(boolean failFast) {
065: _failFast = failFast;
066: }
067:
068: /**
069: * Register an event listener.
070: */
071: public void addListener(Object listener) {
072: if (listener != null)
073: _listeners.add(listener);
074: }
075:
076: /**
077: * Remove an event listener.
078: */
079: public boolean removeListener(Object listener) {
080: return _listeners.remove(listener);
081: }
082:
083: /**
084: * Return whether the given instance is in the list of listeners.
085: */
086: public boolean hasListener(Object listener) {
087: return _listeners.contains(listener);
088: }
089:
090: /**
091: * Return true if there are any registered listeners.
092: */
093: public boolean hasListeners() {
094: return !_listeners.isEmpty();
095: }
096:
097: /**
098: * Return a read-only list of listeners.
099: */
100: public Collection getListeners() {
101: return Collections.unmodifiableCollection(_listeners);
102: }
103:
104: /**
105: * Fire the given event to all listeners.
106: */
107: public Exception[] fireEvent(Object event) {
108: if (_listeners.isEmpty())
109: return EMPTY_EXCEPTIONS;
110:
111: List exceptions = null;
112: for (Iterator itr = _listeners.iterator(); itr.hasNext();) {
113: try {
114: fireEvent(event, itr.next());
115: } catch (Exception e) {
116: if (_failFast)
117: return new Exception[] { e };
118: if (exceptions == null)
119: exceptions = new LinkedList();
120: exceptions.add(e);
121: }
122: }
123:
124: if (exceptions == null)
125: return EMPTY_EXCEPTIONS;
126: return (Exception[]) exceptions
127: .toArray(new Exception[exceptions.size()]);
128: }
129:
130: /**
131: * Implement this method to fire the given event to the given listener.
132: */
133: protected abstract void fireEvent(Object event, Object listener)
134: throws Exception;
135:
136: /**
137: * Return a new concurrent container for listeners. Uses a
138: * {@link CopyOnWriteArrayList} by default.
139: */
140: protected Collection newListenerCollection() {
141: return new CopyOnWriteArrayList();
142: }
143: }
|