blob: 3854436a6541f0d811cc075535469b68c6b052af [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 synchronous event delivery.
* <p><tt>
* It serves two purposes, first it is used to select the appropriate action
* depending on whether the sending thread is the asynchronous, the synchronous, or
* an unrelated thread. 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 push given handler tasks to the queue and
* then wait for the tasks to be completed.
* </tt></p>
* In other words if an unrelated thread is used to send a synchronous event it is
* blocked until the event is send (or a timeout occurs), if an asynchronous thread
* is used its handover callback is called in order to spin-off a new asynchronous
* delivery thread and the former is blocked until the events are delivered and then
* released (or returned to its thread pool), if a synchronous thread is used its
* task is disabled, the events are pushed to the queue and the threads continuous
* with the delivery of the new events (as per spec). Once the new events are done
* the thread wakes-up the disabled task and resumes to execute it.
* <p><tt>
* Note that in case of a timeout while a task is disabled the thread is released and
* we spin-off a new thread that resumes the disabled task hence, this is the only
* place were we break the semantics of the synchronous delivery. While the only one
* to notice this is the timed-out handler - it is the fault of this handler too
* (i.e., it blocked the dispatch for to long) but since it will not receive events
* anymore it will not notice this semantic difference except that it might not see
* events it already sent before.
* </tt></pre>
* @author <a href="mailto:felix-dev@incubator.apache.org">Felix Project Team</a>
*/
public class SyncDeliverTasks implements DeliverTasks, HandoverTask, DeliverTask
{
// The synchronous event queue
final TaskQueue m_queue;
// The thread pool used to spin-off new threads and associate callbacks with
// tasks
final ThreadPool m_pool;
/**
* @param queue The synchronous event queue
* @param pool The thread pool used to spin-off new threads and associate
* callbacks with tasks
*/
public SyncDeliverTasks(final TaskQueue queue, final ThreadPool pool)
{
m_queue = queue;
m_pool = pool;
}
/**
* This will select the appropriate action depending on whether the sending
* thread is the asynchronous, the synchronous, or an unrelated thread.
*
* @return The appropriate action
*
* @see org.apache.felix.eventadmin.impl.tasks.DeliverTasks#createTask()
*/
public DeliverTask createTask()
{
return m_pool.getCallback(Thread.currentThread(), this);
}
/**
* This blocks an unrelated thread used to send a synchronous event until the
* event is send (or a timeout occurs).
*
* @param tasks The event handler 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)
{
final BlockTask waitManager = new BlockTask();
final HandlerTask[] newtasks = new HandlerTask[tasks.length + 1];
System.arraycopy(tasks, 0, newtasks, 0, tasks.length);
newtasks[tasks.length] = waitManager;
m_queue.append(newtasks);
waitManager.block();
}
/**
* 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 push given handler tasks to
* the queue and then wait for the tasks to be completed.
*
* @param task The task to set-up
*
* @see org.apache.felix.eventadmin.impl.tasks.HandoverTask#execute(org.apache.felix.eventadmin.impl.tasks.DispatchTask)
*/
public void execute(final DispatchTask task)
{
m_pool.execute(task, new DeliverTask()
{
public void execute(final HandlerTask[] managers)
{
final ResumeTask resumeManager = new ResumeTask(
task, m_pool);
final HandlerTask[] newmanagers = new HandlerTask[managers.length + 1];
System.arraycopy(managers, 0, newmanagers, 0,
managers.length);
newmanagers[managers.length] = resumeManager;
m_queue.push(newmanagers);
task.hold();
}
});
}
}