diff options
Diffstat (limited to 'common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/synchronizers/SynchronousSynchronizer.java')
-rw-r--r-- | common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/synchronizers/SynchronousSynchronizer.java | 263 |
1 files changed, 0 insertions, 263 deletions
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/synchronizers/SynchronousSynchronizer.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/synchronizers/SynchronousSynchronizer.java deleted file mode 100644 index 7a232f6c0b..0000000000 --- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/synchronizers/SynchronousSynchronizer.java +++ /dev/null @@ -1,263 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008, 2010 Oracle. 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. - * - * Contributors: - * Oracle - initial API and implementation - ******************************************************************************/ -package org.eclipse.jpt.common.utility.internal.synchronizers; - -import java.util.Vector; -import org.eclipse.jpt.common.utility.Command; -import org.eclipse.jpt.common.utility.internal.CompositeException; -import org.eclipse.jpt.common.utility.internal.StringTools; -import org.eclipse.jpt.common.utility.internal.SynchronizedObject; -import org.eclipse.jpt.common.utility.synchronizers.Synchronizer; - -/** - * This synchronizer will synchronize immediately and not return until the - * synchronization and any nested (recursive) synchronizations are complete. - * In some situations this implementation should be used sparingly, and for as - * short a time as possible, as it increases the probability of deadlocks. A - * deadlock can occur when {@link Synchronizer#synchronize()} is called from multiple - * threads and multiple resources are locked by the synchronization in varying - * orders. - * <p> - * As defined in the {@link Synchronizer} interface, {@link Synchronizer#start()} - * and {@link Synchronizer#stop()} - * should be called in the same thread, but it is not required. - * {@link Synchronizer#synchronize()} should - * always be called in the same thread (i.e. only recursively, beyond the - * initial call); although, this too is not required. - * This thread need not be the same thread that executes - * {@link Synchronizer#start()} and {@link Synchronizer#stop()}. - */ -public class SynchronousSynchronizer - implements Synchronizer -{ - /** - * The client-supplied command that performs the synchronization. It may - * trigger further calls to {@link #synchronize()} (i.e. the - * synchronization may recurse). - */ - private final Command command; - - /** - * The synchronizer's current state. - */ - final SynchronizedObject<State> state; - - /** - * The synchronizer's initial state is {@link #STOPPED}. - */ - enum State { - STOPPED, - READY, - EXECUTING, - REPEAT, - STOPPING - } - - /** - * A list of the uncaught exceptions thrown by the command. - */ - final Vector<Throwable> exceptions = new Vector<Throwable>(); - - - // ********** construction ********** - - /** - * Construct a synchronous synchronizer that uses the specified command to - * perform the synchronization. - */ - public SynchronousSynchronizer(Command command) { - super(); - if (command == null) { - throw new NullPointerException(); - } - this.command = command; - // use the synchronizer as the mutex so it is freed up by the wait in #stop() - this.state = new SynchronizedObject<State>(State.STOPPED, this); - } - - - // ********** Synchronizer implementation ********** - - /** - * Set the synchronizer's {@link #state} to {@link State#READY READY} - * and execute the first synchronization. Throw an exception if the - * synchronizer is not {@link State#STOPPED STOPPED}. - */ - public synchronized void start() { - switch (this.state.getValue()) { - case STOPPED: - this.state.setValue(State.READY); - this.synchronize(); - break; - case READY: - case EXECUTING: - case REPEAT: - case STOPPING: - default: - throw this.buildIllegalStateException(); - } - } - - /** - * It's possible to come back here if the synchronization command recurses - * and triggers another synchronization. - */ - public void synchronize() { - if (this.beginSynchronization()) { - this.synchronize_(); - } - } - - /** - * A client has requested a synchronization. - * Return whether we can begin a new synchronization. - * If a synchronization is already under way, return <code>false</code>; - * but set the {@link #state} to {@link State#REPEAT REPEAT} - * so another synchronization will occur once the current - * synchronization is complete. - */ - private synchronized boolean beginSynchronization() { - switch (this.state.getValue()) { - case STOPPED: - // synchronization is not allowed - return false; - case READY: - // begin a new synchronization - this.state.setValue(State.EXECUTING); - return true; - case EXECUTING: - // set flag so a new synchronization will occur once the current one is finished - this.state.setValue(State.REPEAT); - return false; - case REPEAT: - // the "repeat" flag is already set - return false; - case STOPPING: - // no further synchronizations are allowed - return false; - default: - throw this.buildIllegalStateException(); - } - } - - /** - * This method should be called only once per set of "recursing" - * synchronizations. Any recursive call to {@link #synchronize()} will - * simply set the {@link #state} to {@link State#REPEAT REPEAT}, - * causing the command to execute again. - */ - private void synchronize_() { - do { - this.execute(); - } while (this.repeatSynchronization()); - } - - /** - * Execute the client-supplied command. Do not allow any unhandled - * exceptions to kill the thread. Store them up for later pain. - */ - private void execute() { - try { - this.execute_(); - } catch (Throwable ex) { - this.exceptions.add(ex); - } - } - - /** - * By default, just execute the command. - */ - void execute_() { - this.command.execute(); - } - - /** - * The current synchronization has finished. - * Return whether we should begin another synchronization. - */ - private synchronized boolean repeatSynchronization() { - switch (this.state.getValue()) { - case STOPPED: - case READY: - throw this.buildIllegalStateException(); - case EXECUTING: - // synchronization has finished and there are no outstanding requests for another; return to "ready" - this.state.setValue(State.READY); - return false; - case REPEAT: - // the "repeat" flag was set; clear it and start another synchronization - this.state.setValue(State.EXECUTING); - return true; - case STOPPING: - // a client has initiated a "stop"; mark the "stop" complete and perform no more synchronizations - this.state.setValue(State.STOPPED); - return false; - default: - throw this.buildIllegalStateException(); - } - } - - /** - * Set the flags so that no further synchronizations occur. If any uncaught - * exceptions were thrown while the synchronization was executing, - * wrap them in a composite exception and throw the composite exception. - */ - public synchronized void stop() { - switch (this.state.getValue()) { - case STOPPED: - throw this.buildIllegalStateException(); - case READY: - // simply return to "stopped" state - this.state.setValue(State.STOPPED); - break; - case EXECUTING: - case REPEAT: - // set the "stopping" flag and wait until the synchronization has finished - this.state.setValue(State.STOPPING); - this.waitUntilStopped(); - break; - case STOPPING: - throw this.buildIllegalStateException(); - default: - throw this.buildIllegalStateException(); - } - - if (this.exceptions.size() > 0) { - Throwable[] temp = this.exceptions.toArray(new Throwable[this.exceptions.size()]); - this.exceptions.clear(); - throw new CompositeException(temp); - } - } - - /** - * This wait will free up the synchronizer's synchronized methods - * (since the synchronizer is the state's mutex). - */ - private void waitUntilStopped() { - try { - this.state.waitUntilValueIs(State.STOPPED); - } catch (InterruptedException ex) { - // the thread that called #stop() was interrupted while waiting - // for the synchronization to finish - ignore; - // 'state' is still set to 'STOPPING', so the #synchronize_() loop - // will still stop - we just won't wait around for it... - } - } - - private IllegalStateException buildIllegalStateException() { - return new IllegalStateException("state: " + this.state); //$NON-NLS-1$ - } - - @Override - public String toString() { - return StringTools.buildToStringFor(this, this.state); - } - -} |