/*
* org.openmicroscopy.shoola.util.concur.tasks.CmdProcessor
*
*------------------------------------------------------------------------------
* Copyright (C) 2006 University of Dundee. All rights reserved.
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*------------------------------------------------------------------------------
*/
package org.openmicroscopy.shoola.util.concur.tasks;
//Java imports
//Third-party libraries
//Application-internal dependencies
/**
* Exposes the interface to trigger the execution of a service.
* This interface is made up by the different flavors of the <code>exec</code>
* method, which is overloaded to accept a service object (an instance of
* {@link Runnable}, {@link Invocation}, {@link MultiStepTask}, or an
* {@link Invocation} chain) and optionally an {@link ExecMonitor} (to get
* feedback about the execution progress) and/or a {@link ResultAssembler}
* (to provide a specific way to assemble the computatation results from
* partial results).
* <p>This is an abstract class which delegates the service execution to
* subclasses. A concrete subclass encapsulates an execution policy and
* enforces a specific threads management.</p>
* <p>Concrete sublcasses normally execute the service in its own thread, so
* execution is asynchronous with respect to the client thread that called the
* <code>exec</code> method. However, this is not an absolute requirement.
* For example, subclasses could enforce an execution policy by which execution
* takes place in the client thread if no threading resources are available at
* the moment of triggering execution.</p>
*
* @author Jean-Marie Burel
* <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a>
* @author <br>Andrea Falconi
* <a href="mailto:a.falconi@dundee.ac.uk">
* a.falconi@dundee.ac.uk</a>
* @version 2.2
* <small>
* (<b>Internal version:</b> $Revision$ $Date$)
* </small>
* @since OME2.2
*/
public abstract class CmdProcessor
{
/**
* Subclasses have to implement this method in order to execute the
* service.
* Note that the service workflow is completely encapsulated by the
* <code>cmd</code> object, so a subclass will only have to call its
* <code>run</code> method in order to execute the service. However,
* no attempt should ever be made to execute the <code>run</code>
* method twice or by more than one thread an {@link Error}
* would be thrown. A concrete <code>CmdProcessor</code> should also
* check the interrupted status of the executing thread after the
* <code>run</code> method returns as cancellation results in the
* interrupted status being set.
*
* @param cmd Enapsulates the service workflow.
*/
protected abstract void doExec(Runnable cmd);
/**
* Executes the specified <code>task</code>.
*
* @param task The task to execute. Mustn't be <code>null</code>.
* @return An {@link ExecHandle} which can be used to cancel execution.
*/
public ExecHandle exec(Runnable task) { return exec(task, null); }
/**
* Executes the specified <code>task</code>.
*
* @param task The task to execute. Mustn't be <code>null</code>.
* @param observer To get feedback about the execution progress.
* @return An {@link ExecHandle} which can be used to cancel execution.
*/
public ExecHandle exec(Runnable task, ExecMonitor observer)
{
//Adaptation. We need to have a cmd linked to exactly one
//MultiStepTask, ResultAssembler, Future, and ExecMonitor.
MultiStepTask adapter = new TaskAdapter(task);
ResultAssembler nullRA = new NullResultAssembler();
if (observer == null) observer = new NullExecMonitor();
Future execHandle = new NullFuture(); //Not in a legal state yet.
ExecCommand cmd =
new ExecCommand(adapter, nullRA, execHandle, observer);
execHandle.setCommand(cmd); //OK, init completed now (two-step init).
//Transfer command.
doExec(cmd); //Normally executed in a different thread.
//Allow client to cancel execution.
return execHandle;
}
/**
* Executes the specified <code>call</code>.
*
* @param call The call to execute. Mustn't be <code>null</code>.
* @return A {@link Future} to collect the result of the call. It can also
* be used to cancel execution.
*/
public Future exec(Invocation call) { return exec(call, null); }
/**
* Executes the specified <code>call</code>.
*
* @param call The call to execute. Mustn't be <code>null</code>.
* @param observer To get feedback about the execution progress.
* @return A {@link Future} to collect the result of the call. It can also
* be used to cancel execution.
*/
public Future exec(Invocation call, ExecMonitor observer)
{
//Adaptation. We need to have a cmd linked to exactly one
//MultiStepTask, ResultAssembler, Future, and ExecMonitor.
MultiStepTask adapter = new InvocationAdapter(call);
ResultAssembler plainRA = new PlainAssembler();
if (observer == null) observer = new NullExecMonitor();
Future future = new Future(); //Not in a legal state yet.
ExecCommand cmd =
new ExecCommand(adapter, plainRA, future, observer);
future.setCommand(cmd); //OK, init completed now (two-step init).
//Transfer command.
doExec(cmd); //Normally executed in a different thread.
//Allow client to retrieve result and cancel execution.
return future;
}
/**
* Executes the specified {@link Invocation} <code>chain</code>.
* The {@link Invocation} objects that make up the chain are invoked
* following the array order (<code>chain[0]</code>, <code>chain[1]</code>,
* and so on).
*
* @param chain The {@link Invocation} chain to execute. Mustn't be
* <code>null</code> or <code>0</code>-length and none of
* its elements must be <code>null</code> either.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is a {@link java.util.List} whose first element is
* the result of the fisrt call in the chain (<code>chain[0]</code>
* ), the second element is the result of the second call in the
* chain (<code>chain[1]</code>), and so on. The {@link Future}
* object can also be used to cancel execution.
*/
public Future exec(Invocation[] chain)
{
return exec(chain, null, null);
}
/**
* Executes the specified {@link Invocation} <code>chain</code>.
* The {@link Invocation} objects that make up the chain are invoked
* following the array order (<code>chain[0]</code>, <code>chain[1]</code>,
* and so on).
*
* @param chain The {@link Invocation} chain to execute. Mustn't be
* <code>null</code> or <code>0</code>-length and none of
* its elements must be <code>null</code> either.
* @param observer To get feedback about the execution progress.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is a {@link java.util.List} whose first element is
* the result of the fisrt call in the chain (<code>chain[0]</code>
* ), the second element is the result of the second call in the
* chain (<code>chain[1]</code>), and so on. The {@link Future}
* object can also be used to cancel execution.
*/
public Future exec(Invocation[] chain, ExecMonitor observer)
{
return exec(chain, null, observer);
}
/**
* Executes the specified {@link Invocation} <code>chain</code>.
* The {@link Invocation} objects that make up the chain are invoked
* following the array order (<code>chain[0]</code>, <code>chain[1]</code>,
* and so on).
*
* @param chain The {@link Invocation} chain to execute. Mustn't be
* <code>null</code> or <code>0</code>-length and none of
* its elements must be <code>null</code> either.
* @param rAsm To provide a specific way to assemble the computatation
* results from partial results (that is, from the results
* returned by each call in the chain).
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is whatever object was returned by the
* {@link ResultAssembler#assemble() assemble} method of
* <code>rAsm</code>. The {@link Future} object can also be used
* to cancel execution.
*/
public Future exec(Invocation[] chain, ResultAssembler rAsm)
{
return exec(chain, rAsm, null);
}
/**
* Executes the specified {@link Invocation} <code>chain</code>.
* The {@link Invocation} objects that make up the chain are invoked
* following the array order (<code>chain[0]</code>, <code>chain[1]</code>,
* and so on).
*
* @param chain The {@link Invocation} chain to execute. Mustn't be
* <code>null</code> or <code>0</code>-length and none of
* its elements must be <code>null</code> either.
* @param rAsm To provide a specific way to assemble the computatation
* results from partial results (that is, from the results
* returned by each call in the chain).
* @param observer To get feedback about the execution progress.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is whatever object was returned by the
* {@link ResultAssembler#assemble() assemble} method of
* <code>rAsm</code>. The {@link Future} object can also be used
* to cancel execution.
*/
public Future exec(Invocation[] chain, ResultAssembler rAsm,
ExecMonitor observer)
{
//Adaptation. We need to have a cmd linked to exactly one
//MultiStepTask, ResultAssembler, Future, and ExecMonitor.
MultiStepTask adapter = new InvocationChainAdapter(chain);
if (rAsm == null) rAsm = new ListAssembler();
if (observer == null) observer = new NullExecMonitor();
Future future = new Future(); //Not in a legal state yet.
ExecCommand cmd =
new ExecCommand(adapter, rAsm, future, observer);
future.setCommand(cmd); //OK, init completed now (two-step init).
//Transfer command.
doExec(cmd); //Normally executed in a different thread.
//Allow client to retrieve result and cancel execution.
return future;
}
/**
* Executes the specified multi-step <code>task</code>.
* The {@link MultiStepTask#doStep() doStep} method is invoked in a loop
* until the {@link MultiStepTask#isDone() isDone} method returns
* <code>true</code>.
*
* @param task The multi-step task to execute. Mustn't be
* <code>null</code>.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is a {@link java.util.List} whose first element is
* the result of the fisrt step in the computation (that is, the
* first call to the <code>doStep</code> method), the second
* element is the result of the second step in the computation,
* and so on. The {@link Future} object can also be used to
* cancel execution.
*/
public Future exec(MultiStepTask task)
{
return exec(task, null, null);
}
/**
* Executes the specified multi-step <code>task</code>.
* The {@link MultiStepTask#doStep() doStep} method is invoked in a loop
* until the {@link MultiStepTask#isDone() isDone} method returns
* <code>true</code>.
*
* @param task The multi-step task to execute. Mustn't be
* <code>null</code>.
* @param observer To get feedback about the execution progress.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is a {@link java.util.List} whose first element is
* the result of the fisrt step in the computation (that is, the
* first call to the <code>doStep</code> method), the second
* element is the result of the second step in the computation,
* and so on. The {@link Future} object can also be used to
* cancel execution.
*/
public Future exec(MultiStepTask task, ExecMonitor observer)
{
return exec(task, null, observer);
}
/**
* Executes the specified multi-step <code>task</code>.
* The {@link MultiStepTask#doStep() doStep} method is invoked in a loop
* until the {@link MultiStepTask#isDone() isDone} method returns
* <code>true</code>.
*
* @param task The multi-step task to execute. Mustn't be
* <code>null</code>.
* @param rAsm To provide a specific way to assemble the computatation
* results from partial results (that is, from the results
* returned by each call the <code>doStep</code> method).
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is whatever object was returned by the
* {@link ResultAssembler#assemble() assemble} method of
* <code>rAsm</code>. The {@link Future} object can also be used
* to cancel execution.
*/
public Future exec(MultiStepTask task, ResultAssembler rAsm)
{
return exec(task, rAsm, null);
}
/**
* Executes the specified multi-step <code>task</code>.
* The {@link MultiStepTask#doStep() doStep} method is invoked in a loop
* until the {@link MultiStepTask#isDone() isDone} method returns
* <code>true</code>.
*
* @param task The multi-step task to execute. Mustn't be
* <code>null</code>.
* @param rAsm To provide a specific way to assemble the computatation
* results from partial results (that is, from the results
* returned by each call the <code>doStep</code> method).
* @param observer To get feedback about the execution progress.
* @return A {@link Future} to collect the result of the invocation. In
* this case, the object returned by the <code>getResult</code>
* method is whatever object was returned by the
* {@link ResultAssembler#assemble() assemble} method of
* <code>rAsm</code>. The {@link Future} object can also be used
* to cancel execution.
*/
public Future exec(MultiStepTask task, ResultAssembler rAsm,
ExecMonitor observer)
{
if (task == null) throw new NullPointerException("No task.");
//Adaptation. We need to have a cmd linked to exactly one
//MultiStepTask, ResultAssembler, Future, and ExecMonitor.
if (rAsm == null) rAsm = new ListAssembler();
if (observer == null) observer = new NullExecMonitor();
Future future = new Future(); //Not in a legal state yet.
ExecCommand cmd =
new ExecCommand(task, rAsm, future, observer);
future.setCommand(cmd); //OK, init completed now (two-step init).
//Transfer command.
doExec(cmd); //Normally executed in a different thread.
//Allow client to retrieve result and cancel execution.
return future;
}
}