001: // Copyright 2004, 2005 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.hivemind.service.impl;
016:
017: import java.util.Iterator;
018:
019: import org.apache.commons.logging.Log;
020: import org.apache.commons.logging.LogFactory;
021: import org.apache.hivemind.service.ThreadCleanupListener;
022: import org.apache.hivemind.service.ThreadEventNotifier;
023: import org.apache.hivemind.util.Defense;
024: import org.apache.hivemind.util.EventListenerList;
025:
026: /**
027: * Implementation of {@link org.apache.hivemind.service.ThreadEventNotifier}, available as service
028: * <code>hivemind.ThreadEventNotifier</code>.
029: *
030: * @author Howard Lewis Ship
031: */
032: public class ThreadEventNotifierImpl implements ThreadEventNotifier {
033: private static final Log DEFAULT_LOG = LogFactory
034: .getLog(ThreadEventNotifier.class);
035:
036: private final Log _log;
037:
038: private final ThreadLocal _storage = new ThreadLocal();
039:
040: public ThreadEventNotifierImpl() {
041: this (DEFAULT_LOG);
042: }
043:
044: public ThreadEventNotifierImpl(Log log) {
045: Defense.notNull(log, "log");
046:
047: _log = log;
048: }
049:
050: public void addThreadCleanupListener(ThreadCleanupListener listener) {
051: EventListenerList list = (EventListenerList) _storage.get();
052:
053: if (list == null) {
054: list = new EventListenerList();
055: _storage.set(list);
056: }
057:
058: list.addListener(listener);
059: }
060:
061: public void removeThreadCleanupListener(
062: ThreadCleanupListener listener) {
063: EventListenerList list = (EventListenerList) _storage.get();
064:
065: if (list != null)
066: list.removeListener(listener);
067: }
068:
069: public void fireThreadCleanup() {
070: // Here's where we need the CursorableLinkedList since listeners
071: // are free to unregister as listeners from threadDidCleanup() and
072: // we need to avoid concurrent modification errors.
073:
074: EventListenerList list = (EventListenerList) _storage.get();
075:
076: if (list == null)
077: return;
078:
079: Iterator i = list.getListeners();
080:
081: // Discard the list of listeners as early as possible to ensure that
082: // they can in no way be retained, even if this thread aborts abnormally.
083:
084: _storage.set(null);
085:
086: while (i.hasNext()) {
087: ThreadCleanupListener listener = (ThreadCleanupListener) i
088: .next();
089:
090: // Each listener may decide to remove itself; that's OK,
091: // EventListenerList handles that kind of concurrent modification
092: // well.
093:
094: try {
095: listener.threadDidCleanup();
096: } catch (RuntimeException ex) {
097: _log.warn(ServiceMessages.threadCleanupException(ex),
098: ex);
099: }
100: }
101: }
102:
103: }
|