/***************************************************************************** * Copyright (c) 2008 g-Eclipse Consortium * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Moritz Post - initial API and implementation *****************************************************************************/ package eu.geclipse.aws.ec2.op; import java.util.ArrayList; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.FutureTask; import eu.geclipse.aws.ec2.internal.Activator; /** * The {@link OperationExecuter} acts as runner for {@link IOperation} objects. * It takes a single {@link IOperation} or a set of {@link IOperation}s * embedded in a {@link OperationSet} and runs the corresponding * {@link Runnable#run()} method(s). * <p> * When executing an {@link IOperation}, the main thread is forked and the * operation run in its own thread. The same applies to the {@link OperationSet}. * Each contained {@link IOperation} is run in its own thread. To sync op with * the running {@link IOperation} instances, the methods * {@link #execOp(IOperation)} and {@link #execOpGroup(OperationSet)} block * until all contained {@link IOperation} objects have terminated (naturally or * unnaturally). * <p> * The implementation is thread safe and can be reused after its initial * invocation. * <p> * TODO: Refactor the implementation of the operation infrastructure to make use * of the <code>java.util.concurrent</code> package. Especially the * {@link FutureTask}, the {@link ExecutorService} and the * {@link CyclicBarrier}. * * @author Moritz Post * @see IOperation */ public class OperationExecuter { /** The list of currently managed threads. */ private ArrayList<Thread> threadList; /** * Executes the {@link Runnable#run()} method of the given {@link IOperation} * in its own Thread and blocks until the execution is complete. * * @param op the {@link IOperation} to run * @return the {@link IOperation} which has been passed into this method */ public synchronized IOperation execOp( final IOperation op ) { this.threadList = new ArrayList<Thread>(); exec( op ); waitForOp(); this.threadList.clear(); return op; } /** * Executes the {@link Runnable#run()} method of the given {@link IOperation} * instances contained within the passed {@link OperationSet}. * * @param opGroup the {@link OperationSet} containing the {@link IOperation}s * to run * @return the {@link OperationSet} which has been passed into this method */ public synchronized OperationSet execOpGroup( final OperationSet opGroup ) { this.threadList = new ArrayList<Thread>(); for( IOperation op : opGroup.getOps() ) { exec( op ); } waitForOp(); this.threadList.clear(); return opGroup; } /** * Creates a new {@link Thread} which in turn invokes the * {@link Runnable#run()} method of the {@link IOperation} provided. * * @param op the {@link IOperation} to run */ private void exec( final IOperation op ) { Thread thread = new Thread( op, op.getClass().getName() ); thread.run(); this.threadList.add( thread ); } /** * Calls {@link Thread#join()} on any thread in the {@link #threadList} * managed by this {@link OperationExecuter}. */ private void waitForOp() { for( Thread thread : this.threadList ) { try { thread.join(); } catch( InterruptedException interruptedExc ) { Activator.log( "Interrupted while waiting for Operation on " + thread.getName(), //$NON-NLS-1$ interruptedExc ); } } } }