Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.utility')
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java164
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java39
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java225
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java75
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java65
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java90
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java15
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java11
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java33
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java348
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java142
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java149
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java29
18 files changed, 1460 insertions, 194 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java
new file mode 100644
index 0000000000..00baa2efd0
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * This command executor will dispatch commands to be executed in a separate
+ * thread, allowing calls to {@link CommandExecutor#execute(Command)} to return
+ * immediately.
+ * <p>
+ * <strong>NB:</strong> The client-supplied commands should handle any
+ * exception appropriately (e.g. log the exception and return gracefully) so
+ * the command execution thread can continue executing.
+ */
+public class AsynchronousCommandExecutor
+ implements CallbackStatefulCommandExecutor
+{
+ /**
+ * This command queue is shared with the command execution/consumer thread.
+ * Adding a command to it will trigger the command to be executed by the
+ * command execution thread or, if another command is currently executing,
+ * to execute the new command once the currently executing command has
+ * finished executing.
+ */
+ final SynchronizedQueue<Command> commands = new SynchronizedQueue<Command>();
+
+ /**
+ * Most of the thread-related behavior is delegated to this coordinator.
+ */
+ private final ConsumerThreadCoordinator consumerThreadCoordinator;
+
+ private final ListenerList<Listener> listenerList = new ListenerList<Listener>(Listener.class);
+
+
+ // ********** construction **********
+
+ /**
+ * Construct an asynchronous command executor.
+ * Allow the command execution thread(s) to be assigned JDK-generated names.
+ */
+ public AsynchronousCommandExecutor() {
+ this(null);
+ }
+
+ /**
+ * Construct an asynchronous command executor.
+ * Assign the command execution thread(s) the specified name.
+ */
+ public AsynchronousCommandExecutor(String threadName) {
+ super();
+ this.consumerThreadCoordinator = new ConsumerThreadCoordinator(this.buildConsumer(), threadName);
+ }
+
+ private ConsumerThreadCoordinator.Consumer buildConsumer() {
+ return new Consumer();
+ }
+
+
+ // ********** CallbackStatefulCommandExecutor implementation **********
+
+ /**
+ * Build and start the command execution/consumer thread.
+ * <p>
+ * Note: We don't clear the command queue here; so if a command has been
+ * added to the queue <em>before</em> getting here, the first command will
+ * be executed promptly (albeit, asynchronously).
+ * The command queue will be non-empty if:<ul>
+ * <li>{@link #execute(Command)} was called after the command executor was
+ * constructed but before {@link #start()} was called; or
+ * <li>{@link #execute(Command)} was called after {@link #stop()} was called
+ * but before {@link #start()} was called (to restart the command executor); or
+ * <li>{@link #stop()} was called when there were still outstanding commands
+ * remaining in the command queue
+ * </ul>
+ */
+ public void start() {
+ this.consumerThreadCoordinator.start();
+ }
+
+ /**
+ * Put the specified command on the command queue, to be consumed by the
+ * command execution thread.
+ */
+ public void execute(Command command) {
+ this.commands.enqueue(command);
+ }
+
+ /**
+ * Interrupt the command execution thread so that it stops executing at the
+ * end of the current command. Suspend the current thread until
+ * the command execution thread is finished executing. If any uncaught
+ * exceptions were thrown while the execution thread was executing,
+ * wrap them in a composite exception and throw the composite exception.
+ */
+ public void stop() {
+ this.consumerThreadCoordinator.stop();
+ }
+
+ public void addListener(Listener listener) {
+ this.listenerList.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ this.listenerList.remove(listener);
+ }
+
+ /**
+ * Notify our listeners.
+ */
+ /* private */ void commandExecuted(Command command) {
+ for (Listener listener : this.listenerList.getListeners()) {
+ listener.commandExecuted(command);
+ }
+ }
+
+
+ // ********** consumer **********
+
+ /**
+ * This implementation of {@link ConsumerThreadCoordinator.Consumer}
+ * will execute the commands enqueued by the asynchronous command executor.
+ * It will wait until the shared command queue is non-empty to begin executing the
+ * commands in the queue. Once a comand is executed, the thread will quiesce until
+ * another command is placed in the command queue. If a new command is
+ * enqueued during the execution of another command (either recursively by
+ * the command itself or by another thread),
+ * the new command will be executed immediately after the currently
+ * executing command is finished.
+ * Stop the thread by calling {@link Thread#interrupt()}.
+ */
+ class Consumer
+ implements ConsumerThreadCoordinator.Consumer
+ {
+ Consumer() {
+ super();
+ }
+
+ /**
+ * Wait until a command has been placed in the queue.
+ */
+ public void waitForProducer() throws InterruptedException {
+ AsynchronousCommandExecutor.this.commands.waitUntilNotEmpty();
+ }
+
+ /**
+ * Execute the first command in the queue and notify our listeners.
+ */
+ public void execute() {
+ Command command = AsynchronousCommandExecutor.this.commands.dequeue();
+ command.execute();
+ AsynchronousCommandExecutor.this.commandExecuted(command);
+ }
+
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java
new file mode 100644
index 0000000000..d9fb9a1c6b
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import java.util.EventListener;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * This command executor notifies clients commands are executed.
+ */
+public interface CallbackStatefulCommandExecutor
+ extends StatefulCommandExecutor
+{
+ /**
+ * Add the specified listener to be notified whenever a command has been
+ * executed.
+ * @see #removeListener(Listener)
+ */
+ void addListener(Listener listener);
+
+ /**
+ * Remove the specified listener.
+ * @see #addListener(Listener)
+ */
+ void removeListener(Listener listener);
+
+
+ // ********** listener **********
+
+ /**
+ * Interface implemented by listeners to be notified whenever a
+ * command is executed.
+ */
+ public interface Listener
+ extends EventListener
+ {
+ /**
+ * The specified command was executed.
+ */
+ void commandExecuted(Command command);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java
new file mode 100644
index 0000000000..ff603eb0b7
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * <code>CompositeCommand</code> provides support for treating a collection of
+ * {@link Command}s as a single command.
+ */
+public class CompositeCommand
+ implements Command
+{
+ private final Iterable<Command> commands;
+
+ public CompositeCommand(Iterable<Command> commands) {
+ super();
+ this.commands = commands;
+ }
+
+ public void execute() {
+ for (Command command : this.commands) {
+ command.execute();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.commands);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java
new file mode 100644
index 0000000000..abc9e71456
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import java.util.Vector;
+
+/**
+ * A <code>ConsumerThreadCoordinator</code> controls the creation,
+ * starting, and stopping of a general purpose "consumer" thread. Construct
+ * the coordinator with a {@link Consumer} that both waits for the producer
+ * to "produce" something to "consume" and, once the wait is over,
+ * "consumes" whatever is available.
+ * <p>
+ * <strong>NB:</strong> The client-supplied consumer should handle any
+ * exception appropriately (e.g. log the exception and return gracefully) so
+ * the thread can continue executing.
+ */
+public class ConsumerThreadCoordinator {
+ /**
+ * The runnable passed to the consumer thread each time it is built.
+ */
+ private final Runnable runnable;
+
+ /**
+ * Optional, client-supplied name for the consumer thread.
+ * If null, the JDK assigns a name.
+ */
+ private final String threadName;
+
+ /**
+ * The consumer is executed on this thread. A new thread is built
+ * for every start/stop cycle (since a thread cannot be started more than
+ * once).
+ */
+ private volatile Thread thread;
+
+ /**
+ * A list of the uncaught exceptions thrown by the consumer
+ * during the current start/stop cycle.
+ */
+ final Vector<Throwable> exceptions = new Vector<Throwable>();
+
+
+ // ********** construction **********
+
+ /**
+ * Construct a consumer thread coordinator for the specified consumer.
+ * Allow the consumer thread(s) to be assigned JDK-generated names.
+ */
+ public ConsumerThreadCoordinator(Consumer consumer) {
+ this(consumer, null);
+ }
+
+ /**
+ * Construct a consumer thread coordinator for the specified consumer.
+ * Assign the consumer thread(s) the specified name.
+ */
+ public ConsumerThreadCoordinator(Consumer consumer, String threadName) {
+ super();
+ this.runnable = this.buildRunnable(consumer);
+ this.threadName = threadName;
+ }
+
+ private Runnable buildRunnable(Consumer consumer) {
+ return new RunnableConsumer(consumer);
+ }
+
+
+ // ********** Lifecycle support **********
+
+ /**
+ * Build and start the consumer thread.
+ */
+ public synchronized void start() {
+ if (this.thread != null) {
+ throw new IllegalStateException("Not stopped."); //$NON-NLS-1$
+ }
+ this.thread = this.buildThread();
+ this.thread.start();
+ }
+
+ private Thread buildThread() {
+ Thread t = new Thread(this.runnable);
+ if (this.threadName != null) {
+ t.setName(this.threadName);
+ }
+ return t;
+ }
+
+ /**
+ * Interrupt the consumer thread so that it stops executing at the
+ * end of its current iteration. Suspend the current thread until
+ * the consumer thread is finished executing. If any uncaught
+ * exceptions were thrown while the consumer thread was executing,
+ * wrap them in a composite exception and throw the composite exception.
+ */
+ public synchronized void stop() {
+ if (this.thread == null) {
+ throw new IllegalStateException("Not started."); //$NON-NLS-1$
+ }
+ this.thread.interrupt();
+ try {
+ this.thread.join();
+ } catch (InterruptedException ex) {
+ // the thread that called #stop() was interrupted while waiting to
+ // join the consumer thread - ignore;
+ // 'thread' is still "interrupted", so its #run() loop will still stop
+ // after its current execution - we just won't wait around for it...
+ }
+ this.thread = null;
+
+ if (this.exceptions.size() > 0) {
+ Throwable[] temp = this.exceptions.toArray(new Throwable[this.exceptions.size()]);
+ this.exceptions.clear();
+ throw new CompositeException(temp);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.thread);
+ }
+
+
+ // ********** consumer thread runnable **********
+
+ /**
+ * This implementation of {@link Runnable} is a long-running consumer that
+ * will repeatedly execute the consumer {@link Consumer#execute()} method.
+ * With each iteration, the consumer thread will wait
+ * until the other consumer method, {@link Consumer#waitForProducer()}, allows the
+ * consumer thread to proceed (i.e. there is something for the consumer to
+ * consume). Once {@link Consumer#execute()} is finished, the thread will quiesce
+ * until {@link Consumer#waitForProducer()} returns again.
+ * Stop the thread by calling {@link Thread#interrupt()}.
+ */
+ private class RunnableConsumer
+ implements Runnable
+ {
+ /**
+ * Client-supplied consumer that controls waiting for something to consume
+ * and the consuming itself.
+ */
+ private final Consumer consumer;
+
+ RunnableConsumer(Consumer consumer) {
+ super();
+ this.consumer = consumer;
+ }
+
+ /**
+ * Loop while this thread has not been interrupted by another thread.
+ * In each loop: Pause execution until {@link Consumer#waitForProducer()}
+ * allows us to proceed.
+ * <p>
+ * If this thread is interrupted <em>during</em> {@link Consumer#execute()},
+ * the call to {@link Thread#interrupted()} will stop the loop. If this thread is
+ * interrupted during the call to {@link Consumer#waitForProducer()},
+ * we will catch the {@link InterruptedException} and stop the loop also.
+ */
+ public void run() {
+ while ( ! Thread.interrupted()) {
+ try {
+ this.consumer.waitForProducer();
+ } catch (InterruptedException ex) {
+ // we were interrupted while waiting, must be Quittin' Time
+ return;
+ }
+ this.execute();
+ }
+ }
+
+ /**
+ * Execute the consumer {@link Consumer#execute()} method.
+ * Do not allow any unhandled exceptions to kill the thread.
+ * Store them up for later pain.
+ * @see ConsumerThreadCoordinator#stop()
+ */
+ private void execute() {
+ try {
+ this.execute_();
+ } catch (Throwable ex) {
+ ConsumerThreadCoordinator.this.exceptions.add(ex);
+ }
+ }
+
+ /**
+ * Subclass-implemented behavior: consume stuff.
+ */
+ private void execute_() {
+ this.consumer.execute();
+ }
+
+ }
+
+
+ // ********** consumer interface **********
+
+ /**
+ * Interface implemented by clients that controls:<ul>
+ * <li>when the consumer thread suspends, waiting for something to consume
+ * <li>the consuming of whatever is being produced
+ * </ul>
+ */
+ public interface Consumer {
+ /**
+ * Wait for something to consume.
+ * Throw an {@link InterruptedException} if the thread is interrupted.
+ */
+ void waitForProducer() throws InterruptedException;
+
+ /**
+ * Consume whatever is currently available.
+ */
+ void execute();
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java
new file mode 100644
index 0000000000..cf9b1f8b25
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+/**
+ * Interface defining the classic queue behavior,
+ * without the backdoors allowed by {@link java.util.Queue}.
+ *
+ * @param <E> the type of elements contained by the queue
+ */
+public interface Queue<E> {
+
+ /**
+ * "Enqueue" the specified item to the tail of the queue.
+ */
+ void enqueue(E o);
+
+ /**
+ * "Dequeue" an item from the head of the queue.
+ */
+ E dequeue();
+
+ /**
+ * Return the item on the head of the queue
+ * without removing it from the queue.
+ */
+ E peek();
+
+ /**
+ * Return whether the queue is empty.
+ */
+ boolean isEmpty();
+
+
+ final class Empty<E> implements Queue<E>, Serializable {
+ @SuppressWarnings("unchecked")
+ public static final Queue INSTANCE = new Empty();
+ @SuppressWarnings("unchecked")
+ public static <T> Queue<T> instance() {
+ return INSTANCE;
+ }
+ // ensure single instance
+ private Empty() {
+ super();
+ }
+ public void enqueue(E o) {
+ throw new UnsupportedOperationException();
+ }
+ public E dequeue() {
+ throw new NoSuchElementException();
+ }
+ public E peek() {
+ throw new NoSuchElementException();
+ }
+ public boolean isEmpty() {
+ return true;
+ }
+ private static final long serialVersionUID = 1L;
+ private Object readResolve() {
+ // replace this object with the singleton
+ return INSTANCE;
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java
new file mode 100644
index 0000000000..de883b3e8b
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * Straightforward implementation of {@link CallbackStatefulCommandExecutor}.
+ */
+public class SimpleCommandExecutor
+ implements CallbackStatefulCommandExecutor
+{
+ private boolean active = false;
+ private final ListenerList<Listener> listenerList = new ListenerList<Listener>(Listener.class);
+
+ public SimpleCommandExecutor() {
+ super();
+ }
+
+ public void start() {
+ if (this.active) {
+ throw new IllegalStateException("Not stopped."); //$NON-NLS-1$
+ }
+ this.active = true;
+ }
+
+ public void execute(Command command) {
+ if (this.active) {
+ command.execute();
+ this.commandExecuted(command);
+ }
+ }
+
+ public void stop() {
+ if ( ! this.active) {
+ throw new IllegalStateException("Not started."); //$NON-NLS-1$
+ }
+ this.active = false;
+ }
+
+ public void addListener(Listener listener) {
+ this.listenerList.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ this.listenerList.remove(listener);
+ }
+
+ /**
+ * Notify our listeners.
+ */
+ private void commandExecuted(Command command) {
+ for (Listener listener : this.listenerList.getListeners()) {
+ listener.commandExecuted(command);
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java
new file mode 100644
index 0000000000..89a73e1454
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * Straightforward implementation of the {@link Queue} interface.
+ */
+public class SimpleQueue<E>
+ implements Queue<E>, Cloneable, Serializable
+{
+ private LinkedList<E> elements;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct an empty queue.
+ */
+ public SimpleQueue() {
+ super();
+ this.elements = new LinkedList<E>();
+ }
+
+ /**
+ * Construct a queue containing the elements of the specified
+ * collection. The queue will dequeue its elements in the same
+ * order they are returned by the collection's iterator (i.e. the
+ * first element returned by the collection's iterator will be the
+ * first element returned by {@link #dequeue()}).
+ */
+ public SimpleQueue(Collection<? extends E> c) {
+ super();
+ this.elements = new LinkedList<E>(c);
+ }
+
+
+ // ********** Queue implementation **********
+
+ public void enqueue(E o) {
+ this.elements.addLast(o);
+ }
+
+ public E dequeue() {
+ return this.elements.removeFirst();
+ }
+
+ public E peek() {
+ return this.elements.getFirst();
+ }
+
+ public boolean isEmpty() {
+ return this.elements.isEmpty();
+ }
+
+
+ // ********** Cloneable implementation **********
+
+ @Override
+ public SimpleQueue<E> clone() {
+ try {
+ @SuppressWarnings("unchecked")
+ SimpleQueue<E> clone = (SimpleQueue<E>) super.clone();
+ @SuppressWarnings("unchecked")
+ LinkedList<E> ll = (LinkedList<E>) this.elements.clone();
+ clone.elements = ll;
+ return clone;
+ } catch (CloneNotSupportedException ex) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.peek());
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
index 5df2f99e40..ffdea0c519 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
@@ -43,16 +43,16 @@ public class SimpleStack<E>
* last element returned by the collection's iterator will be the
* first element returned by {@link #pop()}).
*/
- public SimpleStack(Collection<? extends E> c) {
+ public SimpleStack(Collection<? extends E> collection) {
super();
- this.elements = new LinkedList<E>(c);
+ this.elements = new LinkedList<E>(collection);
}
// ********** Stack implementation **********
- public void push(E o) {
- this.elements.addLast(o);
+ public void push(E element) {
+ this.elements.addLast(element);
}
public E pop() {
@@ -76,7 +76,7 @@ public class SimpleStack<E>
}
- // ********** Cloneable implementation **********
+ // ********** standard methods **********
@Override
public SimpleStack<E> clone() {
@@ -92,4 +92,9 @@ public class SimpleStack<E>
}
}
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.peek());
+ }
+
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
index 4c3ac1bca6..50ba19877a 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2009 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.
@@ -14,15 +14,16 @@ import java.util.EmptyStackException;
/**
* Interface defining the classic stack behavior,
- * without the backdoors allowed by java.util.Stack.
- * E is the type of elements contained by the Stack.
+ * without the backdoors allowed by {@link java.util.Stack}.
+ *
+ * @param <E> the type of elements contained by the stack
*/
public interface Stack<E> {
/**
* "Push" the specified item on to the top of the stack.
*/
- void push(E o);
+ void push(E element);
/**
* "Pop" an item from the top of the stack.
@@ -52,7 +53,7 @@ public interface Stack<E> {
private Empty() {
super();
}
- public void push(E o) {
+ public void push(E element) {
throw new UnsupportedOperationException();
}
public E pop() {
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java
new file mode 100644
index 0000000000..d4fd37a110
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import org.eclipse.jpt.utility.CommandExecutor;
+
+/**
+ * This interface allows clients to control how a command is executed.
+ * This is useful when the server provides the command but the client provides
+ * the context (e.g. the client would like to dispatch the command to the UI
+ * thread).
+ */
+public interface StatefulCommandExecutor
+ extends CommandExecutor
+{
+ /**
+ * Start the command executor.
+ */
+ void start();
+
+ /**
+ * Stop the command executor.
+ */
+ void stop();
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java
new file mode 100644
index 0000000000..c35a4aa133
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * Thread-safe implementation of the {@link Queue} interface.
+ * This also provides protocol for suspending a thread until the
+ * queue is empty or not empty, with optional time-outs.
+ */
+public class SynchronizedQueue<E>
+ implements Queue<E>, Serializable
+{
+ /** Backing queue. */
+ private final Queue<E> queue;
+
+ /** Object to synchronize on. */
+ private final Object mutex;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a synchronized queue that wraps the
+ * specified queue and locks on the specified mutex.
+ */
+ public SynchronizedQueue(Queue<E> queue, Object mutex) {
+ super();
+ if (queue == null) {
+ throw new NullPointerException();
+ }
+ this.queue = queue;
+ this.mutex = mutex;
+ }
+
+ /**
+ * Construct a synchronized queue that wraps the
+ * specified queue and locks on itself.
+ */
+ public SynchronizedQueue(Queue<E> queue) {
+ super();
+ if (queue == null) {
+ throw new NullPointerException();
+ }
+ this.queue = queue;
+ this.mutex = this;
+ }
+
+ /**
+ * Construct an empty synchronized queue that locks on the specified mutex.
+ */
+ public SynchronizedQueue(Object mutex) {
+ this(new SimpleQueue<E>(), mutex);
+ }
+
+ /**
+ * Construct an empty synchronized queue that locks on itself.
+ */
+ public SynchronizedQueue() {
+ this(new SimpleQueue<E>());
+ }
+
+
+ // ********** Queue implementation **********
+
+ public void enqueue(E element) {
+ synchronized (this.mutex) {
+ this.enqueue_(element);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void enqueue_(E element) {
+ this.queue.enqueue(element);
+ this.mutex.notifyAll();
+ }
+
+ public E dequeue() {
+ synchronized (this.mutex) {
+ return this.dequeue_();
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private E dequeue_() {
+ E element = this.queue.dequeue();
+ this.mutex.notifyAll();
+ return element;
+ }
+
+ public E peek() {
+ synchronized (this.mutex) {
+ return this.queue.peek();
+ }
+ }
+
+ public boolean isEmpty() {
+ synchronized (this.mutex) {
+ return this.queue.isEmpty();
+ }
+ }
+
+
+ // ********** indefinite waits **********
+
+ /**
+ * Suspend the current thread until the queue's empty status changes
+ * to the specified value.
+ */
+ public void waitUntilEmptyIs(boolean empty) throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(empty);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void waitUntilEmptyIs_(boolean empty) throws InterruptedException {
+ while (this.queue.isEmpty() != empty) {
+ this.mutex.wait();
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty.
+ */
+ public void waitUntilEmpty() throws InterruptedException {
+ this.waitUntilEmptyIs(true);
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it.
+ */
+ public void waitUntilNotEmpty() throws InterruptedException {
+ this.waitUntilEmptyIs(false);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty,
+ * then "enqueue" the specified item to the tail of the queue
+ * and continue executing.
+ */
+ public void waitToEnqueue(E element) throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(true);
+ this.enqueue_(element);
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it,
+ * then "dequeue" an item from the head of the queue and return it.
+ */
+ public Object waitToDequeue() throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(false);
+ return this.dequeue_();
+ }
+ }
+
+
+ // ********** timed waits **********
+
+ /**
+ * Suspend the current thread until the queue's empty status changes
+ * to the specified value or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the specified
+ * empty status was achieved; return <code>false</code> if a time-out occurred.
+ * If the queue's empty status is already the specified value,
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilEmptyIs(boolean empty, long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ return this.waitUntilEmptyIs_(empty, timeout);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private boolean waitUntilEmptyIs_(boolean empty, long timeout) throws InterruptedException {
+ if (timeout == 0L) {
+ this.waitUntilEmptyIs_(empty); // wait indefinitely until notified
+ return true; // if it ever comes back, the condition was met
+ }
+
+ long stop = System.currentTimeMillis() + timeout;
+ long remaining = timeout;
+ while ((this.queue.isEmpty() != empty) && (remaining > 0L)) {
+ this.mutex.wait(remaining);
+ remaining = stop - System.currentTimeMillis();
+ }
+ return (this.queue.isEmpty() == empty);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty
+ * or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the queue is empty; return <code>false</code> if a time-out occurred.
+ * If the queue is already empty, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilEmpty(long timeout) throws InterruptedException {
+ return this.waitUntilEmptyIs(true, timeout);
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it.
+ * or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the queue is not empty; return <code>false</code> if a time-out occurred.
+ * If the queue already has something on it, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilNotEmpty(long timeout) throws InterruptedException {
+ return this.waitUntilEmptyIs(false, timeout);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty,
+ * then "enqueue" the specified item to the tail of the queue
+ * and continue executing. If the queue is not emptied out
+ * before the time-out, simply continue executing without
+ * "enqueueing" the item.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the
+ * item was enqueued; return <code>false</code> if a time-out occurred.
+ * If the queue is already empty, "enqueue" the specified item and
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitToEnqueue(E element, long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ boolean success = this.waitUntilEmptyIs_(true, timeout);
+ if (success) {
+ this.enqueue_(element);
+ }
+ return success;
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it,
+ * then "dequeue" an item from the head of the queue and return it.
+ * If the queue is empty and nothing is "enqueued" on to it before the
+ * time-out, throw a no such element exception.
+ * The time-out is specified in milliseconds.
+ * If the queue is not empty, "dequeue" an item and
+ * return it immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public Object waitToDequeue(long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ boolean success = this.waitUntilEmptyIs_(false, timeout);
+ if (success) {
+ return this.dequeue_();
+ }
+ throw new NoSuchElementException();
+ }
+ }
+
+
+ // ********** synchronized behavior **********
+
+ /**
+ * If the current thread is not interrupted, execute the specified command
+ * with the mutex locked. This is useful for initializing the queue in another
+ * thread.
+ */
+ public void execute(Command command) throws InterruptedException {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ synchronized (this.mutex) {
+ command.execute();
+ }
+ }
+
+
+ // ********** additional public protocol **********
+
+ /**
+ * "Drain" all the current items from the queue into specified queue.
+ */
+ public void drainTo(Queue<E> q) {
+ synchronized (this.mutex) {
+ this.drainTo_(q);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void drainTo_(Queue<E> q) {
+ boolean changed = false;
+ while ( ! this.queue.isEmpty()) {
+ q.enqueue(this.queue.dequeue());
+ changed = true;
+ }
+ if (changed) {
+ this.mutex.notifyAll();
+ }
+ }
+
+ /**
+ * Return the object the queue locks on while performing
+ * its operations.
+ */
+ public Object getMutex() {
+ return this.mutex;
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ synchronized (this.mutex) {
+ return '[' + this.queue.toString() + ']';
+ }
+ }
+
+ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+ synchronized (this.mutex) {
+ s.defaultWriteObject();
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
index 1b0b9f33d9..dc0a4dce1b 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
@@ -11,6 +11,7 @@ package org.eclipse.jpt.utility.internal;
import java.io.Serializable;
import java.util.EmptyStackException;
+
import org.eclipse.jpt.utility.Command;
/**
@@ -59,14 +60,14 @@ public class SynchronizedStack<E>
}
/**
- * Construct a synchronized stack that locks on the specified mutex.
+ * Construct an empty synchronized stack that locks on the specified mutex.
*/
public SynchronizedStack(Object mutex) {
this(new SimpleStack<E>(), mutex);
}
/**
- * Construct a synchronized stack that locks on itself.
+ * Construct an empty synchronized stack that locks on itself.
*/
public SynchronizedStack() {
this(new SimpleStack<E>());
@@ -75,21 +76,35 @@ public class SynchronizedStack<E>
// ********** Stack implementation **********
- public void push(E o) {
+ public void push(E element) {
synchronized (this.mutex) {
- this.stack.push(o);
- this.mutex.notifyAll();
+ this.push_(element);
}
}
+ /**
+ * Pre-condition: synchronized
+ */
+ private void push_(E element) {
+ this.stack.push(element);
+ this.mutex.notifyAll();
+ }
+
public E pop() {
synchronized (this.mutex) {
- E o = this.stack.pop();
- this.mutex.notifyAll();
- return o;
+ return this.pop_();
}
}
+ /**
+ * Pre-condition: synchronized
+ */
+ private E pop_() {
+ E o = this.stack.pop();
+ this.mutex.notifyAll();
+ return o;
+ }
+
public E peek() {
synchronized (this.mutex) {
return this.stack.peek();
@@ -111,9 +126,16 @@ public class SynchronizedStack<E>
*/
public void waitUntilEmptyIs(boolean empty) throws InterruptedException {
synchronized (this.mutex) {
- while (this.isEmpty() != empty) {
- this.mutex.wait();
- }
+ this.waitUntilEmptyIs_(empty);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void waitUntilEmptyIs_(boolean empty) throws InterruptedException {
+ while (this.stack.isEmpty() != empty) {
+ this.mutex.wait();
}
}
@@ -121,18 +143,14 @@ public class SynchronizedStack<E>
* Suspend the current thread until the stack is empty.
*/
public void waitUntilEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(true);
- }
+ this.waitUntilEmptyIs(true);
}
/**
* Suspend the current thread until the stack has something on it.
*/
public void waitUntilNotEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(false);
- }
+ this.waitUntilEmptyIs(false);
}
/**
@@ -140,10 +158,10 @@ public class SynchronizedStack<E>
* then "push" the specified item on to the top of the stack
* and continue executing.
*/
- public void waitToPush(E o) throws InterruptedException {
+ public void waitToPush(E element) throws InterruptedException {
synchronized (this.mutex) {
- this.waitUntilEmpty();
- this.push(o);
+ this.waitUntilEmptyIs_(true);
+ this.push_(element);
}
}
@@ -153,8 +171,8 @@ public class SynchronizedStack<E>
*/
public Object waitToPop() throws InterruptedException {
synchronized (this.mutex) {
- this.waitUntilNotEmpty();
- return this.pop();
+ this.waitUntilEmptyIs_(false);
+ return this.pop_();
}
}
@@ -164,48 +182,58 @@ public class SynchronizedStack<E>
/**
* Suspend the current thread until the stack's empty status changes
* to the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the specified
+ * empty status was achieved; return <code>false</code> if a time-out occurred.
+ * If the stack's empty status is already the specified value,
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilEmptyIs(boolean empty, long timeout) throws InterruptedException {
synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilEmptyIs(empty); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
+ return this.waitUntilEmptyIs_(empty, timeout);
+ }
+ }
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.isEmpty() != empty) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.isEmpty() == empty);
+ /**
+ * Pre-condition: synchronized
+ */
+ private boolean waitUntilEmptyIs_(boolean empty, long timeout) throws InterruptedException {
+ if (timeout == 0L) {
+ this.waitUntilEmptyIs_(empty); // wait indefinitely until notified
+ return true; // if it ever comes back, the condition was met
+ }
+
+ long stop = System.currentTimeMillis() + timeout;
+ long remaining = timeout;
+ while ((this.stack.isEmpty() != empty) && (remaining > 0L)) {
+ this.mutex.wait(remaining);
+ remaining = stop - System.currentTimeMillis();
}
+ return (this.stack.isEmpty() == empty);
}
/**
* Suspend the current thread until the stack is empty
* or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack is empty; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the stack is empty; return <code>false</code> if a time-out occurred.
+ * If the stack is already empty, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(true, timeout);
- }
+ return this.waitUntilEmptyIs(true, timeout);
}
/**
* Suspend the current thread until the stack has something on it.
* or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack has something on it; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the stack is not empty; return <code>false</code> if a time-out occurred.
+ * If the stack already has something on it, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilNotEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(false, timeout);
- }
+ return this.waitUntilEmptyIs(false, timeout);
}
/**
@@ -214,14 +242,17 @@ public class SynchronizedStack<E>
* and continue executing. If the stack is not emptied out
* before the time-out, simply continue executing without
* "pushing" the item.
- * The time-out is specified in milliseconds. Return true if the
- * item was pushed; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the
+ * item was pushed; return <code>false</code> if a time-out occurred.
+ * If the stack is already empty, "push" the specified item and
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
- public boolean waitToPush(E o, long timeout) throws InterruptedException {
+ public boolean waitToPush(E element, long timeout) throws InterruptedException {
synchronized (this.mutex) {
- boolean success = this.waitUntilEmpty(timeout);
+ boolean success = this.waitUntilEmptyIs_(true, timeout);
if (success) {
- this.push(o);
+ this.push_(element);
}
return success;
}
@@ -233,12 +264,15 @@ public class SynchronizedStack<E>
* If the stack is empty and nothing is "pushed" on to it before the
* time-out, throw an empty stack exception.
* The time-out is specified in milliseconds.
+ * If the stack is not empty, "pop" an item and
+ * return it immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public Object waitToPop(long timeout) throws InterruptedException {
synchronized (this.mutex) {
- boolean success = this.waitUntilNotEmpty(timeout);
+ boolean success = this.waitUntilEmptyIs_(false, timeout);
if (success) {
- return this.pop();
+ return this.pop_();
}
throw new EmptyStackException();
}
@@ -273,12 +307,12 @@ public class SynchronizedStack<E>
}
- // ********** Object overrides **********
+ // ********** standard methods **********
@Override
public String toString() {
synchronized (this.mutex) {
- return this.stack.toString();
+ return '[' + this.stack.toString() + ']';
}
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java
new file mode 100644
index 0000000000..50819f3f9c
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal.iterables;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.iterators.QueueIterator;
+
+/**
+ * A <code>QueueIterable</code> provides an {@link Iterable}
+ * for a {@link Queue} of objects of type <code>E</code>. The queue's elements
+ * are {@link Queue#dequeue() dequeue}d" as the iterable's iterator returns
+ * them with calls to {@link Iterator#next()}.
+ *
+ * @param <E> the type of elements returned by the iterable's iterator
+ *
+ * @see Queue
+ * @see QueueIterator
+ */
+public class QueueIterable<E>
+ implements Iterable<E>
+{
+ private final Queue<E> queue;
+
+ /**
+ * Construct an iterable for the specified queue.
+ */
+ public QueueIterable(Queue<E> queue) {
+ super();
+ this.queue = queue;
+ }
+
+ public Iterator<E> iterator() {
+ return new QueueIterator<E>(this.queue);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.queue);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java
new file mode 100644
index 0000000000..a1e18318ed
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal.iterables;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Stack;
+import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.iterators.StackIterator;
+
+/**
+ * A <code>StackIterable</code> provides an {@link Iterable}
+ * for a {@link Stack} of objects of type <code>E</code>. The stack's elements
+ * are {@link Stack#pop() pop}ped" as the iterable's iterator returns
+ * them with calls to {@link Iterator#next()}.
+ *
+ * @param <E> the type of elements returned by the iterable's iterator
+ *
+ * @see Stack
+ * @see StackIterator
+ */
+public class StackIterable<E>
+ implements Iterable<E>
+{
+ private final Stack<E> stack;
+
+ /**
+ * Construct an iterable for the specified stack.
+ */
+ public StackIterable(Stack<E> stack) {
+ super();
+ this.stack = stack;
+ }
+
+ public Iterator<E> iterator() {
+ return new StackIterator<E>(this.stack);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.stack);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java
new file mode 100644
index 0000000000..d7a1ff5cec
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal.iterators;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.StringTools;
+
+/**
+ * A <code>QueueIterator</code> provides an {@link Iterator}
+ * for a {@link Queue} of objects of type <code>E</code>. The queue's elements
+ * are {@link Queue#dequeue() dequeue}d" as the iterator returns them with
+ * calls to {@link #next()}.
+ *
+ * @param <E> the type of elements returned by the iterator
+ *
+ * @see Queue
+ */
+public class QueueIterator<E>
+ implements Iterator<E>
+{
+ private final Queue<E> queue;
+
+
+ /**
+ * Construct an iterator for the specified queue.
+ */
+ public QueueIterator(Queue<E> queue) {
+ super();
+ this.queue = queue;
+ }
+
+ public boolean hasNext() {
+ return ! this.queue.isEmpty();
+ }
+
+ public E next() {
+ return this.queue.dequeue();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.queue);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java
new file mode 100644
index 0000000000..af510c8232
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 2009 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.utility.internal.iterators;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Stack;
+import org.eclipse.jpt.utility.internal.StringTools;
+
+/**
+ * A <code>StackIterator</code> provides an {@link Iterator}
+ * for a {@link Stack} of objects of type <code>E</code>. The stack's elements
+ * are {@link Stack#pop() pop}ped" as the iterator returns them with
+ * calls to {@link #next()}.
+ *
+ * @param <E> the type of elements returned by the iterator
+ *
+ * @see Stack
+ */
+public class StackIterator<E>
+ implements Iterator<E>
+{
+ private final Stack<E> stack;
+
+
+ /**
+ * Construct an iterator for the specified stack.
+ */
+ public StackIterator(Stack<E> stack) {
+ super();
+ this.stack = stack;
+ }
+
+ public boolean hasNext() {
+ return ! this.stack.isEmpty();
+ }
+
+ public E next() {
+ return this.stack.pop();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.stack);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
index 75d6fea7fa..970e94c738 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
@@ -9,11 +9,8 @@
******************************************************************************/
package org.eclipse.jpt.utility.internal.synchronizers;
-import java.util.Vector;
-
import org.eclipse.jpt.utility.Command;
-import org.eclipse.jpt.utility.internal.CompositeException;
-import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
/**
@@ -28,7 +25,7 @@ public class AsynchronousSynchronizer
implements Synchronizer
{
/**
- * This flag is shared with the synchronization thread. Setting it to true
+ * This flag is shared with the synchronization/consumer thread. Setting it to true
* will trigger the synchronization to begin or, if the synchronization is
* currently executing, to execute again, once the current execution is
* complete.
@@ -36,34 +33,16 @@ public class AsynchronousSynchronizer
final SynchronizedBoolean synchronizeFlag = new SynchronizedBoolean(false);
/**
- * The runnable passed to the synchronization thread each time it is built.
- */
- private final Runnable runnable;
-
- /**
- * Optional, client-supplied name for the synchronization thread.
- * If null, allow the JDK to assign a name.
- */
- private final String threadName;
-
- /**
- * The synchronization is performed on this thread. A new thread is built
- * for every start/stop cycle (since a thread cannot be started more than
- * once).
+ * Most of the thread-related behavior is delegated to this coordinator.
*/
- private Thread thread;
-
- /**
- * A list of the uncaught exceptions thrown by the command.
- */
- final Vector<Throwable> exceptions = new Vector<Throwable>();
+ private final ConsumerThreadCoordinator consumerThreadCoordinator;
// ********** construction **********
/**
* Construct an asynchronous synchronizer that uses the specified command to
- * perform the synchronization. Allow the generated thread(s) to be assigned
+ * perform the synchronization. Allow the synchronization thread(s) to be assigned
* JDK-generated names.
*/
public AsynchronousSynchronizer(Command command) {
@@ -72,17 +51,19 @@ public class AsynchronousSynchronizer
/**
* Construct an asynchronous synchronizer that uses the specified command to
- * perform the synchronization. Assign the generated thread(s) the specified
+ * perform the synchronization. Assign the synchronization thread(s) the specified
* name.
*/
public AsynchronousSynchronizer(Command command, String threadName) {
super();
- this.runnable = this.buildRunnable(command);
- this.threadName = threadName;
+ if (command == null) {
+ throw new NullPointerException();
+ }
+ this.consumerThreadCoordinator = new ConsumerThreadCoordinator(this.buildConsumer(command), threadName);
}
- Runnable buildRunnable(Command command) {
- return new RunnableSynchronization(command);
+ ConsumerThreadCoordinator.Consumer buildConsumer(Command command) {
+ return new Consumer(command);
}
@@ -106,20 +87,8 @@ public class AsynchronousSynchronizer
* the time {@link #stop()} was called)
* </ul>
*/
- public synchronized void start() {
- if (this.thread != null) {
- throw new IllegalStateException("The Synchronizer was not stopped."); //$NON-NLS-1$
- }
- this.thread = this.buildThread();
- this.thread.start();
- }
-
- private Thread buildThread() {
- Thread t = new Thread(this.runnable);
- if (this.threadName != null) {
- t.setName(this.threadName);
- }
- return t;
+ public void start() {
+ this.consumerThreadCoordinator.start();
}
/**
@@ -140,101 +109,49 @@ public class AsynchronousSynchronizer
* exceptions were thrown while the synchronization thread was executing,
* wrap them in a composite exception and throw the composite exception.
*/
- public synchronized void stop() {
- if (this.thread == null) {
- throw new IllegalStateException("The Synchronizer was not started."); //$NON-NLS-1$
- }
- this.thread.interrupt();
- try {
- this.thread.join();
- } catch (InterruptedException ex) {
- // the thread that called #stop() was interrupted while waiting to
- // join the synchronization thread - ignore;
- // 'thread' is still "interrupted", so its #run() loop will still stop
- // after its current execution - we just won't wait around for it...
- }
- this.thread = null;
-
- if (this.exceptions.size() > 0) {
- Throwable[] temp = this.exceptions.toArray(new Throwable[this.exceptions.size()]);
- this.exceptions.clear();
- throw new CompositeException(temp);
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.thread);
+ public void stop() {
+ this.consumerThreadCoordinator.stop();
}
- // ********** synchronization thread runnable **********
+ // ********** consumer **********
/**
- * This implementation of {@link Runnable} will execute a client-supplied command.
- * It will wait until a shared "synchronize" flag is set to execute the
- * command. Once the the comand is executed, the thread will quiesce until
+ * This implementation of {@link ConsumerThreadCoordinator.Consumer}
+ * will execute the client-supplied "synchronize" command.
+ * It will wait until the shared "synchronize" flag is set to execute the
+ * command. Once the comand is executed, the thread will quiesce until
* the flag is set again. If the flag was set during the execution of the
* command (either recursively by the command itself or by another thread),
* the command will be re-executed immediately. Stop the thread by calling
* {@link Thread#interrupt()}.
*/
- class RunnableSynchronization
- implements Runnable
+ class Consumer
+ implements ConsumerThreadCoordinator.Consumer
{
- /** The client-supplied command that executes on this thread. */
+ /**
+ * The client-supplied command that executes on the
+ * synchronization/consumer thread.
+ */
private final Command command;
-
- RunnableSynchronization(Command command) {
+ Consumer(Command command) {
super();
- if (command == null) {
- throw new NullPointerException();
- }
this.command = command;
}
/**
- * Loop while this thread has not been interrupted by another thread.
- * In each loop: Wait until the "synchronize" flag is set,
- * then clear it and execute the command. If the
- * "synchronize" flag was set <em>during</em> the synchronization,
- * there will be no "wait" before beginning the next synchronization
- * (thus the call to {@link Thread#isInterrupted()} before each cycle).
- * <p>
- * If this thread is interrupted <em>during</em> the synchronization, the
- * call to {@link Thread#interrupted()} will stop the loop. If this thread is
- * interrupted during the call to {@link SynchronizedBoolean#waitToSetFalse()},
- * we will catch the {@link InterruptedException} and stop the loop.
- */
- public void run() {
- while ( ! Thread.interrupted()) {
- try {
- AsynchronousSynchronizer.this.synchronizeFlag.waitToSetFalse();
- } catch (InterruptedException ex) {
- // we were interrupted while waiting, must be Quittin' Time
- return;
- }
- this.execute();
- }
- }
-
- /**
- * Execute the client-supplied command. Do not allow any unhandled
- * exceptions to kill the thread. Store them up for later pain.
+ * Wait until the "synchronize" flag is set,
+ * then clear it and allow the "synchronize" command to execute.
*/
- private void execute() {
- try {
- this.execute_();
- } catch (Throwable ex) {
- AsynchronousSynchronizer.this.exceptions.add(ex);
- }
+ public void waitForProducer() throws InterruptedException {
+ AsynchronousSynchronizer.this.synchronizeFlag.waitToSetFalse();
}
/**
* Execute the client-supplied command.
*/
- void execute_() {
+ public void execute() {
this.command.execute();
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
index 28c610d642..2c30a3241f 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
@@ -10,15 +10,16 @@
package org.eclipse.jpt.utility.internal.synchronizers;
import org.eclipse.jpt.utility.Command;
+import org.eclipse.jpt.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.utility.internal.ListenerList;
/**
* Extend the asynchronous synchronizer to notify listeners
* when a synchronization "cycle" is complete; i.e. the synchronization has,
- * for the moment, handled every "synchronize" request and quiesced.
+ * for the moment, handled every outstanding "synchronize" request and quiesced.
* This notification is <em>not</em> guaranteed to occur with <em>every</em>
- * synchronization "cycle";
- * since other, unrelated, synchronizations can be triggered concurrently.
+ * synchronization "cycle"; since other, unrelated, synchronizations can be
+ * triggered concurrently.
* <p>
* <strong>NB:</strong> Listeners should handle any exceptions
* appropriately (e.g. log the exception and return gracefully so the thread
@@ -35,7 +36,7 @@ public class CallbackAsynchronousSynchronizer
/**
* Construct a callback asynchronous synchronizer that uses the specified
- * command to perform the synchronization. Allow the generated thread(s)
+ * command to perform the synchronization. Allow the synchronization thread(s)
* to be assigned JDK-generated names.
*/
public CallbackAsynchronousSynchronizer(Command command) {
@@ -44,7 +45,7 @@ public class CallbackAsynchronousSynchronizer
/**
* Construct a callback asynchronous synchronizer that uses the specified
- * command to perform the synchronization. Assign the generated thread(s)
+ * command to perform the synchronization. Assign the synchronization thread(s)
* the specified name.
*/
public CallbackAsynchronousSynchronizer(Command command, String threadName) {
@@ -52,12 +53,12 @@ public class CallbackAsynchronousSynchronizer
}
/**
- * Build a runnable that will let us know when the synchronization has
+ * Build a consumer that will let us know when the synchronization has
* quiesced.
*/
@Override
- Runnable buildRunnable(Command command) {
- return new RunnableCallbackSynchronization(command);
+ ConsumerThreadCoordinator.Consumer buildConsumer(Command command) {
+ return new CallbackConsumer(command);
}
@@ -84,7 +85,7 @@ public class CallbackAsynchronousSynchronizer
// ********** synchronization thread runnable **********
/**
- * Extend {@link AsynchronousSynchronizer.RunnableSynchronization}
+ * Extend {@link AsynchronousSynchronizer.Consumer}
* to notify the synchronizer when the synchronization has quiesced
* (i.e. the command has finished executing and there are no further
* requests for synchronization).
@@ -96,16 +97,16 @@ public class CallbackAsynchronousSynchronizer
* but this synchronization will not occur until <em>after</em> all the
* listeners have been notified.
*/
- class RunnableCallbackSynchronization
- extends RunnableSynchronization
+ class CallbackConsumer
+ extends Consumer
{
- RunnableCallbackSynchronization(Command command) {
+ CallbackConsumer(Command command) {
super(command);
}
@Override
- void execute_() {
- super.execute_();
+ public void execute() {
+ super.execute();
// hmmm - we will notify listeners even when we our thread is "interrupted";
// that seems ok... ~bjv
if (CallbackAsynchronousSynchronizer.this.synchronizeFlag.isFalse()) {

Back to the top