/* * 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; } }