blob: bed03a4b596551c98defadbe8a0c3f925583d3fa [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.osgi.framework.util;
import java.util.EventListener;
import java.util.EventObject;
import org.apache.osgi.framework.LogWrapper;
import org.osgi.framework.*;
/**
* This is a subclass of <tt>DispatchQueue</tt> that specifically adds support
* for <tt>SynchronousBundleListener</tt>s; the OSGi specification
* says that synchronous bundle listeners should receive their events
* immediately, i.e., they should not be delivered on a separate thread
* like is the case with the <tt>DispatchQueue</tt>. To achieve this
* functionality, this class overrides the dispatch method to automatically
* fire any bundle events to synchronous bundle listeners using the
* calling thread. In order to ensure that synchronous bundle listeners
* do not receive an event twice, it wraps the passed in <tt>Dipatcher</tt>
* instance so that it filters synchronous bundle listeners.
**/
public class FelixDispatchQueue extends DispatchQueue
{
public FelixDispatchQueue(LogWrapper logger)
{
super(logger);
}
/**
* Dispatches an event to a set of event listeners using a specified
* dispatcher object. This overrides the definition of the super class
* to deliver events to <tt>ServiceListener</tt>s and
* <tt>SynchronousBundleListener</tt>s using
* the calling thread instead of the event dispatching thread. All
* other events are still delivered asynchronously.
*
* @param dispatcher the dispatcher used to actually dispatch the event; this
* varies according to the type of event listener.
* @param clazz the class associated with the target event listener type;
* only event listeners of this type will receive the event.
* @param eventObj the actual event object to dispatch.
**/
public void dispatch(Dispatcher dispatcher, Class clazz, EventObject eventObj)
{
Object[] listeners = getListeners();
// If this is an event for service listeners, then dispatch it
// immediately since service events are never asynchronous.
if ((clazz == ServiceListener.class) && (listeners.length > 0))
{
// Notify appropriate listeners.
for (int i = listeners.length - 2; i >= 0; i -= 2)
{
// If the original listener is a synchronous bundle listener
// or a service listener, then dispatch event immediately
// per the specification.
ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
if (lw.getListenerClass() == ServiceListener.class)
{
try {
dispatcher.dispatch(
(EventListener) lw, eventObj);
} catch (Throwable th) {
getLogger().log(
LogWrapper.LOG_ERROR,
"FelixDispatchQueue: Error during dispatch.", th);
}
}
}
}
// Dispatch bundle events to synchronous bundle listeners immediately,
// but deliver to standard bundle listeners asynchronously.
else if ((clazz == BundleListener.class) && (listeners.length > 0))
{
// Notify appropriate listeners.
for (int i = listeners.length - 2; i >= 0; i -= 2)
{
// If the original listener is a synchronous bundle listener,
// then dispatch event immediately per the specification.
ListenerWrapper lw = (ListenerWrapper) listeners[i + 1];
if (lw.getListenerClass() == SynchronousBundleListener.class)
{
try {
dispatcher.dispatch(
(EventListener) lw, eventObj);
} catch (Throwable th) {
getLogger().log(
LogWrapper.LOG_ERROR,
"FelixDispatchQueue: Error during dispatch.", th);
}
}
}
// Wrap the dispatcher so that it ignores synchronous
// bundle listeners since they have already been dispatched.
IgnoreSynchronousDispatcher ignoreDispatcher = new IgnoreSynchronousDispatcher();
ignoreDispatcher.setDispatcher(dispatcher);
// Dispatch the bundle listener asynchronously.
dispatch(listeners, ignoreDispatcher, clazz, eventObj);
}
// All other events are dispatched asynchronously.
else
{
dispatch(listeners, dispatcher, clazz, eventObj);
}
}
private static class IgnoreSynchronousDispatcher implements Dispatcher
{
private Dispatcher m_dispatcher = null;
public void setDispatcher(Dispatcher dispatcher)
{
m_dispatcher = dispatcher;
}
public void dispatch(EventListener l, EventObject eventObj)
{
if (l instanceof ListenerWrapper)
{
ListenerWrapper lw = (ListenerWrapper) l;
// Do not dispatch events to synchronous listeners,
// since they are dispatched immediately above.
if (!(lw.getListenerClass() == SynchronousBundleListener.class))
{
m_dispatcher.dispatch(l, eventObj);
}
}
}
}
}