blob: 8e8660d1dcc8a38559ed9eebffd565db6878da05 [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.felix.eventadmin.impl.tasks;
import org.apache.felix.eventadmin.impl.dispatch.TaskQueue;
import org.apache.felix.eventadmin.impl.dispatch.ThreadPool;
/**
* This class does the actual work of the asynchronous event dispatch.
*
* <p>It serves two purposes: first, it will append tasks to its queue hence,
* asynchronous event delivery is executed - second, it will set up a given dispatch
* task with its <tt>ThreadPool</tt> in a way that it is associated with a
* <tt>DeliverTask</tt> that will block in case the thread hits the
* <tt>SyncDeliverTasks</tt>.
* </p>
* In other words, if the asynchronous event dispatching thread is used to send a
* synchronous event then it will spin-off a new asynchronous dispatching thread
* while the former waits for the synchronous event to be delivered and then return
* to its <tt>ThreadPool</tt>.
*
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
*/
public class AsyncDeliverTasks implements DeliverTasks, HandoverTask, DeliverTask
{
// The asynchronous event delivery queue
private final TaskQueue m_queue;
// The synchronous event delivery queue needed in case that the asynchronous
// event dispatching thread is used to send a synchronous event. This is a
// private member and only default because it is used in an inner class (for
// performance reasons)
final TaskQueue m_handoverQueue;
// The thread pool to use to spin-off new threads
private final ThreadPool m_pool;
/**
* The constructor of the class that will use the asynchronous queue to append
* event dispatch handlers. Furthermore, a second queue is used to append
* the events in case that the asynchronous event dispatching thread is used to
* send a synchronous event - in this case the given <tt>ThreadPool</tt> is used
* to spin-off a new asynchronous event dispatching thread while the former waits
* for the synchronous event to be delivered.
*
* @param queue The asynchronous event queue
* @param handoverQueue The synchronous event queue, to be used in case that the
* asynchronous event dispatching thread is used to send a synchronous event
* @param pool The thread pool used to spin-off new asynchronous event
* dispatching threads in case of timeout or that the asynchronous event
* dispatching thread is used to send a synchronous event
*/
public AsyncDeliverTasks(final TaskQueue queue, final TaskQueue handoverQueue,
final ThreadPool pool)
{
m_queue = queue;
m_handoverQueue = handoverQueue;
m_pool = pool;
}
/**
* Return a <tt>DeliverTask</tt> that can be used to execute asynchronous event
* dispatch.
*
* @return A task that can be used to execute asynchronous event dispatch
*
* @see org.apache.felix.eventadmin.impl.tasks.DeliverTasks#createTask()
*/
public DeliverTask createTask()
{
return this;
}
/**
* Execute asynchronous event dispatch.
*
* @param tasks The event dispatch tasks to execute
*
* @see org.apache.felix.eventadmin.impl.tasks.DeliverTask#execute(org.apache.felix.eventadmin.impl.tasks.HandlerTask[])
*/
public void execute(final HandlerTask[] tasks)
{
m_queue.append(tasks);
}
/**
* Execute the handover in case of timeout or that the asynchronous event
* dispatching thread is used to send a synchronous event.
*
* @param task The task to set-up in a new thread
*
* @see org.apache.felix.eventadmin.impl.tasks.HandoverTask#execute(org.apache.felix.eventadmin.impl.tasks.DispatchTask)
*/
public void execute(final DispatchTask task)
{
// This will spin-off a new thread using the thread pool and set it up with
// the given task. Additionally, the thread is associated with a callback
// that will handover (i.e., yet again call this method) and append the
// tasks given to to the m_handoverQueue (i.e., the synchronous queue). This
// will happen in case that the current asynchronous thread is used to
// send a synchronous event.
m_pool.execute(task, new DeliverTask()
{
public void execute(final HandlerTask[] managers)
{
final BlockTask waitManager = new BlockTask();
final HandlerTask[] newmanagers = new HandlerTask[managers.length + 1];
System.arraycopy(managers, 0, newmanagers, 0,
managers.length);
newmanagers[managers.length] = waitManager;
m_handoverQueue.append(newmanagers);
task.handover();
waitManager.block();
}
});
}
}