major rework of collections, stacks, queues, and deques
diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/libval/LibraryValidatorTools.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/libval/LibraryValidatorTools.java
index b2af0c2..52ceef8 100644
--- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/libval/LibraryValidatorTools.java
+++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/libval/LibraryValidatorTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -76,7 +76,7 @@
 	private static IStatus validateClassesInLibraries(Iterable<IPath> libraryPaths, Iterable<String> classNames) {
 		HashMap<String, Boolean> flags = new HashMap<String, Boolean>();
 		HashMap<String, String> classFileNameToClassName = new HashMap<String, String>();
-		for (String className : CollectionTools.set(classNames)) {
+		for (String className : CollectionTools.hashSet(classNames)) {
 			String classFileName = className.replace('.', '/') + ".class"; //$NON-NLS-1$
 			flags.put(classFileName, Boolean.FALSE);
 			classFileNameToClassName.put(classFileName, className);
diff --git a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryPackageFragment.java b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryPackageFragment.java
index a8e9073..fb346a6 100644
--- a/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryPackageFragment.java
+++ b/common/plugins/org.eclipse.jpt.common.core/src/org/eclipse/jpt/common/core/internal/resource/java/binary/BinaryPackageFragment.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -57,7 +57,7 @@
 	private Collection<JavaResourceClassFile> buildClassFiles() {
 		IJavaElement[] children = this.getJDTChildren();
 		ArrayList<JavaResourceClassFile> result = new ArrayList<JavaResourceClassFile>(children.length);
-		Collection<String> annotationNames = CollectionTools.collection(this.getAnnotationProvider().getAnnotationNames());
+		Collection<String> annotationNames = CollectionTools.hashBag(this.getAnnotationProvider().getAnnotationNames());
 		for (IJavaElement child : children) {
 			IClassFile jdtClassFile = (IClassFile) child;
 			IType jdtType = jdtClassFile.getType();
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/listeners/SWTListenerWrapperDelegate.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/listeners/SWTListenerWrapperDelegate.java
index fb4eaef..4a8aabd 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/listeners/SWTListenerWrapperDelegate.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/swt/listeners/SWTListenerWrapperDelegate.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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,7 +14,8 @@
 import org.eclipse.jpt.common.utility.exception.ExceptionHandler;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
 import org.eclipse.jpt.common.utility.internal.RunnableAdapter;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
 import org.eclipse.swt.widgets.Display;
 
 /**
@@ -36,7 +37,7 @@
 	private final Display display;
 	private final Runnable forwardEventsRunnable = new ForwardEventsRunnable();
 	private final ExceptionHandler exceptionHandler;
-	private final SynchronizedQueue<E> events = new SynchronizedQueue<E>();
+	private final SynchronizedQueue<E> events = QueueTools.synchronizedQueue();
 
 
 	SWTListenerWrapperDelegate(Wrapper<E> wrapper, Display display, ExceptionHandler exceptionHandler) {
diff --git a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/NewNameDialogBuilder.java b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/NewNameDialogBuilder.java
index f06df88..47bb464 100644
--- a/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/NewNameDialogBuilder.java
+++ b/common/plugins/org.eclipse.jpt.common.ui/src/org/eclipse/jpt/common/ui/internal/widgets/NewNameDialogBuilder.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -145,7 +145,7 @@
 	 * @param names The collection of names that can't be used
 	 */
 	public void setExistingNames(Iterator<String> names) {
-		this.names = CollectionTools.collection(names);
+		this.names = CollectionTools.hashBag(names);
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/META-INF/MANIFEST.MF b/common/plugins/org.eclipse.jpt.common.utility/META-INF/MANIFEST.MF
index 4836dae..3815dfd 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/META-INF/MANIFEST.MF
+++ b/common/plugins/org.eclipse.jpt.common.utility/META-INF/MANIFEST.MF
@@ -14,6 +14,7 @@
  org.eclipse.jpt.common.utility.closure,
  org.eclipse.jpt.common.utility.collection,
  org.eclipse.jpt.common.utility.command,
+ org.eclipse.jpt.common.utility.deque,
  org.eclipse.jpt.common.utility.exception,
  org.eclipse.jpt.common.utility.factory,
  org.eclipse.jpt.common.utility.internal;
@@ -73,6 +74,17 @@
    org.eclipse.jpt.jpa.gen,
    org.eclipse.jpt.jpa.annotate,
    org.eclipse.jpt.jpa.ui",
+ org.eclipse.jpt.common.utility.internal.deque;
+  x-friends:="org.eclipse.jpt.common.core,
+   org.eclipse.jpt.common.ui,
+   org.eclipse.jpt.jaxb.core,
+   org.eclipse.jpt.jaxb.ui,
+   org.eclipse.jpt.jpa.core,
+   org.eclipse.jpt.jpa.db,
+   org.eclipse.jpt.jpa.db.ui,
+   org.eclipse.jpt.jpa.gen,
+   org.eclipse.jpt.jpa.annotate,
+   org.eclipse.jpt.jpa.ui",
  org.eclipse.jpt.common.utility.internal.enumeration;
   x-friends:="org.eclipse.jpt.common.core,
    org.eclipse.jpt.common.ui,
@@ -225,6 +237,17 @@
    org.eclipse.jpt.jpa.gen,
    org.eclipse.jpt.jpa.annotate,
    org.eclipse.jpt.jpa.ui",
+ org.eclipse.jpt.common.utility.internal.queue;
+  x-friends:="org.eclipse.jpt.common.core,
+   org.eclipse.jpt.common.ui,
+   org.eclipse.jpt.jaxb.core,
+   org.eclipse.jpt.jaxb.ui,
+   org.eclipse.jpt.jpa.core,
+   org.eclipse.jpt.jpa.db,
+   org.eclipse.jpt.jpa.db.ui,
+   org.eclipse.jpt.jpa.gen,
+   org.eclipse.jpt.jpa.annotate,
+   org.eclipse.jpt.jpa.ui",
  org.eclipse.jpt.common.utility.internal.reference;
   x-friends:="org.eclipse.jpt.common.core,
    org.eclipse.jpt.common.ui,
@@ -236,6 +259,17 @@
    org.eclipse.jpt.jpa.gen,
    org.eclipse.jpt.jpa.annotate,
    org.eclipse.jpt.jpa.ui",
+ org.eclipse.jpt.common.utility.internal.stack;
+  x-friends:="org.eclipse.jpt.common.core,
+   org.eclipse.jpt.common.ui,
+   org.eclipse.jpt.jaxb.core,
+   org.eclipse.jpt.jaxb.ui,
+   org.eclipse.jpt.jpa.core,
+   org.eclipse.jpt.jpa.db,
+   org.eclipse.jpt.jpa.db.ui,
+   org.eclipse.jpt.jpa.gen,
+   org.eclipse.jpt.jpa.annotate,
+   org.eclipse.jpt.jpa.ui",
  org.eclipse.jpt.common.utility.internal.swing;
   x-friends:="org.eclipse.jpt.common.ui,
    org.eclipse.jpt.jaxb.ui,
@@ -260,5 +294,7 @@
  org.eclipse.jpt.common.utility.model.value,
  org.eclipse.jpt.common.utility.node,
  org.eclipse.jpt.common.utility.predicate,
+ org.eclipse.jpt.common.utility.queue,
  org.eclipse.jpt.common.utility.reference,
+ org.eclipse.jpt.common.utility.stack,
  org.eclipse.jpt.common.utility.transformer
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/Deque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/Deque.java
new file mode 100644
index 0000000..4283b32
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/Deque.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import org.eclipse.jpt.common.utility.queue.Queue;
+
+/**
+ * Interface defining the classic double-ended queue behavior,
+ * without the backdoors allowed by {@link java.util.Deque}.
+ * <p>
+ * Provisional API: This interface is part of an interim API that is still
+ * under development and expected to change significantly before reaching
+ * stability. It is available at this early stage to solicit feedback from
+ * pioneering adopters on the understanding that any code that uses this API
+ * will almost certainly be broken (repeatedly) as the API evolves.
+ * 
+ * @param <E> the type of elements contained by the deque
+ * @see org.eclipse.jpt.common.utility.internal.deque.ArrayDeque
+ * @see org.eclipse.jpt.common.utility.internal.deque.LinkedDeque
+ * @see org.eclipse.jpt.common.utility.internal.deque.DequeTools
+ * @see Queue Queue - for an interface without the semantic baggage of {@link java.util.Queue}
+ */
+public interface Deque<E>
+	extends InputRestrictedDeque<E>, OutputRestrictedDeque<E>
+{
+	// combine the "restricted" interfaces
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/InputRestrictedDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/InputRestrictedDeque.java
new file mode 100644
index 0000000..b15cb36
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/InputRestrictedDeque.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+/**
+ * Interface defining a input-restricted double-ended queue.
+ * Elements can be removed from either end of the queue,
+ * but added to only the tail of the queue.
+ * <p>
+ * Provisional API: This interface is part of an interim API that is still
+ * under development and expected to change significantly before reaching
+ * stability. It is available at this early stage to solicit feedback from
+ * pioneering adopters on the understanding that any code that uses this API
+ * will almost certainly be broken (repeatedly) as the API evolves.
+ * 
+ * @param <E> the type of elements contained by the deque
+ * @see Deque
+ */
+public interface InputRestrictedDeque<E> {
+
+	/**
+	 * "Enqueue" the specified item to the tail of the deque.
+	 */
+	void enqueueTail(E element);
+
+	/**
+	 * "Dequeue" an item from the head of the deque.
+	 */
+	E dequeueHead();
+
+	/**
+	 * "Dequeue" an item from the tail of the deque.
+	 */
+	E dequeueTail();
+
+	/**
+	 * Return the item on the head of the deque
+	 * without removing it from the deque.
+	 */
+	E peekHead();
+
+	/**
+	 * Return the item on the tail of the deque
+	 * without removing it from the deque.
+	 */
+	E peekTail();
+
+	/**
+	 * Return whether the deque is empty.
+	 */
+	boolean isEmpty();
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/OutputRestrictedDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/OutputRestrictedDeque.java
new file mode 100644
index 0000000..b2a42dc
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/deque/OutputRestrictedDeque.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+/**
+ * Interface defining a output-restricted double-ended queue.
+ * Elements can be added to either end of the queue,
+ * but removed from only the head of the queue.
+ * <p>
+ * Provisional API: This interface is part of an interim API that is still
+ * under development and expected to change significantly before reaching
+ * stability. It is available at this early stage to solicit feedback from
+ * pioneering adopters on the understanding that any code that uses this API
+ * will almost certainly be broken (repeatedly) as the API evolves.
+ * 
+ * @param <E> the type of elements contained by the deque
+ * @see Deque
+ */
+public interface OutputRestrictedDeque<E> {
+
+	/**
+	 * "Enqueue" the specified item to the head of the queue.
+	 */
+	void enqueueHead(E element);
+
+	/**
+	 * "Enqueue" the specified item to the tail of the deque.
+	 */
+	void enqueueTail(E element);
+
+	/**
+	 * "Dequeue" an item from the head of the deque.
+	 */
+	E dequeueHead();
+
+	/**
+	 * Return the item on the head of the deque
+	 * without removing it from the deque.
+	 */
+	E peekHead();
+
+	/**
+	 * Return whether the deque is empty.
+	 */
+	boolean isEmpty();
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/ArrayTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/ArrayTools.java
index 7e09f76..7a7b1a0 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/ArrayTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/ArrayTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -160,7 +160,7 @@
 	 */
 	public static Object[] array(Iterator<?> iterator) {
 		return iterator.hasNext() ?
-				ListTools.list(iterator).toArray() :
+				ListTools.arrayList(iterator).toArray() :
 				ObjectTools.EMPTY_OBJECT_ARRAY;
 	}
 
@@ -171,7 +171,7 @@
 	 */
 	public static Object[] array(Iterator<?> iterator, int iteratorSize) {
 		return iterator.hasNext() ?
-				ListTools.list(iterator, iteratorSize).toArray() :
+				ListTools.arrayList(iterator, iteratorSize).toArray() :
 				ObjectTools.EMPTY_OBJECT_ARRAY;
 	}
 
@@ -183,7 +183,7 @@
 	public static <E> E[] array(Iterator<?> iterator, Class<E> componentType) {
 		E[] array = newInstance(componentType, 0);
 		return iterator.hasNext() ?
-				ListTools.list(iterator).toArray(array) :
+				ListTools.arrayList(iterator).toArray(array) :
 				array;
 	}
 
@@ -195,7 +195,7 @@
 	 */
 	public static <E> E[] array(Iterator<?> iterator, int iteratorSize, Class<E> componentType) {
 		return iterator.hasNext() ?
-				ListTools.list(iterator, iteratorSize).toArray(newInstance(componentType, iteratorSize)) :
+				ListTools.arrayList(iterator, iteratorSize).toArray(newInstance(componentType, iteratorSize)) :
 				newInstance(componentType, 0);
 	}
 
@@ -209,7 +209,7 @@
 	 */
 	public static <E> E[] array(Iterator<? extends E> iterator, E[] array) {
 		return iterator.hasNext() ?
-				ListTools.list(iterator).toArray(array) :
+				ListTools.arrayList(iterator).toArray(array) :
 				emptyArray(array);
 	}
 
@@ -224,7 +224,7 @@
 	 */
 	public static <E> E[] array(Iterator<? extends E> iterator, int iteratorSize, E[] array) {
 		return iterator.hasNext() ?
-				ListTools.list(iterator, iteratorSize).toArray(array) :
+				ListTools.arrayList(iterator, iteratorSize).toArray(array) :
 				emptyArray(array);
 	}
 
@@ -423,7 +423,7 @@
 	 * in the specified iterator.
 	 */
 	public static <E> E[] addAll(E[] array, Iterator<? extends E> iterator) {
-		return iterator.hasNext() ? addAll_(array, ListTools.list(iterator)) : array;
+		return iterator.hasNext() ? addAll_(array, ListTools.arrayList(iterator)) : array;
 	}
 
 	/**
@@ -433,7 +433,7 @@
 	 * The specified iterator size is a performance hint.
 	 */
 	public static <E> E[] addAll(E[] array, Iterator<? extends E> iterator, int iteratorSize) {
-		return iterator.hasNext() ? addAll_(array, ListTools.list(iterator, iteratorSize)) : array;
+		return iterator.hasNext() ? addAll_(array, ListTools.arrayList(iterator, iteratorSize)) : array;
 	}
 
 	/**
@@ -597,7 +597,7 @@
 	 * in the specified iterator inserted at the specified index.
 	 */
 	public static <E> E[] addAll(E[] array, int index, Iterator<? extends E> iterator) {
-		return iterator.hasNext() ? addAll_(array, index, ListTools.list(iterator)) : array;
+		return iterator.hasNext() ? addAll_(array, index, ListTools.arrayList(iterator)) : array;
 	}
 
 	/**
@@ -607,7 +607,7 @@
 	 * The specified iterator size is a performance hint.
 	 */
 	public static <E> E[] addAll(E[] array, int index, Iterator<? extends E> iterator, int iteratorSize) {
-		return iterator.hasNext() ? addAll_(array, index, ListTools.list(iterator, iteratorSize)) : array;
+		return iterator.hasNext() ? addAll_(array, index, ListTools.arrayList(iterator, iteratorSize)) : array;
 	}
 
 	/**
@@ -1025,7 +1025,7 @@
 	 */
 	public static boolean containsAll(Object[] array, Iterator<?> iterator) {
 		// use hashed lookup
-		HashSet<Object> set = CollectionTools.set(array);
+		HashSet<Object> set = CollectionTools.hashSet(array);
 		while (iterator.hasNext()) {
 			if ( ! set.contains(iterator.next())) {
 				return false;
@@ -1040,7 +1040,7 @@
 	 */
 	public static boolean containsAll(Object[] array1, Object... array2) {
 		// use hashed lookup
-		HashSet<Object> set = CollectionTools.set(array1);
+		HashSet<Object> set = CollectionTools.hashSet(array1);
 		for (int i = array2.length; i-- > 0; ) {
 			if ( ! set.contains(array2[i])) {
 				return false;
@@ -2054,7 +2054,7 @@
 	 */
 	public static <E> E[] removeAll(E[] array, Iterator<?> iterator) {
 		// convert to a set to take advantage of hashed look-up
-		return iterator.hasNext() ? removeAll_(array, CollectionTools.set(iterator)) : array;
+		return iterator.hasNext() ? removeAll_(array, CollectionTools.hashSet(iterator)) : array;
 	}
 
 	/**
@@ -2064,7 +2064,7 @@
 	 */
 	public static <E> E[] removeAll(E[] array, Iterator<?> iterator, int iteratorSize) {
 		// convert to a set to take advantage of hashed look-up
-		return iterator.hasNext() ? removeAll_(array, CollectionTools.set(iterator, iteratorSize)) : array;
+		return iterator.hasNext() ? removeAll_(array, CollectionTools.hashSet(iterator, iteratorSize)) : array;
 	}
 
 	/**
@@ -2118,7 +2118,7 @@
 	 */
 	public static <E> E[] removeAll(E[] array1, Object... array2) {
 		// convert to a set to take advantage of hashed look-up
-		return (array2.length == 0) ? array1 : removeAll_(array1, CollectionTools.set(array2));
+		return (array2.length == 0) ? array1 : removeAll_(array1, CollectionTools.hashSet(array2));
 	}
 
 	/**
@@ -2553,7 +2553,7 @@
 	 */
 	private static <E> E[] retainAll(E[] array, int arrayLength, Iterator<?> iterator) {
 		return iterator.hasNext() ?
-				retainAll_(array, CollectionTools.set(iterator), arrayLength) :
+				retainAll_(array, CollectionTools.hashSet(iterator), arrayLength) :
 				newInstance(array, 0);
 	}
 
@@ -2562,7 +2562,7 @@
 	 */
 	private static <E> E[] retainAll(E[] array, int arrayLength, Iterator<?> iterator, int iteratorSize) {
 		return iterator.hasNext() ?
-				retainAll_(array, CollectionTools.set(iterator, iteratorSize), arrayLength) :
+				retainAll_(array, CollectionTools.hashSet(iterator, iteratorSize), arrayLength) :
 				newInstance(array, 0);
 	}
 
@@ -2616,7 +2616,7 @@
 				array1 :
 				(array2.length == 0) ?
 					newInstance(array1, 0) :
-					retainAll(array1, CollectionTools.set(array2), array1Length);
+					retainAll(array1, CollectionTools.hashSet(array2), array1Length);
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/NameTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/NameTools.java
index 5167b26..ff08df4 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/NameTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/NameTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -28,7 +28,7 @@
 	 * @see #uniqueName(String, Collection)
 	 */
 	public static String uniqueName(String rootName, Iterable<String> existingNames) {
-		return uniqueName(rootName, CollectionTools.set(existingNames));
+		return uniqueName(rootName, CollectionTools.hashSet(existingNames));
 	}
 	
 	/**
@@ -46,7 +46,7 @@
 	 * @see #uniqueNameIgnoreCase(String, Collection)
 	 */
 	public static String uniqueNameIgnoreCase(String rootName, Iterable<String> existingNames) {
-		return uniqueNameIgnoreCase(rootName, CollectionTools.set(existingNames));
+		return uniqueNameIgnoreCase(rootName, CollectionTools.hashSet(existingNames));
 	}
 
 	/**
@@ -193,7 +193,7 @@
 	 * Java Language Keywords</a>
 	 */
 	public static final SortedSet<String> JAVA_RESERVED_WORDS = 
-		Collections.unmodifiableSortedSet(CollectionTools.sortedSet(JAVA_RESERVED_WORDS_ARRAY));
+		Collections.unmodifiableSortedSet(CollectionTools.treeSet(JAVA_RESERVED_WORDS_ARRAY));
 
 	/**
 	 * Return whether the specified string consists of Java identifier
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/Range.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/Range.java
index c52a936..756a823 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/Range.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/Range.java
@@ -43,7 +43,7 @@
 
 	/**
 	 * Construct a range with the specified start and end, both of which are
-	 * mmutable. If the specified end is less than the specified start, the
+	 * immutable. If the specified end is less than the specified start, the
 	 * values will be swapped in the range.
 	 */
 	public Range(int start, int end) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/AbstractRepeatingElementList.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/AbstractRepeatingElementList.java
index 47287f3..fa93b49 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/AbstractRepeatingElementList.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/AbstractRepeatingElementList.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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,7 +14,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
-
 import org.eclipse.jpt.common.utility.internal.ArrayTools;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
 
@@ -217,7 +216,17 @@
 
 	@Override
 	public String toString() {
-		return ObjectTools.toString(this, this.size);
+		StringBuilder sb = new StringBuilder();
+		sb.append('[');
+		for (int i = this.size; i-- > 0; ) {
+			sb.append(this.getElement());
+			sb.append(", "); //$NON-NLS-1$
+		}
+		if (sb.length() > 1) {
+			sb.setLength(sb.length() - 2);
+		}
+		sb.append(']');
+		return sb.toString();
 	}
 
 	private static final long serialVersionUID = 1L;
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/CollectionTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/CollectionTools.java
index cd51bb3..a1f52a2 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/CollectionTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/CollectionTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -16,12 +16,9 @@
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.List;
 import java.util.TreeSet;
 import java.util.Vector;
 import org.eclipse.jpt.common.utility.collection.Bag;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.predicate.Predicate;
 import org.eclipse.jpt.common.utility.transformer.Transformer;
 
@@ -67,11 +64,11 @@
 	/**
 	 * assume the iterator is not empty
 	 */
-	private static <E> boolean addAll_(Collection<? super E> collection, Iterator<? extends E> iterator) {
+	/* package */ static <E> boolean addAll_(Collection<? super E> collection, Iterator<? extends E> iterator) {
 		boolean modified = false;
-		while (iterator.hasNext()) {
+		do {
 			modified |= collection.add(iterator.next());
-		}
+		} while (iterator.hasNext());
 		return modified;
 	}
 
@@ -82,7 +79,7 @@
 	 * The specified iterator size is a performance hint.
 	 */
 	public static <E> boolean addAll(Collection<? super E> collection, Iterator<? extends E> iterator, int iteratorSize) {
-		return iterator.hasNext() && collection.addAll(ListTools.list(iterator, iteratorSize));
+		return iterator.hasNext() && collection.addAll(ListTools.arrayList(iterator, iteratorSize));
 	}
 
 	/**
@@ -91,69 +88,20 @@
 	 * Return whether the collection changed as a result.
 	 */
 	public static <E> boolean addAll(Collection<? super E> collection, E... array) {
-		return (array.length != 0) && collection.addAll(Arrays.asList(array));
+		return (array.length != 0) && addAll_(collection, array);
 	}
 
 	/**
-	 * Dequeue all the elements from the specified queue and add them
-	 * to the specified collection.
-	 * Return whether the collection changed as a result.
+	 * assume the array is not empty
 	 */
-	public static <E> boolean addAll(Collection<? super E> collection, Queue<? extends E> queue) {
-		return ( ! queue.isEmpty()) && addAll_(collection, queue);
-	}
-
-	/**
-	 * assume the queue is not empty
-	 */
-	private static <E> boolean addAll_(Collection<? super E> collection, Queue<? extends E> queue) {
+	private static <E> boolean addAll_(Collection<? super E> collection, E... array) {
 		boolean modified = false;
-		while ( ! queue.isEmpty()) {
-			modified |= collection.add(queue.dequeue());
+		for (E element : array) {
+			modified |= collection.add(element);
 		}
 		return modified;
 	}
 
-	/**
-	 * Dequeue all the elements from the specified queue and add them
-	 * to the specified collection.
-	 * Return whether the collection changed as a result.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> boolean addAll(Collection<? super E> collection, Queue<? extends E> queue, int queueSize) {
-		return ( ! queue.isEmpty()) && collection.addAll(ListTools.list(queue, queueSize));
-	}
-
-	/**
-	 * Pop all the elements from the specified stack and add them
-	 * to the specified collection.
-	 * Return whether the collection changed as a result.
-	 */
-	public static <E> boolean addAll(Collection<? super E> collection, Stack<? extends E> stack) {
-		return ( ! stack.isEmpty()) && addAll_(collection, stack);
-	}
-
-	/**
-	 * assume the stack is not empty
-	 */
-	private static <E> boolean addAll_(Collection<? super E> collection, Stack<? extends E> stack) {
-		boolean modified = false;
-		while ( ! stack.isEmpty()) {
-			modified |= collection.add(stack.pop());
-		}
-		return modified;
-	}
-
-	/**
-	 * Pop all the elements from the specified stack and add them
-	 * to the specified collection.
-	 * Return whether the collection changed as a result.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> boolean addAll(Collection<? super E> collection, Stack<? extends E> stack, int stackSize) {
-		return ( ! stack.isEmpty()) && collection.addAll(ListTools.list(stack, stackSize));
-	}
-
 
 	// ********** contains all **********
 
@@ -192,34 +140,6 @@
 		return true;
 	}
 
-	/**
-	 * Return whether the specified collection contains all of the
-	 * elements in the specified queue, dequeueing elements from the queue
-	 * until one is not found in the collection.
-	 */
-	public static boolean containsAll(Collection<?> collection, Queue<?> queue) {
-		while ( ! queue.isEmpty()) {
-			if ( ! collection.contains(queue.dequeue())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Return whether the specified collection contains all of the
-	 * elements in the specified stack, popping elements from the stack
-	 * until one is not found in the collection.
-	 */
-	public static boolean containsAll(Collection<?> collection, Stack<?> stack) {
-		while ( ! stack.isEmpty()) {
-			if ( ! collection.contains(stack.pop())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
 
 	// ********** filter **********
 
@@ -228,7 +148,7 @@
 	 * elements of the specified collection.
 	 */
 	public static <E> HashBag<E> filter(Collection<? extends E> collection, Predicate<? super E> filter) {
-		HashBag<E> result = new HashBag<E>(collection.size());
+		HashBag<E> result = hashBag(collection.size());
 		for (E e : collection) {
 			if (filter.evaluate(e)) {
 				result.add(e);
@@ -314,7 +234,7 @@
 	 * Return whether the collection changed as a result.
 	 */
 	public static boolean removeAll(Collection<?> collection, Iterator<?> iterator) {
-		return iterator.hasNext() && collection.removeAll(set(iterator));
+		return iterator.hasNext() && collection.removeAll(hashSet(iterator));
 	}
 
 	/**
@@ -324,7 +244,7 @@
 	 * The specified iterator size is a performance hint.
 	 */
 	public static boolean removeAll(Collection<?> collection, Iterator<?> iterator, int iteratorSize) {
-		return iterator.hasNext() && collection.removeAll(set(iterator, iteratorSize));
+		return iterator.hasNext() && collection.removeAll(hashSet(iterator, iteratorSize));
 	}
 
 	/**
@@ -333,45 +253,7 @@
 	 * Return whether the collection changed as a result.
 	 */
 	public static boolean removeAll(Collection<?> collection, Object... array) {
-		return (array.length != 0) && collection.removeAll(set(array));
-	}
-
-	/**
-	 * Remove all the elements dequeued from the specified queue
-	 * from the specified collection, draining the queue in the process.
-	 * Return whether the collection changed as a result.
-	 */
-	public static boolean removeAll(Collection<?> collection, Queue<?> queue) {
-		return ( ! queue.isEmpty()) && collection.removeAll(set(queue));
-	}
-
-	/**
-	 * Remove all the elements dequeued from the specified queue
-	 * from the specified collection, draining the queue in the process.
-	 * Return whether the collection changed as a result.
-	 * The specified queue size is a performance hint.
-	 */
-	public static boolean removeAll(Collection<?> collection, Queue<?> queue, int queueSize) {
-		return ( ! queue.isEmpty()) && collection.removeAll(set(queue, queueSize));
-	}
-
-	/**
-	 * Remove all the elements from the specified stack
-	 * from the specified collection, draining the stack in the process.
-	 * Return whether the collection changed as a result.
-	 */
-	public static boolean removeAll(Collection<?> collection, Stack<?> stack) {
-		return ( ! stack.isEmpty()) && collection.removeAll(set(stack));
-	}
-
-	/**
-	 * Remove all the elements from the specified stack
-	 * from the specified collection, draining the stack in the process.
-	 * Return whether the collection changed as a result.
-	 * The specified stack size is a performance hint.
-	 */
-	public static boolean removeAll(Collection<?> collection, Stack<?> stack, int stackSize) {
-		return ( ! stack.isEmpty()) && collection.removeAll(set(stack, stackSize));
+		return (array.length != 0) && collection.removeAll(hashSet(array));
 	}
 
 
@@ -432,7 +314,7 @@
 	 */
 	public static boolean retainAll(Collection<?> collection, Iterator<?> iterator) {
 		if (iterator.hasNext()) {
-			return collection.retainAll(set(iterator));
+			return collection.retainAll(hashSet(iterator));
 		}
 		if (collection.isEmpty()) {
 			return false;
@@ -449,7 +331,7 @@
 	 */
 	public static boolean retainAll(Collection<?> collection, Iterator<?> iterator, int iteratorSize) {
 		if (iterator.hasNext()) {
-			return collection.retainAll(set(iterator, iteratorSize));
+			return collection.retainAll(hashSet(iterator, iteratorSize));
 		}
 		if (collection.isEmpty()) {
 			return false;
@@ -465,73 +347,7 @@
 	 */
 	public static boolean retainAll(Collection<?> collection, Object... array) {
 		if (array.length > 0) {
-			return collection.retainAll(set(array));
-		}
-		if (collection.isEmpty()) {
-			return false;
-		}
-		collection.clear();
-		return true;
-	}
-
-	/**
-	 * Retain only the elements in the specified queue
-	 * in the specified collection, draining the queue in the process.
-	 * Return whether the collection changed as a result.
-	 */
-	public static boolean retainAll(Collection<?> collection, Queue<?> queue) {
-		if ( ! queue.isEmpty()) {
-			return collection.retainAll(set(queue));
-		}
-		if (collection.isEmpty()) {
-			return false;
-		}
-		collection.clear();
-		return true;
-	}
-
-	/**
-	 * Retain only the elements in the specified queue
-	 * in the specified collection, draining the queue in the process.
-	 * Return whether the collection changed as a result.
-	 * The specified queue size is a performance hint.
-	 */
-	public static boolean retainAll(Collection<?> collection, Queue<?> queue, int queueSize) {
-		if ( ! queue.isEmpty()) {
-			return collection.retainAll(set(queue, queueSize));
-		}
-		if (collection.isEmpty()) {
-			return false;
-		}
-		collection.clear();
-		return true;
-	}
-
-	/**
-	 * Retain only the elements in the specified stack
-	 * in the specified collection, draining the stack in the process.
-	 * Return whether the collection changed as a result.
-	 */
-	public static boolean retainAll(Collection<?> collection, Stack<?> stack) {
-		if ( ! stack.isEmpty()) {
-			return collection.retainAll(set(stack));
-		}
-		if (collection.isEmpty()) {
-			return false;
-		}
-		collection.clear();
-		return true;
-	}
-
-	/**
-	 * Retain only the elements in the specified stack
-	 * in the specified collection, draining the stack in the process.
-	 * Return whether the collection changed as a result.
-	 * The specified stack size is a performance hint.
-	 */
-	public static boolean retainAll(Collection<?> collection, Stack<?> stack, int stackSize) {
-		if ( ! stack.isEmpty()) {
-			return collection.retainAll(set(stack, stackSize));
+			return collection.retainAll(hashSet(array));
 		}
 		if (collection.isEmpty()) {
 			return false;
@@ -561,7 +377,7 @@
 	 * elements in the specified collection.
 	 */
 	public static <E1, E2> HashBag<E2> transform(Collection<E1> collection, Transformer<? super E1, ? extends E2> transformer) {
-		HashBag<E2> result = new HashBag<E2>(collection.size());
+		HashBag<E2> result = hashBag(collection.size());
 		for (E1 e : collection) {
 			result.add(transformer.transform(e));
 		}
@@ -569,39 +385,63 @@
 	}
 
 
-	// ********** bag factory methods **********
+	// ********** hash bag factory methods **********
 
 	/**
-	 * Return a bag corresponding to the specified iterable.
+	 * Return a new hash bag.
 	 */
-	public static <E> HashBag<E> bag(Iterable<? extends E> iterable) {
-		return bag(iterable.iterator());
+	public static <E> HashBag<E> hashBag() {
+		return new HashBag<E>();
 	}
 
 	/**
-	 * Return a bag corresponding to the specified iterable.
+	 * Return a new hash bag with the specified initial capacity.
+	 */
+	public static <E> HashBag<E> hashBag(int initialCapacity) {
+		return new HashBag<E>(initialCapacity);
+	}
+
+	/**
+	 * Return a new hash bag with the specified initial capacity
+	 * and load factor.
+	 */
+	public static <E> HashBag<E> hashBag(int initialCapacity, float loadFactor) {
+		return new HashBag<E>(initialCapacity, loadFactor);
+	}
+
+	/**
+	 * Return a new hash bag corresponding to the specified iterable.
+	 */
+	public static <E> HashBag<E> hashBag(Iterable<? extends E> iterable) {
+		return hashBag(iterable.iterator());
+	}
+
+	/**
+	 * Return a new hash bag corresponding to the specified iterable.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E> HashBag<E> bag(Iterable<? extends E> iterable, int iterableSize) {
-		return bag(iterable.iterator(), iterableSize);
+	public static <E> HashBag<E> hashBag(Iterable<? extends E> iterable, int iterableSize) {
+		return hashBag(iterable.iterator(), iterableSize);
 	}
 
 	/**
-	 * Return a bag corresponding to the specified iterator.
+	 * Return a new hash bag corresponding to the specified iterator.
 	 */
-	public static <E> HashBag<E> bag(Iterator<? extends E> iterator) {
-		return bag(iterator, new HashBag<E>());
+	public static <E> HashBag<E> hashBag(Iterator<? extends E> iterator) {
+		HashBag<E> bag = hashBag();
+		return hashBag(iterator, bag);
 	}
 
 	/**
-	 * Return a bag corresponding to the specified iterator.
+	 * Return a new hash bag corresponding to the specified iterator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E> HashBag<E> bag(Iterator<? extends E> iterator, int iteratorSize) {
-		return bag(iterator, new HashBag<E>(iteratorSize));
+	public static <E> HashBag<E> hashBag(Iterator<? extends E> iterator, int iteratorSize) {
+		HashBag<E> bag = hashBag(iteratorSize);
+		return hashBag(iterator, bag);
 	}
 
-	private static <E> HashBag<E> bag(Iterator<? extends E> iterator, HashBag<E> bag) {
+	private static <E> HashBag<E> hashBag(Iterator<? extends E> iterator, HashBag<E> bag) {
 		while (iterator.hasNext()) {
 			bag.add(iterator.next());
 		}
@@ -609,63 +449,49 @@
 	}
 
 	/**
-	 * Return a bag corresponding to the specified array.
+	 * Return a new hash bag corresponding to the specified array.
 	 */
-	public static <E> HashBag<E> bag(E... array) {
+	public static <E> HashBag<E> hashBag(E... array) {
 		int len = array.length;
-		HashBag<E> bag = new HashBag<E>(len);
+		HashBag<E> bag = hashBag(len);
 		for (E item : array) {
 			bag.add(item);
 		}
 		return bag;
 	}
 
+
+	// ********** synchronized bag factory methods **********
+
 	/**
-	 * Return a bag corresponding to the specified queue, draining the queue
-	 * in the process.
+	 * Return a synchronized bag.
 	 */
-	public static <E> HashBag<E> bag(Queue<? extends E> queue) {
-		return bag(queue, new HashBag<E>());
+	public static <E> SynchronizedBag<E> synchronizedBag() {
+		HashBag<E> bag = hashBag();
+		return synchronizedBag(bag);
 	}
 
 	/**
-	 * Return a bag corresponding to the specified queue, draining the queue
-	 * in the process.
-	 * The specified queue size is a performance hint.
+	 * Return a bag that synchronizes with specified mutex.
 	 */
-	public static <E> HashBag<E> bag(Queue<? extends E> queue, int queueSize) {
-		return bag(queue, new HashBag<E>(queueSize));
-	}
-
-	private static <E> HashBag<E> bag(Queue<? extends E> queue, HashBag<E> set) {
-		while ( ! queue.isEmpty()) {
-			set.add(queue.dequeue());
-		}
-		return set;
+	public static <E> SynchronizedBag<E> synchronizedBag(Object mutex) {
+		HashBag<E> bag = hashBag();
+		return synchronizedBag(bag, mutex);
 	}
 
 	/**
-	 * Return a bag corresponding to the specified stack, draining the stack
-	 * in the process.
+	 * Return a bag that synchronizes the specified bag.
 	 */
-	public static <E> HashBag<E> bag(Stack<? extends E> stack) {
-		return bag(stack, new HashBag<E>());
+	public static <E> SynchronizedBag<E> synchronizedBag(Bag<E> bag) {
+		return new SynchronizedBag<E>(bag);
 	}
 
 	/**
-	 * Return a bag corresponding to the specified stack, draining the stack
-	 * in the process.
-	 * The specified stack size is a performance hint.
+	 * Return a bag that synchronizes the specified bag
+	 * with specified mutex.
 	 */
-	public static <E> HashBag<E> bag(Stack<? extends E> stack, int stackSize) {
-		return bag(stack, new HashBag<E>(stackSize));
-	}
-
-	private static <E> HashBag<E> bag(Stack<? extends E> stack, HashBag<E> set) {
-		while ( ! stack.isEmpty()) {
-			set.add(stack.pop());
-		}
-		return set;
+	public static <E> SynchronizedBag<E> synchronizedBag(Bag<E> bag, Object mutex) {
+		return new SynchronizedBag<E>(bag, mutex);
 	}
 
 	/**
@@ -674,43 +500,67 @@
 	 * The specified stack size is a performance hint.
 	 */
 	public static <E> Bag<E> emptyBag() {
-		return EmptyBag.<E>instance();
+		return EmptyBag.instance();
 	}
 
 
-	// ********** identity bag factory methods **********
+	// ********** identity hash bag factory methods **********
 
 	/**
-	 * Return an identity bag corresponding to the specified iterable.
+	 * Return a new identity hash bag.
 	 */
-	public static <E> IdentityHashBag<E> identityBag(Iterable<? extends E> iterable) {
-		return identityBag(iterable.iterator());
+	public static <E> IdentityHashBag<E> identityHashBag() {
+		return new IdentityHashBag<E>();
 	}
 
 	/**
-	 * Return an identity bag corresponding to the specified iterable.
+	 * Return a new identity hash bag with the specified initial capacity.
+	 */
+	public static <E> IdentityHashBag<E> identityHashBag(int initialCapacity) {
+		return new IdentityHashBag<E>(initialCapacity);
+	}
+
+	/**
+	 * Return a new identity hash bag with the specified initial capacity
+	 * and load factor.
+	 */
+	public static <E> IdentityHashBag<E> identityHashBag(int initialCapacity, float loadFactor) {
+		return new IdentityHashBag<E>(initialCapacity, loadFactor);
+	}
+
+	/**
+	 * Return a new identity hash bag corresponding to the specified iterable.
+	 */
+	public static <E> IdentityHashBag<E> identityHashBag(Iterable<? extends E> iterable) {
+		return identityHashBag(iterable.iterator());
+	}
+
+	/**
+	 * Return a new identity hash bag corresponding to the specified iterable.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E> IdentityHashBag<E> identityBag(Iterable<? extends E> iterable, int iterableSize) {
-		return identityBag(iterable.iterator(), iterableSize);
+	public static <E> IdentityHashBag<E> identityHashBag(Iterable<? extends E> iterable, int iterableSize) {
+		return identityHashBag(iterable.iterator(), iterableSize);
 	}
 
 	/**
-	 * Return an identity bag corresponding to the specified iterator.
+	 * Return a new identity hash bag corresponding to the specified iterator.
 	 */
-	public static <E> IdentityHashBag<E> identityBag(Iterator<? extends E> iterator) {
-		return identityBag(iterator, new IdentityHashBag<E>());
+	public static <E> IdentityHashBag<E> identityHashBag(Iterator<? extends E> iterator) {
+		IdentityHashBag<E> bag = identityHashBag();
+		return identityHashBag(iterator, bag);
 	}
 
 	/**
-	 * Return an identity bag corresponding to the specified iterator.
+	 * Return a new identity hash bag corresponding to the specified iterator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E> IdentityHashBag<E> identityBag(Iterator<? extends E> iterator, int iteratorSize) {
-		return identityBag(iterator, new IdentityHashBag<E>(iteratorSize));
+	public static <E> IdentityHashBag<E> identityHashBag(Iterator<? extends E> iterator, int iteratorSize) {
+		IdentityHashBag<E> bag = identityHashBag(iteratorSize);
+		return identityHashBag(iterator, bag);
 	}
 
-	private static <E> IdentityHashBag<E> identityBag(Iterator<? extends E> iterator, IdentityHashBag<E> bag) {
+	private static <E> IdentityHashBag<E> identityHashBag(Iterator<? extends E> iterator, IdentityHashBag<E> bag) {
 		while (iterator.hasNext()) {
 			bag.add(iterator.next());
 		}
@@ -718,11 +568,11 @@
 	}
 
 	/**
-	 * Return an identity bag corresponding to the specified array.
+	 * Return a new identity hash bag corresponding to the specified array.
 	 */
-	public static <E> IdentityHashBag<E> identityBag(E... array) {
+	public static <E> IdentityHashBag<E> identityHashBag(E... array) {
 		int len = array.length;
-		IdentityHashBag<E> bag = new IdentityHashBag<E>(len);
+		IdentityHashBag<E> bag = identityHashBag(len);
 		for (E item : array) {
 			bag.add(item);
 		}
@@ -730,113 +580,39 @@
 	}
 
 
-	// ********** collection factory methods **********
+	// ********** hash set factory methods **********
 
 	/**
-	 * Return a collection corresponding to the specified iterable.
+	 * Return a new hash set corresponding to the specified iterable.
 	 */
-	public static <E> HashBag<E> collection(Iterable<? extends E> iterable) {
-		return collection(iterable.iterator());
+	public static <E> HashSet<E> hashSet(Iterable<? extends E> iterable) {
+		return hashSet(iterable.iterator());
 	}
 
 	/**
-	 * Return a collection corresponding to the specified iterable.
+	 * Return a new hash set corresponding to the specified iterable.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E> HashBag<E> collection(Iterable<? extends E> iterable, int iterableSize) {
-		return collection(iterable.iterator(), iterableSize);
+	public static <E> HashSet<E> hashSet(Iterable<? extends E> iterable, int iterableSize) {
+		return hashSet(iterable.iterator(), iterableSize);
 	}
 
 	/**
-	 * Return a collection corresponding to the specified iterator.
+	 * Return a new hash set corresponding to the specified iterator.
 	 */
-	public static <E> HashBag<E> collection(Iterator<? extends E> iterator) {
-		return bag(iterator);
+	public static <E> HashSet<E> hashSet(Iterator<? extends E> iterator) {
+		return hashSet(iterator, new HashSet<E>());
 	}
 
 	/**
-	 * Return a collection corresponding to the specified iterator.
+	 * Return a new hash set corresponding to the specified iterator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E> HashBag<E> collection(Iterator<? extends E> iterator, int iteratorSize) {
-		return bag(iterator, iteratorSize);
+	public static <E> HashSet<E> hashSet(Iterator<? extends E> iterator, int iteratorSize) {
+		return hashSet(iterator, new HashSet<E>(iteratorSize));
 	}
 
-	/**
-	 * Return a collection corresponding to the specified array.
-	 */
-	public static <E> HashBag<E> collection(E... array) {
-		return bag(array);
-	}
-
-	/**
-	 * Return a collection corresponding to the specified queue, draining the queue
-	 * in the process.
-	 */
-	public static <E> HashBag<E> collection(Queue<? extends E> queue) {
-		return bag(queue);
-	}
-
-	/**
-	 * Return a collection corresponding to the specified queue, draining the queue
-	 * in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> HashBag<E> collection(Queue<? extends E> queue, int queueSize) {
-		return bag(queue, queueSize);
-	}
-
-	/**
-	 * Return a collection corresponding to the specified stack, draining the stack
-	 * in the process.
-	 */
-	public static <E> HashBag<E> collection(Stack<? extends E> stack) {
-		return bag(stack);
-	}
-
-	/**
-	 * Return a collection corresponding to the specified stack, draining the stack
-	 * in the process.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> HashBag<E> collection(Stack<? extends E> stack, int stackSize) {
-		return bag(stack, stackSize);
-	}
-
-
-	// ********** set factory methods **********
-
-	/**
-	 * Return a set corresponding to the specified iterable.
-	 */
-	public static <E> HashSet<E> set(Iterable<? extends E> iterable) {
-		return set(iterable.iterator());
-	}
-
-	/**
-	 * Return a set corresponding to the specified iterable.
-	 * The specified iterable size is a performance hint.
-	 */
-	public static <E> HashSet<E> set(Iterable<? extends E> iterable, int iterableSize) {
-		return set(iterable.iterator(), iterableSize);
-	}
-
-	/**
-	 * Return a set corresponding to the specified iterator.
-	 */
-	public static <E> HashSet<E> set(Iterator<? extends E> iterator) {
-		return set(iterator, new HashSet<E>());
-	}
-
-	/**
-	 * Return a set corresponding to the specified iterator.
-	 * The specified iterator size is a performance hint.
-	 */
-	public static <E> HashSet<E> set(Iterator<? extends E> iterator, int iteratorSize) {
-		return set(iterator, new HashSet<E>(iteratorSize));
-	}
-
-	private static <E> HashSet<E> set(Iterator<? extends E> iterator, HashSet<E> set) {
+	private static <E> HashSet<E> hashSet(Iterator<? extends E> iterator, HashSet<E> set) {
 		while (iterator.hasNext()) {
 			set.add(iterator.next());
 		}
@@ -844,9 +620,9 @@
 	}
 
 	/**
-	 * Return a set corresponding to the specified array.
+	 * Return a new hash set corresponding to the specified array.
 	 */
-	public static <E> HashSet<E> set(E... array) {
+	public static <E> HashSet<E> hashSet(E... array) {
 		HashSet<E> set = new HashSet<E>(array.length);
 		for (int i = array.length; i-- > 0;) {
 			set.add(array[i]);
@@ -854,213 +630,96 @@
 		return set;
 	}
 
+
+	// ********** tree (sorted) set factory methods **********
+
 	/**
-	 * Return a set corresponding to the specified queue, draining the queue
-	 * in the process.
+	 * Return a new tree (sorted) set corresponding to the specified iterable.
 	 */
-	public static <E> HashSet<E> set(Queue<? extends E> queue) {
-		return set(queue, new HashSet<E>());
+	public static <E extends Comparable<? super E>> TreeSet<E> treeSet(Iterable<? extends E> iterable) {
+		return treeSet(iterable.iterator());
 	}
 
 	/**
-	 * Return a set corresponding to the specified queue, draining the queue
-	 * in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> HashSet<E> set(Queue<? extends E> queue, int queueSize) {
-		return set(queue, new HashSet<E>(queueSize));
-	}
-
-	private static <E> HashSet<E> set(Queue<? extends E> queue, HashSet<E> set) {
-		while ( ! queue.isEmpty()) {
-			set.add(queue.dequeue());
-		}
-		return set;
-	}
-
-	/**
-	 * Return a set corresponding to the specified stack, draining the stack
-	 * in the process.
-	 */
-	public static <E> HashSet<E> set(Stack<? extends E> stack) {
-		return set(stack, new HashSet<E>());
-	}
-
-	/**
-	 * Return a set corresponding to the specified stack, draining the stack
-	 * in the process.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> HashSet<E> set(Stack<? extends E> stack, int stackSize) {
-		return set(stack, new HashSet<E>(stackSize));
-	}
-
-	private static <E> HashSet<E> set(Stack<? extends E> stack, HashSet<E> set) {
-		while ( ! stack.isEmpty()) {
-			set.add(stack.pop());
-		}
-		return set;
-	}
-
-
-	// ********** sorted set factory methods **********
-
-	/**
-	 * Return a sorted set corresponding to the specified iterable.
-	 */
-	public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterable<? extends E> iterable) {
-		return sortedSet(iterable.iterator());
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified iterable.
+	 * Return a new tree (sorted) set corresponding to the specified iterable.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterable<? extends E> iterable, int iterableSize) {
-		return sortedSet(iterable.iterator(), iterableSize);
+	public static <E extends Comparable<? super E>> TreeSet<E> treeSet(Iterable<? extends E> iterable, int iterableSize) {
+		return treeSet(iterable.iterator(), iterableSize);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterable
+	 * Return a new tree (sorted) set corresponding to the specified iterable
 	 * and comparator.
 	 */
-	public static <E> TreeSet<E> sortedSet(Iterable<? extends E> iterable, Comparator<? super E> comparator) {
-		return sortedSet(iterable.iterator(), comparator);
+	public static <E> TreeSet<E> treeSet(Iterable<? extends E> iterable, Comparator<? super E> comparator) {
+		return treeSet(iterable.iterator(), comparator);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterable
+	 * Return a new tree (sorted) set corresponding to the specified iterable
 	 * and comparator.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E> TreeSet<E> sortedSet(Iterable<? extends E> iterable, Comparator<? super E> comparator, int iterableSize) {
-		return sortedSet(iterable.iterator(), comparator, iterableSize);
+	public static <E> TreeSet<E> treeSet(Iterable<? extends E> iterable, Comparator<? super E> comparator, int iterableSize) {
+		return treeSet(iterable.iterator(), comparator, iterableSize);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterator.
+	 * Return a new tree (sorted) set corresponding to the specified iterator.
 	 */
-	public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterator<? extends E> iterator) {
-		return sortedSet(iterator, null);
+	public static <E extends Comparable<? super E>> TreeSet<E> treeSet(Iterator<? extends E> iterator) {
+		return treeSet(iterator, null);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterator.
+	 * Return a new tree (sorted) set corresponding to the specified iterator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(Iterator<? extends E> iterator, int iteratorSize) {
-		return sortedSet(iterator, null, iteratorSize);
+	public static <E extends Comparable<? super E>> TreeSet<E> treeSet(Iterator<? extends E> iterator, int iteratorSize) {
+		return treeSet(iterator, null, iteratorSize);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterator
+	 * Return a new tree (sorted) set corresponding to the specified iterator
 	 * and comparator.
 	 */
-	public static <E> TreeSet<E> sortedSet(Iterator<? extends E> iterator, Comparator<? super E> comparator) {
-		return sortedSet(ListTools.list(iterator), comparator);
+	public static <E> TreeSet<E> treeSet(Iterator<? extends E> iterator, Comparator<? super E> comparator) {
+		return treeSet(ListTools.arrayList(iterator), comparator);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified iterator
+	 * Return a new tree (sorted) set corresponding to the specified iterator
 	 * and comparator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E> TreeSet<E> sortedSet(Iterator<? extends E> iterator, Comparator<? super E> comparator, int iteratorSize) {
-		return sortedSet(ListTools.list(iterator, iteratorSize), comparator);
+	public static <E> TreeSet<E> treeSet(Iterator<? extends E> iterator, Comparator<? super E> comparator, int iteratorSize) {
+		return treeSet(ListTools.arrayList(iterator, iteratorSize), comparator);
 	}
 
-	private static <E> TreeSet<E> sortedSet(List<E> list, Comparator<? super E> comparator) {
+	private static <E> TreeSet<E> treeSet(ArrayList<E> list, Comparator<? super E> comparator) {
 		TreeSet<E> sortedSet = new TreeSet<E>(comparator);
 		sortedSet.addAll(list);
 		return sortedSet;
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified array.
+	 * Return a new tree (sorted) set corresponding to the specified array.
 	 */
-	public static <E extends Comparable<? super E>> TreeSet<E> sortedSet(E... array) {
-		return sortedSet(array, null);
+	public static <E extends Comparable<? super E>> TreeSet<E> treeSet(E... array) {
+		return treeSet(array, null);
 	}
 
 	/**
-	 * Return a sorted set corresponding to the specified array
+	 * Return a new tree (sorted) set corresponding to the specified array
 	 * and comparator.
 	 */
-	public static <E> TreeSet<E> sortedSet(E[] array, Comparator<? super E> comparator) {
+	public static <E> TreeSet<E> treeSet(E[] array, Comparator<? super E> comparator) {
 		TreeSet<E> sortedSet = new TreeSet<E>(comparator);
 		sortedSet.addAll(Arrays.asList(array));
 		return sortedSet;
 	}
 
-	/**
-	 * Return a sorted set corresponding to the specified queue,
-	 * draining the queue in the process.
-	 */
-	public static <E> TreeSet<E> sortedSet(Queue<? extends E> queue) {
-		return sortedSet(queue, null);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified queue,
-	 * draining the queue in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> TreeSet<E> sortedSet(Queue<? extends E> queue, int queueSize) {
-		return sortedSet(queue, null, queueSize);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified queue and comparator,
-	 * draining the queue in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> TreeSet<E> sortedSet(Queue<? extends E> queue, Comparator<? super E> comparator) {
-		return sortedSet(ListTools.list(queue), comparator);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified queue and comparator,
-	 * draining the queue in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> TreeSet<E> sortedSet(Queue<? extends E> queue, Comparator<? super E> comparator, int queueSize) {
-		return sortedSet(ListTools.list(queue, queueSize), comparator);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified stack,
-	 * draining the stack in the process.
-	 */
-	public static <E> TreeSet<E> sortedSet(Stack<? extends E> stack) {
-		return sortedSet(stack, null);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified stack,
-	 * draining the stack in the process.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> TreeSet<E> sortedSet(Stack<? extends E> stack, int stackSize) {
-		return sortedSet(stack, null, stackSize);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified stack and comparator,
-	 * draining the stack in the process.
-	 */
-	public static <E> TreeSet<E> sortedSet(Stack<? extends E> stack, Comparator<? super E> comparator) {
-		return sortedSet(ListTools.list(stack), comparator);
-	}
-
-	/**
-	 * Return a sorted set corresponding to the specified stack and comparator,
-	 * draining the stack in the process.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> TreeSet<E> sortedSet(Stack<? extends E> stack, Comparator<? super E> comparator, int stackSize) {
-		return sortedSet(ListTools.list(stack, stackSize), comparator);
-	}
-
 
 	// ********** Old School Vector factory methods **********
 
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayQueue.java
deleted file mode 100644
index 1308adf..0000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayQueue.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2015 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.collection;
-
-import java.io.Serializable;
-import java.util.Arrays;
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-
-/**
- * Fixed-sized array FIFO implementation of the {@link Queue} interface.
- * This implementation will throw an exception if its capacity is exceeded.
- * @param <E> the type of elements maintained by the queue
- * @see ArrayQueue
- * @see QueueTools
- */
-public class FixedSizeArrayQueue<E>
-	implements Queue<E>, Cloneable, Serializable
-{
-	private final E[] elements;
-
-	/** Index of next element to be "dequeued". */
-	private int head = 0;
-
-	/** Index of next element to be "enqueued". */
-	private int tail = 0;
-
-	private int size = 0;
-
-	private static final long serialVersionUID = 1L;
-
-
-	// ********** constructors **********
-
-	/**
-	 * Construct an empty queue with the specified capacity.
-	 */
-	@SuppressWarnings("unchecked")
-	public FixedSizeArrayQueue(int capacity) {
-		super();
-		if (capacity < 0) {
-			throw new IllegalArgumentException("Illegal capacity: " + capacity); //$NON-NLS-1$
-		}
-		this.elements = (E[]) new Object[capacity];
-	}
-
-
-	// ********** Queue implementation **********
-
-	/**
-	 * @exception IllegalStateException if the queue is full
-	 */
-	public void enqueue(E element) {
-		if (this.isFull()) {
-			throw new IllegalStateException("Queue is full."); //$NON-NLS-1$
-		}
-		this.elements[this.tail] = element;
-		if (++this.tail == this.elements.length) {
-			this.tail = 0;
-		}
-		this.size++;
-	}
-
-	public E dequeue() {
-		if (this.size == 0) {
-			throw new NoSuchElementException();
-		}
-		E element = this.elements[this.head];
-		this.elements[this.head] = null; // allow GC to work
-		if (++this.head == this.elements.length) {
-			this.head = 0;
-		}
-		this.size--;
-		return element;
-	}
-
-	public E peek() {
-		if (this.size == 0) {
-			throw new NoSuchElementException();
-		}
-		return this.elements[this.head];
-	}
-
-	public boolean isEmpty() {
-		return this.size == 0;
-	}
-
-	/**
-	 * Return whether the queue is full,
-	 * as its capacity is fixed.
-	 */
-	public boolean isFull() {
-		return this.size == this.elements.length;
-	}
-
-
-	// ********** standard methods **********
-
-	@Override
-	public FixedSizeArrayQueue<E> clone() {
-		int len = this.elements.length;
-		FixedSizeArrayQueue<E> clone = new FixedSizeArrayQueue<E>(len);
-		System.arraycopy(this.elements, 0, clone.elements, 0, len);
-		clone.head = this.head;
-		clone.tail = this.tail;
-		clone.size = this.size;
-		return clone;
-	}
-
-	@Override
-	public String toString() {
-		return Arrays.toString(this.copyElements());
-	}
-
-	private Object[] copyElements() {
-		if (this.size == 0) {
-			return ObjectTools.EMPTY_OBJECT_ARRAY;
-		}
-		Object[] result = new Object[this.size];
-		if ((this.head == 0) || (this.head < this.tail) || (this.tail == 0)) {
-			// elements are contiguous
-			System.arraycopy(this.elements, this.head, result, 0, this.size);
-		} else {
-			// elements wrap past end of array
-			int fragmentSize = this.elements.length - this.head;
-			System.arraycopy(this.elements, this.head, result, 0, fragmentSize);
-			System.arraycopy(this.elements, 0, result, fragmentSize, (this.size - fragmentSize));
-		}
-		return result;
-	}
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/HashBag.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/HashBag.java
index cacf9d5..4c98665 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/HashBag.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/HashBag.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -76,7 +76,7 @@
 	implements Bag<E>, Cloneable, Serializable
 {
 	/** The hash table. Resized as necessary. Length MUST Always be a power of two. */
-	transient Entry<E>[] table;
+	transient Entry[] table;
 
 	/** The total number of entries in the bag. */
 	transient int size = 0;
@@ -254,7 +254,7 @@
 	private void add_(E o, int cnt) {
 		int hash = this.hash(o);
 		int index = this.index(hash);
-		for (Entry<E> e = this.table[index]; e != null; e = e.next) {
+		for (Entry e = this.table[index]; e != null; e = e.next) {
 			Object eo;
 			if ((e.hash == hash) && (((eo = e.object) == o) || ((o != null) && o.equals(eo)))) {
 				e.count += cnt;
@@ -264,7 +264,7 @@
 		}
 
 		// create the new entry and put it in the table
-		Entry<E> e = this.buildEntry(hash, o, cnt, this.table[index]);
+		Entry e = this.buildEntry(hash, o, cnt, this.table[index]);
 		this.table[index] = e;
 		this.size += cnt;
 		this.uniqueCount++;
@@ -291,9 +291,9 @@
 	 * the object's hash code and examining the entries in the corresponding hash
 	 * table bucket.
 	 */
-	private Entry<E> getEntry(Object o) {
+	private Entry getEntry(Object o) {
 		int hash = this.hash(o);
-		for (Entry<E> e = this.table[this.index(hash)]; e != null; e = e.next) {
+		for (Entry e = this.table[this.index(hash)]; e != null; e = e.next) {
 			Object eo;
 			if ((e.hash == hash) && (((eo = e.object) == o) || ((o != null) && o.equals(eo)))) {
 				return e;
@@ -308,7 +308,7 @@
 	}
 
 	public int count(Object o) {
-		Entry<E> e = this.getEntry(o);
+		Entry e = this.getEntry(o);
 		return (e == null) ? 0 : e.count;
 	}
 
@@ -319,7 +319,7 @@
 	 * capacity and load factor.
 	 */
 	private void rehash() {
-		Entry<E>[] oldTable = this.table;
+		Entry[] oldTable = this.table;
 		int oldCapacity = oldTable.length;
 
 		if (oldCapacity == MAXIMUM_CAPACITY) {
@@ -328,11 +328,11 @@
 		}
 
 		int newCapacity = 2 * oldCapacity;
-		Entry<E>[] newTable = this.buildTable(newCapacity);
+		Entry[] newTable = this.buildTable(newCapacity);
 
 		for (int i = oldCapacity; i-- > 0; ) {
-			for (Entry<E> old = oldTable[i]; old != null; ) {
-				Entry<E> e = old;
+			for (Entry old = oldTable[i]; old != null; ) {
+				Entry e = old;
 				old = old.next;
 
 				int index = this.index(e.hash, newCapacity);
@@ -347,8 +347,8 @@
 
 	// minimize scope of suppressed warnings
 	@SuppressWarnings("unchecked")
-	private Entry<E>[] buildTable(int capacity) {
-		return new Entry[capacity];
+	private Entry[] buildTable(int capacity) {
+		return new HashBag.Entry[capacity];
 	}
 
 	/**
@@ -375,7 +375,7 @@
 		int index = this.index(hash);
 
 		// if the object is already in the bag, simply bump its count
-		for (Entry<E> e = this.table[index]; e != null; e = e.next) {
+		for (Entry e = this.table[index]; e != null; e = e.next) {
 			Object eo;
 			if ((e.hash == hash) && (((eo = e.object) == o) || ((o != null) && o.equals(eo)))) {
 				e.count += cnt;
@@ -391,7 +391,7 @@
 		}
 
 		// create the new entry and put it in the table
-		Entry<E> e = this.buildEntry(hash, o, cnt, this.table[index]);
+		Entry e = this.buildEntry(hash, o, cnt, this.table[index]);
 		this.table[index] = e;
 		this.size += cnt;
 		this.uniqueCount++;
@@ -399,9 +399,9 @@
 	}
 
 	// minimize scope of suppressed warnings
-	@SuppressWarnings({ "rawtypes", "unchecked" } )
-	private Entry<E> buildEntry(int hash, Object o, int cnt, Entry next) {
-		return new Entry<E>(hash, (E) o, cnt, (Entry<E>) next);
+	@SuppressWarnings("unchecked")
+	private Entry buildEntry(int hash, Object o, int cnt, Entry next) {
+		return new Entry(hash, (E) o, cnt, next);
 	}
 
 	/**
@@ -426,7 +426,7 @@
 		int hash = this.hash(o);
 		int index = this.index(hash);
 
-		for (Entry<E> e = this.table[index], prev = null; e != null; prev = e, e = e.next) {
+		for (Entry e = this.table[index], prev = null; e != null; prev = e, e = e.next) {
 			Object eo;
 			if ((e.hash == hash) && (((eo = e.object) == o) || ((o != null) && o.equals(eo)))) {
 				this.modCount++;
@@ -454,7 +454,7 @@
 	 */
 	@Override
 	public void clear() {
-		Entry<E>[] tab = this.table;
+		Entry[] tab = this.table;
 		this.modCount++;
 		for (int i = tab.length; i-- > 0; ) {
 			tab[i] = null;
@@ -489,15 +489,15 @@
 	/**
 	 * Hash table collision list entry.
 	 */
-	private static class Entry<E>
+	private class Entry
 		implements Bag.Entry<E>
 	{
 		final int hash;
 		final E object;
 		int count;
-		Entry<E> next;
+		Entry next;
 
-		Entry(int hash, E object, int count, Entry<E> next) {
+		Entry(int hash, E object, int count, Entry next) {
 			this.hash = hash;
 			this.object = object;
 			this.count = count;
@@ -519,6 +519,7 @@
 			}
 			int old = this.count;
 			this.count = count;
+			HashBag.this.size += (count - old);
 			return old;
 		}
 
@@ -599,9 +600,9 @@
 		implements Iterator<E>
 	{
 		private int index = HashBag.this.table.length;	// start at the end of the table
-		private Entry<E> nextEntry = null;
+		private Entry nextEntry = null;
 		private int nextEntryCount = 0;
-		private Entry<E> lastReturnedEntry = null;
+		private Entry lastReturnedEntry = null;
 
 		/**
 		 * The modCount value that the iterator believes that the backing
@@ -615,9 +616,9 @@
 		}
 
 		public boolean hasNext() {
-			Entry<E> e = this.nextEntry;
+			Entry e = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = HashBag.this.table;
+			Entry[] tab = HashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((e == null) && (i > 0)) {
 				e = tab[--i];		// move backwards through the table
@@ -631,9 +632,9 @@
 			if (HashBag.this.modCount != this.expectedModCount) {
 				throw new ConcurrentModificationException();
 			}
-			Entry<E> et = this.nextEntry;
+			Entry et = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = HashBag.this.table;
+			Entry[] tab = HashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((et == null) && (i > 0)) {
 				et = tab[--i];		// move backwards through the table
@@ -643,7 +644,7 @@
 			if (et == null) {
 				throw new NoSuchElementException();
 			}
-			Entry<E> e = this.lastReturnedEntry = this.nextEntry;
+			Entry e = this.lastReturnedEntry = this.nextEntry;
 			this.nextEntryCount++;
 			if (this.nextEntryCount == e.count) {
 				this.nextEntry = e.next;
@@ -660,7 +661,7 @@
 				throw new ConcurrentModificationException();
 			}
 			int slot = HashBag.this.index(this.lastReturnedEntry.hash, HashBag.this.table.length);
-			for (Entry<E> e = HashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
+			for (Entry e = HashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
 				if (e == this.lastReturnedEntry) {
 					HashBag.this.modCount++;
 					this.expectedModCount++;
@@ -688,11 +689,11 @@
 
 
 	private class EntryIterator
-		implements Iterator<Entry<E>>
+		implements Iterator<Entry>
 	{
 		private int index = HashBag.this.table.length;	// start at the end of the table
-		private Entry<E> nextEntry = null;
-		private Entry<E> lastReturnedEntry = null;
+		private Entry nextEntry = null;
+		private Entry lastReturnedEntry = null;
 
 		/**
 		 * The modCount value that the iterator believes that the backing
@@ -706,9 +707,9 @@
 		}
 
 		public boolean hasNext() {
-			Entry<E> e = this.nextEntry;
+			Entry e = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = HashBag.this.table;
+			Entry[] tab = HashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((e == null) && (i > 0)) {
 				e = tab[--i];		// move backwards through the table
@@ -718,13 +719,13 @@
 			return e != null;
 		}
 
-		public Entry<E> next() {
+		public Entry next() {
 			if (HashBag.this.modCount != this.expectedModCount) {
 				throw new ConcurrentModificationException();
 			}
-			Entry<E> et = this.nextEntry;
+			Entry et = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = HashBag.this.table;
+			Entry[] tab = HashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((et == null) && (i > 0)) {
 				et = tab[--i];		// move backwards through the table
@@ -734,7 +735,7 @@
 			if (et == null) {
 				throw new NoSuchElementException();
 			}
-			Entry<E> e = this.lastReturnedEntry = this.nextEntry;
+			Entry e = this.lastReturnedEntry = this.nextEntry;
 			this.nextEntry = e.next;
 			return e;
 		}
@@ -747,7 +748,7 @@
 				throw new ConcurrentModificationException();
 			}
 			int slot = HashBag.this.index(this.lastReturnedEntry.hash, HashBag.this.table.length);
-			for (Entry<E> e = HashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
+			for (Entry e = HashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
 				if (e == this.lastReturnedEntry) {
 					HashBag.this.modCount++;
 					this.expectedModCount++;
@@ -848,7 +849,7 @@
 
 		// write out elements and counts (alternating)
 		if (this.uniqueCount > 0) {
-			for (Entry<E> entry : this.table) {
+			for (Entry entry : this.table) {
 				while (entry != null) {
 					s.writeObject(entry.object);
 					s.writeInt(entry.count);
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/IdentityHashBag.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/IdentityHashBag.java
index ef7b413..203bb14 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/IdentityHashBag.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/IdentityHashBag.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -92,7 +92,7 @@
 	implements Bag<E>, Cloneable, Serializable
 {
 	/** The hash table. Resized as necessary. Length MUST Always be a power of two. */
-	transient Entry<E>[] table;
+	transient Entry[] table;
 
 	/** The total number of entries in the bag. */
 	transient int size = 0;
@@ -277,7 +277,7 @@
 	private void add_(E o, int cnt) {
 		int hash = this.hash(o);
 		int index = this.index(hash);
-		for (Entry<E> e = this.table[index]; e != null; e = e.next) {
+		for (Entry e = this.table[index]; e != null; e = e.next) {
 			if (e.object == o) {
 				e.count += cnt;
 				this.size += cnt;
@@ -286,7 +286,7 @@
 		}
 
 		// create the new entry and put it in the table
-		Entry<E> e = this.buildEntry(hash, o, cnt, this.table[index]);
+		Entry e = this.buildEntry(hash, o, cnt, this.table[index]);
 		this.table[index] = e;
 		this.size += cnt;
 		this.uniqueCount++;
@@ -313,8 +313,8 @@
 	 * the object's identity hash code and examining the entries in the corresponding hash
 	 * table bucket.
 	 */
-	private Entry<E> getEntry(Object o) {
-		for (Entry<E> e = this.table[this.index(o)]; e != null; e = e.next) {
+	private Entry getEntry(Object o) {
+		for (Entry e = this.table[this.index(o)]; e != null; e = e.next) {
 			if (e.object == o) {
 				return e;
 			}
@@ -328,7 +328,7 @@
 	}
 
 	public int count(Object o) {
-		Entry<E> e = this.getEntry(o);
+		Entry e = this.getEntry(o);
 		return (e == null) ? 0 : e.count;
 	}
 
@@ -339,7 +339,7 @@
 	 * capacity and load factor.
 	 */
 	private void rehash() {
-		Entry<E>[] oldTable = this.table;
+		Entry[] oldTable = this.table;
 		int oldCapacity = oldTable.length;
 
 		if (oldCapacity == MAXIMUM_CAPACITY) {
@@ -348,11 +348,11 @@
 		}
 
 		int newCapacity = 2 * oldCapacity;
-		Entry<E>[] newTable = this.buildTable(newCapacity);
+		Entry[] newTable = this.buildTable(newCapacity);
 
 		for (int i = oldCapacity; i-- > 0; ) {
-			for (Entry<E> old = oldTable[i]; old != null; ) {
-				Entry<E> e = old;
+			for (Entry old = oldTable[i]; old != null; ) {
+				Entry e = old;
 				old = old.next;
 
 				int index = this.index(e.hash, newCapacity);
@@ -367,8 +367,8 @@
 
 	// minimize scope of suppressed warnings
 	@SuppressWarnings("unchecked")
-	private Entry<E>[] buildTable(int capacity) {
-		return new Entry[capacity];
+	private Entry[] buildTable(int capacity) {
+		return new IdentityHashBag.Entry[capacity];
 	}
 
 	/**
@@ -395,7 +395,7 @@
 		int index = this.index(hash);
 
 		// if the object is already in the bag, simply bump its count
-		for (Entry<E> e = this.table[index]; e != null; e = e.next) {
+		for (Entry e = this.table[index]; e != null; e = e.next) {
 			if (e.object == o) {
 				e.count += cnt;
 				this.size += cnt;
@@ -410,7 +410,7 @@
 		}
 
 		// create the new entry and put it in the table
-		Entry<E> e = this.buildEntry(hash, o, cnt, this.table[index]);
+		Entry e = this.buildEntry(hash, o, cnt, this.table[index]);
 		this.table[index] = e;
 		this.size += cnt;
 		this.uniqueCount++;
@@ -418,9 +418,9 @@
 	}
 
 	// minimize scope of suppressed warnings
-	@SuppressWarnings({ "unchecked", "rawtypes" })
-	private Entry<E> buildEntry(int hash, Object o, int cnt, Entry next) {
-		return new Entry<E>(hash, (E) o, cnt, (Entry<E>) next);
+	@SuppressWarnings("unchecked")
+	private Entry buildEntry(int hash, Object o, int cnt, Entry next) {
+		return new Entry(hash, (E) o, cnt, next);
 	}
 
 	/**
@@ -444,7 +444,7 @@
 		}
 		int index = this.index(o);
 
-		for (Entry<E> e = this.table[index], prev = null; e != null; prev = e, e = e.next) {
+		for (Entry e = this.table[index], prev = null; e != null; prev = e, e = e.next) {
 			if (e.object == o) {
 				this.modCount++;
 				cnt = (cnt < e.count) ? cnt : e.count;
@@ -489,7 +489,7 @@
 	 */
 	@Override
 	public void clear() {
-		Entry<E>[] tab = this.table;
+		Entry[] tab = this.table;
 		this.modCount++;
 		for (int i = tab.length; i-- > 0; ) {
 			tab[i] = null;
@@ -524,15 +524,15 @@
 	/**
 	 * Hash table collision list entry.
 	 */
-	private static class Entry<E>
+	private class Entry
 		implements Bag.Entry<E>
 	{
 		final int hash;  // cache the hash for re-hashes
 		final E object;
 		int count;
-		Entry<E> next;
+		Entry next;
 
-		Entry(int hash, E object, int count, Entry<E> next) {
+		Entry(int hash, E object, int count, Entry next) {
 			this.hash = hash;
 			this.object = object;
 			this.count = count;
@@ -554,6 +554,7 @@
 			}
 			int old = this.count;
 			this.count = count;
+			IdentityHashBag.this.size += (count - old);
 			return old;
 		}
 
@@ -634,9 +635,9 @@
 		implements Iterator<E>
 	{
 		private int index = IdentityHashBag.this.table.length;	// start at the end of the table
-		private Entry<E> nextEntry = null;
+		private Entry nextEntry = null;
 		private int nextEntryCount = 0;
-		private Entry<E> lastReturnedEntry = null;
+		private Entry lastReturnedEntry = null;
 
 		/**
 		 * The modCount value that the iterator believes that the backing
@@ -650,9 +651,9 @@
 		}
 
 		public boolean hasNext() {
-			Entry<E> e = this.nextEntry;
+			Entry e = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = IdentityHashBag.this.table;
+			Entry[] tab = IdentityHashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((e == null) && (i > 0)) {
 				e = tab[--i];		// move backwards through the table
@@ -666,9 +667,9 @@
 			if (IdentityHashBag.this.modCount != this.expectedModCount) {
 				throw new ConcurrentModificationException();
 			}
-			Entry<E> et = this.nextEntry;
+			Entry et = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = IdentityHashBag.this.table;
+			Entry[] tab = IdentityHashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((et == null) && (i > 0)) {
 				et = tab[--i];		// move backwards through the table
@@ -678,7 +679,7 @@
 			if (et == null) {
 				throw new NoSuchElementException();
 			}
-			Entry<E> e = this.lastReturnedEntry = this.nextEntry;
+			Entry e = this.lastReturnedEntry = this.nextEntry;
 			this.nextEntryCount++;
 			if (this.nextEntryCount == e.count) {
 				this.nextEntry = e.next;
@@ -695,7 +696,7 @@
 				throw new ConcurrentModificationException();
 			}
 			int slot = IdentityHashBag.this.index(this.lastReturnedEntry.hash, IdentityHashBag.this.table.length);
-			for (Entry<E> e = IdentityHashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
+			for (Entry e = IdentityHashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
 				if (e == this.lastReturnedEntry) {
 					IdentityHashBag.this.modCount++;
 					this.expectedModCount++;
@@ -723,11 +724,11 @@
 
 
 	private class EntryIterator
-		implements Iterator<Entry<E>>
+		implements Iterator<Entry>
 	{
 		private int index = IdentityHashBag.this.table.length;	// start at the end of the table
-		private Entry<E> nextEntry = null;
-		private Entry<E> lastReturnedEntry = null;
+		private Entry nextEntry = null;
+		private Entry lastReturnedEntry = null;
 
 		/**
 		 * The modCount value that the iterator believes that the backing
@@ -741,9 +742,9 @@
 		}
 
 		public boolean hasNext() {
-			Entry<E> e = this.nextEntry;
+			Entry e = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = IdentityHashBag.this.table;
+			Entry[] tab = IdentityHashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((e == null) && (i > 0)) {
 				e = tab[--i];		// move backwards through the table
@@ -753,13 +754,13 @@
 			return e != null;
 		}
 
-		public Entry<E> next() {
+		public Entry next() {
 			if (IdentityHashBag.this.modCount != this.expectedModCount) {
 				throw new ConcurrentModificationException();
 			}
-			Entry<E> et = this.nextEntry;
+			Entry et = this.nextEntry;
 			int i = this.index;
-			Entry<E>[] tab = IdentityHashBag.this.table;
+			Entry[] tab = IdentityHashBag.this.table;
 			// Use locals for faster loop iteration
 			while ((et == null) && (i > 0)) {
 				et = tab[--i];		// move backwards through the table
@@ -769,7 +770,7 @@
 			if (et == null) {
 				throw new NoSuchElementException();
 			}
-			Entry<E> e = this.lastReturnedEntry = this.nextEntry;
+			Entry e = this.lastReturnedEntry = this.nextEntry;
 			this.nextEntry = e.next;
 			return e;
 		}
@@ -782,7 +783,7 @@
 				throw new ConcurrentModificationException();
 			}
 			int slot = IdentityHashBag.this.index(this.lastReturnedEntry.hash, IdentityHashBag.this.table.length);
-			for (Entry<E> e = IdentityHashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
+			for (Entry e = IdentityHashBag.this.table[slot], prev = null; e != null; prev = e, e = e.next) {
 				if (e == this.lastReturnedEntry) {
 					IdentityHashBag.this.modCount++;
 					this.expectedModCount++;
@@ -887,7 +888,7 @@
 
 		// write out elements and counts (alternating)
 		if (this.uniqueCount > 0) {
-			for (Entry<E> entry : this.table) {
+			for (Entry entry : this.table) {
 				while (entry != null) {
 					s.writeObject(entry.object);
 					s.writeInt(entry.count);
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListTools.java
index 5192bf1..1864cae 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -20,8 +20,6 @@
 import java.util.ListIterator;
 import java.util.Random;
 import java.util.RandomAccess;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.internal.Range;
 import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
 import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
@@ -61,7 +59,14 @@
 	 * Return whether the list changed as a result.
 	 */
 	public static <E> boolean addAll(List<? super E> list, int index, Iterator<? extends E> iterator) {
-		return iterator.hasNext() && list.addAll(index, list(iterator));
+		return iterator.hasNext() && addAll_(list, index, iterator);
+	}
+
+	/**
+	 * assume the iterator is not empty
+	 */
+	private static <E> boolean addAll_(List<? super E> list, int index, Iterator<? extends E> iterator) {
+		return (index == list.size()) ? CollectionTools.addAll_(list, iterator) : list.addAll(index, arrayList(iterator));
 	}
 
 	/**
@@ -71,7 +76,7 @@
 	 * The specified iterator size is a performance hint.
 	 */
 	public static <E> boolean addAll(List<? super E> list, int index, Iterator<? extends E> iterator, int iteratorSize) {
-		return iterator.hasNext() && list.addAll(index, list(iterator, iteratorSize));
+		return iterator.hasNext() && list.addAll(index, arrayList(iterator, iteratorSize));
 	}
 
 	/**
@@ -83,48 +88,6 @@
 		return (array.length != 0) && list.addAll(index, Arrays.asList(array));
 	}
 
-	/**
-	 * Add all the elements in the specified queue
-	 * to the specified list at the specified index,
-	 * draining the queue in the process.
-	 * Return whether the list changed as a result.
-	 */
-	public static <E> boolean addAll(List<? super E> list, int index, Queue<? extends E> queue) {
-		return ( ! queue.isEmpty()) && list.addAll(index, list(queue));
-	}
-
-	/**
-	 * Add all the elements in the specified queue
-	 * to the specified list at the specified index,
-	 * draining the queue in the process.
-	 * Return whether the list changed as a result.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> boolean addAll(List<? super E> list, int index, Queue<? extends E> queue, int queueSize) {
-		return ( ! queue.isEmpty()) && list.addAll(index, list(queue, queueSize));
-	}
-
-	/**
-	 * Add all the elements in the specified stack
-	 * to the specified list at the specified index,
-	 * draining the stack in the process.
-	 * Return whether the list changed as a result.
-	 */
-	public static <E> boolean addAll(List<? super E> list, int index, Stack<? extends E> stack) {
-		return ( ! stack.isEmpty()) && list.addAll(index, list(stack));
-	}
-
-	/**
-	 * Add all the elements in the specified stack
-	 * to the specified list at the specified index,
-	 * draining the stack in the process.
-	 * Return whether the list changed as a result.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> boolean addAll(List<? super E> list, int index, Stack<? extends E> stack, int stackSize) {
-		return ( ! stack.isEmpty()) && list.addAll(index, list(stack, stackSize));
-	}
-
 
 	// ********** diff **********
 
@@ -585,7 +548,7 @@
 	 * Return a new list with transformations of the
 	 * elements in the specified list.
 	 */
-	public static <I, O> ArrayList<O> transform(List<I> list, Transformer<? super I, ? extends O> transformer) {
+	public static <I, O> ArrayList<O> transform(Collection<I> list, Transformer<? super I, ? extends O> transformer) {
 		ArrayList<O> result = new ArrayList<O>(list.size());
 		for (I each : list) {
 			result.add(transformer.transform(each));
@@ -683,36 +646,36 @@
 	// ********** factory methods **********
 
 	/**
-	 * Return a list corresponding to the specified iterable.
+	 * Return an array list corresponding to the specified iterable.
 	 */
-	public static <E> ArrayList<E> list(Iterable<? extends E> iterable) {
-		return list(iterable.iterator());
+	public static <E> ArrayList<E> arrayList(Iterable<? extends E> iterable) {
+		return arrayList(iterable.iterator());
 	}
 
 	/**
-	 * Return a list corresponding to the specified iterable.
+	 * Return an array list corresponding to the specified iterable.
 	 * The specified iterable size is a performance hint.
 	 */
-	public static <E> ArrayList<E> list(Iterable<? extends E> iterable, int iterableSize) {
-		return list(iterable.iterator(), iterableSize);
+	public static <E> ArrayList<E> arrayList(Iterable<? extends E> iterable, int iterableSize) {
+		return arrayList(iterable.iterator(), iterableSize);
 	}
 
 	/**
-	 * Return a list corresponding to the specified iterator.
+	 * Return an array list corresponding to the specified iterator.
 	 */
-	public static <E> ArrayList<E> list(Iterator<? extends E> iterator) {
-		return list(iterator, new ArrayList<E>());
+	public static <E> ArrayList<E> arrayList(Iterator<? extends E> iterator) {
+		return arrayList(iterator, new ArrayList<E>());
 	}
 
 	/**
-	 * Return a list corresponding to the specified iterator.
+	 * Return an array list corresponding to the specified iterator.
 	 * The specified iterator size is a performance hint.
 	 */
-	public static <E> ArrayList<E> list(Iterator<? extends E> iterator, int iteratorSize) {
-		return list(iterator, new ArrayList<E>(iteratorSize));
+	public static <E> ArrayList<E> arrayList(Iterator<? extends E> iterator, int iteratorSize) {
+		return arrayList(iterator, new ArrayList<E>(iteratorSize));
 	}
 
-	private static <E> ArrayList<E> list(Iterator<? extends E> iterator, ArrayList<E> list) {
+	private static <E> ArrayList<E> arrayList(Iterator<? extends E> iterator, ArrayList<E> list) {
 		while (iterator.hasNext()) {
 			list.add(iterator.next());
 		}
@@ -720,11 +683,11 @@
 	}
 
 	/**
-	 * Return a list corresponding to the specified array.
+	 * Return an array list corresponding to the specified array.
 	 * Unlike {@link Arrays#asList(Object[])}, the list
 	 * is modifiable and is not backed by the array.
 	 */
-	public static <E> ArrayList<E> list(E... array) {
+	public static <E> ArrayList<E> arrayList(E... array) {
 		ArrayList<E> list = new ArrayList<E>(array.length);
 		for (E e : array) {
 			list.add(e);
@@ -732,54 +695,6 @@
 		return list;
 	}
 
-	/**
-	 * Return a list corresponding to the specified queue,
-	 * draining the queue in the process.
-	 */
-	public static <E> ArrayList<E> list(Queue<? extends E> queue) {
-		return list(queue, new ArrayList<E>());
-	}
-
-	/**
-	 * Return a list corresponding to the specified queue,
-	 * draining the queue in the process.
-	 * The specified queue size is a performance hint.
-	 */
-	public static <E> ArrayList<E> list(Queue<? extends E> queue, int queueSize) {
-		return list(queue, new ArrayList<E>(queueSize));
-	}
-
-	private static <E> ArrayList<E> list(Queue<? extends E> queue, ArrayList<E> list) {
-		while ( ! queue.isEmpty()) {
-			list.add(queue.dequeue());
-		}
-		return list;
-	}
-
-	/**
-	 * Return a list corresponding to the specified stack,
-	 * draining the stack in the process.
-	 */
-	public static <E> ArrayList<E> list(Stack<? extends E> stack) {
-		return list(stack, new ArrayList<E>());
-	}
-
-	/**
-	 * Return a list corresponding to the specified stack,
-	 * draining the stack in the process.
-	 * The specified stack size is a performance hint.
-	 */
-	public static <E> ArrayList<E> list(Stack<? extends E> stack, int stackSize) {
-		return list(stack, new ArrayList<E>(stackSize));
-	}
-
-	private static <E> ArrayList<E> list(Stack<? extends E> stack, ArrayList<E> list) {
-		while ( ! stack.isEmpty()) {
-			list.add(stack.pop());
-		}
-		return list;
-	}
-
 
 	// ********** transformers **********
 
@@ -820,7 +735,7 @@
 	 * <em>read-only</em> {@link ListIterator}.
 	 */
 	@SuppressWarnings("unchecked")
-	public static <E> Transformer<List<? extends E>, ListIterator<? extends E>> readOnlyListIteratorTransformer() {
+	public static <E> Transformer<List<? extends E>, ListIterator<E>> readOnlyListIteratorTransformer() {
 		return READ_ONLY_LIST_ITERATOR_TRANSFORMER;
 	}
 
@@ -836,10 +751,10 @@
 	 * <em>read-only</em> {@link ListIterator}.
 	 */
 	public static class ReadOnlyListIteratorTransformer<E>
-		implements Transformer<List<? extends E>, ListIterator<? extends E>>
+		implements Transformer<List<? extends E>, ListIterator<E>>
 	{
-		public ListIterator<? extends E> transform(List<? extends E> list) {
-			return IteratorTools.readOnly(list.listIterator());
+		public ListIterator<E> transform(List<? extends E> list) {
+			return IteratorTools.<E>readOnly(list.listIterator());
 		}
 		@Override
 		public String toString() {
@@ -884,7 +799,7 @@
 	 * <em>read-only</em> {@link ListIterable}.
 	 */
 	@SuppressWarnings("unchecked")
-	public static <E> Transformer<List<? extends E>, ListIterable<? extends E>> readOnlyListIterableTransformer() {
+	public static <E> Transformer<List<? extends E>, ListIterable<E>> readOnlyListIterableTransformer() {
 		return READ_ONLY_LIST_ITERABLE_TRANSFORMER;
 	}
 
@@ -900,10 +815,10 @@
 	 * <em>read-only</em> {@link ListIterable}.
 	 */
 	public static class ReadOnlyListIterableTransformer<E>
-		implements Transformer<List<? extends E>, ListIterable<? extends E>>
+		implements Transformer<List<? extends E>, ListIterable<E>>
 	{
-		public ListIterable<? extends E> transform(List<? extends E> list) {
-			return IterableTools.listIterable(list);
+		public ListIterable<E> transform(List<? extends E> list) {
+			return IterableTools.<E>readOnly(IterableTools.listIterable(list));
 		}
 		@Override
 		public String toString() {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/MapTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/MapTools.java
index 812b8f0..109b38b 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/MapTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/MapTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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,8 +14,6 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.factory.Factory;
 import org.eclipse.jpt.common.utility.internal.ClassTools;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
@@ -117,7 +115,7 @@
 	 * @see Map#get(Object)
 	 * @see Map#containsKey(Object)
 	 */
-	public static <K, V> V get(Map<K, V> map, K key, Class<? extends V> clazz, Class<?> parameterType, Object argument) {
+	public static <K, V, C extends V> V get(Map<K, V> map, K key, Class<C> clazz, Class<?> parameterType, Object argument) {
 		return get(map, key, clazz, new Class[] {parameterType}, new Object[] {argument});
 	}
 
@@ -125,8 +123,8 @@
 	 * <em>Assume</em> the map does not contain any <code>null</code> values.
 	 * @see #get(Map, Object, Class, Class, Object)
 	 */
-	public static <K, V> V get_(Map<K, V> map, K key, Class<? extends V> clazz, Class<?> parameterType, Object argument) {
-		return get(map, key, clazz, new Class[] {parameterType}, new Object[] {argument});
+	public static <K, V, C extends V> V get_(Map<K, V> map, K key, Class<C> clazz, Class<?> parameterType, Object argument) {
+		return get_(map, key, clazz, new Class[] {parameterType}, new Object[] {argument});
 	}
 
 	/**
@@ -208,30 +206,6 @@
 	}
 
 	/**
-	 * With the specified map, map the values dequeued from the specified queue
-	 * to the keys generated by passing the values to the specified key
-	 * transformer.
-	 * @see Map#putAll(Map)
-	 */
-	public static <K, V, E extends V> void addAll(Map<K, V> map, Queue<E> values, Transformer<? super E, ? extends K> keyTransformer) {
-		while ( ! values.isEmpty()) {
-			add(map, values.dequeue(), keyTransformer);
-		}
-	}
-
-	/**
-	 * With the specified map, map the values popped from the specified stack
-	 * to the keys generated by passing the values to the specified key
-	 * transformer.
-	 * @see Map#putAll(Map)
-	 */
-	public static <K, V, E extends V> void addAll(Map<K, V> map, Stack<E> values, Transformer<? super E, ? extends K> keyTransformer) {
-		while ( ! values.isEmpty()) {
-			add(map, values.pop(), keyTransformer);
-		}
-	}
-
-	/**
 	 * With the specified map, map the specified values to the keys generated by
 	 * passing the values to the specified key transformer.
 	 * @see Map#putAll(Map)
@@ -265,32 +239,6 @@
 	}
 
 	/**
-	 * With the specified map, map the values generated by passing the elements
-	 * dequeued from the specified queue to the specified value transformer to
-	 * the key generated by passing the elements to the specified key
-	 * transformer.
-	 * @see Map#putAll(Map)
-	 */
-	public static <K, V, E> void addAll(Map<K, V> map, Queue<E> elements, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
-		while ( ! elements.isEmpty()) {
-			add(map, elements.dequeue(), keyTransformer, valueTransformer);
-		}
-	}
-
-	/**
-	 * With the specified map, map the values generated by passing the elements
-	 * popped from the specified stack to the specified value transformer to
-	 * the key generated by passing the elements to the specified key
-	 * transformer.
-	 * @see Map#putAll(Map)
-	 */
-	public static <K, V, E> void addAll(Map<K, V> map, Stack<E> elements, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
-		while ( ! elements.isEmpty()) {
-			add(map, elements.pop(), keyTransformer, valueTransformer);
-		}
-	}
-
-	/**
 	 * With the specified map, map the values generated by passing the specified
 	 * elements to the specified value transformer to the key generated by
 	 * passing the elements to the specified key transformer.
@@ -378,36 +326,6 @@
 		return true;
 	}
 
-	/**
-	 * Return whether the specified map contains all of the
-	 * keys in the specified queue, dequeueing elements from the queue
-	 * until one is not found in the map.
-	 * @see Map#containsKey(Object)
-	 */
-	public static boolean containsAllKeys(Map<?, ?> map, Queue<?> keys) {
-		while ( ! keys.isEmpty()) {
-			if ( ! map.containsKey(keys.dequeue())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Return whether the specified map contains all of the
-	 * keys in the specified stack, popping elements from the stack
-	 * until one is not found in the map.
-	 * @see Map#containsKey(Object)
-	 */
-	public static boolean containsAllKeys(Map<?, ?> map, Stack<?> keys) {
-		while ( ! keys.isEmpty()) {
-			if ( ! map.containsKey(keys.pop())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
 
 	// ********** contains all values **********
 
@@ -449,36 +367,6 @@
 		return true;
 	}
 
-	/**
-	 * Return whether the specified map contains all of the
-	 * values in the specified queue, dequeueing elements from the queue
-	 * until one is not found in the map.
-	 * @see Map#containsValue(Object)
-	 */
-	public static boolean containsAllValues(Map<?, ?> map, Queue<?> values) {
-		while ( ! values.isEmpty()) {
-			if ( ! map.containsValue(values.dequeue())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
-	/**
-	 * Return whether the specified map contains all of the
-	 * values in the specified stack, popping elements from the stack
-	 * until one is not found in the map.
-	 * @see Map#containsValue(Object)
-	 */
-	public static boolean containsAllValues(Map<?, ?> map, Stack<?> values) {
-		while ( ! values.isEmpty()) {
-			if ( ! map.containsValue(values.pop())) {
-				return false;
-			}
-		}
-		return true;
-	}
-
 
 	// ********** remove all **********
 
@@ -513,28 +401,6 @@
 		}
 	}
 
-	/**
-	 * Remove from the specified map all of the
-	 * keys dequeued from the specified queue.
-	 * @see Map#remove(Object)
-	 */
-	public static void removeAll(Map<?, ?> map, Queue<?> keys) {
-		while ( ! keys.isEmpty()) {
-			map.remove(keys.dequeue());
-		}
-	}
-
-	/**
-	 * Remove from the specified map all of the
-	 * keys popped from the specified stack.
-	 * @see Map#remove(Object)
-	 */
-	public static void removeAll(Map<?, ?> map, Stack<?> keys) {
-		while ( ! keys.isEmpty()) {
-			map.remove(keys.pop());
-		}
-	}
-
 
 	// ********** retain all **********
 
@@ -573,7 +439,7 @@
 	 */
 	public static void retainAll(Map<?, ?> map, Iterator<?> keys) {
 		if (keys.hasNext()) {
-			retainAll_(map, CollectionTools.set(keys));
+			retainAll_(map, CollectionTools.hashSet(keys));
 		} else {
 			map.clear();
 		}
@@ -586,7 +452,7 @@
 	 */
 	public static void retainAll(Map<?, ?> map, Iterator<?> keys, int keysSize) {
 		if (keys.hasNext()) {
-			retainAll_(map, CollectionTools.set(keys, keysSize));
+			retainAll_(map, CollectionTools.hashSet(keys, keysSize));
 		} else {
 			map.clear();
 		}
@@ -598,37 +464,13 @@
 	 */
 	public static void retainAll(Map<?, ?> map, Object... keys) {
 		if (keys.length > 0) {
-			retainAll_(map, CollectionTools.set(keys));
+			retainAll_(map, CollectionTools.hashSet(keys));
 		} else {
 			map.clear();
 		}
 	}
 
 	/**
-	 * Retain in the specified map only the
-	 * keys dequeued from the specified queue.
-	 */
-	public static void retainAll(Map<?, ?> map, Queue<?> keys) {
-		if (keys.isEmpty()) {
-			map.clear();
-		} else {
-			retainAll_(map, CollectionTools.set(keys));
-		}
-	}
-
-	/**
-	 * Retain in the specified map only the
-	 * keys popped from the specified stack.
-	 */
-	public static void retainAll(Map<?, ?> map, Stack<?> keys) {
-		if (keys.isEmpty()) {
-			map.clear();
-		} else {
-			retainAll_(map, CollectionTools.set(keys));
-		}
-	}
-
-	/**
 	 * no empty check
 	 */
 	private static void retainAll_(Map<?, ?> map, Collection<?> keys) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/NullList.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/NullList.java
index 8592624..a44cea6 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/NullList.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/NullList.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -100,7 +100,10 @@
 	}
 
 	public ListIterator<E> listIterator(int index) {
-		return EmptyListIterator.instance();
+		if (index == 0) {
+			return EmptyListIterator.instance();
+		}
+		throw new IndexOutOfBoundsException("Index: " + index + ", Size: 0"); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
 	public boolean remove(Object o) {
@@ -128,7 +131,10 @@
 	}
 
 	public List<E> subList(int fromIndex, int toIndex) {
-		return this;
+		if ((fromIndex == 0) && (toIndex == 0)) {
+			return this;
+		}
+		throw new IndexOutOfBoundsException("Index: " + fromIndex + ", Size: 0"); //$NON-NLS-1$ //$NON-NLS-2$
 	}
 
 	public Object[] toArray() {
@@ -141,7 +147,7 @@
 
 	@Override
 	public String toString() {
-		return this.getClass().getSimpleName();
+		return "[]"; //$NON-NLS-1$
 	}
 
 	private static final long serialVersionUID = 1L;
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/PriorityQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/PriorityQueue.java
deleted file mode 100644
index e928ab2..0000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/PriorityQueue.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013, 2015 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.collection;
-
-import java.io.Serializable;
-import java.util.SortedSet;
-import org.eclipse.jpt.common.utility.collection.Queue;
-
-/**
- * Adapt a {@link SortedSet} to create a priority implementation of the
- * {@link Queue} interface. Elements will dequeue in the order determined by
- * wrapped sorted set (i.e. {@link #dequeue} will return the element returned
- * by {@link SortedSet#first}.
- * @param <E> the type of elements maintained by the queue
- * @see QueueTools
- */
-public class PriorityQueue<E>
-	implements Queue<E>, Serializable
-{
-	private final SortedSet<E> elements;
-
-	private static final long serialVersionUID = 1L;
-
-
-	public PriorityQueue(SortedSet<E> elements) {
-		super();
-		if (elements == null) {
-			throw new NullPointerException();
-		}
-		this.elements = elements;
-	}
-
-	public void enqueue(E element) {
-		this.elements.add(element);
-	}
-
-	public E dequeue() {
-		E result = this.elements.first();
-		this.elements.remove(result);
-		return result;
-	}
-
-	public E peek() {
-		return this.elements.first();
-	}
-
-	public boolean isEmpty() {
-		return this.elements.isEmpty();
-	}
-
-	@Override
-	public String toString() {
-		return this.elements.toString();
-	}
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/QueueTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/QueueTools.java
deleted file mode 100644
index 9de1eab..0000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/QueueTools.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013, 2015 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.collection;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
-
-/**
- * {@link Queue} utility methods.
- */
-public final class QueueTools {
-
-	// ********** enqueue all **********
-
-	/**
-	 * Enqueue all the elements returned by the specified iterable
-	 * on the specified queue.
-	 * Return the queue.
-	 */
-	public static <Q extends Queue<? super E>, E> Q enqueueAll(Q queue, Iterable<? extends E> iterable) {
-		return enqueueAll(queue, iterable.iterator());
-	}
-
-	/**
-	 * Enqueue all the elements returned by the specified iterator
-	 * on the specified queue.
-	 * Return the queue.
-	 */
-	public static <Q extends Queue<? super E>, E> Q enqueueAll(Q queue, Iterator<? extends E> iterator) {
-		while (iterator.hasNext()) {
-			queue.enqueue(iterator.next());
-		}
-		return queue;
-	}
-
-	/**
-	 * Enqueue all the elements in the specified array
-	 * on the specified queue.
-	 * Return the queue.
-	 */
-	public static <Q extends Queue<? super E>, E> Q enqueueAll(Q queue, E... array) {
-		for (E element : array) {
-			queue.enqueue(element);
-		}
-		return queue;
-	}
-
-	/**
-	 * Pop all the elements from the specified stack and enqueue them
-	 * on the specified queue.
-	 * Return the queue.
-	 */
-	public static <Q extends Queue<? super E>, E> Q enqueueAll(Q queue, Stack<? extends E> stack) {
-		while ( ! stack.isEmpty()) {
-			queue.enqueue(stack.pop());
-		}
-		return queue;
-	}
-
-	/**
-	 * Dequeue all the elements from the second specified queue and enqueue them
-	 * on the first specified queue.
-	 * Return the first queue.
-	 * @see #drainTo(Queue, Queue)
-	 */
-	public static <Q extends Queue<? super E>, E> Q enqueueAll(Q queue1, Queue<? extends E> queue2) {
-		while ( ! queue2.isEmpty()) {
-			queue1.enqueue(queue2.dequeue());
-		}
-		return queue1;
-	}
-
-
-	// ********** drain **********
-
-	/**
-	 * Drain all the elements from the specified queue and return them in a
-	 * list.
-	 */
-	public static <E> ArrayList<E> drain(Queue<? extends E> queue) {
-		return drainTo(queue, new ArrayList<E>());
-	}
-
-	/**
-	 * Drain all the elements from the specified queue and add them to the
-	 * specified collection.
-	 * Return the collection.
-	 */
-	public static <C extends Collection<? super E>, E> C drainTo(Queue<? extends E> queue, C collection) {
-		while ( ! queue.isEmpty()) {
-			collection.add(queue.dequeue());
-		}
-		return collection;
-	}
-
-	/**
-	 * Drain all the elements from the specified queue and push them on the
-	 * specified stack.
-	 * Return the stack.
-	 */
-	public static <S extends Stack<? super E>, E> S drainTo(Queue<? extends E> queue, S stack) {
-		while ( ! queue.isEmpty()) {
-			stack.push(queue.dequeue());
-		}
-		return stack;
-	}
-
-	/**
-	 * Drain all the elements from the first specified queue and enqueue them
-	 * on the second specified queue.
-	 * Return the second queue.
-	 * @see #enqueueAll(Queue, Queue)
-	 */
-	public static <Q extends Queue<? super E>, E> Q drainTo(Queue<? extends E> queue1, Q queue2) {
-		while ( ! queue1.isEmpty()) {
-			queue2.enqueue(queue1.dequeue());
-		}
-		return queue2;
-	}
-
-
-	// ********** factory methods **********
-
-	/**
-	 * Return an empty array-based FIFO queue.
-	 */
-	public static <E> ArrayQueue<E> queue() {
-		return arrayQueue();
-	}
-
-	/**
-	 * Return an empty array-based FIFO queue with specified initial capacity.
-	 */
-	public static <E> ArrayQueue<E> queue(int initialCapacity) {
-		return arrayQueue(initialCapacity);
-	}
-
-	/**
-	 * Return a FIFO queue corresponding to the specified iterable.
-	 */
-	public static <E> ArrayQueue<E> queue(Iterable<? extends E> iterable) {
-		return arrayQueue(iterable);
-	}
-
-	/**
-	 * Return a FIFO queue corresponding to the specified iterable.
-	 * The specified iterable size is a performance hint.
-	 */
-	public static <E> ArrayQueue<E> queue(Iterable<? extends E> iterable, int iterableSize) {
-		return arrayQueue(iterable, iterableSize);
-	}
-
-	/**
-	 * Return a FIFO queue corresponding to the specified iterator.
-	 */
-	public static <E> ArrayQueue<E> queue(Iterator<? extends E> iterator) {
-		return arrayQueue(iterator);
-	}
-
-	/**
-	 * Return a FIFO queue corresponding to the specified iterator.
-	 * The specified iterator size is a performance hint.
-	 */
-	public static <E> ArrayQueue<E> queue(Iterator<? extends E> iterator, int iteratorSize) {
-		return arrayQueue(iterator, iteratorSize);
-	}
-
-	/**
-	 * Return a FIFO queue corresponding to the specified array.
-	 */
-	public static <E> ArrayQueue<E> queue(E... array) {
-		return arrayQueue(array);
-	}
-
-	/**
-	 * Return an empty array-based FIFO queue.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue() {
-		return arrayQueue(10);
-	}
-
-	/**
-	 * Return an empty array-based FIFO queue with specified initial capacity.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(int initialCapacity) {
-		return new ArrayQueue<E>(initialCapacity);
-	}
-
-	/**
-	 * Return an array-based FIFO queue corresponding to the specified iterable.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(Iterable<? extends E> iterable) {
-		return arrayQueue(iterable.iterator());
-	}
-
-	/**
-	 * Return an array-based FIFO queue corresponding to the specified iterable.
-	 * The specified iterable size is a performance hint.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(Iterable<? extends E> iterable, int iterableSize) {
-		return arrayQueue(iterable.iterator(), iterableSize);
-	}
-
-	/**
-	 * Return an array-based FIFO queue corresponding to the specified iterator.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(Iterator<? extends E> iterator) {
-		return enqueueAll(QueueTools.<E>arrayQueue(), iterator);
-	}
-
-	/**
-	 * Return an array-based FIFO queue corresponding to the specified iterator.
-	 * The specified iterator size is a performance hint.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(Iterator<? extends E> iterator, int iteratorSize) {
-		return enqueueAll(QueueTools.<E>arrayQueue(iteratorSize), iterator);
-	}
-
-	/**
-	 * Return an array-based FIFO queue corresponding to the specified array.
-	 */
-	public static <E> ArrayQueue<E> arrayQueue(E... array) {
-		return enqueueAll(QueueTools.<E>arrayQueue(array.length), array);
-	}
-
-	/**
-	 * Return an empty link-based FIFO queue with no node cache.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue() {
-		return linkedQueue(0);
-	}
-
-	/**
-	 * Return an empty link-based FIFO queue
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(int cacheSize) {
-		return new LinkedQueue<E>(cacheSize);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified iterable.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(Iterable<? extends E> iterable) {
-		return linkedQueue(iterable, 0);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified iterable
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(Iterable<? extends E> iterable, int cacheSize) {
-		return linkedQueue(iterable.iterator(), cacheSize);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified iterator.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(Iterator<? extends E> iterator) {
-		return linkedQueue(iterator, 0);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified iterator
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(Iterator<? extends E> iterator, int cacheSize) {
-		return enqueueAll(QueueTools.<E>linkedQueue(cacheSize), iterator);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified array.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(E... array) {
-		return linkedQueue(array, 0);
-	}
-
-	/**
-	 * Return a link-based FIFO queue corresponding to the specified array
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedQueue<E> linkedQueue(E[] array, int cacheSize) {
-		return enqueueAll(QueueTools.<E>linkedQueue(cacheSize), array);
-	}
-
-	/**
-	 * Return a fixed-size queue with the specified capacity.
-	 */
-	public static <E> FixedSizeArrayQueue<E> fixedSizeQueue(int capacity) {
-		return new FixedSizeArrayQueue<E>(capacity);
-	}
-
-	/**
-	 * Return a fized-size 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 Queue#dequeue()}).
-	 * The queue's capacity will be match the collection's size.
-	 */
-	public static <E> FixedSizeArrayQueue<E> fixedSizeQueue(Collection<? extends E> collection) {
-		return enqueueAll(QueueTools.<E>fixedSizeQueue(collection.size()), collection);
-	}
-
-	/**
-	 * Return a LIFO queue.
-	 */
-	public static <E> StackQueue<E> stackQueue() {
-		return queue(new ArrayStack<E>());
-	}
-
-	/**
-	 * Adapt the specified stack to the {@link Queue} interface,
-	 * implementing a LIFO queue.
-	 */
-	public static <E> StackQueue<E> queue(Stack<E> stack) {
-		return new StackQueue<E>(stack);
-	}
-
-	/**
-	 * Return a priority queue that returns its elements in
-	 * {@linkplain Comparable natural order}.
-	 */
-	public static <E> PriorityQueue<E> priorityQueue() {
-		return queue((Comparator<? super E>) null);
-	}
-
-	/**
-	 * Return a priority queue whose elements are returned in
-	 * the order determined by the specified comparator.
-	 * If the specified comparator is <code>null</code>, the elements will be
-	 * returned in {@linkplain Comparable natural order}.
-	 */
-	public static <E> PriorityQueue<E> queue(Comparator<? super E> comparator) {
-		return queue(new TreeSet<E>(comparator));
-	}
-
-	/**
-	 * Adapt the specified sorted set to the {@link Queue} interface,
-	 * implementing a priority queue.
-	 */
-	public static <E> PriorityQueue<E> queue(SortedSet<E> elements) {
-		return new PriorityQueue<E>(elements);
-	}
-
-	/**
-	 * Adapt the specified list to the {@link Queue} interface.
-	 */
-	public static <E> ListQueue<E> wrap(List<E> list) {
-		return new ListQueue<E>(list);
-	}
-
-	/**
-	 * Return a queue that synchronizes the specified queue
-	 * with specified mutex.
-	 */
-	public static <E> SynchronizedQueue<E> synchronizedQueue(Queue<E> queue, Object mutex) {
-		return new SynchronizedQueue<E>(queue, mutex);
-	}
-
-	/**
-	 * Return a queue that synchronizes the specified queue.
-	 */
-	public static <E> SynchronizedQueue<E> synchronizedQueue(Queue<E> queue) {
-		return new SynchronizedQueue<E>(queue);
-	}
-
-	/**
-	 * Return an unmodifiable empty queue.
-	 */
-	public static <E> Queue<E> emptyQueue() {
-		return EmptyQueue.<E>instance();
-	}
-
-
-	// ********** constructor **********
-
-	/**
-	 * Suppress default constructor, ensuring non-instantiability.
-	 */
-	private QueueTools() {
-		super();
-		throw new UnsupportedOperationException();
-	}
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackTools.java
deleted file mode 100644
index 57eb050..0000000
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackTools.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2013, 2015 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.collection;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
-
-/**
- * {@link Stack} utility methods.
- */
-public class StackTools {
-
-	// ********** push all **********
-
-	/**
-	 * Push all the elements returned by the specified iterable
-	 * on the specified stack.
-	 * Return the stack.
-	 */
-	public static <S extends Stack<? super E>, E> S pushAll(S stack, Iterable<? extends E> iterable) {
-		return pushAll(stack, iterable.iterator());
-	}
-
-	/**
-	 * Push all the elements returned by the specified iterator
-	 * on the specified stack.
-	 * Return the stack.
-	 */
-	public static <S extends Stack<? super E>, E> S pushAll(S stack, Iterator<? extends E> iterator) {
-		while (iterator.hasNext()) {
-			stack.push(iterator.next());
-		}
-		return stack;
-	}
-
-	/**
-	 * Push all the elements in the specified array
-	 * on the specified stack.
-	 * Return the stack.
-	 */
-	public static <S extends Stack<? super E>, E> S pushAll(S stack, E... array) {
-		for (E element : array) {
-			stack.push(element);
-		}
-		return stack;
-	}
-
-	/**
-	 * Dequeue all the elements from the specified queue and push them
-	 * on the specified stack.
-	 * Return the stack.
-	 */
-	public static <S extends Stack<? super E>, E> S pushAll(S stack, Queue<? extends E> queue) {
-		while ( ! queue.isEmpty()) {
-			stack.push(queue.dequeue());
-		}
-		return stack;
-	}
-
-	/**
-	 * Pop all the elements from the second specified stack and push them
-	 * on the first specified stack.
-	 * Return the first stack.
-	 * @see #popAllTo(Stack, Stack)
-	 */
-	public static <S extends Stack<? super E>, E> S pushAll(S stack1, Stack<? extends E> stack2) {
-		while ( ! stack2.isEmpty()) {
-			stack1.push(stack2.pop());
-		}
-		return stack1;
-	}
-
-
-	// ********** pop all **********
-
-	/**
-	 * Pop all the elements from the specified stack and return them in a
-	 * list.
-	 */
-	public static <E> ArrayList<E> popAll(Stack<? extends E> stack) {
-		return popAllTo(stack, new ArrayList<E>());
-	}
-
-	/**
-	 * Pop all the elements from the specified stack and add them to the
-	 * specified collection.
-	 * Return the collection.
-	 */
-	public static <C extends Collection<? super E>, E> C popAllTo(Stack<? extends E> stack, C collection) {
-		while ( ! stack.isEmpty()) {
-			collection.add(stack.pop());
-		}
-		return collection;
-	}
-
-	/**
-	 * Pop all the elements from the specified stack and enqueue them on the
-	 * specified queue.
-	 * Return the queue.
-	 */
-	public static <Q extends Queue<? super E>, E> Q popAllTo(Stack<? extends E> stack, Q queue) {
-		while ( ! stack.isEmpty()) {
-			queue.enqueue(stack.pop());
-		}
-		return queue;
-	}
-
-	/**
-	 * Pop all the elements from the first specified stack and push them
-	 * on the second specified stack.
-	 * Return the second stack.
-	 * @see #pushAll(Stack, Stack)
-	 */
-	public static <S extends Stack<? super E>, E> S popAllTo(Stack<? extends E> stack1, S stack2) {
-		while ( ! stack1.isEmpty()) {
-			stack2.push(stack1.pop());
-		}
-		return stack2;
-	}
-
-
-	// ********** factory methods **********
-
-	/**
-	 * Return an empty LIFO stack.
-	 */
-	public static <E> ArrayStack<E> stack() {
-		return arrayStack();
-	}
-
-	/**
-	 * Return an empty LIFO stack with the specified initial capacity.
-	 */
-	public static <E> ArrayStack<E> stack(int initialCapacity) {
-		return arrayStack(initialCapacity);
-	}
-
-	/**
-	 * Return a LIFO stack corresponding to the specified iterable.
-	 */
-	public static <E> ArrayStack<E> stack(Iterable<? extends E> iterable) {
-		return arrayStack(iterable);
-	}
-
-	/**
-	 * Return a LIFO stack corresponding to the specified iterable.
-	 * The specified iterable size is a performance hint.
-	 */
-	public static <E> ArrayStack<E> stack(Iterable<? extends E> iterable, int iterableSize) {
-		return arrayStack(iterable, iterableSize);
-	}
-
-	/**
-	 * Return a LIFO stack corresponding to the specified iterator.
-	 */
-	public static <E> ArrayStack<E> stack(Iterator<? extends E> iterator) {
-		return arrayStack(iterator);
-	}
-
-	/**
-	 * Return a LIFO stack corresponding to the specified iterator.
-	 * The specified iterator size is a performance hint.
-	 */
-	public static <E> ArrayStack<E> stack(Iterator<? extends E> iterator, int iteratorSize) {
-		return arrayStack(iterator, iteratorSize);
-	}
-
-	/**
-	 * Return a LIFO stack corresponding to the specified array.
-	 */
-	public static <E> ArrayStack<E> stack(E... array) {
-		return arrayStack(array);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding.
-	 */
-	public static <E> ArrayStack<E> arrayStack() {
-		return arrayStack(10);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding with the specified initial capacity.
-	 */
-	public static <E> ArrayStack<E> arrayStack(int initialCapacity) {
-		return new ArrayStack<E>(initialCapacity);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding to the specified iterable.
-	 * The stack will pop its elements in reverse of the
-	 * order they are returned by the iterable's iterator (i.e. the
-	 * last element returned by the iterable's iterator will be the
-	 * first element returned by {@link Stack#pop()}; the first, last.).
-	 */
-	public static <E> ArrayStack<E> arrayStack(Iterable<? extends E> iterable) {
-		return arrayStack(iterable.iterator());
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding to the specified iterable.
-	 * The stack will pop its elements in reverse of the
-	 * order they are returned by the iterable's iterator (i.e. the
-	 * last element returned by the iterable's iterator will be the
-	 * first element returned by {@link Stack#pop()}; the first, last.).
-	 * The specified iterable size is a performance hint.
-	 */
-	public static <E> ArrayStack<E> arrayStack(Iterable<? extends E> iterable, int iterableSize) {
-		return arrayStack(iterable.iterator(), iterableSize);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding to the specified iterator.
-	 * The stack will pop its elements in reverse of the
-	 * order they are returned by the iterator (i.e. the
-	 * last element returned by the iterator will be the
-	 * first element returned by {@link Stack#pop()}; the first, last.).
-	 */
-	public static <E> ArrayStack<E> arrayStack(Iterator<? extends E> iterator) {
-		return pushAll(StackTools.<E>arrayStack(), iterator);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding to the specified iterator.
-	 * The stack will pop its elements in reverse of the
-	 * order they are returned by the iterator (i.e. the
-	 * last element returned by the iterator will be the
-	 * first element returned by {@link Stack#pop()}; the first, last.).
-	 * The specified iterator size is a performance hint.
-	 */
-	public static <E> ArrayStack<E> arrayStack(Iterator<? extends E> iterator, int iteratorSize) {
-		return pushAll(StackTools.<E>arrayStack(iteratorSize), iterator);
-	}
-
-	/**
-	 * Return an array-based LIFO stack corresponding to the specified array.
-	 */
-	public static <E> ArrayStack<E> arrayStack(E... array) {
-		return pushAll(StackTools.<E>arrayStack(array.length), array);
-	}
-
-	/**
-	 * Return an empty link-based LIFO stack with no node cache.
-	 */
-	public static <E> LinkedStack<E> linkedStack() {
-		return linkedStack(0);
-	}
-
-	/**
-	 * Return an empty link-based LIFO stack
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedStack<E> linkedStack(int cacheSize) {
-		return new LinkedStack<E>(cacheSize);
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified iterable.
-	 */
-	public static <E> LinkedStack<E> linkedStack(Iterable<? extends E> iterable) {
-		return linkedStack(iterable.iterator());
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified iterable
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedStack<E> linkedStack(Iterable<? extends E> iterable, int cacheSize) {
-		return linkedStack(iterable.iterator(), cacheSize);
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified iterator.
-	 */
-	public static <E> LinkedStack<E> linkedStack(Iterator<? extends E> iterator) {
-		return pushAll(StackTools.<E>linkedStack(), iterator);
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified iterator
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedStack<E> linkedStack(Iterator<? extends E> iterator, int cacheSize) {
-		return pushAll(StackTools.<E>linkedStack(cacheSize), iterator);
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified array.
-	 */
-	public static <E> LinkedStack<E> linkedStack(E... array) {
-		return pushAll(StackTools.<E>linkedStack(), array);
-	}
-
-	/**
-	 * Return a link-based LIFO stack corresponding to the specified array
-	 * with the specified node cache size.
-	 * Specify a cache size of -1 for an unlimited cache.
-	 */
-	public static <E> LinkedStack<E> linkedStack(E[] array, int cacheSize) {
-		return pushAll(StackTools.<E>linkedStack(cacheSize), array);
-	}
-
-	/**
-	 * Return a fixed-size stack with the specified capacity.
-	 */
-	public static <E> FixedSizeArrayStack<E> fixedSizeStack(int capacity) {
-		return new FixedSizeArrayStack<E>(capacity);
-	}
-
-	/**
-	 * Return a fized-size stack containing the elements of the specified
-	 * collection. The stack will pop its elements in reverse of the
-	 * order they are returned by the collection's iterator (i.e. the
-	 * last element returned by the collection's iterator will be the
-	 * first element returned by {@link Stack#pop()}; the first, last.).
-	 */
-	public static <E> FixedSizeArrayStack<E> fixedSizeStack(Collection<? extends E> collection) {
-		return pushAll(StackTools.<E>fixedSizeStack(collection.size()), collection);
-	}
-
-	/**
-	 * Adapt the specified list to the {@link Stack} interface.
-	 */
-	public static <E> ListStack<E> wrap(List<E> list) {
-		return new ListStack<E>(list);
-	}
-
-	/**
-	 * Return a stack that synchronizes the specified stack
-	 * with specified mutex.
-	 */
-	public static <E> SynchronizedStack<E> synchronizedStack(Stack<E> stack, Object mutex) {
-		return new SynchronizedStack<E>(stack, mutex);
-	}
-
-	/**
-	 * Return a stack that synchronizes the specified stack.
-	 */
-	public static <E> SynchronizedStack<E> synchronizedStack(Stack<E> stack) {
-		return new SynchronizedStack<E>(stack);
-	}
-
-	/**
-	 * Return an unmodifiable empty LIFO stack.
-	 */
-	public static <E> Stack<E> emptyStack() {
-		return EmptyStack.<E>instance();
-	}
-
-
-	// ********** constructor **********
-
-	/**
-	 * Suppress default constructor, ensuring non-instantiability.
-	 */
-	private StackTools() {
-		super();
-		throw new UnsupportedOperationException();
-	}
-}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedBag.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedBag.java
index 42d8829..d85b62e 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedBag.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedBag.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -59,20 +59,6 @@
 		this.mutex = this;
 	}
 
-	/**
-	 * Construct a synchronized bag that locks on the specified mutex.
-	 */
-	public SynchronizedBag(Object mutex) {
-		this(new HashBag<E>(), mutex);
-	}
-
-	/**
-	 * Construct a synchronized bag that locks on itself.
-	 */
-	public SynchronizedBag() {
-		this(new HashBag<E>());
-	}
-
 
 	// ********** Bag implementation **********
 
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractAsynchronousCommandContext.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractAsynchronousCommandContext.java
index 09c0ff9..cc4bf69 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractAsynchronousCommandContext.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractAsynchronousCommandContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -16,8 +16,9 @@
 import org.eclipse.jpt.common.utility.internal.ConsumerThreadCoordinator;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
 import org.eclipse.jpt.common.utility.internal.SimpleThreadFactory;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedQueue;
 import org.eclipse.jpt.common.utility.internal.exception.RuntimeExceptionHandler;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
 
 /**
  * This command context will dispatch commands to be executed in a separate
@@ -44,7 +45,7 @@
 	 * to execute the new command once the currently executing command has
 	 * finished executing.
 	 */
-	private final SynchronizedQueue<Command> commands = new SynchronizedQueue<Command>();
+	private final SynchronizedQueue<Command> commands = QueueTools.synchronizedQueue();
 
 	/**
 	 * Most of the thread-related behavior is delegated to this coordinator.
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractQueueingCommandContext.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractQueueingCommandContext.java
index 0373d7f..71d7c77 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractQueueingCommandContext.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractQueueingCommandContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2012, 2015 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.
@@ -12,7 +12,7 @@
 import org.eclipse.jpt.common.utility.command.Command;
 import org.eclipse.jpt.common.utility.command.StatefulCommandContext;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
 import org.eclipse.jpt.common.utility.internal.reference.SynchronizedBoolean;
 
 /**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractSingleUseQueueingCommandContext.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractSingleUseQueueingCommandContext.java
index 25df443..b2a71b9 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractSingleUseQueueingCommandContext.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/command/AbstractSingleUseQueueingCommandContext.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2012, 2015 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.
@@ -12,7 +12,7 @@
 import org.eclipse.jpt.common.utility.command.Command;
 import org.eclipse.jpt.common.utility.command.StatefulCommandContext;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
 
 /**
  * This is a command context that queues up any commands that are
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractArrayDeque.java
similarity index 62%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractArrayDeque.java
index 5b7b87d..e894d76 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractArrayDeque.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2015 Oracle. All rights reserved.
+ * Copyright (c) 2015 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.
@@ -7,31 +7,29 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.deque;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
+import org.eclipse.jpt.common.utility.deque.Deque;
 
 /**
- * Resizable-array FIFO implementation of the {@link Queue} interface.
- * @param <E> the type of elements maintained by the queue
- * @see FixedSizeArrayQueue
- * @see QueueTools
+ * Abstract array implementation of the {@link Deque} interface.
+ * @param <E> the type of elements maintained by the deque
  */
-public class ArrayQueue<E>
-	implements Queue<E>, Cloneable, Serializable
+public abstract class AbstractArrayDeque<E>
+	implements Deque<E>, Cloneable, Serializable
 {
-	private transient E[] elements;
+	protected transient E[] elements;
 
-	/** Index of next element to be "dequeued". */
-	private transient int head = 0;
+	/** Index of head element */
+	protected transient int head = 0;
 
-	/** Index of next element to be "enqueued". */
-	private transient int tail = 0;
+	/** Index of the <em>next</em> tail element. */
+	protected transient int tail = 0;
 
-	private int size = 0;
+	protected int size = 0;
 
 	private static final long serialVersionUID = 1L;
 
@@ -39,17 +37,10 @@
 	// ********** constructors **********
 
 	/**
-	 * Construct an empty queue.
-	 */
-	public ArrayQueue() {
-		this(10);
-	}
-
-	/**
-	 * Construct an empty queue with the specified initial capacity.
+	 * Construct an empty deque with the specified initial capacity.
 	 */
 	@SuppressWarnings("unchecked")
-	public ArrayQueue(int initialCapacity) {
+	protected AbstractArrayDeque(int initialCapacity) {
 		super();
 		if (initialCapacity < 0) {
 			throw new IllegalArgumentException("Illegal capacity: " + initialCapacity); //$NON-NLS-1$
@@ -58,10 +49,9 @@
 	}
 
 
-	// ********** Queue implementation **********
+	// ********** Deque implementation **********
 
-	public void enqueue(E element) {
-		this.ensureCapacity(this.size + 1);
+	public void enqueueTail(E element) {
 		this.elements[this.tail] = element;
 		if (++this.tail == this.elements.length) {
 			this.tail = 0;
@@ -69,53 +59,15 @@
 		this.size++;
 	}
 
-	/**
-	 * Increase the queue's capacity, if necessary, to ensure it has at least
-	 * the specified minimum capacity.
-	 */
-	public void ensureCapacity(int minCapacity) {
-		int oldCapacity = this.elements.length;
-		if (oldCapacity < minCapacity) {
-			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
-			if (newCapacity < minCapacity) {
-				newCapacity = minCapacity;
-			}
-			this.elements = this.copyElements(newCapacity);
-			this.head = 0;
-			this.tail = this.size;
+	public void enqueueHead(E element) {
+		if (this.head == 0) {
+			this.head = this.elements.length;
 		}
+		this.elements[--this.head] = element;
+		this.size++;
 	}
 
-	/**
-	 * Decrease the queue's capacity, if necessary, to match its current size.
-	 */
-	public void trimToSize() {
-		if (this.elements.length > this.size) {
-			this.elements = this.copyElements(this.size);
-			this.head = 0;
-			this.tail = this.size;
-		}
-	}
-
-	private E[] copyElements(int newCapacity) {
-		@SuppressWarnings("unchecked")
-		E[] newElements = (E[]) new Object[newCapacity];
-		if (this.size != 0) {
-			Object oldElements[] = this.elements;
-			if ((this.head == 0) || (this.head < this.tail) || (this.tail == 0)) {
-				// elements are contiguous
-				System.arraycopy(oldElements, this.head, newElements, 0, this.size);
-			} else {
-				// elements wrap past end of array
-				int fragmentSize = oldElements.length - this.head;
-				System.arraycopy(oldElements, this.head, newElements, 0, fragmentSize);
-				System.arraycopy(oldElements, 0, newElements, fragmentSize, (this.size - fragmentSize));
-			}
-		}
-		return newElements;
-	}
-
-	public E dequeue() {
+	public E dequeueHead() {
 		if (this.size == 0) {
 			throw new NoSuchElementException();
 		}
@@ -128,13 +80,34 @@
 		return element;
 	}
 
-	public E peek() {
+	public E dequeueTail() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		if (this.tail == 0) {
+			this.tail = this.elements.length;
+		}
+		E element = this.elements[--this.tail];
+		this.elements[this.tail] = null; // allow GC to work
+		this.size--;
+		return element;
+	}
+
+	public E peekHead() {
 		if (this.size == 0) {
 			throw new NoSuchElementException();
 		}
 		return this.elements[this.head];
 	}
 
+	public E peekTail() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		int index = (this.tail == 0) ? this.elements.length : this.tail;
+		return this.elements[--index];
+	}
+
 	public boolean isEmpty() {
 		return this.size == 0;
 	}
@@ -143,10 +116,10 @@
 	// ********** standard methods **********
 
 	@Override
-	public ArrayQueue<E> clone() {
+	public AbstractArrayDeque<E> clone() {
 		try {
 			@SuppressWarnings("unchecked")
-			ArrayQueue<E> clone = (ArrayQueue<E>) super.clone();
+			AbstractArrayDeque<E> clone = (AbstractArrayDeque<E>) super.clone();
 			@SuppressWarnings("cast")
 			E[] array = (E[]) this.elements.clone();
 			clone.elements = array;
@@ -161,6 +134,28 @@
 		return Arrays.toString(this.copyElements(this.size));
 	}
 
+	protected E[] copyElements(int newCapacity) {
+		@SuppressWarnings("unchecked")
+		E[] newElements = (E[]) new Object[newCapacity];
+		if (this.size != 0) {
+			Object oldElements[] = this.elements;
+			int t = this.tail;
+			if (t == 0) {
+				t = oldElements.length;
+			}
+			if (this.head < t) {
+				// elements are contiguous
+				System.arraycopy(oldElements, this.head, newElements, 0, this.size);
+			} else {
+				// elements wrap past end of array
+				int fragmentSize = oldElements.length - this.head;
+				System.arraycopy(oldElements, this.head, newElements, 0, fragmentSize);
+				System.arraycopy(oldElements, 0, newElements, fragmentSize, (this.size - fragmentSize));
+			}
+		}
+		return newElements;
+	}
+
 
 	// ********** Serializable "implementation" **********
 
@@ -174,11 +169,15 @@
 			return;
 		}
 		// save the elements in contiguous order
-		if (this.head < this.tail) { // elements are contiguous
-			for (int i = this.head; i < this.tail; i++) {
+		int t = this.tail;
+		if (t == 0) {
+			t = elementsLength;
+		}
+		if (this.head < t) { // elements are contiguous
+			for (int i = this.head; i < t; i++) {
 				stream.writeObject(array[i]);
 			}
-		} else { // (this.head >= this.tail) - elements wrap past end of array
+		} else { // (this.head >= t) - elements wrap past end of array
 			for (int i = this.head; i < elementsLength; i++) {
 				stream.writeObject(array[i]);
 			}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractPriorityDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractPriorityDeque.java
new file mode 100644
index 0000000..e2b01d7
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/AbstractPriorityDeque.java
@@ -0,0 +1,396 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.deque;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.InputRestrictedDeque;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
+
+/**
+ * Abstract priority implementation of the {@link InputRestrictedDeque} interface.
+ * Elements will dequeue from the deque's head in the order determined by a comparator
+ * (i.e. {@link #dequeueHead} will return the element sorted first
+ * while {@link #dequeueTail} will return the element sorted last).
+ * @param <E> the type of elements maintained by the deque
+ */
+public abstract class AbstractPriorityDeque<E>
+	implements InputRestrictedDeque<E>, Cloneable, Serializable
+{
+	protected final Comparator<? super E> comparator;
+
+	/**
+	 * Standard min-max heap implementation.
+	 * To simplify our math, we leave the first slot [0] empty.
+	 */
+	protected transient E[] elements;
+
+	protected int size = 0;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty priority deque with the specified comparator
+	 * and initial capacity.
+	 */
+	@SuppressWarnings("unchecked")
+	protected AbstractPriorityDeque(Comparator<? super E> comparator, int initialCapacity) {
+		super();
+		if (comparator == null) {
+			throw new NullPointerException();
+		}
+		this.comparator = comparator;
+		if (initialCapacity < 0) {
+			throw new IllegalArgumentException("Illegal capacity: " + initialCapacity); //$NON-NLS-1$
+		}
+		
+		this.elements = (E[]) new Object[initialCapacity + 1];
+	}
+
+
+	// ********** Deque implementation **********
+
+	/**
+	 * The element is not enqueued strictly to the deque's tail;
+	 * it is placed in its proper position, as determined by the
+	 * deque's priority comparator.
+	 */
+	public void enqueueTail(E element) {
+		this.enqueue(element);
+	}
+
+	public void enqueue(E element) {
+		this.size++;
+		int current = this.size;
+		this.elements[current] = element;
+		int parent = current >> 1;
+		if (parent == 0) {
+			return;
+		}
+
+		int level = 31 - Integer.numberOfLeadingZeros(current); // 'current' is never zero
+		if ((level & 1) == 0) { // even levels are min levels (top level is zero)
+			if (this.comparator.compare(this.elements[current], this.elements[parent]) > 0) {
+				// move to max level before bubbling up
+				ArrayTools.swap(this.elements, current, parent);
+				current = parent;
+				int gp = current >> 2;
+				while ((gp != 0) && this.comparator.compare(this.elements[current], this.elements[gp]) > 0) {
+					ArrayTools.swap(this.elements, current, gp);
+					current = gp;
+					gp = current >> 2;
+				}
+			} else {
+				// bubble up min levels
+				int gp = current >> 2;
+				while ((gp != 0) && this.comparator.compare(this.elements[current], this.elements[gp]) < 0) {
+					ArrayTools.swap(this.elements, current, gp);
+					current = gp;
+					gp = current >> 2;
+				}
+			}
+		} else { // max level
+			if (this.comparator.compare(this.elements[current], this.elements[parent]) < 0) {
+				// move to min level before bubbling up
+				ArrayTools.swap(this.elements, current, parent);
+				current = parent;
+				int gp = current >> 2;
+				while ((gp != 0) && this.comparator.compare(this.elements[current], this.elements[gp]) < 0) {
+					ArrayTools.swap(this.elements, current, gp);
+					current = gp;
+					gp = current >> 2;
+				}
+			} else {
+				// bubble up max levels
+				int gp = current >> 2;
+				while ((gp != 0) && this.comparator.compare(this.elements[current], this.elements[gp]) > 0) {
+					ArrayTools.swap(this.elements, current, gp);
+					current = gp;
+					gp = current >> 2;
+				}
+			}
+		}
+	}
+
+// reduce the redundant code, but add more conditional logic
+//	public void enqueue(E element) {
+//		this.size++;
+//		int current = this.size;
+//		this.elements[current] = element;
+//		int parent = current >> 1;
+//		if (parent == 0) {
+//			return;
+//		}
+//
+//		int level = 31 - Integer.numberOfLeadingZeros(current); // 'current' is never zero
+//		boolean minLevel = (level & 1) == 0;
+//		int first = minLevel ? current : parent;
+//		int second = minLevel ? parent : current;
+//		if (this.comparator.compare(this.elements[first], this.elements[second]) > 0) {
+//			ArrayTools.swap(this.elements, current, parent);
+//			minLevel = ! minLevel;
+//			current = parent;
+//		}
+//		int gp = current >> 2;
+//		while (gp != 0) {
+//			first = minLevel ? current : gp;
+//			second = minLevel ? gp : current;
+//			if (this.comparator.compare(this.elements[first], this.elements[second]) > 0) {
+//				break;
+//			}
+//			ArrayTools.swap(this.elements, current, gp);
+//			current = gp;
+//			gp = current >> 2;
+//		}
+//	}
+
+	/**
+	 * Dequeue first/min element.
+	 */
+	public E dequeueHead() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		E element = this.elements[1];
+		if (this.size != 1) {
+			// replace root with last node and move it to its new position
+			ArrayTools.swap(this.elements, 1, this.size);
+			this.trickleDownMin(1, this.size - 1);
+		}
+		this.elements[this.size] = null; // allow GC to work
+		this.size--;
+		return element;
+	}
+
+	private void trickleDownMin(int index, int newSize) {
+		int minChildIndex = index << 1; // left child
+		if (minChildIndex > newSize) {
+			return; // no children
+		}
+
+		E element = this.elements[index];
+		E minChild = this.elements[minChildIndex];
+		int rightChildIndex = minChildIndex + 1;
+		if (rightChildIndex > newSize) {
+			// no right child; and, therefore, no possible grandchildren
+			if (this.comparator.compare(minChild, element) < 0) {
+				ArrayTools.swap(this.elements, minChildIndex, index);
+			}
+			return;
+		}
+
+		E rightChild = this.elements[rightChildIndex];
+		if (this.comparator.compare(rightChild, minChild) < 0) {
+			// right child exists and is less than left
+			minChildIndex = rightChildIndex;
+			minChild = rightChild;
+		}
+
+		// now find min grandchild
+		int minGCIndex = -1;
+		E minGC = null;
+		int i = index << 2; // leftmost grandchild
+		if (i <= newSize) {
+			minGCIndex = i;
+			minGC = this.elements[i];
+			int last = Math.min(i + 3, newSize);
+			while (++i <= last) {
+				E temp = this.elements[i];
+				if (this.comparator.compare(temp, minGC) < 0) {
+					minGCIndex = i;
+					minGC = temp;
+				}
+			}
+		}
+
+		if ((minGC != null) && (this.comparator.compare(minGC, minChild) < 0)) {
+			// min descendant is a grandchild
+			if (this.comparator.compare(minGC, element) < 0) {
+				ArrayTools.swap(this.elements, minGCIndex, index);
+				int parentIndex = minGCIndex >> 1; // 'element' is now at 'minGCIndex'
+				if (this.comparator.compare(element, this.elements[parentIndex]) > 0) {
+					// move element to max level
+					ArrayTools.swap(this.elements, minGCIndex, parentIndex);
+				}
+				this.trickleDownMin(minGCIndex, newSize); // recurse - still on a min level
+			}
+		} else {
+			// min is a direct child and, therefore, has no children itself (since it would have to be greater than its children)
+			if (this.comparator.compare(minChild, element) < 0) {
+				ArrayTools.swap(this.elements, minChildIndex, index);
+			}
+		}
+	}
+
+	/**
+	 * Dequeue last/max element.
+	 */
+	public E dequeueTail() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		int index = (this.size == 1) ? 1 : (this.size == 2) ? 2 : (this.comparator.compare(this.elements[2], this.elements[3]) > 0) ? 2 : 3;
+		E element = this.elements[index];
+		if (this.size != 1) {
+			// replace removed element with last node and move it to its new position
+			ArrayTools.swap(this.elements, index, this.size);
+			this.trickleDownMax(index, this.size - 1);
+		}
+		this.elements[this.size] = null; // allow GC to work
+		this.size--;
+		return element;
+	}
+
+	private void trickleDownMax(int index, int newSize) {
+		int maxChildIndex = index << 1; // left child
+		if (maxChildIndex > newSize) {
+			return; // no children
+		}
+
+		E element = this.elements[index];
+		E maxChild = this.elements[maxChildIndex];
+		int rightChildIndex = maxChildIndex + 1;
+		if (rightChildIndex > newSize) {
+			// no right child; and, therefore, no possible grandchildren
+			if (this.comparator.compare(maxChild, element) > 0) {
+				ArrayTools.swap(this.elements, maxChildIndex, index);
+			}
+			return;
+		}
+
+		E rightChild = this.elements[rightChildIndex];
+		if (this.comparator.compare(rightChild, maxChild) > 0) {
+			// right child exists and is greater than left
+			maxChildIndex = rightChildIndex;
+			maxChild = rightChild;
+		}
+
+		// now find max grandchild
+		int maxGCIndex = -1;
+		E maxGC = null;
+		int i = index << 2; // leftmost grandchild
+		if (i <= newSize) {
+			maxGCIndex = i;
+			maxGC = this.elements[i];
+			int last = Math.min(i + 3, newSize);
+			while (++i <= last) {
+				E temp = this.elements[i];
+				if (this.comparator.compare(temp, maxGC) > 0) {
+					maxGCIndex = i;
+					maxGC = temp;
+				}
+			}
+		}
+
+		if ((maxGC != null) && (this.comparator.compare(maxGC, maxChild) > 0)) {
+			// max descendant is a grandchild
+			if (this.comparator.compare(maxGC, element) > 0) {
+				ArrayTools.swap(this.elements, maxGCIndex, index);
+				int parentIndex = maxGCIndex >> 1; // 'element' is now at 'maxGCIndex'
+				if (this.comparator.compare(element, this.elements[parentIndex]) < 0) {
+					// move element to min level
+					ArrayTools.swap(this.elements, maxGCIndex, parentIndex);
+				}
+				this.trickleDownMax(maxGCIndex, newSize); // recurse - still on a max level
+			}
+		} else {
+			// max is a direct child and, therefore, has no children itself (since it would have to be less than its children)
+			if (this.comparator.compare(maxChild, element) > 0) {
+				ArrayTools.swap(this.elements, maxChildIndex, index);
+			}
+		}
+	}
+
+	/**
+	 * Return first/min element.
+	 */
+	public E peekHead() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.elements[1];
+	}
+
+	/**
+	 * Return last/max element.
+	 */
+	public E peekTail() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		if (this.size == 1) {
+			return this.elements[1];
+		}
+		E left = this.elements[2];
+		if (this.size == 2) {
+			return left;
+		}
+		E right = this.elements[3];
+		return (this.comparator.compare(left, right) > 0) ? left : right;
+	}
+
+	public boolean isEmpty() {
+		return this.size == 0;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public AbstractPriorityDeque<E> clone() {
+		try {
+			@SuppressWarnings("unchecked")
+			AbstractPriorityDeque<E> clone = (AbstractPriorityDeque<E>) super.clone();
+			@SuppressWarnings("cast")
+			E[] array = (E[]) this.elements.clone();
+			clone.elements = array;
+			return clone;
+		} catch (CloneNotSupportedException ex) {
+			throw new InternalError();
+		}
+	}
+
+	@Override
+	public String toString() {
+		return Arrays.toString(ArrayTools.subArray(this.elements, 1, this.size + 1));
+	}
+
+
+	// ********** Serializable "implementation" **********
+
+	private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException {
+		// write comparator and size (and any hidden stuff)
+		stream.defaultWriteObject();
+		stream.writeInt(this.elements.length);
+		if (this.size == 0) {
+			return;
+		}
+		for (int i = 1; i <= this.size; i++) { // skip 0
+			stream.writeObject(this.elements[i]);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException {
+		// read comparator and size (and any hidden stuff)
+		stream.defaultReadObject();
+		int elementsLength = stream.readInt();
+		Object[] array = new Object[elementsLength];
+		for (int i = 1; i <= this.size; i++) { // skip 0
+			array[i] = stream.readObject();
+		}
+		this.elements = (E[]) array;
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ArrayDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ArrayDeque.java
new file mode 100644
index 0000000..4e29e59
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ArrayDeque.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import org.eclipse.jpt.common.utility.deque.Deque;
+
+/**
+ * Resizable-array implementation of the {@link Deque} interface.
+ * @param <E> the type of elements maintained by the deque
+ * @see FixedCapacityArrayDeque
+ * @see DequeTools
+ */
+public class ArrayDeque<E>
+	extends AbstractArrayDeque<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty deque with the specified initial capacity.
+	 */
+	public ArrayDeque(int initialCapacity) {
+		super(initialCapacity);
+	}
+
+
+	// ********** Deque implementation **********
+
+	@Override
+	public void enqueueTail(E element) {
+		this.ensureCapacity(this.size + 1);
+		super.enqueueTail(element);
+	}
+
+	@Override
+	public void enqueueHead(E element) {
+		this.ensureCapacity(this.size + 1);
+		super.enqueueHead(element);
+	}
+
+	/**
+	 * Increase the deque's capacity, if necessary, to ensure it has at least
+	 * the specified minimum capacity.
+	 */
+	public void ensureCapacity(int minCapacity) {
+		int oldCapacity = this.elements.length;
+		if (oldCapacity < minCapacity) {
+			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
+			if (newCapacity < minCapacity) {
+				newCapacity = minCapacity;
+			}
+			this.elements = this.copyElements(newCapacity);
+			this.head = 0;
+			this.tail = this.size;
+		}
+	}
+
+	/**
+	 * Decrease the deque's capacity, if necessary, to match its current size.
+	 */
+	public void trimToSize() {
+		if (this.elements.length > this.size) {
+			this.elements = this.copyElements(this.size);
+			this.head = 0;
+			this.tail = this.size;
+		}
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public ArrayDeque<E> clone() {
+		return (ArrayDeque<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/DequeTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/DequeTools.java
new file mode 100644
index 0000000..aedc729
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/DequeTools.java
@@ -0,0 +1,799 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.deque;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.internal.comparator.ComparatorTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * {@link Deque} utility methods.
+ */
+public final class DequeTools {
+
+	// ********** enqueue all **********
+
+	/**
+	 * Enqueue all the elements returned by the specified iterable
+	 * on the specified deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueTailAll(Deque<? super E> deque, Iterable<? extends E> iterable) {
+		return enqueueTailAll(deque, iterable.iterator());
+	}
+
+	/**
+	 * Enqueue all the elements returned by the specified iterable
+	 * on the specified deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueHeadAll(Deque<? super E> deque, Iterable<? extends E> iterable) {
+		return enqueueHeadAll(deque, iterable.iterator());
+	}
+
+	/**
+	 * Enqueue all the elements returned by the specified iterator
+	 * on the specified deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueTailAll(Deque<? super E> deque, Iterator<? extends E> iterator) {
+		return iterator.hasNext() && enqueueTailAll_(deque, iterator);
+	}
+
+	/**
+	 * assume the iterator is not empty
+	 */
+	private static <E> boolean enqueueTailAll_(Deque<? super E> deque, Iterator<? extends E> iterator) {
+		do {
+			deque.enqueueTail(iterator.next());
+		} while (iterator.hasNext());
+		return true;
+	}
+
+	/**
+	 * Enqueue all the elements returned by the specified iterator
+	 * on the specified deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueHeadAll(Deque<? super E> deque, Iterator<? extends E> iterator) {
+		return iterator.hasNext() && enqueueHeadAll_(deque, iterator);
+	}
+
+	/**
+	 * assume the iterator is not empty
+	 */
+	private static <E> boolean enqueueHeadAll_(Deque<? super E> deque, Iterator<? extends E> iterator) {
+		do {
+			deque.enqueueHead(iterator.next());
+		} while (iterator.hasNext());
+		return true;
+	}
+
+	/**
+	 * Enqueue all the elements in the specified array
+	 * on the specified deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueTailAll(Deque<? super E> deque, E... array) {
+		int len = array.length;
+		return (len != 0) && enqueueTailAll_(deque, array, len);
+	}
+
+	/**
+	 * assume the array is not empty
+	 */
+	private static <E> boolean enqueueTailAll_(Deque<? super E> deque, E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			deque.enqueueTail(array[i++]);
+		} while (i < arrayLength);
+		return true;
+	}
+
+	/**
+	 * Enqueue all the elements in the specified array
+	 * on the specified deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean enqueueHeadAll(Deque<? super E> deque, E... array) {
+		int len = array.length;
+		return (len != 0) && enqueueHeadAll_(deque, array, len);
+	}
+
+	/**
+	 * assume the array is not empty
+	 */
+	private static <E> boolean enqueueHeadAll_(Deque<? super E> deque, E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			deque.enqueueHead(array[i++]);
+		} while (i < arrayLength);
+		return true;
+	}
+
+
+	// ********** drain **********
+
+	/**
+	 * Drain all the elements from the specified deque's head and return them in a
+	 * list.
+	 */
+	public static <E> ArrayList<E> drainHead(Deque<? extends E> deque) {
+		ArrayList<E> result = new ArrayList<E>();
+		drainHeadTo(deque, result);
+		return result;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail and return them in a
+	 * list.
+	 */
+	public static <E> ArrayList<E> drainTail(Deque<? extends E> deque) {
+		ArrayList<E> result = new ArrayList<E>();
+		drainTailTo(deque, result);
+		return result;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head and add them to the
+	 * specified collection.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainHeadTo(Deque<? extends E> deque, Collection<? super E> collection) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, collection);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainHeadTo_(Deque<? extends E> deque, Collection<? super E> collection) {
+		do {
+			collection.add(deque.dequeueHead());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail and add them to the
+	 * specified collection.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainTailTo(Deque<? extends E> deque, Collection<? super E> collection) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, collection);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainTailTo_(Deque<? extends E> deque, Collection<? super E> collection) {
+		do {
+			collection.add(deque.dequeueTail());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head
+	 * to the specified list at the specified index.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainHeadTo(Deque<? extends E> deque, List<? super E> list, int index) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, list, index);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainHeadTo_(Deque<? extends E> deque, List<? super E> list, int index) {
+		return (index == list.size()) ? drainHeadTo_(deque, list) : list.addAll(index, drainHead(deque));
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail
+	 * to the specified list at the specified index.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainTailTo(Deque<? extends E> deque, List<? super E> list, int index) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, list, index);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainTailTo_(Deque<? extends E> deque, List<? super E> list, int index) {
+		return (index == list.size()) ? drainTailTo_(deque, list) : list.addAll(index, drainTail(deque));
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head and push them on the
+	 * specified stack.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainHeadTo(Deque<? extends E> deque, Stack<? super E> stack) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, stack);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainHeadTo_(Deque<? extends E> deque, Stack<? super E> stack) {
+		do {
+			stack.push(deque.dequeueHead());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail and push them on the
+	 * specified stack.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainTailTo(Deque<? extends E> deque, Stack<? super E> stack) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, stack);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainTailTo_(Deque<? extends E> deque, Stack<? super E> stack) {
+		do {
+			stack.push(deque.dequeueTail());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head and enqueue them
+	 * on the specified queue.
+	 * Return whether the deque changed as a result.
+	 */
+	public static <E> boolean drainHeadTo(Deque<? extends E> deque, Queue<? super E> queue) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, queue);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainHeadTo_(Deque<? extends E> deque, Queue<? super E> queue) {
+		do {
+			queue.enqueue(deque.dequeueHead());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail and enqueue them
+	 * on the specified queue.
+	 * Return whether the first deque changed as a result.
+	 */
+	public static <E> boolean drainTailTo(Deque<? extends E> deque, Queue<? super E> queue) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, queue);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <E> boolean drainTailTo_(Deque<? extends E> deque, Queue<? super E> queue) {
+		do {
+			queue.enqueue(deque.dequeueTail());
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the first specified deque's head and enqueue them
+	 * on the second specified deque's tail.
+	 * Return whether the first deque changed as a result.
+	 */
+	public static <E> boolean drainHeadTo(Deque<? extends E> deque1, Deque<? super E> deque2) {
+		return ( ! deque1.isEmpty()) && drainHeadTo_(deque1, deque2);
+	}
+
+	/**
+	 * assume deque 1 is not empty
+	 */
+	private static <E> boolean drainHeadTo_(Deque<? extends E> deque1, Deque<? super E> deque2) {
+		do {
+			deque2.enqueueTail(deque1.dequeueHead());
+		} while ( ! deque1.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the first specified deque's tail and enqueue them
+	 * on the second specified deque's head.
+	 * Return whether the first deque changed as a result.
+	 */
+	public static <E> boolean drainTailTo(Deque<? extends E> deque1, Deque<? super E> deque2) {
+		return ( ! deque1.isEmpty()) && drainTailTo_(deque1, deque2);
+	}
+
+	/**
+	 * assume deque 1 is not empty
+	 */
+	private static <E> boolean drainTailTo_(Deque<? extends E> deque1, Deque<? super E> deque2) {
+		do {
+			deque2.enqueueHead(deque1.dequeueTail());
+		} while ( ! deque1.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head, passing each element to the
+	 * specified key transformer. Map the generated key to its element.
+	 */
+	public static <K, V, E extends V> boolean drainHeadTo(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, map, keyTransformer);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <K, V, E extends V> boolean drainHeadTo_(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		do {
+			MapTools.add(map, deque.dequeueHead(), keyTransformer);
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail, passing each element to the
+	 * specified key transformer. Map the generated key to its element.
+	 */
+	public static <K, V, E extends V> boolean drainTailTo(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, map, keyTransformer);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <K, V, E extends V> boolean drainTailTo_(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		do {
+			MapTools.add(map, deque.dequeueTail(), keyTransformer);
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's head, passing each element to the
+	 * specified key and value transformers. Add the generated key/value pairs
+	 * to the specified map.
+	 */
+	public static <K, V, E> boolean drainHeadTo(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		return ( ! deque.isEmpty()) && drainHeadTo_(deque, map, keyTransformer, valueTransformer);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <K, V, E> boolean drainHeadTo_(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		do {
+			MapTools.add(map, deque.dequeueHead(), keyTransformer, valueTransformer);
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified deque's tail, passing each element to the
+	 * specified key and value transformers. Add the generated key/value pairs
+	 * to the specified map.
+	 */
+	public static <K, V, E> boolean drainTailTo(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		return ( ! deque.isEmpty()) && drainTailTo_(deque, map, keyTransformer, valueTransformer);
+	}
+
+	/**
+	 * assume the deque is not empty
+	 */
+	private static <K, V, E> boolean drainTailTo_(Deque<E> deque, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		do {
+			MapTools.add(map, deque.dequeueTail(), keyTransformer, valueTransformer);
+		} while ( ! deque.isEmpty());
+		return true;
+	}
+
+
+	// ********** array deque factory methods **********
+
+	/**
+	 * Return an empty array-based deque.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque() {
+		return arrayDeque(10);
+	}
+
+	/**
+	 * Return an empty array-based deque with specified initial capacity.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(int initialCapacity) {
+		return new ArrayDeque<E>(initialCapacity);
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the specified iterable.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(Iterable<? extends E> iterable) {
+		return arrayDeque(iterable.iterator());
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the reverse of the specified iterable.
+	 */
+	public static <E> ArrayDeque<E> reverseArrayDeque(Iterable<? extends E> iterable) {
+		return reverseArrayDeque(iterable.iterator());
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the specified iterable.
+	 * The specified iterable size is a performance hint.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(Iterable<? extends E> iterable, int iterableSize) {
+		return arrayDeque(iterable.iterator(), iterableSize);
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the reverse of the specified iterable.
+	 * The specified iterable size is a performance hint.
+	 */
+	public static <E> ArrayDeque<E> reverseArrayDeque(Iterable<? extends E> iterable, int iterableSize) {
+		return reverseArrayDeque(iterable.iterator(), iterableSize);
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the specified iterator.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(Iterator<? extends E> iterator) {
+		ArrayDeque<E> deque = arrayDeque();
+		enqueueTailAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the reverse of the specified iterator.
+	 */
+	public static <E> ArrayDeque<E> reverseArrayDeque(Iterator<? extends E> iterator) {
+		ArrayDeque<E> deque = arrayDeque();
+		enqueueHeadAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the specified iterator.
+	 * The specified iterator size is a performance hint.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(Iterator<? extends E> iterator, int iteratorSize) {
+		ArrayDeque<E> deque = arrayDeque(iteratorSize);
+		enqueueTailAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the reverse of the specified iterator.
+	 * The specified iterator size is a performance hint.
+	 */
+	public static <E> ArrayDeque<E> reverseArrayDeque(Iterator<? extends E> iterator, int iteratorSize) {
+		ArrayDeque<E> deque = arrayDeque(iteratorSize);
+		enqueueHeadAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the specified array.
+	 */
+	public static <E> ArrayDeque<E> arrayDeque(E... array) {
+		ArrayDeque<E> deque = arrayDeque(array.length);
+		enqueueTailAll(deque, array);
+		return deque;
+	}
+
+	/**
+	 * Return an array-based deque corresponding to the reverse of the specified array.
+	 */
+	public static <E> ArrayDeque<E> reverseArrayDeque(E... array) {
+		ArrayDeque<E> deque = arrayDeque(array.length);
+		enqueueHeadAll(deque, array);
+		return deque;
+	}
+
+
+	// ********** linked deque factory methods **********
+
+	/**
+	 * Return an empty link-based deque with no node cache.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque() {
+		return linkedDeque(0);
+	}
+
+	/**
+	 * Return an empty link-based deque
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(int cacheSize) {
+		return new LinkedDeque<E>(cacheSize);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified iterable.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(Iterable<? extends E> iterable) {
+		return linkedDeque(iterable, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified iterable.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(Iterable<? extends E> iterable) {
+		return reverseLinkedDeque(iterable, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified iterable
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(Iterable<? extends E> iterable, int cacheSize) {
+		return linkedDeque(iterable.iterator(), cacheSize);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified iterable
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(Iterable<? extends E> iterable, int cacheSize) {
+		return reverseLinkedDeque(iterable.iterator(), cacheSize);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified iterator.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(Iterator<? extends E> iterator) {
+		return linkedDeque(iterator, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified iterator.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(Iterator<? extends E> iterator) {
+		return reverseLinkedDeque(iterator, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified iterator
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(Iterator<? extends E> iterator, int cacheSize) {
+		LinkedDeque<E> deque = linkedDeque(cacheSize);
+		enqueueTailAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified iterator
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(Iterator<? extends E> iterator, int cacheSize) {
+		LinkedDeque<E> deque = linkedDeque(cacheSize);
+		enqueueHeadAll(deque, iterator);
+		return deque;
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified array.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(E... array) {
+		return linkedDeque(array, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified array.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(E... array) {
+		return reverseLinkedDeque(array, 0);
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the specified array
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> linkedDeque(E[] array, int cacheSize) {
+		LinkedDeque<E> deque = linkedDeque(cacheSize);
+		enqueueTailAll(deque, array);
+		return deque;
+	}
+
+	/**
+	 * Return a link-based deque corresponding to the reverse of the specified array
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedDeque<E> reverseLinkedDeque(E[] array, int cacheSize) {
+		LinkedDeque<E> deque = linkedDeque(cacheSize);
+		enqueueHeadAll(deque, array);
+		return deque;
+	}
+
+
+	// ********** fixed size array deque factory methods **********
+
+	/**
+	 * Return a fixed-capacity array deque with the specified capacity.
+	 */
+	public static <E> FixedCapacityArrayDeque<E> fixedCapacityArrayDeque(int capacity) {
+		return new FixedCapacityArrayDeque<E>(capacity);
+	}
+
+	/**
+	 * Return a fized-capacity array deque containing the elements of the specified
+	 * collection. The deque will dequeue its head 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 Deque#dequeueHead()}).
+	 * The deque's capacity will be match the collection's size.
+	 */
+	public static <E> FixedCapacityArrayDeque<E> fixedCapacityArrayDeque(Collection<? extends E> collection) {
+		FixedCapacityArrayDeque<E> deque = fixedCapacityArrayDeque(collection.size());
+		enqueueTailAll(deque, collection);
+		return deque;
+	}
+
+	/**
+	 * Return a fized-capacity array deque containing the elements of the specified
+	 * collection. The deque will dequeue its tail 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 Deque#dequeueTail()}).
+	 * The deque's capacity will be match the collection's size.
+	 */
+	public static <E> FixedCapacityArrayDeque<E> reverseFixedCapacityArrayDeque(Collection<? extends E> collection) {
+		FixedCapacityArrayDeque<E> deque = fixedCapacityArrayDeque(collection.size());
+		enqueueHeadAll(deque, collection);
+		return deque;
+	}
+
+
+	// ********** priority deque factory methods **********
+
+	/**
+	 * Return a priority deque that returns its elements in
+	 * {@linkplain Comparable natural order}.
+	 */
+	public static <E extends Comparable<E>> PriorityDeque<E> priorityDeque() {
+		return priorityDeque(10);
+	}
+
+	/**
+	 * Return a priority deque that returns its elements in
+	 * {@linkplain Comparable natural order} and has the specified initial capacity.
+	 */
+	public static <E extends Comparable<E>> PriorityDeque<E> priorityDeque(int initialCapacity) {
+		return priorityDeque(ComparatorTools.<E>naturalComparator(), initialCapacity);
+	}
+
+	/**
+	 * Return a priority deque whose elements are returned in
+	 * the order determined by the specified comparator.
+	 */
+	public static <E> PriorityDeque<E> priorityDeque(Comparator<? super E> comparator) {
+		return priorityDeque(comparator, 10);
+	}
+
+	/**
+	 * Return a priority deque whose elements are returned in
+	 * the order determined by the specified comparator
+	 * and has the specified initial capacity.
+	 */
+	public static <E> PriorityDeque<E> priorityDeque(Comparator<? super E> comparator, int initialCapacity) {
+		return new PriorityDeque<E>(comparator, initialCapacity);
+	}
+
+
+	// ********** fixed size priority deque factory methods **********
+
+	/**
+	 * Return a fixed-capacity priority deque that returns its elements in
+	 * {@linkplain Comparable natural order} and has the specified capacity.
+	 */
+	public static <E extends Comparable<E>> FixedCapacityPriorityDeque<E> fixedCapacityPriorityDeque(int capacity) {
+		return fixedCapacityPriorityDeque(ComparatorTools.<E>naturalComparator(), capacity);
+	}
+
+	/**
+	 * Return a fixed-capacity priority deque whose elements are returned in
+	 * the order determined by the specified comparator
+	 * and has the specified capacity.
+	 */
+	public static <E> FixedCapacityPriorityDeque<E> fixedCapacityPriorityDeque(Comparator<? super E> comparator, int capacity) {
+		return new FixedCapacityPriorityDeque<E>(comparator, capacity);
+	}
+
+
+	// ********** synchronized deque factory methods **********
+
+	/**
+	 * Return a synchronized deque.
+	 */
+	public static <E> SynchronizedDeque<E> synchronizedDeque() {
+		ArrayDeque<E> deque = arrayDeque();
+		return synchronizedDeque(deque);
+	}
+
+	/**
+	 * Return a deque that synchronizes the specified deque.
+	 */
+	public static <E> SynchronizedDeque<E> synchronizedDeque(Object mutex) {
+		ArrayDeque<E> deque = arrayDeque();
+		return synchronizedDeque(deque, mutex);
+	}
+
+	/**
+	 * Return a deque that synchronizes the specified deque.
+	 */
+	public static <E> SynchronizedDeque<E> synchronizedDeque(Deque<E> deque) {
+		return new SynchronizedDeque<E>(deque);
+	}
+
+	/**
+	 * Return a deque that synchronizes the specified deque
+	 * with specified mutex.
+	 */
+	public static <E> SynchronizedDeque<E> synchronizedDeque(Deque<E> deque, Object mutex) {
+		return new SynchronizedDeque<E>(deque, mutex);
+	}
+
+
+	// ********** misc deque factory methods **********
+
+	/**
+	 * Adapt the specified list to the {@link Deque} interface.
+	 */
+	public static <E> ListDeque<E> adapt(List<E> list) {
+		return new ListDeque<E>(list);
+	}
+
+	/**
+	 * Return a deque that reverses the specified deque.
+	 */
+	public static <E> Deque<E> reverse(Deque<E> deque) {
+		return new ReverseDeque<E>(deque);
+	}
+
+	/**
+	 * Return an unmodifiable empty deque.
+	 */
+	public static <E> Deque<E> emptyDeque() {
+		return EmptyDeque.instance();
+	}
+
+
+	// ********** constructor **********
+
+	/**
+	 * Suppress default constructor, ensuring non-instantiability.
+	 */
+	private DequeTools() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/EmptyDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/EmptyDeque.java
new file mode 100644
index 0000000..7408bfa
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/EmptyDeque.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+
+/**
+ * Empty implementation of the {@link Deque} interface.
+ * @param <E> the type of elements maintained by the deque
+ * @see DequeTools
+ */
+public final class EmptyDeque<E>
+	implements Deque<E>, Serializable
+{
+	@SuppressWarnings("rawtypes")
+	public static final Deque INSTANCE = new EmptyDeque();
+	@SuppressWarnings("unchecked")
+	public static <E> Deque<E> instance() {
+		return INSTANCE;
+	}
+
+	// ensure single instance
+	private EmptyDeque() {
+		super();
+	}
+
+	public void enqueueTail(E o) {
+		throw new UnsupportedOperationException();
+	}
+
+	public void enqueueHead(E o) {
+		throw new UnsupportedOperationException();
+	}
+
+	public E dequeueHead() {
+		throw new NoSuchElementException();
+	}
+
+	public E dequeueTail() {
+		throw new NoSuchElementException();
+	}
+
+	public E peekHead() {
+		throw new NoSuchElementException();
+	}
+
+	public E peekTail() {
+		throw new NoSuchElementException();
+	}
+
+	public boolean isEmpty() {
+		return true;
+	}
+
+	@Override
+	public String toString() {
+		return "[]"; //$NON-NLS-1$
+	}
+
+	private static final long serialVersionUID = 1L;
+	private Object readResolve() {
+		// replace this object with the singleton
+		return INSTANCE;
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityArrayDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityArrayDeque.java
new file mode 100644
index 0000000..e225c55
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityArrayDeque.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import org.eclipse.jpt.common.utility.deque.Deque;
+
+/**
+ * Fixed-capacity array implementation of the {@link Deque} interface.
+ * This implementation will throw an exception if its capacity is exceeded.
+ * @param <E> the type of elements maintained by the queue
+ * @see ArrayDeque
+ * @see DequeTools
+ */
+public class FixedCapacityArrayDeque<E>
+	extends AbstractArrayDeque<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty deque with the specified capacity.
+	 */
+	public FixedCapacityArrayDeque(int capacity) {
+		super(capacity);
+	}
+
+
+	// ********** Deque implementation **********
+
+	/**
+	 * @exception IllegalStateException if the deque is full
+	 */
+	@Override
+	public void enqueueTail(E element) {
+		if (this.isFull()) {
+			throw new IllegalStateException("Deque is full."); //$NON-NLS-1$
+		}
+		super.enqueueTail(element);
+	}
+
+	/**
+	 * @exception IllegalStateException if the deque is full
+	 */
+	@Override
+	public void enqueueHead(E element) {
+		if (this.isFull()) {
+			throw new IllegalStateException("Deque is full."); //$NON-NLS-1$
+		}
+		super.enqueueHead(element);
+	}
+
+	/**
+	 * Return whether the deque is full,
+	 * as its capacity is fixed.
+	 */
+	public boolean isFull() {
+		return this.size == this.elements.length;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public FixedCapacityArrayDeque<E> clone() {
+		return (FixedCapacityArrayDeque<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityPriorityDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityPriorityDeque.java
new file mode 100644
index 0000000..0934b18
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/FixedCapacityPriorityDeque.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import java.util.Comparator;
+import org.eclipse.jpt.common.utility.deque.InputRestrictedDeque;
+
+/**
+ * Fixed capacity priority implementation of the {@link InputRestrictedDeque} interface.
+ * Elements will dequeue from the deque's head in the order determined by a comparator
+ * (i.e. {@link #dequeueHead} will return the element sorted first
+ * while {@link #dequeueTail} will return the element sorted last).
+ * @param <E> the type of elements maintained by the deque
+ * @see PriorityDeque
+ * @see DequeTools
+ */
+public class FixedCapacityPriorityDeque<E>
+	extends AbstractPriorityDeque<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty, fixed-capacity priority deque with the specified comparator
+	 * and capacity.
+	 */
+	public FixedCapacityPriorityDeque(Comparator<? super E> comparator, int capacity) {
+		super(comparator, capacity);
+	}
+
+
+	// ********** Deque implementation **********
+
+	/**
+	 * @exception IllegalStateException if the deque is full
+	 */
+	@Override
+	public void enqueue(E element) {
+		if (this.isFull()) {
+			throw new IllegalStateException("Deque is full."); //$NON-NLS-1$
+		}
+		super.enqueue(element);
+	}
+
+	/**
+	 * Return whether the deque is full,
+	 * as its capacity is fixed.
+	 */
+	public boolean isFull() {
+		return this.size == this.elements.length - 1;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public FixedCapacityPriorityDeque<E> clone() {
+		return (FixedCapacityPriorityDeque<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/LinkedDeque.java
similarity index 68%
copy from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java
copy to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/LinkedDeque.java
index ee07946..937d38e 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/LinkedDeque.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2015 Oracle. All rights reserved.
+ * Copyright (c) 2015 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.
@@ -7,25 +7,25 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.deque;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
+import org.eclipse.jpt.common.utility.deque.Deque;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
 
 /**
- * Linked FIFO implementation of the {@link Queue} interface.
- * @param <E> the type of elements maintained by the queue
- * @see QueueTools
+ * Linked implementation of the {@link Deque} interface.
+ * @param <E> the type of elements maintained by the deque
+ * @see DequeTools
  */
-public class LinkedQueue<E>
-	implements Queue<E>, Cloneable, Serializable
+public class LinkedDeque<E>
+	implements Deque<E>, Cloneable, Serializable
 {
 	private final NodeFactory<E> nodeFactory;
-	private transient Node<E> head; // next element to dequeue
-	private transient Node<E> tail; // last element
+	private transient Node<E> head; // next element to dequeue head
+	private transient Node<E> tail; // next element to dequeue tail
 
 	private static final long serialVersionUID = 1L;
 
@@ -33,18 +33,18 @@
 	// ********** constructors **********
 
 	/**
-	 * Construct an empty queue with no node cache.
+	 * Construct an empty deque with no node cache.
 	 */
-	public LinkedQueue() {
+	public LinkedDeque() {
 		this(0);
 	}
 
 	/**
-	 * Construct an empty queue with a node cache with the specified size.
+	 * Construct an empty deque with a node cache with the specified size.
 	 * Specify a cache size of -1 for an unlimited cache.
 	 */
-	public LinkedQueue(int cacheSize) {
-		this(LinkedQueue.<E>buildNodeFactory(cacheSize));
+	public LinkedDeque(int cacheSize) {
+		this(LinkedDeque.<E>buildNodeFactory(cacheSize));
 		this.head = null;
 	}
 
@@ -55,7 +55,7 @@
 		return (cacheSize == 0) ? SimpleNodeFactory.<E>instance() : new CachingNodeFactory<E>(cacheSize);
 	}
 
-	private LinkedQueue(NodeFactory<E> nodeFactory) {
+	private LinkedDeque(NodeFactory<E> nodeFactory) {
 		super();
 		this.nodeFactory = nodeFactory;
 		this.head = null;
@@ -63,10 +63,10 @@
 	}
 
 
-	// ********** Queue implementation **********
+	// ********** Deque implementation **********
 
-	public void enqueue(E element) {
-		Node<E> newNode = this.nodeFactory.buildNode(element, null);
+	public void enqueueTail(E element) {
+		Node<E> newNode = this.nodeFactory.buildNode(element, null, this.tail);
 		if (this.tail == null) {
 			this.head = newNode; // first node
 		} else {
@@ -75,7 +75,17 @@
 		this.tail = newNode;
 	}
 
-	public E dequeue() {
+	public void enqueueHead(E element) {
+		Node<E> newNode = this.nodeFactory.buildNode(element, this.head, null);
+		if (this.head == null) {
+			this.tail = newNode; // first node
+		} else {
+			this.head.prev = newNode;
+		}
+		this.head = newNode;
+	}
+
+	public E dequeueHead() {
 		if (this.head == null) {
 			throw new NoSuchElementException();
 		}
@@ -83,19 +93,44 @@
 		this.head = node.next;
 		if (this.head == null) {
 			this.tail = null; // last node
+		} else {
+			this.head.prev = null;
 		}
 		E element = node.element;
 		this.nodeFactory.release(node);
 		return element;
 	}
 
-	public E peek() {
+	public E dequeueTail() {
+		if (this.tail == null) {
+			throw new NoSuchElementException();
+		}
+		Node<E> node = this.tail;
+		this.tail = node.prev;
+		if (this.tail == null) {
+			this.head = null; // last node
+		} else {
+			this.tail.next = null;
+		}
+		E element = node.element;
+		this.nodeFactory.release(node);
+		return element;
+	}
+
+	public E peekHead() {
 		if (this.head == null) {
 			throw new NoSuchElementException();
 		}
 		return this.head.element;
 	}
 
+	public E peekTail() {
+		if (this.tail == null) {
+			throw new NoSuchElementException();
+		}
+		return this.tail.element;
+	}
+
 	public boolean isEmpty() {
 		return this.head == null;
 	}
@@ -104,11 +139,11 @@
 	// ********** standard methods **********
 
 	@Override
-	public LinkedQueue<E> clone() {
-		LinkedQueue<E> clone = new LinkedQueue<E>(this.nodeFactory.copy());
+	public LinkedDeque<E> clone() {
+		LinkedDeque<E> clone = new LinkedDeque<E>(this.nodeFactory.copy());
 		E[] elements = this.buildElements();
 		for (E element : elements) {
-			clone.enqueue(element);
+			clone.enqueueTail(element);
 		}
 		return clone;
 	}
@@ -159,7 +194,7 @@
 		stream.defaultReadObject();
 		int len = stream.readInt();
 		for (int i = len; i-- > 0; ) {
-			this.enqueue((E) stream.readObject());
+			this.enqueueTail((E) stream.readObject());
 		}
 	}
 
@@ -169,11 +204,13 @@
 	private static final class Node<E> {
 		E element;
 		Node<E> next;
+		Node<E> prev;
 
-		Node(E element, Node<E> next) {
+		Node(E element, Node<E> next, Node<E> prev) {
 			super();
 			this.element = element;
 			this.next = next;
+			this.prev = prev;
 		}
 
 		@Override
@@ -187,8 +224,8 @@
 			super();
 		}
 
-		Node<E> buildNode(E element, Node<E> next) {
-			return new Node<E>(element, next);
+		Node<E> buildNode(E element, Node<E> next, Node<E> prev) {
+			return new Node<E>(element, next, prev);
 		}
 
 		abstract void release(Node<E> node);
@@ -221,6 +258,11 @@
 			return this;
 		}
 
+		@Override
+		public String toString() {
+			return ObjectTools.singletonToString(this);
+		}
+
 		private static final long serialVersionUID = 1L;
 		private Object readResolve() {
 			// replace this object with the singleton
@@ -243,9 +285,9 @@
 		}
 
 		@Override
-		Node<E> buildNode(E element, Node<E> next) {
+		Node<E> buildNode(E element, Node<E> next, Node<E> prev) {
 			if (this.cacheHead == null) {
-				return super.buildNode(element, next);
+				return super.buildNode(element, next, prev);
 			}
 			Node<E> node = this.cacheHead;
 			this.cacheHead = node.next;
@@ -260,6 +302,7 @@
 			if ((this.maxCacheSize == -1) || (this.cacheSize < this.maxCacheSize)) {
 				node.element = null; // allow GC to work
 				node.next = this.cacheHead;
+				node.prev = null;
 				this.cacheHead = node;
 				this.cacheSize++;
 			}
@@ -269,5 +312,10 @@
 		NodeFactory<E> copy() {
 			return new CachingNodeFactory<E>(this.maxCacheSize);
 		}
+
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, this.cacheSize);
+		}
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ListDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ListDeque.java
new file mode 100644
index 0000000..bd86cdf
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ListDeque.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+
+/**
+ * Adapt a {@link List} to the {@link Deque} interface.
+ * Head elements are dequeueHeadd from the front of the list (i.e. index 0);
+ * while tail elements are dequeueHeadd from the end of the list.
+ * @param <E> the type of elements maintained by the deque
+ * @see DequeTools
+ */
+public class ListDeque<E>
+	implements Deque<E>, Serializable
+{
+	private List<E> list;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a deque, adapting the specified list.
+	 * The deque's head will dequeueHead its elements in the same
+	 * order they are returned by the list's iterator (i.e. the
+	 * first element returned by the list's iterator will be the
+	 * first element returned by {@link #dequeueHead()}).
+	 */
+	public ListDeque(List<E> list) {
+		super();
+		this.list = list;
+	}
+
+
+	// ********** Deque implementation **********
+
+	public void enqueueTail(E element) {
+		this.list.add(element);
+	}
+
+	public void enqueueHead(E element) {
+		this.list.add(0, element);
+	}
+
+	public E dequeueHead() {
+		if (this.list.size() == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.list.remove(0);
+	}
+
+	public E dequeueTail() {
+		int size = this.list.size();
+		if (size == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.list.remove(size - 1);
+	}
+
+	public E peekHead() {
+		if (this.list.size() == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.list.get(0);
+	}
+
+	public E peekTail() {
+		int size = this.list.size();
+		if (size == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.list.get(size - 1);
+	}
+
+	public boolean isEmpty() {
+		return this.list.isEmpty();
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return this.list.toString();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/PriorityDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/PriorityDeque.java
new file mode 100644
index 0000000..270b04a
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/PriorityDeque.java
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.deque;
+
+import java.util.Comparator;
+import org.eclipse.jpt.common.utility.deque.InputRestrictedDeque;
+
+/**
+ * Resizable priority implementation of the {@link InputRestrictedDeque} interface.
+ * Elements will dequeue from the deque's head in the order determined by a comparator
+ * (i.e. {@link #dequeueHead} will return the element sorted first
+ * while {@link #dequeueTail} will return the element sorted last).
+ * @param <E> the type of elements maintained by the deque
+ * @see FixedCapacityPriorityDeque
+ * @see DequeTools
+ */
+public class PriorityDeque<E>
+	extends AbstractPriorityDeque<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty priority deque with the specified comparator
+	 * and initial capacity.
+	 */
+	public PriorityDeque(Comparator<? super E> comparator, int initialCapacity) {
+		super(comparator, initialCapacity);
+	}
+
+
+	// ********** Deque implementation **********
+
+	@Override
+	public void enqueue(E element) {
+		this.ensureCapacity(this.size + 1);
+		super.enqueue(element);
+	}
+
+	/**
+	 * Increase the deque's capacity, if necessary, to ensure it has at least
+	 * the specified minimum capacity.
+	 */
+	public void ensureCapacity(int minCapacity) {
+		int oldCapacity = this.elements.length - 1;
+		if (oldCapacity < minCapacity) {
+			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
+			if (newCapacity < minCapacity) {
+				newCapacity = minCapacity;
+			}
+			this.elements = this.copyElements(newCapacity);
+		}
+	}
+
+	/**
+	 * Decrease the deque's capacity, if necessary, to match its current size.
+	 */
+	public void trimToSize() {
+		if (this.elements.length > this.size + 1) {
+			this.elements = this.copyElements(this.size);
+		}
+	}
+
+	private E[] copyElements(int newCapacity) {
+		@SuppressWarnings("unchecked")
+		E[] newElements = (E[]) new Object[newCapacity + 1];
+		System.arraycopy(this.elements, 1, newElements, 1, this.size); // skip 0
+		return newElements;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public PriorityDeque<E> clone() {
+		return (PriorityDeque<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ReverseDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ReverseDeque.java
new file mode 100644
index 0000000..e834b86
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/ReverseDeque.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import java.io.Serializable;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+
+/**
+ * This deque will reverse the order of the configured deque.
+ * @param <E> the type of elements maintained by the deque
+ * @see DequeTools
+ */
+public class ReverseDeque<E>
+	implements Deque<E>, Serializable
+{
+	private Deque<E> deque;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a deque that reverses the specified deque.
+	 */
+	public ReverseDeque(Deque<E> deque) {
+		super();
+		if (deque == null) {
+			throw new NullPointerException();
+		}
+		this.deque = deque;
+	}
+
+
+	// ********** Deque implementation **********
+
+	public void enqueueTail(E element) {
+		this.deque.enqueueHead(element);
+	}
+
+	public void enqueueHead(E element) {
+		this.deque.enqueueTail(element);
+	}
+
+	public E dequeueHead() {
+		return this.deque.dequeueTail();
+	}
+
+	public E dequeueTail() {
+		return this.deque.dequeueHead();
+	}
+
+	public E peekHead() {
+		return this.deque.peekTail();
+	}
+
+	public E peekTail() {
+		return this.deque.peekHead();
+	}
+
+	public boolean isEmpty() {
+		return this.deque.isEmpty();
+	}
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.deque);
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/SynchronizedDeque.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/SynchronizedDeque.java
new file mode 100644
index 0000000..d89d60a
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/deque/SynchronizedDeque.java
@@ -0,0 +1,984 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.deque;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.command.Command;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * Thread-safe implementation of the {@link Deque} interface.
+ * This also provides protocol for suspending a thread until the
+ * deque is empty or not empty, with optional time-outs.
+ * @param <E> the type of elements maintained by the deque
+ * @see DequeTools
+ */
+public class SynchronizedDeque<E>
+	implements Deque<E>, Serializable
+{
+	/** Backing deque. */
+	private final Deque<E> deque;
+
+	/** Object to synchronize on. */
+	private final Object mutex;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a synchronized deque that wraps the
+	 * specified deque and locks on the specified mutex.
+	 */
+	public SynchronizedDeque(Deque<E> deque, Object mutex) {
+		super();
+		if ((deque == null) || (mutex == null)) {
+			throw new NullPointerException();
+		}
+		this.deque = deque;
+		this.mutex = mutex;
+	}
+
+	/**
+	 * Construct a synchronized deque that wraps the
+	 * specified deque and locks on itself.
+	 */
+	public SynchronizedDeque(Deque<E> deque) {
+		super();
+		if (deque == null) {
+			throw new NullPointerException();
+		}
+		this.deque = deque;
+		this.mutex = this;
+	}
+
+
+	// ********** Deque implementation **********
+
+	public void enqueueTail(E element) {
+		synchronized (this.mutex) {
+			this.enqueueTail_(element);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private void enqueueTail_(E element) {
+		this.deque.enqueueTail(element);
+		this.mutex.notifyAll();
+	}
+
+	public void enqueueHead(E element) {
+		synchronized (this.mutex) {
+			this.enqueueHead_(element);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private void enqueueHead_(E element) {
+		this.deque.enqueueHead(element);
+		this.mutex.notifyAll();
+	}
+
+	public E dequeueHead() {
+		synchronized (this.mutex) {
+			return this.dequeueHead_();
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private E dequeueHead_() {
+		E element = this.deque.dequeueHead();
+		this.mutex.notifyAll();
+		return element;
+	}
+
+	public E dequeueTail() {
+		synchronized (this.mutex) {
+			return this.dequeueTail_();
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private E dequeueTail_() {
+		E element = this.deque.dequeueTail();
+		this.mutex.notifyAll();
+		return element;
+	}
+
+	public E peekHead() {
+		synchronized (this.mutex) {
+			return this.deque.peekHead();
+		}
+	}
+
+	public E peekTail() {
+		synchronized (this.mutex) {
+			return this.deque.peekTail();
+		}
+	}
+
+	public boolean isEmpty() {
+		synchronized (this.mutex) {
+			return this.deque.isEmpty();
+		}
+	}
+
+
+	// ********** indefinite waits **********
+
+	/**
+	 * Suspend the current thread until the deque'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.deque.isEmpty() != empty) {
+			this.mutex.wait();
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque is empty.
+	 */
+	public void waitUntilEmpty() throws InterruptedException {
+		this.waitUntilEmptyIs(true);
+	}
+
+	/**
+	 * Suspend the current thread until the deque has something on it.
+	 */
+	public void waitUntilNotEmpty() throws InterruptedException {
+		this.waitUntilEmptyIs(false);
+	}
+
+	/**
+	 * Suspend the current thread until the deque is empty,
+	 * then "enqueue" the specified item to the tail of the deque
+	 * and continue executing.
+	 */
+	public void waitToEnqueueTail(E element) throws InterruptedException {
+		synchronized (this.mutex) {
+			this.waitUntilEmptyIs_(true);
+			this.enqueueTail_(element);
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque is empty,
+	 * then "enqueue" the specified item to the head of the deque
+	 * and continue executing.
+	 */
+	public void waitToEnqueueHead(E element) throws InterruptedException {
+		synchronized (this.mutex) {
+			this.waitUntilEmptyIs_(true);
+			this.enqueueHead_(element);
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque has something on it,
+	 * then "dequeue" an item from the head of the deque and return it.
+	 */
+	public Object waitToDequeueHead() throws InterruptedException {
+		synchronized (this.mutex) {
+			this.waitUntilEmptyIs_(false);
+			return this.dequeueHead_();
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque has something on it,
+	 * then "dequeue" an item from the tail of the deque and return it.
+	 */
+	public Object waitToDequeueTail() throws InterruptedException {
+		synchronized (this.mutex) {
+			this.waitUntilEmptyIs_(false);
+			return this.dequeueTail_();
+		}
+	}
+
+
+	// ********** timed waits **********
+
+	/**
+	 * Suspend the current thread until the deque'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 deque'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.deque.isEmpty() != empty) && (remaining > 0L)) {
+			this.mutex.wait(remaining);
+			remaining = stop - System.currentTimeMillis();
+		}
+		return (this.deque.isEmpty() == empty);
+	}
+
+	/**
+	 * Suspend the current thread until the deque is empty
+	 * or the specified time-out occurs.
+	 * The time-out is specified in milliseconds. Return <code>true</code> if
+	 * the deque is empty; return <code>false</code> if a time-out occurred.
+	 * If the deque 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 deque has something on it.
+	 * or the specified time-out occurs.
+	 * The time-out is specified in milliseconds. Return <code>true</code> if
+	 * the deque is not empty; return <code>false</code> if a time-out occurred.
+	 * If the deque 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 deque is empty,
+	 * then "enqueue" the specified item to the tail of the deque
+	 * and continue executing. If the deque 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 deque is already empty, "enqueue" the specified item and
+	 * return <code>true</code> immediately.
+	 * If the time-out is zero, wait indefinitely.
+	 */
+	public boolean waitToEnqueueTail(E element, long timeout) throws InterruptedException {
+		synchronized (this.mutex) {
+			boolean success = this.waitUntilEmptyIs_(true, timeout);
+			if (success) {
+				this.enqueueTail_(element);
+			}
+			return success;
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque is empty,
+	 * then "enqueue" the specified item to the head of the deque
+	 * and continue executing. If the deque 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 deque is already empty, "enqueue" the specified item and
+	 * return <code>true</code> immediately.
+	 * If the time-out is zero, wait indefinitely.
+	 */
+	public boolean waitToEnqueueHead(E element, long timeout) throws InterruptedException {
+		synchronized (this.mutex) {
+			boolean success = this.waitUntilEmptyIs_(true, timeout);
+			if (success) {
+				this.enqueueHead_(element);
+			}
+			return success;
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque has something on it,
+	 * then "dequeue" an item from the head of the deque and return it.
+	 * If the deque 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 deque is not empty, "dequeue" an item and
+	 * return it immediately.
+	 * If the time-out is zero, wait indefinitely.
+	 */
+	public Object waitToDequeueHead(long timeout) throws InterruptedException {
+		synchronized (this.mutex) {
+			boolean success = this.waitUntilEmptyIs_(false, timeout);
+			if (success) {
+				return this.dequeueHead_();
+			}
+			throw new NoSuchElementException();
+		}
+	}
+
+	/**
+	 * Suspend the current thread until the deque has something on it,
+	 * then "dequeue" an item from the tail of the deque and return it.
+	 * If the deque 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 deque is not empty, "dequeue" an item and
+	 * return it immediately.
+	 * If the time-out is zero, wait indefinitely.
+	 */
+	public Object waitToDequeueTail(long timeout) throws InterruptedException {
+		synchronized (this.mutex) {
+			boolean success = this.waitUntilEmptyIs_(false, timeout);
+			if (success) {
+				return this.dequeueTail_();
+			}
+			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 deque in another
+	 * thread.
+	 */
+	public void execute(Command command) throws InterruptedException {
+		if (Thread.currentThread().isInterrupted()) {
+			throw new InterruptedException();
+		}
+		synchronized (this.mutex) {
+			command.execute();
+		}
+	}
+
+
+	// ********** additional public protocol **********
+
+	/**
+	 * "Enqueue" all the elements returned by the specified iterable to the deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueTailAll(Iterable<? extends E> iterable) {
+		return this.enqueueTailAll(iterable.iterator());
+	}
+
+	/**
+	 * "Enqueue" all the elements returned by the specified iterable to the deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueHeadAll(Iterable<? extends E> iterable) {
+		return this.enqueueHeadAll(iterable.iterator());
+	}
+
+	/**
+	 * "Enqueue" all the elements returned by the specified iterator to the deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueTailAll(Iterator<? extends E> iterator) {
+		if ( ! iterator.hasNext()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueTailAll_(iterator);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the iterator is not empty.
+	 */
+	private boolean enqueueTailAll_(Iterator<? extends E> iterator) {
+		do {
+			this.deque.enqueueTail(iterator.next());
+		} while (iterator.hasNext());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Enqueue" all the elements returned by the specified iterator to the deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueHeadAll(Iterator<? extends E> iterator) {
+		if ( ! iterator.hasNext()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueHeadAll_(iterator);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the iterator is not empty.
+	 */
+	private boolean enqueueHeadAll_(Iterator<? extends E> iterator) {
+		do {
+			this.deque.enqueueHead(iterator.next());
+		} while (iterator.hasNext());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Enqueue" all the elements in the specified array to the deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueTailAll(E... array) {
+		int len = array.length;
+		if (len == 0) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueTailAll_(array, len);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the array is not empty.
+	 */
+	private boolean enqueueTailAll_(E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			this.deque.enqueueTail(array[i++]);
+		} while (i < arrayLength);
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Enqueue" all the elements in the specified array to the deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueHeadAll(E... array) {
+		int len = array.length;
+		if (len == 0) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueHeadAll_(array, len);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the array is not empty.
+	 */
+	private boolean enqueueHeadAll_(E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			this.deque.enqueueHead(array[i++]);
+		} while (i < arrayLength);
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack and "enqueue" them to the deque's tail.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueTailAll(Stack<? extends E> stack) {
+		if (stack.isEmpty()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueTailAll_(stack);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the stack is not empty.
+	 */
+	private boolean enqueueTailAll_(Stack<? extends E> stack) {
+		do {
+			this.deque.enqueueTail(stack.pop());
+		} while ( ! stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack and "enqueue" them to the deque's head.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean enqueueHeadAll(Stack<? extends E> stack) {
+		if (stack.isEmpty()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueHeadAll_(stack);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the stack is not empty.
+	 */
+	private boolean enqueueHeadAll_(Stack<? extends E> stack) {
+		do {
+			this.deque.enqueueHead(stack.pop());
+		} while ( ! stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Dequeue" all the elements from the specified deque's head and
+	 * "enqueue" them to the deque's tail.
+	 * Return whether the deque changed as a result.
+	 * @see #drainHeadTo(Deque)
+	 */
+	public boolean enqueueTailAll(Deque<? extends E> q) {
+		if (q.isEmpty()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueTailAll_(q);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the deque is not empty.
+	 */
+	private boolean enqueueTailAll_(Deque<? extends E> q) {
+		do {
+			this.deque.enqueueTail(q.dequeueHead());
+		} while ( ! q.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Dequeue" all the elements from the specified deque's tail and
+	 * "enqueue" them to the deque's head.
+	 * Return whether the deque changed as a result.
+	 * @see #drainTailTo(Deque)
+	 */
+	public boolean enqueueHeadAll(Deque<? extends E> q) {
+		if (q.isEmpty()) {
+			return false;
+		}
+		synchronized (this.mutex) {
+			return this.enqueueHeadAll_(q);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the deque is not empty.
+	 */
+	private boolean enqueueHeadAll_(Deque<? extends E> q) {
+		do {
+			this.deque.enqueueHead(q.dequeueTail());
+		} while ( ! q.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head and return them in a list.
+	 */
+	public ArrayList<E> drainHead() {
+		ArrayList<E> result = new ArrayList<E>();
+		this.drainHeadTo(result);
+		return result;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail and return them in a list.
+	 */
+	public ArrayList<E> drainTail() {
+		ArrayList<E> result = new ArrayList<E>();
+		this.drainTailTo(result);
+		return result;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head into specified collection.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainHeadTo(Collection<? super E> collection) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(collection);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainHeadTo_(Collection<? super E> collection) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		return this.drainHeadTo__(collection);
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the deque is not empty.
+	 */
+	private boolean drainHeadTo__(Collection<? super E> collection) {
+		do {
+			collection.add(this.deque.dequeueHead());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail into specified collection.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainTailTo(Collection<? super E> collection) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(collection);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainTailTo_(Collection<? super E> collection) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		return this.drainTailTo__(collection);
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the deque is not empty.
+	 */
+	private boolean drainTailTo__(Collection<? super E> collection) {
+		do {
+			collection.add(this.deque.dequeueTail());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head into specified list
+	 * at the specified index.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainHeadTo(List<? super E> list, int index) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(list, index);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainHeadTo_(List<? super E> list, int index) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		if (index == list.size()) {
+			return this.drainHeadTo__(list);
+		}
+		ArrayList<E> temp = new ArrayList<E>();
+		this.drainHeadTo__(temp);
+		list.addAll(index, temp);
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail into specified list
+	 * at the specified index.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainTailTo(List<? super E> list, int index) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(list, index);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainTailTo_(List<? super E> list, int index) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		if (index == list.size()) {
+			return this.drainTailTo__(list);
+		}
+		ArrayList<E> temp = new ArrayList<E>();
+		this.drainTailTo__(temp);
+		list.addAll(index, temp);
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head into specified stack.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainHeadTo(Stack<? super E> stack) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(stack);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainHeadTo_(Stack<? super E> stack) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			stack.push(this.deque.dequeueHead());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail into specified stack.
+	 * Return whether the deque changed as a result.
+	 */
+	public boolean drainTailTo(Stack<? super E> stack) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(stack);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainTailTo_(Stack<? super E> stack) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			stack.push(this.deque.dequeueTail());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head into specified deque's tail.
+	 * Return whether the deque changed as a result.
+	 * @see #enqueueTailAll(Deque)
+	 */
+	public boolean drainHeadTo(Deque<? super E> q) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(q);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainHeadTo_(Deque<? super E> q) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			q.enqueueTail(this.deque.dequeueHead());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail into specified deque's head.
+	 * Return whether the deque changed as a result.
+	 * @see #enqueueTailAll(Deque)
+	 */
+	public boolean drainTailTo(Deque<? super E> q) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(q);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainTailTo_(Deque<? super E> q) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			q.enqueueHead(this.deque.dequeueTail());
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each item.
+	 * Return whether the deque changed as a result.
+	 */
+	public <K> boolean drainHeadTo(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(map, keyTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K> boolean drainHeadTo_(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.deque.dequeueHead(), keyTransformer);
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each item.
+	 * Return whether the deque changed as a result.
+	 */
+	public <K> boolean drainTailTo(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(map, keyTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K> boolean drainTailTo_(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.deque.dequeueTail(), keyTransformer);
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's head
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each dequeued item and the specified value transformer
+	 * to generator the value for each dequeued item.
+	 * Return whether the deque changed as a result.
+	 */
+	public <K, V> boolean drainHeadTo(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		synchronized (this.mutex) {
+			return this.drainHeadTo_(map, keyTransformer, valueTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K, V> boolean drainHeadTo_(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.deque.dequeueHead(), keyTransformer, valueTransformer);
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the deque's tail
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each dequeued item and the specified value transformer
+	 * to generator the value for each dequeued item.
+	 * Return whether the deque changed as a result.
+	 */
+	public <K, V> boolean drainTailTo(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		synchronized (this.mutex) {
+			return this.drainTailTo_(map, keyTransformer, valueTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K, V> boolean drainTailTo_(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		if (this.deque.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.deque.dequeueTail(), keyTransformer, valueTransformer);
+		} while ( ! this.deque.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * Return the object the deque locks on while performing
+	 * its operations.
+	 */
+	public Object getMutex() {
+		return this.mutex;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		synchronized (this.mutex) {
+			return this.deque.toString();
+		}
+	}
+
+	private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+		synchronized (this.mutex) {
+			s.defaultWriteObject();
+		}
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/enumeration/EnumerationTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/enumeration/EnumerationTools.java
index 9ce3de3..6b2ca1c 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/enumeration/EnumerationTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/enumeration/EnumerationTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -53,7 +53,7 @@
 	 * elements in the specified collection.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, Collection<?> collection) {
-		return CollectionTools.set(iterator(enumeration)).containsAll(collection);
+		return CollectionTools.hashSet(iterator(enumeration)).containsAll(collection);
 	}
 
 	/**
@@ -62,7 +62,7 @@
 	 * The specified enumeration size is a performance hint.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, int enumerationSize, Collection<?> collection) {
-		return CollectionTools.set(iterator(enumeration), enumerationSize).containsAll(collection);
+		return CollectionTools.hashSet(iterator(enumeration), enumerationSize).containsAll(collection);
 	}
 
 	/**
@@ -70,7 +70,7 @@
 	 * elements in the specified iterable.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, Iterable<?> iterable) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration)), iterable);
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration)), iterable);
 	}
 
 	/**
@@ -79,7 +79,7 @@
 	 * The specified enumeration size is a performance hint.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, int enumerationSize, Iterable<?> iterable) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration), enumerationSize), iterable);
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration), enumerationSize), iterable);
 	}
 
 	/**
@@ -87,7 +87,7 @@
 	 * elements in the specified enumeration 2.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration1, Enumeration<?> enumeration2) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration1)), iterator(enumeration2));
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration1)), iterator(enumeration2));
 	}
 
 	/**
@@ -96,7 +96,7 @@
 	 * The specified iterator 1 size is a performance hint.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration1, int enumeration1Size, Enumeration<?> enumeration2) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration1), enumeration1Size), iterator(enumeration2));
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration1), enumeration1Size), iterator(enumeration2));
 	}
 
 	/**
@@ -104,7 +104,7 @@
 	 * elements in the specified array.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, Object... array) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration)), array);
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration)), array);
 	}
 
 	/**
@@ -113,7 +113,7 @@
 	 * The specified enumeration size is a performance hint.
 	 */
 	public static boolean containsAll(Enumeration<?> enumeration, int enumerationSize, Object... array) {
-		return CollectionTools.containsAll(CollectionTools.set(iterator(enumeration), enumerationSize), array);
+		return CollectionTools.containsAll(CollectionTools.hashSet(iterator(enumeration), enumerationSize), array);
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ChainIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ChainIterable.java
index 83bbe90..babbca5 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ChainIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ChainIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -56,6 +56,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeIterable.java
index 8170130..cf84a8c 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -66,6 +66,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeListIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeListIterable.java
index cf85171..45c7c5c 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeListIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/CompositeListIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -68,6 +68,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/FilteringIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/FilteringIterable.java
index 2fceff8..0d6274a 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/FilteringIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/FilteringIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -50,6 +50,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/GraphIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/GraphIterable.java
index aa99463..3728603 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/GraphIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/GraphIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -72,6 +72,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/IterableTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/IterableTools.java
index 0b84ffb..8b45db2 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/IterableTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/IterableTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2011, 2013 Oracle. All rights reserved.

+ * Copyright (c) 2011, 2015 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.

@@ -18,8 +18,6 @@
 import java.util.ListIterator;

 import org.eclipse.jpt.common.utility.closure.Closure;

 import org.eclipse.jpt.common.utility.closure.InterruptibleClosure;

-import org.eclipse.jpt.common.utility.collection.Queue;

-import org.eclipse.jpt.common.utility.collection.Stack;

 import org.eclipse.jpt.common.utility.exception.ExceptionHandler;

 import org.eclipse.jpt.common.utility.internal.closure.DisabledClosure;

 import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;

@@ -30,6 +28,8 @@
 import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;

 import org.eclipse.jpt.common.utility.iterable.ListIterable;

 import org.eclipse.jpt.common.utility.predicate.Predicate;

+import org.eclipse.jpt.common.utility.queue.Queue;

+import org.eclipse.jpt.common.utility.stack.Stack;

 import org.eclipse.jpt.common.utility.transformer.Transformer;

 

 /**

@@ -56,18 +56,18 @@
 	}

 

 	/**

-	 * Return a collection corresponding to the specified iterable.

+	 * Return a hash bag corresponding to the specified iterable.

 	 */

-	public static <E> HashBag<E> collection(Iterable<? extends E> iterable) {

-		return IteratorTools.collection(iterable.iterator());

+	public static <E> HashBag<E> hashBag(Iterable<? extends E> iterable) {

+		return IteratorTools.hashBag(iterable.iterator());

 	}

 

 	/**

-	 * Return a collection corresponding to the specified iterable.

+	 * Return a hash bag corresponding to the specified iterable.

 	 * The specified iterable size is a performance hint.

 	 */

-	public static <E> HashBag<E> collection(Iterable<? extends E> iterable, int iterableSize) {

-		return IteratorTools.collection(iterable.iterator(), iterableSize);

+	public static <E> HashBag<E> hashBag(Iterable<? extends E> iterable, int iterableSize) {

+		return IteratorTools.hashBag(iterable.iterator(), iterableSize);

 	}

 

 	/**

@@ -388,7 +388,7 @@
 	public static <E> Iterable<E> sort(Iterable<? extends E> iterable, Comparator<? super E> comparator) {

 		Iterator<? extends E> iterator = iterable.iterator();

 		if (iterator.hasNext()) {

-			return ListTools.sort(ListTools.list(iterator), comparator);

+			return ListTools.sort(ListTools.arrayList(iterator), comparator);

 		}

 		return emptyIterable();

 	}

@@ -400,7 +400,7 @@
 	public static <E> Iterable<E> sort(Iterable<? extends E> iterable, Comparator<? super E> comparator, int iterableSize) {

 		Iterator<? extends E> iterator = iterable.iterator();

 		if (iterator.hasNext()) {

-			return ListTools.sort(ListTools.list(iterator, iterableSize), comparator);

+			return ListTools.sort(ListTools.arrayList(iterator, iterableSize), comparator);

 		}

 		return emptyIterable();

 	}

diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/QueueIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/QueueIterable.java
index 7831132..42e2c1f 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/QueueIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/QueueIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -10,8 +10,8 @@
 package org.eclipse.jpt.common.utility.internal.iterable;
 
 import java.util.Iterator;
-import org.eclipse.jpt.common.utility.collection.Queue;
 import org.eclipse.jpt.common.utility.internal.iterator.QueueIterator;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * A <code>QueueIterable</code> provides an {@link Iterable}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ReadOnlyCompositeListIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ReadOnlyCompositeListIterable.java
index eddb200..9459e1f 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ReadOnlyCompositeListIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/ReadOnlyCompositeListIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -68,6 +68,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/StackIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/StackIterable.java
index 32e7d61..8281166 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/StackIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/StackIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -10,8 +10,8 @@
 package org.eclipse.jpt.common.utility.internal.iterable;
 
 import java.util.Iterator;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.internal.iterator.StackIterator;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * A <code>StackIterable</code> provides an {@link Iterable}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationIterable.java
index ce29623..91ac5d9 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -52,6 +52,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationListIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationListIterable.java
index a704681..e1b3a73 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationListIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TransformationListIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -53,6 +53,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TreeIterable.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TreeIterable.java
index a9c62a7..d4d6e75 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TreeIterable.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterable/TreeIterable.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -58,6 +58,6 @@
 
 	@Override
 	public String toString() {
-		return ListTools.list(this).toString();
+		return ListTools.arrayList(this).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/CloneListIterator.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/CloneListIterator.java
index ce02223..80c6337 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/CloneListIterator.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/CloneListIterator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -68,7 +68,7 @@
 		}
 		// build a copy of the list and keep it in sync with original (if the mutator allows changes)
 		// that way the nested list iterator will maintain some of our state
-		this.listIterator = ListTools.list(array).listIterator();
+		this.listIterator = ListTools.arrayList(array).listIterator();
 		this.adapter = adapter;
 		this.cursor = 0;
 		this.state = State.UNKNOWN;
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/IteratorTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/IteratorTools.java
index 2dc251b..1bdd506 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/IteratorTools.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/IteratorTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2011, 2013 Oracle. All rights reserved.

+ * Copyright (c) 2011, 2015 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.

@@ -18,8 +18,6 @@
 import java.util.ListIterator;

 import org.eclipse.jpt.common.utility.closure.Closure;

 import org.eclipse.jpt.common.utility.closure.InterruptibleClosure;

-import org.eclipse.jpt.common.utility.collection.Queue;

-import org.eclipse.jpt.common.utility.collection.Stack;

 import org.eclipse.jpt.common.utility.exception.ExceptionHandler;

 import org.eclipse.jpt.common.utility.internal.ArrayTools;

 import org.eclipse.jpt.common.utility.internal.ObjectTools;

@@ -32,6 +30,8 @@
 import org.eclipse.jpt.common.utility.internal.iterator.CloneListIterator.Adapter;

 import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;

 import org.eclipse.jpt.common.utility.predicate.Predicate;

+import org.eclipse.jpt.common.utility.queue.Queue;

+import org.eclipse.jpt.common.utility.stack.Stack;

 import org.eclipse.jpt.common.utility.transformer.Transformer;

 

 /**

@@ -46,7 +46,7 @@
 	 * Return a bag corresponding to the specified iterator.

 	 */

 	public static <E> HashBag<E> bag(Iterator<? extends E> iterator) {

-		return CollectionTools.bag(iterator);

+		return CollectionTools.hashBag(iterator);

 	}

 

 	/**

@@ -54,22 +54,22 @@
 	 * The specified iterator size is a performance hint.

 	 */

 	public static <E> HashBag<E> bag(Iterator<? extends E> iterator, int iteratorSize) {

-		return CollectionTools.bag(iterator, iteratorSize);

+		return CollectionTools.hashBag(iterator, iteratorSize);

 	}

 

 	/**

-	 * Return a collection corresponding to the specified iterator.

+	 * Return a hash bag corresponding to the specified iterator.

 	 */

-	public static <E> HashBag<E> collection(Iterator<? extends E> iterator) {

-		return CollectionTools.collection(iterator);

+	public static <E> HashBag<E> hashBag(Iterator<? extends E> iterator) {

+		return CollectionTools.hashBag(iterator);

 	}

 

 	/**

-	 * Return a collection corresponding to the specified iterator.

+	 * Return a hash bag corresponding to the specified iterator.

 	 * The specified iterator size is a performance hint.

 	 */

-	public static <E> HashBag<E> collection(Iterator<? extends E> iterator, int iteratorSize) {

-		return CollectionTools.collection(iterator, iteratorSize);

+	public static <E> HashBag<E> hashBag(Iterator<? extends E> iterator, int iteratorSize) {

+		return CollectionTools.hashBag(iterator, iteratorSize);

 	}

 

 	/**

@@ -155,7 +155,7 @@
 	 * elements in the specified collection.

 	 */

 	public static boolean containsAll(Iterator<?> iterator, Collection<?> collection) {

-		return collection.isEmpty() || CollectionTools.set(iterator).containsAll(collection);

+		return collection.isEmpty() || CollectionTools.hashSet(iterator).containsAll(collection);

 	}

 

 	/**

@@ -164,7 +164,7 @@
 	 * The specified iterator size is a performance hint.

 	 */

 	public static boolean containsAll(Iterator<?> iterator, int iteratorSize, Collection<?> collection) {

-		return collection.isEmpty() || CollectionTools.set(iterator, iteratorSize).containsAll(collection);

+		return collection.isEmpty() || CollectionTools.hashSet(iterator, iteratorSize).containsAll(collection);

 	}

 

 	/**

@@ -189,7 +189,7 @@
 	 * elements in the specified iterator 2.

 	 */

 	public static boolean containsAll(Iterator<?> iterator1, Iterator<?> iterator2) {

-		return isEmpty(iterator2) || CollectionTools.containsAll(CollectionTools.set(iterator1), iterator2);

+		return isEmpty(iterator2) || CollectionTools.containsAll(CollectionTools.hashSet(iterator1), iterator2);

 	}

 

 	/**

@@ -198,7 +198,7 @@
 	 * The specified iterator 1 size is a performance hint.

 	 */

 	public static boolean containsAll(Iterator<?> iterator1, int iterator1Size, Iterator<?> iterator2) {

-		return isEmpty(iterator2) || CollectionTools.containsAll(CollectionTools.set(iterator1, iterator1Size), iterator2);

+		return isEmpty(iterator2) || CollectionTools.containsAll(CollectionTools.hashSet(iterator1, iterator1Size), iterator2);

 	}

 

 	/**

@@ -206,7 +206,7 @@
 	 * elements in the specified array.

 	 */

 	public static boolean containsAll(Iterator<?> iterator, Object... array) {

-		return (array.length == 0) || CollectionTools.containsAll(CollectionTools.set(iterator), array);

+		return (array.length == 0) || CollectionTools.containsAll(CollectionTools.hashSet(iterator), array);

 	}

 

 	/**

@@ -215,7 +215,7 @@
 	 * The specified iterator size is a performance hint.

 	 */

 	public static boolean containsAll(Iterator<?> iterator, int iteratorSize, Object... array) {

-		return (array.length == 0) || CollectionTools.containsAll(CollectionTools.set(iterator, iteratorSize), array);

+		return (array.length == 0) || CollectionTools.containsAll(CollectionTools.hashSet(iterator, iteratorSize), array);

 	}

 

 	/**

@@ -472,7 +472,7 @@
 	 * Return a list corresponding to the specified iterator.

 	 */

 	public static <E> ArrayList<E> list(Iterator<? extends E> iterator) {

-		return ListTools.list(iterator);

+		return ListTools.arrayList(iterator);

 	}

 

 	/**

@@ -480,7 +480,7 @@
 	 * The specified iterator size is a performance hint.

 	 */

 	public static <E> ArrayList<E> list(Iterator<? extends E> iterator, int iteratorSize) {

-		return ListTools.list(iterator, iteratorSize);

+		return ListTools.arrayList(iterator, iteratorSize);

 	}

 

 	/**

@@ -533,7 +533,7 @@
 		if (isEmpty(iterator)) {

 			return emptyListIterator();

 		}

-		return ListTools.sort(ListTools.list(iterator), comparator).listIterator();

+		return ListTools.sort(ListTools.arrayList(iterator), comparator).listIterator();

 	}

 

 	/**

@@ -544,7 +544,7 @@
 		if (isEmpty(iterator)) {

 			return emptyListIterator();

 		}

-		return ListTools.sort(ListTools.list(iterator, iteratorSize), comparator).listIterator();

+		return ListTools.sort(ListTools.arrayList(iterator, iteratorSize), comparator).listIterator();

 	}

 

 	/**

diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/QueueIterator.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/QueueIterator.java
index 2f6a5ad..12c5934 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/QueueIterator.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/QueueIterator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -10,9 +10,8 @@
 package org.eclipse.jpt.common.utility.internal.iterator;
 
 import java.util.Iterator;
-
-import org.eclipse.jpt.common.utility.collection.Queue;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * A <code>QueueIterator</code> provides an {@link Iterator}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/ReverseIterator.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/ReverseIterator.java
index 256b695..4ee3b96 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/ReverseIterator.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/ReverseIterator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -35,14 +35,14 @@
 	 * Construct a reverse iterator for the specified iterator.
 	 */
 	public ReverseIterator(Iterator<? extends E> iterator) {
-		this(ListTools.reverse(ListTools.list(iterator)));
+		this(ListTools.reverse(ListTools.arrayList(iterator)));
 	}
 
 	/**
 	 * Construct a reverse iterator for the specified iterator.
 	 */
 	public ReverseIterator(Iterator<? extends E> iterator, int size) {
-		this(ListTools.reverse(ListTools.list(iterator, size)));
+		this(ListTools.reverse(ListTools.arrayList(iterator, size)));
 	}
 
 	private ReverseIterator(ArrayList<E> reverseList) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/StackIterator.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/StackIterator.java
index e1108cf..cc9dad4 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/StackIterator.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/iterator/StackIterator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -10,9 +10,8 @@
 package org.eclipse.jpt.common.utility.internal.iterator;
 
 import java.util.Iterator;
-
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * A <code>StackIterator</code> provides an {@link Iterator}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/ChangeSupport.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/ChangeSupport.java
index 269b4e9..7b796ef 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/ChangeSupport.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/ChangeSupport.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -1233,7 +1233,7 @@
 	 * no empty checks
 	 */
 	protected boolean removeItemsFromCollection_(Iterator<?> items, Collection<?> collection, String collectionName) {
-		HashBag<?> removedItems = CollectionTools.collection(items);
+		HashBag<?> removedItems = CollectionTools.hashBag(items);
 		removedItems.retainAll(collection);
 		boolean changed = collection.removeAll(removedItems);
 
@@ -1305,8 +1305,8 @@
 	 * no empty checks
 	 */
 	protected boolean retainItemsInCollection_(Iterator<?> items, Collection<?> collection, String collectionName) {
-		HashBag<?> retainedItems = CollectionTools.collection(items);
-		HashBag<?> removedItems = CollectionTools.collection(collection);
+		HashBag<?> retainedItems = CollectionTools.hashBag(items);
+		HashBag<?> removedItems = CollectionTools.hashBag(collection);
 		removedItems.removeAll(retainedItems);
 		boolean changed = collection.retainAll(retainedItems);
 
@@ -1378,7 +1378,7 @@
 			return this.addItemsToCollection_(newCollection, collection, collectionName);
 		}
 
-		return this.synchronizeCollection_(CollectionTools.collection(newCollection), collection, collectionName);
+		return this.synchronizeCollection_(CollectionTools.hashBag(newCollection), collection, collectionName);
 	}
 
 	/**
@@ -2191,7 +2191,7 @@
 			return false;
 		}
 
-		ArrayList<E> addedItems = ListTools.list(items);
+		ArrayList<E> addedItems = ListTools.arrayList(items);
 		if (list.addAll(index, addedItems)) {
 			this.fireItemsAdded(listName, index, addedItems);
 			return true;
@@ -2264,7 +2264,7 @@
 	 * no empty check
 	 */
 	protected <E> boolean addItemsToList_(Iterator<? extends E> items, List<E> list, String listName) {
-		ArrayList<E> addedItems = ListTools.list(items);
+		ArrayList<E> addedItems = ListTools.arrayList(items);
 		int index = list.size();
 		if (list.addAll(addedItems)) {
 			this.fireItemsAdded(listName, index, addedItems);
@@ -2467,8 +2467,8 @@
 	 * no empty checks
 	 */
 	protected boolean retainItemsInList_(Iterator<?> items, List<?> list, String listName) {
-		HashBag<?> retainedItems = CollectionTools.collection(items);
-		HashBag<?> removedItems = CollectionTools.collection(list);
+		HashBag<?> retainedItems = CollectionTools.hashBag(items);
+		HashBag<?> removedItems = CollectionTools.hashBag(list);
 		removedItems.removeAll(retainedItems);
 		return this.removeItemsFromList(removedItems, list, listName);
 	}
@@ -2642,7 +2642,7 @@
 		if (list.isEmpty()) {
 			return this.addItemsToList_(newList, list, listName);
 		}
-		return this.synchronizeList_(ListTools.list(newList), list, listName);
+		return this.synchronizeList_(ListTools.arrayList(newList), list, listName);
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java
index 0f5ecad..db3dd3d 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTPropertyChangeListenerWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -11,7 +11,8 @@
 
 import java.awt.EventQueue;
 import org.eclipse.jpt.common.utility.internal.RunnableAdapter;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
 import org.eclipse.jpt.common.utility.model.event.PropertyChangeEvent;
 import org.eclipse.jpt.common.utility.model.listener.PropertyChangeListener;
 
@@ -32,7 +33,7 @@
 	implements PropertyChangeListener
 {
 	private final PropertyChangeListener listener;
-	private final SynchronizedQueue<PropertyChangeEvent> events = new SynchronizedQueue<PropertyChangeEvent>();
+	private final SynchronizedQueue<PropertyChangeEvent> events = QueueTools.synchronizedQueue();
 
 
 	public AWTPropertyChangeListenerWrapper(PropertyChangeListener listener) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java
index 600014f..3d78f7b 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/listener/awt/AWTStateChangeListenerWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -11,7 +11,8 @@
 
 import java.awt.EventQueue;
 import org.eclipse.jpt.common.utility.internal.RunnableAdapter;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
 import org.eclipse.jpt.common.utility.model.event.StateChangeEvent;
 import org.eclipse.jpt.common.utility.model.listener.StateChangeListener;
 
@@ -30,7 +31,7 @@
 	implements StateChangeListener
 {
 	private final StateChangeListener listener;
-	private final SynchronizedQueue<StateChangeEvent> events = new SynchronizedQueue<StateChangeEvent>();
+	private final SynchronizedQueue<StateChangeEvent> events = QueueTools.synchronizedQueue();
 
 
 	public AWTStateChangeListenerWrapper(StateChangeListener listener) {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractTreeNodeValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractTreeNodeValueModel.java
index 6300294..b431533 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractTreeNodeValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AbstractTreeNodeValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -114,7 +114,7 @@
 	
 	@SuppressWarnings("unchecked")
 	public TreeNodeValueModel<V>[] path() {
-		List<TreeNodeValueModel<V>> path = ListTools.reverse(ListTools.list(this.backPath()));
+		List<TreeNodeValueModel<V>> path = ListTools.reverse(ListTools.arrayList(this.backPath()));
 		return path.toArray(new TreeNodeValueModel[path.size()]);
 	}
 
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectCollectionValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectCollectionValueModelAdapter.java
index 4736f8f..74bb555 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectCollectionValueModelAdapter.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectCollectionValueModelAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -147,7 +147,7 @@
 	}
 
 	protected Collection<E> buildValueCollection() {
-		return CollectionTools.collection(this.iterator());
+		return CollectionTools.hashBag(this.iterator());
 	}
 
 	@Override
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectListValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectListValueModelAdapter.java
index 6b7ea12..227ba6b 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectListValueModelAdapter.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/AspectListValueModelAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -189,7 +189,7 @@
 	}
 
 	protected List<E> buildValueList() {
-		return ListTools.list(this.iterator());
+		return ListTools.arrayList(this.iterator());
 	}
 
 	@Override
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeCollectionValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeCollectionValueModel.java
index b720c88..54a5a00 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeCollectionValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeCollectionValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -344,7 +344,7 @@
 	protected void collectionChanged(CollectionChangeEvent event) {
 		this.removeAllComponentSources();
 		this.addAllComponentSources();
-		this.fireCollectionChanged(VALUES, CollectionTools.collection(this.iterator()));
+		this.fireCollectionChanged(VALUES, CollectionTools.hashBag(this.iterator()));
 	}
 
 
@@ -396,7 +396,7 @@
 		ArrayList<E2> componentCollection = this.collections.get(componentCVM);
 		this.removeComponentItems(componentCollection);
 		this.addComponentItems(componentCVM, componentCollection);
-		this.fireCollectionChanged(VALUES, CollectionTools.collection(this.iterator()));
+		this.fireCollectionChanged(VALUES, CollectionTools.hashBag(this.iterator()));
 	}
 
 	// minimize scope of suppressed warnings
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeListValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeListValueModel.java
index ac9e7d2..ff4406a 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeListValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/CompositeListValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -479,14 +479,14 @@
 
 	protected Iterable<? extends E1> buildSubListHolder(int fromIndex) {
 		int listModelSize = this.listModel.size();
-		return ListTools.list(this.listModel, listModelSize).subList(fromIndex, listModelSize);
+		return ListTools.arrayList(this.listModel, listModelSize).subList(fromIndex, listModelSize);
 	}
 
 	protected Iterable<? extends E1> buildSubListHolder(int fromIndex, int toIndex) {
 		int listModelSize = this.listModel.size();
 		return ((fromIndex == 0) && (toIndex == listModelSize)) ?
 				this.listModel :
-				ListTools.list(this.listModel, listModelSize).subList(fromIndex, toIndex);
+				ListTools.arrayList(this.listModel, listModelSize).subList(fromIndex, toIndex);
 	}
 
 	@Override
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ExtendedListValueModelWrapper.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ExtendedListValueModelWrapper.java
index 9d1fe07..4545b8b 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ExtendedListValueModelWrapper.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ExtendedListValueModelWrapper.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -206,7 +206,7 @@
 	}
 
 	private List<E> buildList() {
-		return ListTools.list(this.listIterator_());
+		return ListTools.arrayList(this.listIterator_());
 	}
 
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ItemAspectListValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ItemAspectListValueModelAdapter.java
index 0d922e3..a567b95 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ItemAspectListValueModelAdapter.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ItemAspectListValueModelAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2007, 2012 Oracle. All rights reserved.

+ * Copyright (c) 2007, 2015 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.

@@ -268,7 +268,7 @@
 	 * whether the item aspect change is significant.

 	 */

 	protected void itemAspectChanged(@SuppressWarnings("unused") EventObject event) {

-		this.fireListChanged(LIST_VALUES, ListTools.list(this.listModel, this.listModel.size()));

+		this.fireListChanged(LIST_VALUES, ListTools.arrayList(this.listModel, this.listModel.size()));

 	}

 

 }

diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCurator.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCurator.java
index 71b92ca..a95b278 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCurator.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/ListCurator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2007, 2013 Oracle. All rights reserved.

+ * Copyright (c) 2007, 2015 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.

@@ -180,7 +180,7 @@
 	// ********** behavior **********

 

 	void submitInventoryReport() {

-		List<E> newRecord = ListTools.list(this.iteratorForRecord());

+		List<E> newRecord = ListTools.arrayList(this.iteratorForRecord());

 		int recordIndex = 0;

 

 		// add items from the new record

diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
index d10e736..3842893 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleCollectionValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -137,9 +137,9 @@
 			return true;
 		}
 		if ((o instanceof Collection<?>) && (o instanceof CollectionValueModel<?>)) {
-			Collection<E> c1 = CollectionTools.collection(this.collection);
+			Collection<E> c1 = CollectionTools.hashBag(this.collection);
 			@SuppressWarnings("unchecked")
-			Collection<E> c2 = CollectionTools.collection(((Collection<E>) o).iterator());
+			Collection<E> c2 = CollectionTools.hashBag(((Collection<E>) o).iterator());
 			return c1.equals(c2);
 		}
 		return false;
@@ -147,7 +147,7 @@
 
 	@Override
 	public int hashCode() {
-		return CollectionTools.collection(this.collection).hashCode();
+		return CollectionTools.hashBag(this.collection).hashCode();
 	}
 
 
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
index f2056b9..da81f0c 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SimpleListValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -152,9 +152,9 @@
 			return true;
 		}
 		if ((o instanceof List<?>) && (o instanceof ListValueModel<?>)) {
-			List<E> l1 = ListTools.list(this.list);
+			List<E> l1 = ListTools.arrayList(this.list);
 			@SuppressWarnings("unchecked")
-			List<E> l2 = ListTools.list(((List<E>) o).iterator());
+			List<E> l2 = ListTools.arrayList(((List<E>) o).iterator());
 			return l1.equals(l2);
 		}
 		return false;
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SortedListValueModelAdapter.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SortedListValueModelAdapter.java
index 39bcd0c..455ef6a 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SortedListValueModelAdapter.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/SortedListValueModelAdapter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -105,7 +105,7 @@
 
 	@Override
 	protected Iterable<? extends E> buildSyncList() {
-		return CollectionTools.sortedSet(this.collectionHolder, this.comparator, this.collectionHolder.size());
+		return CollectionTools.treeSet(this.collectionHolder, this.comparator, this.collectionHolder.size());
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java
index 58f65bf..23dfebd 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/model/value/prefs/PreferencesCollectionValueModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -133,7 +133,7 @@
 	@Override
 	protected void fireAspectChanged(Object oldValue, Object newValue) {
     	@SuppressWarnings("unchecked") Iterator<PreferencePropertyValueModel<P>> iterator = (Iterator<PreferencePropertyValueModel<P>>) newValue;
-		this.fireCollectionChanged(VALUES, CollectionTools.collection(iterator));
+		this.fireCollectionChanged(VALUES, CollectionTools.hashBag(iterator));
 	}
 
     @Override
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/AbstractArrayQueue.java
similarity index 61%
copy from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java
copy to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/AbstractArrayQueue.java
index 5b7b87d..0f9d756 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/AbstractArrayQueue.java
@@ -7,31 +7,29 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
- * Resizable-array FIFO implementation of the {@link Queue} interface.
+ * Abstract array implementation of the {@link Queue} interface.
  * @param <E> the type of elements maintained by the queue
- * @see FixedSizeArrayQueue
- * @see QueueTools
  */
-public class ArrayQueue<E>
+public abstract class AbstractArrayQueue<E>
 	implements Queue<E>, Cloneable, Serializable
 {
-	private transient E[] elements;
+	protected transient E[] elements;
 
 	/** Index of next element to be "dequeued". */
-	private transient int head = 0;
+	protected transient int head = 0;
 
 	/** Index of next element to be "enqueued". */
-	private transient int tail = 0;
+	protected transient int tail = 0;
 
-	private int size = 0;
+	protected int size = 0;
 
 	private static final long serialVersionUID = 1L;
 
@@ -39,17 +37,10 @@
 	// ********** constructors **********
 
 	/**
-	 * Construct an empty queue.
-	 */
-	public ArrayQueue() {
-		this(10);
-	}
-
-	/**
 	 * Construct an empty queue with the specified initial capacity.
 	 */
 	@SuppressWarnings("unchecked")
-	public ArrayQueue(int initialCapacity) {
+	protected AbstractArrayQueue(int initialCapacity) {
 		super();
 		if (initialCapacity < 0) {
 			throw new IllegalArgumentException("Illegal capacity: " + initialCapacity); //$NON-NLS-1$
@@ -61,7 +52,6 @@
 	// ********** Queue implementation **********
 
 	public void enqueue(E element) {
-		this.ensureCapacity(this.size + 1);
 		this.elements[this.tail] = element;
 		if (++this.tail == this.elements.length) {
 			this.tail = 0;
@@ -69,52 +59,6 @@
 		this.size++;
 	}
 
-	/**
-	 * Increase the queue's capacity, if necessary, to ensure it has at least
-	 * the specified minimum capacity.
-	 */
-	public void ensureCapacity(int minCapacity) {
-		int oldCapacity = this.elements.length;
-		if (oldCapacity < minCapacity) {
-			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
-			if (newCapacity < minCapacity) {
-				newCapacity = minCapacity;
-			}
-			this.elements = this.copyElements(newCapacity);
-			this.head = 0;
-			this.tail = this.size;
-		}
-	}
-
-	/**
-	 * Decrease the queue's capacity, if necessary, to match its current size.
-	 */
-	public void trimToSize() {
-		if (this.elements.length > this.size) {
-			this.elements = this.copyElements(this.size);
-			this.head = 0;
-			this.tail = this.size;
-		}
-	}
-
-	private E[] copyElements(int newCapacity) {
-		@SuppressWarnings("unchecked")
-		E[] newElements = (E[]) new Object[newCapacity];
-		if (this.size != 0) {
-			Object oldElements[] = this.elements;
-			if ((this.head == 0) || (this.head < this.tail) || (this.tail == 0)) {
-				// elements are contiguous
-				System.arraycopy(oldElements, this.head, newElements, 0, this.size);
-			} else {
-				// elements wrap past end of array
-				int fragmentSize = oldElements.length - this.head;
-				System.arraycopy(oldElements, this.head, newElements, 0, fragmentSize);
-				System.arraycopy(oldElements, 0, newElements, fragmentSize, (this.size - fragmentSize));
-			}
-		}
-		return newElements;
-	}
-
 	public E dequeue() {
 		if (this.size == 0) {
 			throw new NoSuchElementException();
@@ -143,10 +87,10 @@
 	// ********** standard methods **********
 
 	@Override
-	public ArrayQueue<E> clone() {
+	public AbstractArrayQueue<E> clone() {
 		try {
 			@SuppressWarnings("unchecked")
-			ArrayQueue<E> clone = (ArrayQueue<E>) super.clone();
+			AbstractArrayQueue<E> clone = (AbstractArrayQueue<E>) super.clone();
 			@SuppressWarnings("cast")
 			E[] array = (E[]) this.elements.clone();
 			clone.elements = array;
@@ -161,29 +105,53 @@
 		return Arrays.toString(this.copyElements(this.size));
 	}
 
+	protected E[] copyElements(int newCapacity) {
+		@SuppressWarnings("unchecked")
+		E[] newElements = (E[]) new Object[newCapacity];
+		if (this.size != 0) {
+			int t = this.tail;
+			if (t == 0) {
+				t = this.elements.length;
+			}
+			if (this.head < t) {
+				// elements are contiguous
+				System.arraycopy(this.elements, this.head, newElements, 0, this.size);
+			} else {
+				// elements wrap past end of array
+				int fragmentSize = this.elements.length - this.head;
+				System.arraycopy(this.elements, this.head, newElements, 0, fragmentSize);
+				System.arraycopy(this.elements, 0, newElements, fragmentSize, (this.size - fragmentSize));
+			}
+		}
+		return newElements;
+	}
+
 
 	// ********** Serializable "implementation" **********
 
 	private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException {
 		// write size (and any hidden stuff)
 		stream.defaultWriteObject();
-		Object[] array = this.elements;
-		int elementsLength = array.length;
+		int elementsLength = this.elements.length;
 		stream.writeInt(elementsLength);
 		if (this.size == 0) {
 			return;
 		}
 		// save the elements in contiguous order
-		if (this.head < this.tail) { // elements are contiguous
-			for (int i = this.head; i < this.tail; i++) {
-				stream.writeObject(array[i]);
+		int t = this.tail;
+		if (t == 0) {
+			t = elementsLength;
+		}
+		if (this.head < t) { // elements are contiguous
+			for (int i = this.head; i < t; i++) {
+				stream.writeObject(this.elements[i]);
 			}
-		} else { // (this.head >= this.tail) - elements wrap past end of array
+		} else { // (this.head >= t) - elements wrap past end of array
 			for (int i = this.head; i < elementsLength; i++) {
-				stream.writeObject(array[i]);
+				stream.writeObject(this.elements[i]);
 			}
 			for (int i = 0; i < this.tail; i++) {
-				stream.writeObject(array[i]);
+				stream.writeObject(this.elements[i]);
 			}
 		}
 	}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ArrayQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ArrayQueue.java
new file mode 100644
index 0000000..5d0db4d
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ArrayQueue.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.queue;
+
+import org.eclipse.jpt.common.utility.queue.Queue;
+
+/**
+ * Resizable-array FIFO implementation of the {@link Queue} interface.
+ * @param <E> the type of elements maintained by the queue
+ * @see FixedCapacityArrayQueue
+ * @see QueueTools
+ */
+public class ArrayQueue<E>
+	extends AbstractArrayQueue<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty queue with the specified initial capacity.
+	 */
+	public ArrayQueue(int initialCapacity) {
+		super(initialCapacity);
+	}
+
+
+	// ********** Queue implementation **********
+
+	@Override
+	public void enqueue(E element) {
+		this.ensureCapacity(this.size + 1);
+		super.enqueue(element);
+	}
+
+	/**
+	 * Increase the queue's capacity, if necessary, to ensure it has at least
+	 * the specified minimum capacity.
+	 */
+	public void ensureCapacity(int minCapacity) {
+		if (this.elements.length < minCapacity) {
+			int newCapacity = ((this.elements.length * 3) >> 1) + 1;
+			if (newCapacity < minCapacity) {
+				newCapacity = minCapacity;
+			}
+			this.elements = this.copyElements(newCapacity);
+			this.head = 0;
+			this.tail = this.size;
+		}
+	}
+
+	/**
+	 * Decrease the queue's capacity, if necessary, to match its current size.
+	 */
+	public void trimToSize() {
+		if (this.elements.length > this.size) {
+			this.elements = this.copyElements(this.size);
+			this.head = 0;
+			this.tail = this.size;
+		}
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public ArrayQueue<E> clone() {
+		return (ArrayQueue<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/DequeQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/DequeQueue.java
new file mode 100644
index 0000000..041d4e4
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/DequeQueue.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.queue;
+
+import java.io.Serializable;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.queue.Queue;
+
+/**
+ * Adapt a {@link Deque} to the {@link Queue} interface.
+ * Elements are dequeued from the head of the deque and
+ * enqueued to the tail of the deque.
+ * @param <E> the type of elements maintained by the queue
+ * @see QueueTools
+ */
+public class DequeQueue<E>
+	implements Queue<E>, Serializable
+{
+	private Deque<E> deque;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a queue, adapting the specified deque.
+	 * Elements are dequeued from the head of the deque and
+	 * enqueued to the tail of the deque.
+	 */
+	public DequeQueue(Deque<E> deque) {
+		super();
+		this.deque = deque;
+	}
+
+
+	// ********** Queue implementation **********
+
+	public void enqueue(E element) {
+		this.deque.enqueueTail(element);
+	}
+
+	public E dequeue() {
+		return this.deque.dequeueHead();
+	}
+
+	public E peek() {
+		return this.deque.peekHead();
+	}
+
+	public boolean isEmpty() {
+		return this.deque.isEmpty();
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return this.deque.toString();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/EmptyQueue.java
similarity index 92%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/EmptyQueue.java
index 074e885..2d4c277 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/EmptyQueue.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * Empty implementation of the {@link Queue} interface.
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/FixedCapacityArrayQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/FixedCapacityArrayQueue.java
new file mode 100644
index 0000000..124bdc7
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/FixedCapacityArrayQueue.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.queue;
+
+import org.eclipse.jpt.common.utility.queue.Queue;
+
+/**
+ * Fixed-capacity array FIFO implementation of the {@link Queue} interface.
+ * This implementation will throw an exception if its capacity is exceeded.
+ * @param <E> the type of elements maintained by the queue
+ * @see ArrayQueue
+ * @see QueueTools
+ */
+public class FixedCapacityArrayQueue<E>
+	extends AbstractArrayQueue<E>
+{
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty queue with the specified capacity.
+	 */
+	public FixedCapacityArrayQueue(int capacity) {
+		super(capacity);
+	}
+
+
+	// ********** Queue implementation **********
+
+	/**
+	 * @exception IllegalStateException if the queue is full
+	 */
+	@Override
+	public void enqueue(E element) {
+		if (this.isFull()) {
+			throw new IllegalStateException("Queue is full."); //$NON-NLS-1$
+		}
+		super.enqueue(element);
+	}
+
+	/**
+	 * Return whether the queue is full,
+	 * as its capacity is fixed.
+	 */
+	public boolean isFull() {
+		return this.size == this.elements.length;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public FixedCapacityArrayQueue<E> clone() {
+		return (FixedCapacityArrayQueue<E>) super.clone();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/LinkedQueue.java
similarity index 95%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/LinkedQueue.java
index ee07946..83aeb35 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/LinkedQueue.java
@@ -7,13 +7,13 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * Linked FIFO implementation of the {@link Queue} interface.
@@ -221,6 +221,11 @@
 			return this;
 		}
 
+		@Override
+		public String toString() {
+			return ObjectTools.singletonToString(this);
+		}
+
 		private static final long serialVersionUID = 1L;
 		private Object readResolve() {
 			// replace this object with the singleton
@@ -269,5 +274,10 @@
 		NodeFactory<E> copy() {
 			return new CachingNodeFactory<E>(this.maxCacheSize);
 		}
+
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, this.cacheSize);
+		}
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ListQueue.java
similarity index 93%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ListQueue.java
index c119164..14fe489 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/ListQueue.java
@@ -7,12 +7,12 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
 import java.util.List;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * Adapt a {@link List} to the {@link Queue} interface.
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/PriorityQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/PriorityQueue.java
new file mode 100644
index 0000000..6dec365
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/PriorityQueue.java
@@ -0,0 +1,249 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.queue;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+
+/**
+ * Resizable priority implementation of the {@link Queue} interface.
+ * Elements will dequeue in the order determined by a comparator
+ * (i.e. {@link #dequeue} will return the element sorted first).
+ * @param <E> the type of elements maintained by the queue
+ * @see QueueTools
+ */
+public class PriorityQueue<E>
+	implements Queue<E>, Cloneable, Serializable
+{
+	private final Comparator<? super E> comparator;
+
+	/**
+	 * Standard heap implementation.
+	 * To simplify our math, we leave the first slot [0] empty.
+	 */
+	private transient E[] elements;
+
+	private int size = 0;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct an empty priority queue with the specified comparator
+	 * and initial capacity.
+	 */
+	@SuppressWarnings("unchecked")
+	public PriorityQueue(Comparator<? super E> comparator, int initialCapacity) {
+		super();
+		if (comparator == null) {
+			throw new NullPointerException();
+		}
+		this.comparator = comparator;
+		if (initialCapacity < 0) {
+			throw new IllegalArgumentException("Illegal capacity: " + initialCapacity); //$NON-NLS-1$
+		}
+		
+		this.elements = (E[]) new Object[initialCapacity + 1];
+	}
+
+	/**
+	 * Construct a priority queue with the specified comparator,
+	 * initial array of elements, and size. The array of elements
+	 * should hold elements at contiguous indices from
+	 * 1 to the the specified size, inclusive. The array should <em>not</em>
+	 * hold an element at index 0. The queue will <em>not</em> copy the
+	 * elements from the supplied array; i.e. the queue will directly use
+	 * and manipulate the supplied array.
+	 */
+	public PriorityQueue(Comparator<? super E> comparator, E[] initialElements, int size) {
+		super();
+		if (comparator == null) {
+			throw new NullPointerException();
+		}
+		this.comparator = comparator;
+
+		if (initialElements == null) {
+			throw new NullPointerException();
+		}
+		if (initialElements.length == 0) {
+			throw new IllegalArgumentException("Initial elements array must have a length of at least 1."); //$NON-NLS-1$
+		}
+		this.elements = initialElements;
+
+		if (size < 0) {
+			throw new IllegalArgumentException("Illegal size: " + size); //$NON-NLS-1$
+		}
+		this.size = size;
+
+		if (this.size > 1) {
+			// this is similar to what we do when an element is dequeued
+			int nonLeafMax = this.size >> 1;
+			for (int i = nonLeafMax; i > 0; i--) { // we need move only non-leaf nodes
+				int current = i;
+				do {
+					int child = current << 1; // left child
+					if ((child < this.size) && (this.comparator.compare(this.elements[child + 1], this.elements[child]) < 0)) {
+						// right child exists and is less than left (i.e. dequeues first)
+						child++;
+					}
+					if (this.comparator.compare(this.elements[current], this.elements[child]) < 0) {
+						break;
+					}
+					ArrayTools.swap(this.elements, current, child);
+					current = child;
+				} while (current <= nonLeafMax); // i.e. not a leaf (i.e. has at least one child)
+			}
+		}
+	}
+
+
+	// ********** Queue implementation **********
+
+	public void enqueue(E element) {
+		this.ensureCapacity(this.size + 1);
+		this.size++;
+		int current = this.size;
+		this.elements[current] = element;
+		int parent = current >> 1;
+		while ((parent != 0) && this.comparator.compare(this.elements[current], this.elements[parent]) < 0) {
+			ArrayTools.swap(this.elements, current, parent);
+			current = parent;
+			parent = current >> 1;
+		}
+	}
+
+	/**
+	 * Increase the queue's capacity, if necessary, to ensure it has at least
+	 * the specified minimum capacity.
+	 */
+	public void ensureCapacity(int minCapacity) {
+		int oldCapacity = this.elements.length - 1;
+		if (oldCapacity < minCapacity) {
+			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
+			if (newCapacity < minCapacity) {
+				newCapacity = minCapacity;
+			}
+			this.elements = this.copyElements(newCapacity);
+		}
+	}
+
+	/**
+	 * Decrease the queue's capacity, if necessary, to match its current size.
+	 */
+	public void trimToSize() {
+		if (this.elements.length > this.size + 1) {
+			this.elements = this.copyElements(this.size);
+		}
+	}
+
+	private E[] copyElements(int newCapacity) {
+		@SuppressWarnings("unchecked")
+		E[] newElements = (E[]) new Object[newCapacity + 1];
+		System.arraycopy(this.elements, 1, newElements, 1, this.size); // skip 0
+		return newElements;
+	}
+
+	public E dequeue() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		E element = this.elements[1];
+		if (this.size != 1) {
+			// replace root with last node and move it to its new position
+			ArrayTools.swap(this.elements, 1, this.size);
+			int newSize = this.size - 1;
+			int nonLeafMax = newSize >> 1;
+			int current = 1;
+			while (current <= nonLeafMax) { // i.e. not a leaf (i.e. has at least one child)
+				int child = current << 1; // left child
+				if ((child < newSize) && (this.comparator.compare(this.elements[child + 1], this.elements[child]) < 0)) {
+					// right child exists and is less than left (i.e. dequeues first)
+					child++;
+				}
+				if (this.comparator.compare(this.elements[current], this.elements[child]) < 0) {
+					break;
+				}
+				ArrayTools.swap(this.elements, current, child);
+				current = child;
+			}
+		}
+		this.elements[this.size] = null; // allow GC to work
+		this.size--;
+		return element;
+	}
+
+	public E peek() {
+		if (this.size == 0) {
+			throw new NoSuchElementException();
+		}
+		return this.elements[1];
+	}
+
+	public boolean isEmpty() {
+		return this.size == 0;
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public PriorityQueue<E> clone() {
+		try {
+			@SuppressWarnings("unchecked")
+			PriorityQueue<E> clone = (PriorityQueue<E>) super.clone();
+			@SuppressWarnings("cast")
+			E[] array = (E[]) this.elements.clone();
+			clone.elements = array;
+			return clone;
+		} catch (CloneNotSupportedException ex) {
+			throw new InternalError();
+		}
+	}
+
+	@Override
+	public String toString() {
+		return Arrays.toString(ArrayTools.subArray(this.elements, 1, this.size + 1));
+	}
+
+
+	// ********** Serializable "implementation" **********
+
+	private void writeObject(java.io.ObjectOutputStream stream) throws java.io.IOException {
+		// write comparator and size (and any hidden stuff)
+		stream.defaultWriteObject();
+		Object[] array = this.elements;
+		int elementsLength = array.length;
+		stream.writeInt(elementsLength);
+		if (this.size == 0) {
+			return;
+		}
+		for (int i = 1; i <= this.size; i++) { // skip 0
+			stream.writeObject(array[i]);
+		}
+	}
+
+	@SuppressWarnings("unchecked")
+	private void readObject(java.io.ObjectInputStream stream) throws java.io.IOException, ClassNotFoundException {
+		// read comparator and size (and any hidden stuff)
+		stream.defaultReadObject();
+		int elementsLength = stream.readInt();
+		Object[] array = new Object[elementsLength];
+		for (int i = 1; i <= this.size; i++) { // skip 0
+			array[i] = stream.readObject();
+		}
+		this.elements = (E[]) array;
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/QueueTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/QueueTools.java
new file mode 100644
index 0000000..88b7bb3
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/QueueTools.java
@@ -0,0 +1,534 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.queue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.internal.comparator.ComparatorTools;
+import org.eclipse.jpt.common.utility.internal.stack.ArrayStack;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * {@link Queue} utility methods.
+ */
+public final class QueueTools {
+
+	// ********** enqueue all **********
+
+	/**
+	 * Enqueue all the elements returned by the specified iterable
+	 * on the specified queue.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean enqueueAll(Queue<? super E> queue, Iterable<? extends E> iterable) {
+		return enqueueAll(queue, iterable.iterator());
+	}
+
+	/**
+	 * Enqueue all the elements returned by the specified iterator
+	 * on the specified queue.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean enqueueAll(Queue<? super E> queue, Iterator<? extends E> iterator) {
+		return iterator.hasNext() && enqueueAll_(queue, iterator);
+	}
+
+	/**
+	 * assume the iterator is not empty
+	 */
+	private static <E> boolean enqueueAll_(Queue<? super E> queue, Iterator<? extends E> iterator) {
+		do {
+			queue.enqueue(iterator.next());
+		} while (iterator.hasNext());
+		return true;
+	}
+
+	/**
+	 * Enqueue all the elements in the specified array
+	 * on the specified queue.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean enqueueAll(Queue<? super E> queue, E... array) {
+		int len = array.length;
+		return (len != 0) && enqueueAll_(queue, array, len);
+	}
+
+	/**
+	 * assume the array is not empty
+	 */
+	private static <E> boolean enqueueAll_(Queue<? super E> queue, E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			queue.enqueue(array[i++]);
+		} while (i < arrayLength);
+		return true;
+	}
+
+
+	// ********** drain **********
+
+	/**
+	 * Drain all the elements from the specified queue and return them in a
+	 * list.
+	 */
+	public static <E> ArrayList<E> drain(Queue<? extends E> queue) {
+		ArrayList<E> result = new ArrayList<E>();
+		drainTo(queue, result);
+		return result;
+	}
+
+	/**
+	 * Drain all the elements from the specified queue and add them to the
+	 * specified collection.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean drainTo(Queue<? extends E> queue, Collection<? super E> collection) {
+		return ( ! queue.isEmpty()) && drainTo_(queue, collection);
+	}
+
+	/**
+	 * assume the queue is not empty
+	 */
+	private static <E> boolean drainTo_(Queue<? extends E> queue, Collection<? super E> collection) {
+		do {
+			collection.add(queue.dequeue());
+		} while ( ! queue.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified queue
+	 * to the specified list at the specified index.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean drainTo(Queue<? extends E> queue, List<? super E> list, int index) {
+		return ( ! queue.isEmpty()) && drainTo_(queue, list, index);
+	}
+
+	/**
+	 * assume the queue is not empty
+	 */
+	private static <E> boolean drainTo_(Queue<? extends E> queue, List<? super E> list, int index) {
+		return (index == list.size()) ? drainTo_(queue, list) : list.addAll(index, drain(queue));
+	}
+
+	/**
+	 * Drain all the elements from the specified queue and push them on the
+	 * specified stack.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <E> boolean drainTo(Queue<? extends E> queue, Stack<? super E> stack) {
+		return ( ! queue.isEmpty()) && drainTo_(queue, stack);
+	}
+
+	/**
+	 * assume the queue is not empty
+	 */
+	private static <E> boolean drainTo_(Queue<? extends E> queue, Stack<? super E> stack) {
+		do {
+			stack.push(queue.dequeue());
+		} while ( ! queue.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the first specified queue and enqueue them
+	 * on the second specified queue.
+	 * Return whether the first queue changed as a result.
+	 */
+	public static <E> boolean drainTo(Queue<? extends E> queue1, Queue<? super E> queue2) {
+		return ( ! queue1.isEmpty()) && drainTo_(queue1, queue2);
+	}
+
+	/**
+	 * assume queue 1 is not empty
+	 */
+	private static <E> boolean drainTo_(Queue<? extends E> queue1, Queue<? super E> queue2) {
+		do {
+			queue2.enqueue(queue1.dequeue());
+		} while ( ! queue1.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified queue, passing each element to the
+	 * specified key transformer. Map the generated key to its element.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <K, V, E extends V> boolean drainTo(Queue<E> queue, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		return ( ! queue.isEmpty()) && drainTo_(queue, map, keyTransformer);
+	}
+
+	/**
+	 * assume the queue is not empty
+	 */
+	private static <K, V, E extends V> boolean drainTo_(Queue<E> queue, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		do {
+			MapTools.add(map, queue.dequeue(), keyTransformer);
+		} while ( ! queue.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Drain all the elements from the specified queue, passing each element to the
+	 * specified key and value transformers. Add the generated key/value pairs
+	 * to the specified map.
+	 * Return whether the queue changed as a result.
+	 */
+	public static <K, V, E> boolean drainTo(Queue<E> queue, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		return ( ! queue.isEmpty()) && drainTo_(queue, map, keyTransformer, valueTransformer);
+	}
+
+	/**
+	 * assume the queue is not empty
+	 */
+	private static <K, V, E> boolean drainTo_(Queue<E> queue, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		do {
+			MapTools.add(map, queue.dequeue(), keyTransformer, valueTransformer);
+		} while ( ! queue.isEmpty());
+		return true;
+	}
+
+
+	// ********** array queue factory methods **********
+
+	/**
+	 * Return an empty array-based FIFO queue.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue() {
+		return arrayQueue(10);
+	}
+
+	/**
+	 * Return an empty array-based FIFO queue with specified initial capacity.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(int initialCapacity) {
+		return new ArrayQueue<E>(initialCapacity);
+	}
+
+	/**
+	 * Return an array-based FIFO queue corresponding to the specified iterable.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(Iterable<? extends E> iterable) {
+		return arrayQueue(iterable.iterator());
+	}
+
+	/**
+	 * Return an array-based FIFO queue corresponding to the specified iterable.
+	 * The specified iterable size is a performance hint.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(Iterable<? extends E> iterable, int iterableSize) {
+		return arrayQueue(iterable.iterator(), iterableSize);
+	}
+
+	/**
+	 * Return an array-based FIFO queue corresponding to the specified iterator.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(Iterator<? extends E> iterator) {
+		ArrayQueue<E> result = QueueTools.arrayQueue();
+		enqueueAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return an array-based FIFO queue corresponding to the specified iterator.
+	 * The specified iterator size is a performance hint.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(Iterator<? extends E> iterator, int iteratorSize) {
+		ArrayQueue<E> result = QueueTools.arrayQueue(iteratorSize);
+		enqueueAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return an array-based FIFO queue corresponding to the specified array.
+	 */
+	public static <E> ArrayQueue<E> arrayQueue(E... array) {
+		ArrayQueue<E> result = QueueTools.arrayQueue(array.length);
+		enqueueAll(result, array);
+		return result;
+	}
+
+
+	// ********** linked queue factory methods **********
+
+	/**
+	 * Return an empty link-based FIFO queue with no node cache.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue() {
+		return linkedQueue(0);
+	}
+
+	/**
+	 * Return an empty link-based FIFO queue
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(int cacheSize) {
+		return new LinkedQueue<E>(cacheSize);
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified iterable.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(Iterable<? extends E> iterable) {
+		return linkedQueue(iterable, 0);
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified iterable
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(Iterable<? extends E> iterable, int cacheSize) {
+		return linkedQueue(iterable.iterator(), cacheSize);
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified iterator.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(Iterator<? extends E> iterator) {
+		return linkedQueue(iterator, 0);
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified iterator
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(Iterator<? extends E> iterator, int cacheSize) {
+		LinkedQueue<E> result = QueueTools.linkedQueue(cacheSize);
+		enqueueAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified array.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(E... array) {
+		return linkedQueue(array, 0);
+	}
+
+	/**
+	 * Return a link-based FIFO queue corresponding to the specified array
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedQueue<E> linkedQueue(E[] array, int cacheSize) {
+		LinkedQueue<E> result = QueueTools.linkedQueue(cacheSize);
+		enqueueAll(result, array);
+		return result;
+	}
+
+
+	// ********** fixed size queue factory methods **********
+
+	/**
+	 * Return a fixed-capacity array queue with the specified capacity.
+	 */
+	public static <E> FixedCapacityArrayQueue<E> fixedCapacityArrayQueue(int capacity) {
+		return new FixedCapacityArrayQueue<E>(capacity);
+	}
+
+	/**
+	 * Return a fized-capacity array 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 Queue#dequeue()}).
+	 * The queue's capacity will be match the collection's size.
+	 */
+	public static <E> FixedCapacityArrayQueue<E> fixedCapacityArrayQueue(Collection<? extends E> collection) {
+		FixedCapacityArrayQueue<E> result = QueueTools.fixedCapacityArrayQueue(collection.size());
+		enqueueAll(result, collection);
+		return result;
+	}
+
+
+	// ********** stack queue factory methods **********
+
+	/**
+	 * Return a LIFO queue.
+	 */
+	public static <E> StackQueue<E> stackQueue() {
+		return adapt(new ArrayStack<E>());
+	}
+
+	/**
+	 * Adapt the specified stack to the {@link Queue} interface,
+	 * implementing a LIFO queue.
+	 */
+	public static <E> StackQueue<E> adapt(Stack<E> stack) {
+		return new StackQueue<E>(stack);
+	}
+
+
+	// ********** priority queue factory methods **********
+
+	/**
+	 * Return a priority queue that returns its elements in
+	 * {@linkplain Comparable natural order}.
+	 */
+	public static <E extends Comparable<E>> PriorityQueue<E> priorityQueue() {
+		return priorityQueue(10);
+	}
+
+	/**
+	 * Return a priority queue that returns its elements in
+	 * {@linkplain Comparable natural order} and has the specified initial capacity.
+	 */
+	public static <E extends Comparable<E>> PriorityQueue<E> priorityQueue(int initialCapacity) {
+		return priorityQueue(ComparatorTools.<E>naturalComparator(), initialCapacity);
+	}
+
+	/**
+	 * Return a priority queue whose elements are returned in
+	 * the order determined by the specified comparator.
+	 */
+	public static <E> PriorityQueue<E> priorityQueue(Comparator<? super E> comparator) {
+		return priorityQueue(comparator, 10);
+	}
+
+	/**
+	 * Return a priority queue whose elements are returned in
+	 * the order determined by the specified comparator
+	 * and has the specified initial capacity.
+	 */
+	public static <E> PriorityQueue<E> priorityQueue(Comparator<? super E> comparator, int initialCapacity) {
+		return new PriorityQueue<E>(comparator, initialCapacity);
+	}
+
+	/**
+	 * Construct a priority queue with the specified initial full array of elements.
+	 * The priority queue will return its elements in {@linkplain Comparable natural order}.
+	 * The array of elements should hold elements at
+	 * every index except 0. The queue will <em>not</em> copy the
+	 * elements from the supplied array; i.e. the queue will directly use and manipulate
+	 * the supplied array.
+	 */
+	public static <E extends Comparable<E>> PriorityQueue<E> priorityQueue(E[] initialElements) {
+		return priorityQueue(initialElements, initialElements.length - 1);
+	}
+
+	/**
+	 * Construct a priority queue with the specified initial array of elements and size.
+	 * The priority queue will return its elements in {@linkplain Comparable natural order}.
+	 * The array of elements should hold elements at contiguous indices from
+	 * 1 to the the specified size, inclusive. The array should <em>not</em>
+	 * hold an element at index 0. The queue will <em>not</em> copy the
+	 * elements from the supplied array; i.e. the queue will directly use and manipulate
+	 * the supplied array.
+	 */
+	public static <E extends Comparable<E>> PriorityQueue<E> priorityQueue(E[] initialElements, int size) {
+		return priorityQueue(ComparatorTools.<E>naturalComparator(), initialElements, size);
+	}
+
+	/**
+	 * Construct a priority queue with the specified comparator and
+	 * initial full array of elements.
+	 * The array of elements should hold elements at
+	 * every index except 0. The queue will <em>not</em> copy the
+	 * elements from the supplied array; i.e. the queue will directly use and manipulate
+	 * the supplied array.
+	 */
+	public static <E> PriorityQueue<E> priorityQueue(Comparator<? super E> comparator, E[] initialElements) {
+		return priorityQueue(comparator, initialElements, initialElements.length - 1);
+	}
+
+	/**
+	 * Construct a priority queue with the specified comparator,
+	 * initial array of elements, and size. The array of elements
+	 * should hold elements at contiguous indices from
+	 * 1 to the the specified size, inclusive. The array should <em>not</em>
+	 * hold an element at index 0. The queue will <em>not</em> copy the
+	 * elements from the supplied array; i.e. the queue will directly use and manipulate
+	 * the supplied array.
+	 */
+	public static <E> PriorityQueue<E> priorityQueue(Comparator<? super E> comparator, E[] initialElements, int size) {
+		return new PriorityQueue<E>(comparator, initialElements, size);
+	}
+
+
+	// ********** synchronized queue factory methods **********
+
+	/**
+	 * Return a synchronized queue.
+	 */
+	public static <E> SynchronizedQueue<E> synchronizedQueue() {
+		ArrayQueue<E> queue = arrayQueue();
+		return synchronizedQueue(queue);
+	}
+
+	/**
+	 * Return a queue that synchronizes with specified mutex.
+	 */
+	public static <E> SynchronizedQueue<E> synchronizedQueue(Object mutex) {
+		ArrayQueue<E> queue = arrayQueue();
+		return synchronizedQueue(queue, mutex);
+	}
+
+	/**
+	 * Return a queue that synchronizes the specified queue.
+	 */
+	public static <E> SynchronizedQueue<E> synchronizedQueue(Queue<E> queue) {
+		return new SynchronizedQueue<E>(queue);
+	}
+
+	/**
+	 * Return a queue that synchronizes the specified queue
+	 * with specified mutex.
+	 */
+	public static <E> SynchronizedQueue<E> synchronizedQueue(Queue<E> queue, Object mutex) {
+		return new SynchronizedQueue<E>(queue, mutex);
+	}
+
+
+	// ********** misc queue factory methods **********
+
+	/**
+	 * Adapt the specified deque to the {@link Queue} interface.
+	 */
+	public static <E> DequeQueue<E> adapt(Deque<E> deque) {
+		return new DequeQueue<E>(deque);
+	}
+
+	/**
+	 * Adapt the specified list to the {@link Queue} interface.
+	 */
+	public static <E> ListQueue<E> adapt(List<E> list) {
+		return new ListQueue<E>(list);
+	}
+
+	/**
+	 * Return an unmodifiable empty queue.
+	 */
+	public static <E> Queue<E> emptyQueue() {
+		return EmptyQueue.instance();
+	}
+
+
+	// ********** constructor **********
+
+	/**
+	 * Suppress default constructor, ensuring non-instantiability.
+	 */
+	private QueueTools() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/StackQueue.java
similarity index 88%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/StackQueue.java
index 4239a82..1150338 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/StackQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/StackQueue.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Adapt a {@link Stack} to create a LIFO implementation of the {@link Queue}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedQueue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/SynchronizedQueue.java
similarity index 64%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedQueue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/SynchronizedQueue.java
index 769deb4..c5c1dee 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedQueue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/queue/SynchronizedQueue.java
@@ -7,16 +7,20 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.queue;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.command.Command;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
 
 /**
  * Thread-safe implementation of the {@link Queue} interface.
@@ -65,20 +69,6 @@
 		this.mutex = this;
 	}
 
-	/**
-	 * Construct an empty synchronized queue that locks on the specified mutex.
-	 */
-	public SynchronizedQueue(Object mutex) {
-		this(new LinkedQueue<E>(), mutex);
-	}
-
-	/**
-	 * Construct an empty synchronized queue that locks on itself.
-	 */
-	public SynchronizedQueue() {
-		this(new LinkedQueue<E>());
-	}
-
 
 	// ********** Queue implementation **********
 
@@ -306,122 +296,189 @@
 
 	/**
 	 * "Enqueue" all the elements returned by the specified iterable.
+	 * Return whether the queue changed as a result.
 	 */
-	public void enqueueAll(Iterable<? extends E> iterable) {
-		this.enqueueAll(iterable.iterator());
+	public boolean enqueueAll(Iterable<? extends E> iterable) {
+		return this.enqueueAll(iterable.iterator());
 	}
 
 	/**
 	 * "Enqueue" all the elements returned by the specified iterator.
+	 * Return whether the queue changed as a result.
 	 */
-	public void enqueueAll(Iterator<? extends E> iterator) {
+	public boolean enqueueAll(Iterator<? extends E> iterator) {
+		if ( ! iterator.hasNext()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.enqueueAll_(iterator);
+			return this.enqueueAll_(iterator);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the iterator is not empty.
 	 */
-	private void enqueueAll_(Iterator<? extends E> iterator) {
-		while (iterator.hasNext()) {
-			this.enqueue_(iterator.next());
-		}
+	private boolean enqueueAll_(Iterator<? extends E> iterator) {
+		do {
+			this.queue.enqueue(iterator.next());
+		} while (iterator.hasNext());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
 	 * "Enqueue" all the elements in the specified array.
+	 * Return whether the queue changed as a result.
 	 */
-	public void enqueueAll(E... array) {
+	public boolean enqueueAll(E... array) {
+		int len = array.length;
+		if (len == 0) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.enqueueAll_(array);
+			return this.enqueueAll_(array, len);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the array is not empty.
 	 */
-	private void enqueueAll_(E[] array) {
-		for (E element : array) {
-			this.enqueue_(element);
-		}
+	private boolean enqueueAll_(E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			this.queue.enqueue(array[i++]);
+		} while (i < arrayLength);
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
 	 * Pop all the elements from the specified stack and "enqueue" them.
+	 * Return whether the queue changed as a result.
 	 */
-	public void enqueueAll(Stack<? extends E> stack) {
+	public boolean enqueueAll(Stack<? extends E> stack) {
+		if (stack.isEmpty()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.enqueueAll_(stack);
+			return this.enqueueAll_(stack);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the stack is not empty.
 	 */
-	private void enqueueAll_(Stack<? extends E> stack) {
-		while ( ! stack.isEmpty()) {
-			this.enqueue_(stack.pop());
-		}
+	private boolean enqueueAll_(Stack<? extends E> stack) {
+		do {
+			this.queue.enqueue(stack.pop());
+		} while ( ! stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
-	 * "Dequeue" all the elements from the second specified queue and
+	 * "Dequeue" all the elements from the specified queue and
 	 * "enqueue" them.
+	 * Return whether the queue changed as a result.
 	 * @see #drainTo(Queue)
 	 */
-	public void enqueueAll(Queue<? extends E> q) {
+	public boolean enqueueAll(Queue<? extends E> q) {
+		if (q.isEmpty()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.enqueueAll_(q);
+			return this.enqueueAll_(q);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the queue is not empty.
 	 */
-	private void enqueueAll_(Queue<? extends E> q) {
-		while ( ! q.isEmpty()) {
-			this.enqueue_(q.dequeue());
-		}
+	private boolean enqueueAll_(Queue<? extends E> q) {
+		do {
+			this.queue.enqueue(q.dequeue());
+		} while ( ! q.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
 	 * "Drain" all the current items from the queue and return them in a list.
 	 */
-	public Iterable<E> drain() {
-		return this.drainTo(new ArrayList<E>());
+	public ArrayList<E> drain() {
+		ArrayList<E> result = new ArrayList<E>();
+		this.drainTo(result);
+		return result;
 	}
 
 	/**
 	 * "Drain" all the current items from the queue into specified collection.
-	 * Return the collection.
+	 * Return whether the queue changed as a result.
 	 */
-	public <C extends Collection<? super E>> C drainTo(C c) {
+	public boolean drainTo(Collection<? super E> collection) {
 		synchronized (this.mutex) {
-			return this.drainTo_(c);
+			return this.drainTo_(collection);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <C extends Collection<? super E>> C drainTo_(C c) {
-		boolean changed = false;
-		while ( ! this.queue.isEmpty()) {
-			c.add(this.queue.dequeue());
-			changed = true;
+	private boolean drainTo_(Collection<? super E> collection) {
+		if (this.queue.isEmpty()) {
+			return false;
 		}
-		if (changed) {
-			this.mutex.notifyAll();
+		return this.drainTo__(collection);
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the queue is not empty.
+	 */
+	private boolean drainTo__(Collection<? super E> collection) {
+		do {
+			collection.add(this.queue.dequeue());
+		} while ( ! this.queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the queue into specified list
+	 * at the specified index.
+	 * Return whether the queue changed as a result.
+	 */
+	public boolean drainTo(List<? super E> list, int index) {
+		synchronized (this.mutex) {
+			return this.drainTo_(list, index);
 		}
-		return c;
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private boolean drainTo_(List<? super E> list, int index) {
+		if (this.queue.isEmpty()) {
+			return false;
+		}
+		if (index == list.size()) {
+			return this.drainTo__(list);
+		}
+		ArrayList<E> temp = new ArrayList<E>();
+		this.drainTo__(temp);
+		list.addAll(index, temp);
+		return true;
 	}
 
 	/**
 	 * "Drain" all the current items from the queue into specified stack.
-	 * Return the stack.
+	 * Return whether the queue changed as a result.
 	 */
-	public <S extends Stack<? super E>> S drainTo(S stack) {
+	public boolean drainTo(Stack<? super E> stack) {
 		synchronized (this.mutex) {
 			return this.drainTo_(stack);
 		}
@@ -430,24 +487,23 @@
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <S extends Stack<? super E>> S drainTo_(S stack) {
-		boolean changed = false;
-		while ( ! this.queue.isEmpty()) {
+	private boolean drainTo_(Stack<? super E> stack) {
+		if (this.queue.isEmpty()) {
+			return false;
+		}
+		do {
 			stack.push(this.queue.dequeue());
-			changed = true;
-		}
-		if (changed) {
-			this.mutex.notifyAll();
-		}
-		return stack;
+		} while ( ! this.queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
 	 * "Drain" all the current items from the queue into specified queue.
-	 * Return the specified queue.
+	 * Return whether the queue changed as a result.
 	 * @see #enqueueAll(Queue)
 	 */
-	public <Q extends Queue<? super E>> Q drainTo(Q q) {
+	public boolean drainTo(Queue<? super E> q) {
 		synchronized (this.mutex) {
 			return this.drainTo_(q);
 		}
@@ -456,16 +512,68 @@
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <Q extends Queue<? super E>> Q drainTo_(Q q) {
-		boolean changed = false;
-		while ( ! this.queue.isEmpty()) {
+	private boolean drainTo_(Queue<? super E> q) {
+		if (this.queue.isEmpty()) {
+			return false;
+		}
+		do {
 			q.enqueue(this.queue.dequeue());
-			changed = true;
+		} while ( ! this.queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the queue
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each item.
+	 * Return whether the queue changed as a result.
+	 */
+	public <K> boolean drainTo(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		synchronized (this.mutex) {
+			return this.drainTo_(map, keyTransformer);
 		}
-		if (changed) {
-			this.mutex.notifyAll();
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K> boolean drainTo_(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		if (this.queue.isEmpty()) {
+			return false;
 		}
-		return q;
+		do {
+			MapTools.add(map, this.queue.dequeue(), keyTransformer);
+		} while ( ! this.queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Drain" all the current items from the queue
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each popped item and the specified value transformer
+	 * to generator the value for each dequeued item.
+	 * Return whether the queue changed as a result.
+	 */
+	public <K, V> boolean drainTo(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		synchronized (this.mutex) {
+			return this.drainTo_(map, keyTransformer, valueTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K, V> boolean drainTo_(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		if (this.queue.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.queue.dequeue(), keyTransformer, valueTransformer);
+		} while ( ! this.queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ArrayStack.java
similarity index 69%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ArrayStack.java
index 20fdf31..ed5fe75 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ArrayStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ArrayStack.java
@@ -7,17 +7,18 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.EmptyStackException;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Resizable-array LIFO implementation of the {@link Stack} interface.
  * @param <E> the type of elements maintained by the stack
- * @see FixedSizeArrayStack
+ * @see FixedCapacityArrayStack
  * @see StackTools
  */
 public class ArrayStack<E>
@@ -25,9 +26,6 @@
 {
 	private transient E[] elements;
 
-	/** The index of where the next "pushed" element will go. */
-	private transient int next = 0;
-
 	private int size = 0;
 
 	private static final long serialVersionUID = 1L;
@@ -59,11 +57,7 @@
 
 	public void push(E element) {
 		this.ensureCapacity(this.size + 1);
-		this.elements[this.next] = element;
-		if (++this.next == this.elements.length) {
-			this.next = 0;
-		}
-		this.size++;
+		this.elements[this.size++] = element;
 	}
 
 	/**
@@ -71,14 +65,12 @@
 	 * the specified minimum capacity.
 	 */
 	public void ensureCapacity(int minCapacity) {
-		int oldCapacity = this.elements.length;
-		if (oldCapacity < minCapacity) {
-			int newCapacity = ((oldCapacity * 3) >> 1) + 1;
+		if (this.elements.length < minCapacity) {
+			int newCapacity = ((this.elements.length * 3) >> 1) + 1;
 			if (newCapacity < minCapacity) {
 				newCapacity = minCapacity;
 			}
 			this.elements = this.copyElements(newCapacity);
-			this.next = this.size;
 		}
 	}
 
@@ -88,16 +80,14 @@
 	public void trimToSize() {
 		if (this.elements.length > this.size) {
 			this.elements = this.copyElements(this.size);
-			this.next = this.size;
 		}
 	}
 
 	private E[] copyElements(int newCapacity) {
 		@SuppressWarnings("unchecked")
 		E[] newElements = (E[]) new Object[newCapacity];
-		int len = this.size;
-		if (len != 0) {
-			System.arraycopy(this.elements, 0, newElements, 0, len);
+		if (this.size != 0) {
+			System.arraycopy(this.elements, 0, newElements, 0, this.size);
 		}
 		return newElements;
 	}
@@ -106,14 +96,9 @@
 		if (this.size == 0) {
 			throw new EmptyStackException();
 		}
-		int index = this.next;
-		if (index == 0) {
-			index = this.elements.length;
-		}
-		index--;
+		int index = this.size - 1;
 		E element = this.elements[index];
 		this.elements[index] = null; // allow GC to work
-		this.next = index;
 		this.size--;
 		return element;
 	}
@@ -122,12 +107,7 @@
 		if (this.size == 0) {
 			throw new EmptyStackException();
 		}
-		int index = this.next;
-		if (index == 0) {
-			index = this.elements.length;
-		}
-		index--;
-		return this.elements[index];
+		return this.elements[this.size - 1];
 	}
 
 	public boolean isEmpty() {
@@ -151,14 +131,9 @@
 		}
 	}
 
-	/**
-	 * Print the elements in the order in which they are "pushed" on to
-	 * the stack (as opposed to the order in which they will be "popped"
-	 * off of the stack).
-	 */
 	@Override
 	public String toString() {
-		return Arrays.toString(this.copyElements(this.size));
+		return Arrays.toString(ArrayTools.reverse(this.copyElements(this.size)));
 	}
 
 
@@ -170,21 +145,8 @@
 		Object[] array = this.elements;
 		int elementsLength = array.length;
 		stream.writeInt(elementsLength);
-		if (this.size == 0) {
-			return;
-		}
-		// save the elements in contiguous order
-		if (this.next >= this.size) { // elements are contiguous
-			for (int i = (this.next - this.size); i < this.next; i++) {
-				stream.writeObject(array[i]);
-			}
-		} else { // (this.next < this.size) - elements wrap past end of array
-			for (int i = (elementsLength - (this.size - this.next)); i < elementsLength; i++) {
-				stream.writeObject(array[i]);
-			}
-			for (int i = 0; i < this.next; i++) {
-				stream.writeObject(array[i]);
-			}
+		for (int i = 0; i < this.size; i++) {
+			stream.writeObject(array[i]);
 		}
 	}
 
@@ -198,6 +160,5 @@
 			array[i] = stream.readObject();
 		}
 		this.elements = (E[]) array;
-		this.next = this.size;
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/DequeStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/DequeStack.java
new file mode 100644
index 0000000..20aaab9
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/DequeStack.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.stack;
+
+import java.io.Serializable;
+import java.util.EmptyStackException;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.stack.Stack;
+
+/**
+ * Adapt a {@link Deque} to the {@link Stack} interface.
+ * Elements are pushed to and popped from the head of the deque.
+ * @param <E> the type of elements maintained by the stack
+ * @see StackTools
+ */
+public class DequeStack<E>
+	implements Stack<E>, Serializable
+{
+	private Deque<E> deque;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a stack, adapting the specified deque.
+	 * Elements are pushed to and popped from the head of the deque.
+	 */
+	public DequeStack(Deque<E> deque) {
+		super();
+		this.deque = deque;
+	}
+
+
+	// ********** Stack implementation **********
+
+	public void push(E element) {
+		this.deque.enqueueHead(element);
+	}
+
+	public E pop() {
+		try {
+			return this.deque.dequeueHead();
+		} catch (NoSuchElementException ex) {
+			throw new EmptyStackException();
+		}
+	}
+
+	public E peek() {
+		try {
+			return this.deque.peekHead();
+		} catch (NoSuchElementException ex) {
+			throw new EmptyStackException();
+		}
+	}
+
+	public boolean isEmpty() {
+		return this.deque.isEmpty();
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return this.deque.toString();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/EmptyStack.java
similarity index 92%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/EmptyStack.java
index e1ed4b3..cf18881 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/EmptyStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/EmptyStack.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.EmptyStackException;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Empty implementation of the {@link Stack} interface.
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/FixedCapacityArrayStack.java
similarity index 72%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/FixedCapacityArrayStack.java
index 3eec5f9..44b55ab 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/FixedSizeArrayStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/FixedCapacityArrayStack.java
@@ -7,22 +7,23 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.EmptyStackException;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
- * Fixed-size array LIFO implementation of the {@link Stack} interface.
+ * Fixed-capacity array LIFO implementation of the {@link Stack} interface.
  * This implementation will throw an exception if its capacity is exceeded.
  * @param <E> the type of elements maintained by the stack
  * @see ArrayStack
  * @see StackTools
  */
-public class FixedSizeArrayStack<E>
+public class FixedCapacityArrayStack<E>
 	implements Stack<E>, Cloneable, Serializable
 {
 	private E[] elements;
@@ -41,7 +42,7 @@
 	 * Construct an empty stack with the specified capacity.
 	 */
 	@SuppressWarnings("unchecked")
-	public FixedSizeArrayStack(int capacity) {
+	public FixedCapacityArrayStack(int capacity) {
 		super();
 		if (capacity < 0) {
 			throw new IllegalArgumentException("Illegal capacity: " + capacity); //$NON-NLS-1$
@@ -107,9 +108,9 @@
 	// ********** standard methods **********
 
 	@Override
-	public FixedSizeArrayStack<E> clone() {
+	public FixedCapacityArrayStack<E> clone() {
 		int len = this.elements.length;
-		FixedSizeArrayStack<E> clone = new FixedSizeArrayStack<E>(len);
+		FixedCapacityArrayStack<E> clone = new FixedCapacityArrayStack<E>(len);
 		System.arraycopy(this.elements, 0, clone.elements, 0, len);
 		clone.next = this.next;
 		clone.size = this.size;
@@ -123,26 +124,16 @@
 	 */
 	@Override
 	public String toString() {
-		return Arrays.toString(this.copyElements());
+		return Arrays.toString(ArrayTools.reverse(this.copyElements()));
 	}
 
 	private Object[] copyElements() {
-		if (this.size == 0) {
+		int len = this.size;
+		if (len == 0) {
 			return ObjectTools.EMPTY_OBJECT_ARRAY;
 		}
-		Object[] result = new Object[this.size];
-		if (this.next >= this.size) {
-			// elements are contiguous, but not to end of array
-			System.arraycopy(this.elements, (this.next - this.size), result, 0, this.size);
-		} else if (this.next == 0) {
-			// elements are contiguous to end of array
-			System.arraycopy(this.elements, (this.elements.length - this.size), result, 0, this.size);
-		} else {
-			// elements wrap past end of array
-			int fragmentSize = this.size - this.next;
-			System.arraycopy(this.elements, (this.elements.length - fragmentSize), result, 0, fragmentSize);
-			System.arraycopy(this.elements, 0, result, fragmentSize, (this.size - fragmentSize));
-		}
+		Object[] result = new Object[len];
+		System.arraycopy(this.elements, 0, result, 0, len);
 		return result;
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/LinkedStack.java
similarity index 95%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/LinkedStack.java
index 97456c6..87aba7e 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/LinkedStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/LinkedStack.java
@@ -7,13 +7,13 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.Arrays;
 import java.util.EmptyStackException;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Linked LIFO implementation of the {@link Stack} interface.
@@ -212,6 +212,11 @@
 			return this;
 		}
 
+		@Override
+		public String toString() {
+			return ObjectTools.singletonToString(this);
+		}
+
 		private static final long serialVersionUID = 1L;
 		private Object readResolve() {
 			// replace this object with the singleton
@@ -260,5 +265,10 @@
 		NodeFactory<E> copy() {
 			return new CachingNodeFactory<E>(this.maxCacheSize);
 		}
+
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, this.cacheSize);
+		}
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ListStack.java
similarity index 86%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ListStack.java
index b9a08fd..fd9c0c3 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/ListStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/ListStack.java
@@ -7,12 +7,13 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.EmptyStackException;
 import java.util.List;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import org.eclipse.jpt.common.utility.internal.collection.ListTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Adapt a {@link List} to the {@link Stack} interface.
@@ -54,7 +55,7 @@
 		if (size == 0) {
 			throw new EmptyStackException();
 		}
-		return this.list.remove(size - 1);
+		return this.list.remove(--size);
 	}
 
 	public E peek() {
@@ -62,7 +63,7 @@
 		if (size == 0) {
 			throw new EmptyStackException();
 		}
-		return this.list.get(size - 1);
+		return this.list.get(--size);
 	}
 
 	public boolean isEmpty() {
@@ -74,6 +75,6 @@
 
 	@Override
 	public String toString() {
-		return this.list.toString();
+		return ListTools.reverse(this.list).toString();
 	}
 }
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/StackTools.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/StackTools.java
new file mode 100644
index 0000000..40ddeb4
--- /dev/null
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/StackTools.java
@@ -0,0 +1,447 @@
+/*******************************************************************************
+ * Copyright (c) 2013, 2015 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.stack;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+
+/**
+ * {@link Stack} utility methods.
+ */
+public class StackTools {
+
+	// ********** push all **********
+
+	/**
+	 * Push all the elements returned by the specified iterable
+	 * on the specified stack.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean pushAll(Stack<? super E> stack, Iterable<? extends E> iterable) {
+		return pushAll(stack, iterable.iterator());
+	}
+
+	/**
+	 * Push all the elements returned by the specified iterator
+	 * on the specified stack.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean pushAll(Stack<? super E> stack, Iterator<? extends E> iterator) {
+		return iterator.hasNext() && pushAll_(stack, iterator);
+	}
+
+	/**
+	 * assume the iterator is not empty
+	 */
+	private static <E> boolean pushAll_(Stack<? super E> stack, Iterator<? extends E> iterator) {
+		do {
+			stack.push(iterator.next());
+		} while (iterator.hasNext());
+		return true;
+	}
+
+	/**
+	 * Push all the elements in the specified array
+	 * on the specified stack.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean pushAll(Stack<? super E> stack, E... array) {
+		int len = array.length;
+		return (len != 0) && pushAll_(stack, array, len);
+	}
+
+	/**
+	 * assume the array is not empty
+	 */
+	private static <E> boolean pushAll_(Stack<? super E> stack, E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			stack.push(array[i++]);
+		} while (i < arrayLength);
+		return true;
+	}
+
+
+	// ********** pop all **********
+
+	/**
+	 * Pop all the elements from the specified stack and return them in a
+	 * list.
+	 */
+	public static <E> ArrayList<E> popAll(Stack<? extends E> stack) {
+		ArrayList<E> result = new ArrayList<E>();
+		popAllTo(stack, result);
+		return result;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack and add them to the
+	 * specified collection.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean popAllTo(Stack<? extends E> stack, Collection<? super E> collection) {
+		return ( ! stack.isEmpty()) && popAllTo_(stack, collection);
+	}
+
+	/**
+	 * assume the stack is not empty
+	 */
+	private static <E> boolean popAllTo_(Stack<? extends E> stack, Collection<? super E> collection) {
+		do {
+			collection.add(stack.pop());
+		} while ( ! stack.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack
+	 * to the specified list at the specified index.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean popAllTo(Stack<? extends E> stack, List<? super E> list, int index) {
+		return ( ! stack.isEmpty()) && popAllTo_(stack, list, index);
+	}
+
+	/**
+	 * assume the stack is not empty
+	 */
+	private static <E> boolean popAllTo_(Stack<? extends E> stack, List<? super E> list, int index) {
+		return (index == list.size()) ? popAllTo_(stack, list) : list.addAll(index, popAll(stack));
+	}
+
+	/**
+	 * Pop all the elements from the specified stack and enqueue them on the
+	 * specified queue.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <E> boolean popAllTo(Stack<? extends E> stack, Queue<? super E> queue) {
+		return ( ! stack.isEmpty()) && popAllTo_(stack, queue);
+	}
+
+	/**
+	 * assume the stack is not empty
+	 */
+	private static <E> boolean popAllTo_(Stack<? extends E> stack, Queue<? super E> queue) {
+		do {
+			queue.enqueue(stack.pop());
+		} while ( ! stack.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the first specified stack and push them
+	 * on the second specified stack.
+	 * Return whether the first stack changed as a result.
+	 */
+	public static <E> boolean popAllTo(Stack<? extends E> stack1, Stack<? super E> stack2) {
+		return ( ! stack1.isEmpty()) && popAllTo_(stack1, stack2);
+	}
+
+	/**
+	 * assume stack 1 is not empty
+	 */
+	private static <E> boolean popAllTo_(Stack<? extends E> stack1, Stack<? super E> stack2) {
+		do {
+			stack2.push(stack1.pop());
+		} while ( ! stack1.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack, passing each element to the
+	 * specified key transformer. Map the generated key to its element.
+	 * Return whether the stack changed as a result.
+	 */
+//	public static <K, V, E extends V> boolean popAllTo(Stack<E> stack, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+	public static <K, V> boolean popAllTo(Stack<? extends V> stack, Map<K, V> map, Transformer<? super V, ? extends K> keyTransformer) {
+		return ( ! stack.isEmpty()) && popAllTo_(stack, map, keyTransformer);
+	}
+
+	/**
+	 * assume the stack is not empty
+	 */
+	private static <K, V, E extends V> boolean popAllTo_(Stack<E> stack, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer) {
+		do {
+			MapTools.add(map, stack.pop(), keyTransformer);
+		} while ( ! stack.isEmpty());
+		return true;
+	}
+
+	/**
+	 * Pop all the elements from the specified stack, passing each element to the
+	 * specified key and value transformers. Add the generated key/value pairs
+	 * to the specified map.
+	 * Return whether the stack changed as a result.
+	 */
+	public static <K, V, E> boolean popAllTo(Stack<E> stack, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		return ( ! stack.isEmpty()) && popAllTo_(stack, map, keyTransformer, valueTransformer);
+	}
+
+	/**
+	 * assume the stack is not empty
+	 */
+	private static <K, V, E> boolean popAllTo_(Stack<E> stack, Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		do {
+			MapTools.add(map, stack.pop(), keyTransformer, valueTransformer);
+		} while ( ! stack.isEmpty());
+		return true;
+	}
+
+
+	// ********** array stack factory methods **********
+
+	/**
+	 * Return an array-based LIFO stack corresponding.
+	 */
+	public static <E> ArrayStack<E> arrayStack() {
+		return arrayStack(10);
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding with the specified initial capacity.
+	 */
+	public static <E> ArrayStack<E> arrayStack(int initialCapacity) {
+		return new ArrayStack<E>(initialCapacity);
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding to the specified iterable.
+	 * The stack will pop its elements in reverse of the
+	 * order they are returned by the iterable's iterator (i.e. the
+	 * last element returned by the iterable's iterator will be the
+	 * first element returned by {@link Stack#pop()}; the first, last.).
+	 */
+	public static <E> ArrayStack<E> arrayStack(Iterable<? extends E> iterable) {
+		return arrayStack(iterable.iterator());
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding to the specified iterable.
+	 * The stack will pop its elements in reverse of the
+	 * order they are returned by the iterable's iterator (i.e. the
+	 * last element returned by the iterable's iterator will be the
+	 * first element returned by {@link Stack#pop()}; the first, last.).
+	 * The specified iterable size is a performance hint.
+	 */
+	public static <E> ArrayStack<E> arrayStack(Iterable<? extends E> iterable, int iterableSize) {
+		return arrayStack(iterable.iterator(), iterableSize);
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding to the specified iterator.
+	 * The stack will pop its elements in reverse of the
+	 * order they are returned by the iterator (i.e. the
+	 * last element returned by the iterator will be the
+	 * first element returned by {@link Stack#pop()}; the first, last.).
+	 */
+	public static <E> ArrayStack<E> arrayStack(Iterator<? extends E> iterator) {
+		ArrayStack<E> result = StackTools.arrayStack();
+		pushAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding to the specified iterator.
+	 * The stack will pop its elements in reverse of the
+	 * order they are returned by the iterator (i.e. the
+	 * last element returned by the iterator will be the
+	 * first element returned by {@link Stack#pop()}; the first, last.).
+	 * The specified iterator size is a performance hint.
+	 */
+	public static <E> ArrayStack<E> arrayStack(Iterator<? extends E> iterator, int iteratorSize) {
+		ArrayStack<E> result = StackTools.arrayStack(iteratorSize);
+		pushAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return an array-based LIFO stack corresponding to the specified array.
+	 */
+	public static <E> ArrayStack<E> arrayStack(E... array) {
+		ArrayStack<E> result = StackTools.arrayStack(array.length);
+		pushAll(result, array);
+		return result;
+	}
+
+
+	// ********** linked stack factory methods **********
+
+	/**
+	 * Return an empty link-based LIFO stack with no node cache.
+	 */
+	public static <E> LinkedStack<E> linkedStack() {
+		return linkedStack(0);
+	}
+
+	/**
+	 * Return an empty link-based LIFO stack
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedStack<E> linkedStack(int cacheSize) {
+		return new LinkedStack<E>(cacheSize);
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified iterable.
+	 */
+	public static <E> LinkedStack<E> linkedStack(Iterable<? extends E> iterable) {
+		return linkedStack(iterable.iterator());
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified iterable
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedStack<E> linkedStack(Iterable<? extends E> iterable, int cacheSize) {
+		return linkedStack(iterable.iterator(), cacheSize);
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified iterator.
+	 */
+	public static <E> LinkedStack<E> linkedStack(Iterator<? extends E> iterator) {
+		LinkedStack<E> result = StackTools.linkedStack();
+		pushAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified iterator
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedStack<E> linkedStack(Iterator<? extends E> iterator, int cacheSize) {
+		LinkedStack<E> result = StackTools.linkedStack(cacheSize);
+		pushAll(result, iterator);
+		return result;
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified array.
+	 */
+	public static <E> LinkedStack<E> linkedStack(E... array) {
+		LinkedStack<E> result = StackTools.linkedStack();
+		pushAll(result, array);
+		return result;
+	}
+
+	/**
+	 * Return a link-based LIFO stack corresponding to the specified array
+	 * with the specified node cache size.
+	 * Specify a cache size of -1 for an unlimited cache.
+	 */
+	public static <E> LinkedStack<E> linkedStack(E[] array, int cacheSize) {
+		LinkedStack<E> result = StackTools.linkedStack(cacheSize);
+		pushAll(result, array);
+		return result;
+	}
+
+
+	// ********** fixed capacity stack factory methods **********
+
+	/**
+	 * Return a fixed-capacity stack with the specified capacity.
+	 */
+	public static <E> FixedCapacityArrayStack<E> fixedCapacityArrayStack(int capacity) {
+		return new FixedCapacityArrayStack<E>(capacity);
+	}
+
+	/**
+	 * Return a fized-capacity stack containing the elements of the specified
+	 * collection. The stack will pop its elements in reverse of the
+	 * order they are returned by the collection's iterator (i.e. the
+	 * last element returned by the collection's iterator will be the
+	 * first element returned by {@link Stack#pop()}; the first, last.).
+	 */
+	public static <E> FixedCapacityArrayStack<E> fixedCapacityArrayStack(Collection<? extends E> collection) {
+		FixedCapacityArrayStack<E> result = StackTools.fixedCapacityArrayStack(collection.size());
+		pushAll(result, collection);
+		return result;
+	}
+
+
+	// ********** synchronized stack factory methods **********
+
+	/**
+	 * Return a synchronized stack.
+	 */
+	public static <E> SynchronizedStack<E> synchronizedStack() {
+		ArrayStack<E> stack = arrayStack();
+		return synchronizedStack(stack);
+	}
+
+	/**
+	 * Return a stack that synchronizes with specified mutex.
+	 */
+	public static <E> SynchronizedStack<E> synchronizedStack(Object mutex) {
+		LinkedStack<E> stack = linkedStack();
+		return synchronizedStack(stack, mutex);
+	}
+
+	/**
+	 * Return a stack that synchronizes the specified stack.
+	 */
+	public static <E> SynchronizedStack<E> synchronizedStack(Stack<E> stack) {
+		return new SynchronizedStack<E>(stack);
+	}
+
+	/**
+	 * Return a stack that synchronizes the specified stack
+	 * with specified mutex.
+	 */
+	public static <E> SynchronizedStack<E> synchronizedStack(Stack<E> stack, Object mutex) {
+		return new SynchronizedStack<E>(stack, mutex);
+	}
+
+
+	// ********** misc stack factory methods **********
+
+	/**
+	 * Adapt the specified list to the {@link Stack} interface.
+	 */
+	public static <E> ListStack<E> adapt(List<E> list) {
+		return new ListStack<E>(list);
+	}
+
+	/**
+	 * Adapt the specified deque to the {@link Stack} interface.
+	 */
+	public static <E> DequeStack<E> adapt(Deque<E> deque) {
+		return new DequeStack<E>(deque);
+	}
+
+	/**
+	 * Return an unmodifiable empty LIFO stack.
+	 */
+	public static <E> Stack<E> emptyStack() {
+		return EmptyStack.instance();
+	}
+
+
+	// ********** constructor **********
+
+	/**
+	 * Suppress default constructor, ensuring non-instantiability.
+	 */
+	private StackTools() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedStack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/SynchronizedStack.java
similarity index 61%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedStack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/SynchronizedStack.java
index 4f43815..b8baf0e 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/collection/SynchronizedStack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/internal/stack/SynchronizedStack.java
@@ -7,16 +7,20 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.internal.collection;
+package org.eclipse.jpt.common.utility.internal.stack;
 
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EmptyStackException;
 import java.util.Iterator;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
+import java.util.List;
+import java.util.Map;
 import org.eclipse.jpt.common.utility.command.Command;
+import org.eclipse.jpt.common.utility.internal.collection.MapTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
 
 /**
  * Thread-safe implementation of the {@link Stack} interface.
@@ -65,20 +69,6 @@
 		this.mutex = this;
 	}
 
-	/**
-	 * Construct an empty synchronized stack that locks on the specified mutex.
-	 */
-	public SynchronizedStack(Object mutex) {
-		this(new LinkedStack<E>(), mutex);
-	}
-
-	/**
-	 * Construct an empty synchronized stack that locks on itself.
-	 */
-	public SynchronizedStack() {
-		this(new LinkedStack<E>());
-	}
-
 
 	// ********** Stack implementation **********
 
@@ -302,152 +292,220 @@
 	}
 
 
-	// ********** additional public protocol **********
+	// ********** additional (synchronized) public protocol **********
 
 	/**
 	 * "Push" all the elements returned by the specified iterable.
+	 * Return whether the stack changed as a result.
 	 */
-	public void pushAll(Iterable<? extends E> iterable) {
-		this.pushAll(iterable.iterator());
+	public boolean pushAll(Iterable<? extends E> iterable) {
+		return this.pushAll(iterable.iterator());
 	}
 
 	/**
 	 * "Push" all the elements returned by the specified iterator.
+	 * Return whether the stack changed as a result.
 	 */
-	public void pushAll(Iterator<? extends E> iterator) {
+	public boolean pushAll(Iterator<? extends E> iterator) {
+		if ( ! iterator.hasNext()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.pushAll_(iterator);
+			return this.pushAll_(iterator);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the iterator is not empty.
 	 */
-	private void pushAll_(Iterator<? extends E> iterator) {
-		while (iterator.hasNext()) {
-			this.push_(iterator.next());
-		}
+	private boolean pushAll_(Iterator<? extends E> iterator) {
+		do {
+			this.stack.push(iterator.next());
+		} while (iterator.hasNext());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
 	 * "Push" all the elements in the specified array.
+	 * Return whether the stack changed as a result.
 	 */
-	public void pushAll(E... array) {
+	public boolean pushAll(E... array) {
+		int len = array.length;
+		if (len == 0) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.pushAll_(array);
+			return this.pushAll_(array, len);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the array is not empty.
 	 */
-	private void pushAll_(E[] array) {
-		for (E element : array) {
-			this.push_(element);
-		}
+	private boolean pushAll_(E[] array, int arrayLength) {
+		int i = 0;
+		do {
+			this.stack.push(array[i++]);
+		} while (i < arrayLength);
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
-	 * Pop all the elements from the specified stack and "push" them.
+	 * "Pop" all the elements from the specified stack and "push" them.
+	 * Return whether the stack changed as a result.
 	 */
-	public void pushAll(Stack<? extends E> s) {
+	public boolean pushAll(Stack<? extends E> s) {
+		if (s.isEmpty()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.pushAll_(s);
+			return this.pushAll_(s);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
+	 * Assume the stack is not empty.
 	 */
-	private void pushAll_(Stack<? extends E> s) {
-		while ( ! s.isEmpty()) {
-			this.push_(s.pop());
-		}
+	private boolean pushAll_(Stack<? extends E> s) {
+		do {
+			this.stack.push(s.pop());
+		} while ( ! s.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
-	 * "Dequeue" all the elements from the second specified queue and
+	 * "Dequeue" all the elements from the specified queue and
 	 * "push" them.
+	 * Return whether the stack changed as a result.
 	 * @see #popAllTo(Queue)
 	 */
-	public void pushAll(Queue<? extends E> queue) {
+	public boolean pushAll(Queue<? extends E> queue) {
+		if (queue.isEmpty()) {
+			return false;
+		}
 		synchronized (this.mutex) {
-			this.pushAll_(queue);
+			return this.pushAll_(queue);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 * Assume the queue is not empty.
+	 */
+	private boolean pushAll_(Queue<? extends E> queue) {
+		do {
+			this.stack.push(queue.dequeue());
+		} while ( ! queue.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Pop" all the current items from the stack and return them in a list.
+	 */
+	public ArrayList<E> popAll() {
+		ArrayList<E> result = new ArrayList<E>();
+		this.popAllTo(result);
+		return result;
+	}
+
+	/**
+	 * "Pop" all the current items from the stack into specified collection.
+	 * Return whether the stack changed as a result.
+	 */
+	public boolean popAllTo(Collection<? super E> collection) {
+		synchronized (this.mutex) {
+			return this.popAllTo_(collection);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private void pushAll_(Queue<? extends E> queue) {
-		while ( ! queue.isEmpty()) {
-			this.push_(queue.dequeue());
+	private boolean popAllTo_(Collection<? super E> collection) {
+		if (this.stack.isEmpty()) {
+			return false;
 		}
+		return this.popAllTo__(collection);
 	}
 
 	/**
-	 * Pop all the current items from the stack and return them in a list.
+	 * Pre-condition: synchronized
+	 * Assume the stack is not empty.
 	 */
-	public Iterable<E> popAll() {
-		return this.popAllTo(new ArrayList<E>());
+	private boolean popAllTo__(Collection<? super E> collection) {
+		do {
+			collection.add(this.stack.pop());
+		} while ( ! this.stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
-	 * Pop all the current items from the stack into specified collection.
-	 * Return the collection.
+	 * "Pop" all the current items from the stack into specified list
+	 * at the specified index.
+	 * Return whether the stack changed as a result.
 	 */
-	public <C extends Collection<? super E>> C popAllTo(C c) {
+	public boolean popAllTo(List<? super E> list, int index) {
 		synchronized (this.mutex) {
-			return this.popAllTo_(c);
+			return this.popAllTo_(list, index);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <C extends Collection<? super E>> C popAllTo_(C c) {
-		boolean changed = false;
-		while ( ! this.stack.isEmpty()) {
-			c.add(this.stack.pop());
-			changed = true;
+	private boolean popAllTo_(List<? super E> list, int index) {
+		if (this.stack.isEmpty()) {
+			return false;
 		}
-		if (changed) {
-			this.mutex.notifyAll();
+		if (index == list.size()) {
+			return this.popAllTo__(list);
 		}
-		return c;
+		ArrayList<E> temp = new ArrayList<E>();
+		this.popAllTo__(temp);
+		list.addAll(index, temp);
+		return true;
 	}
 
 	/**
-	 * Pop all the current items from the stack into specified stack.
-	 * Return the stack.
+	 * "Pop" all the current items from the stack
+	 * and "push" them onto the specified stack.
+	 * Return whether the stack changed as a result.
 	 */
-	public <S extends Stack<? super E>> S popAllTo(S s) {
+	public boolean popAllTo(Stack<? super E> stack2) {
 		synchronized (this.mutex) {
-			return this.popAllTo_(s);
+			return this.popAllTo_(stack2);
 		}
 	}
 
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <S extends Stack<? super E>> S popAllTo_(S s) {
-		boolean changed = false;
-		while ( ! this.stack.isEmpty()) {
-			s.push(this.stack.pop());
-			changed = true;
+	public boolean popAllTo_(Stack<? super E> stack2) {
+		if (this.stack.isEmpty()) {
+			return false;
 		}
-		if (changed) {
-			this.mutex.notifyAll();
-		}
-		return s;
+		do {
+			stack2.push(this.stack.pop());
+		} while ( ! this.stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
-	 * Pop all the current items from the stack into specified queue.
-	 * Return the specified queue.
+	 * "Pop" all the current items from the stack
+	 * and "enqueue" them on the specified queue.
+	 * Return whether the stack changed as a result.
 	 * @see #pushAll(Queue)
 	 */
-	public <Q extends Queue<? super E>> Q popAllTo(Q queue) {
+	public boolean popAllTo(Queue<? super E> queue) {
 		synchronized (this.mutex) {
 			return this.popAllTo_(queue);
 		}
@@ -456,16 +514,68 @@
 	/**
 	 * Pre-condition: synchronized
 	 */
-	private <Q extends Queue<? super E>> Q popAllTo_(Q queue) {
-		boolean changed = false;
-		while ( ! this.stack.isEmpty()) {
+	public boolean popAllTo_(Queue<? super E> queue) {
+		if (this.stack.isEmpty()) {
+			return false;
+		}
+		do {
 			queue.enqueue(this.stack.pop());
-			changed = true;
+		} while ( ! this.stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Pop" all the current items from the stack
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each item.
+	 * Return whether the stack changed as a result.
+	 */
+	public <K> boolean popAllTo(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		synchronized (this.mutex) {
+			return this.popAllTo_(map, keyTransformer);
 		}
-		if (changed) {
-			this.mutex.notifyAll();
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K> boolean popAllTo_(Map<K, ? super E> map, Transformer<? super E, ? extends K> keyTransformer) {
+		if (this.stack.isEmpty()) {
+			return false;
 		}
-		return queue;
+		do {
+			MapTools.add(map, this.stack.pop(), keyTransformer);
+		} while ( ! this.stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
+	}
+
+	/**
+	 * "Pop" all the current items from the stack
+	 * and add them on the specified map, using the specified key transformer
+	 * to generate the key for each popped item and the specified value transformer
+	 * to generator the value for each popped item.
+	 * Return whether the stack changed as a result.
+	 */
+	public <K, V> boolean popAllTo(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		synchronized (this.mutex) {
+			return this.popAllTo_(map, keyTransformer, valueTransformer);
+		}
+	}
+
+	/**
+	 * Pre-condition: synchronized
+	 */
+	private <K, V> boolean popAllTo_(Map<K, V> map, Transformer<? super E, ? extends K> keyTransformer, Transformer<? super E, ? extends V> valueTransformer) {
+		if (this.stack.isEmpty()) {
+			return false;
+		}
+		do {
+			MapTools.add(map, this.stack.pop(), keyTransformer, valueTransformer);
+		} while ( ! this.stack.isEmpty());
+		this.mutex.notifyAll();
+		return true;
 	}
 
 	/**
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Queue.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/queue/Queue.java
similarity index 77%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Queue.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/queue/Queue.java
index 5329925..2b04a58 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Queue.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/queue/Queue.java
@@ -7,7 +7,10 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.collection;
+package org.eclipse.jpt.common.utility.queue;
+
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 /**
  * Interface defining the classic queue behavior,
@@ -20,9 +23,10 @@
  * will almost certainly be broken (repeatedly) as the API evolves.
  * 
  * @param <E> the type of elements contained by the queue
- * @see org.eclipse.jpt.common.utility.internal.collection.ArrayQueue
- * @see org.eclipse.jpt.common.utility.internal.collection.LinkedQueue
- * @see org.eclipse.jpt.common.utility.internal.collection.QueueTools
+ * @see org.eclipse.jpt.common.utility.internal.queue.ArrayQueue
+ * @see org.eclipse.jpt.common.utility.internal.queue.LinkedQueue
+ * @see org.eclipse.jpt.common.utility.internal.queue.QueueTools
+ * @see Deque Deque - for an interface without the semantic baggage of {@link java.util.Deque}
  * @see Stack Stack - for an interface without the semantic baggage of {@link java.util.Stack}
  */
 public interface Queue<E> {
diff --git a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Stack.java b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/stack/Stack.java
similarity index 83%
rename from common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Stack.java
rename to common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/stack/Stack.java
index 11efaf5..df382cc 100644
--- a/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/collection/Stack.java
+++ b/common/plugins/org.eclipse.jpt.common.utility/src/org/eclipse/jpt/common/utility/stack/Stack.java
@@ -7,7 +7,9 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.collection;
+package org.eclipse.jpt.common.utility.stack;
+
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 /**
  * Interface defining the classic stack behavior,
@@ -20,9 +22,9 @@
  * will almost certainly be broken (repeatedly) as the API evolves.
  * 
  * @param <E> the type of elements contained by the stack
- * @see org.eclipse.jpt.common.utility.internal.collection.ArrayStack
- * @see org.eclipse.jpt.common.utility.internal.collection.LinkedStack
- * @see org.eclipse.jpt.common.utility.internal.collection.StackTools
+ * @see org.eclipse.jpt.common.utility.internal.stack.ArrayStack
+ * @see org.eclipse.jpt.common.utility.internal.stack.LinkedStack
+ * @see org.eclipse.jpt.common.utility.internal.stack.StackTools
  * @see Queue Queue - for an interface without the semantic baggage of {@link java.util.Queue}
  */
 public interface Stack<E> {
diff --git a/common/tests/org.eclipse.jpt.common.core.tests/src/org/eclipse/jpt/common/core/tests/internal/utility/jdt/ASTToolsTests.java b/common/tests/org.eclipse.jpt.common.core.tests/src/org/eclipse/jpt/common/core/tests/internal/utility/jdt/ASTToolsTests.java
index df1c3a1..69ac508 100644
--- a/common/tests/org.eclipse.jpt.common.core.tests/src/org/eclipse/jpt/common/core/tests/internal/utility/jdt/ASTToolsTests.java
+++ b/common/tests/org.eclipse.jpt.common.core.tests/src/org/eclipse/jpt/common/core/tests/internal/utility/jdt/ASTToolsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2015 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.
@@ -134,8 +134,8 @@
 		Iterable<String> actual = ASTTools.resolveFullyQualifiedNames(daea.getExpression(field.getModifiedDeclaration(this.buildASTRoot(cu))));
 		
 		assertEquals(
-				ListTools.list(new String[] {fqOtherClassName, fqOtherClassName2}),
-				ListTools.list(actual));
+				ListTools.arrayList(new String[] {fqOtherClassName, fqOtherClassName2}),
+				ListTools.arrayList(actual));
 	}
 	
 	public void testResolveFullyQualifiedNames2() throws Exception {
@@ -162,8 +162,8 @@
 		Iterable<String> actual = ASTTools.resolveFullyQualifiedNames(daea.getExpression(field.getModifiedDeclaration(this.buildASTRoot(cu))));
 		
 		assertEquals(
-				ListTools.list(new String[] {null, fqOtherClassName}),
-				ListTools.list(actual));
+				ListTools.arrayList(new String[] {null, fqOtherClassName}),
+				ListTools.arrayList(actual));
 	}
 	
 	public void testResolveFullyQualifiedNames3() throws Exception {
@@ -190,7 +190,7 @@
 		Iterable<String> actual = ASTTools.resolveFullyQualifiedNames(daea.getExpression(field.getModifiedDeclaration(this.buildASTRoot(cu))));
 		
 		assertEquals(
-				ListTools.list(new String[] {null, fqOtherClassName}),
-				ListTools.list(actual));
+				ListTools.arrayList(new String[] {null, fqOtherClassName}),
+				ListTools.arrayList(actual));
 	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.ui.tests/src/org/eclipse/jpt/common/ui/tests/internal/jface/TreeContentProviderUiTest.java b/common/tests/org.eclipse.jpt.common.ui.tests/src/org/eclipse/jpt/common/ui/tests/internal/jface/TreeContentProviderUiTest.java
index 6e95ea0..5c349e0 100644
--- a/common/tests/org.eclipse.jpt.common.ui.tests/src/org/eclipse/jpt/common/ui/tests/internal/jface/TreeContentProviderUiTest.java
+++ b/common/tests/org.eclipse.jpt.common.ui.tests/src/org/eclipse/jpt/common/ui/tests/internal/jface/TreeContentProviderUiTest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -376,7 +376,7 @@
 		public CollectionValueModel<TreeNode> transform(TreeNode value) {
 			return (value instanceof Nest) ?
 						this.transform((Nest) value) :
-						new StaticCollectionValueModel<TreeNode>(CollectionTools.collection(value));
+						new StaticCollectionValueModel<TreeNode>(CollectionTools.hashBag(value));
 		}
 
 		private CollectionValueModel<TreeNode> transform(Nest nest) {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/JptCommonUtilityTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/JptCommonUtilityTests.java
index 34edf48..28e0f2a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/JptCommonUtilityTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/JptCommonUtilityTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -9,11 +9,10 @@
  ******************************************************************************/
 package org.eclipse.jpt.common.utility.tests.internal;
 
-import junit.framework.Test;
-import junit.framework.TestSuite;
 import org.eclipse.jpt.common.utility.tests.internal.collection.JptCommonUtilityCollectionTests;
 import org.eclipse.jpt.common.utility.tests.internal.command.JptCommonUtilityCommandTests;
 import org.eclipse.jpt.common.utility.tests.internal.comparator.JptCommonUtilityComparatorTests;
+import org.eclipse.jpt.common.utility.tests.internal.deque.JptCommonUtilityDequeTests;
 import org.eclipse.jpt.common.utility.tests.internal.enumeration.JptCommonUtilityEnumerationTests;
 import org.eclipse.jpt.common.utility.tests.internal.exception.JptCommonUtilityExceptionTests;
 import org.eclipse.jpt.common.utility.tests.internal.factory.JptCommonUtilityFactoryTests;
@@ -24,8 +23,12 @@
 import org.eclipse.jpt.common.utility.tests.internal.model.JptCommonUtilityModelTests;
 import org.eclipse.jpt.common.utility.tests.internal.node.JptCommonUtilityNodeTests;
 import org.eclipse.jpt.common.utility.tests.internal.predicate.JptCommonUtilityPredicateTests;
+import org.eclipse.jpt.common.utility.tests.internal.queue.JptCommonUtilityQueueTests;
 import org.eclipse.jpt.common.utility.tests.internal.reference.JptCommonUtilityReferenceTests;
+import org.eclipse.jpt.common.utility.tests.internal.stack.JptCommonUtilityStackTests;
 import org.eclipse.jpt.common.utility.tests.internal.transformer.JptCommonUtilityTransformerTests;
+import junit.framework.Test;
+import junit.framework.TestSuite;
 
 /**
  * decentralize test creation code
@@ -38,6 +41,7 @@
 		suite.addTest(JptCommonUtilityCollectionTests.suite());
 		suite.addTest(JptCommonUtilityCommandTests.suite());
 		suite.addTest(JptCommonUtilityComparatorTests.suite());
+		suite.addTest(JptCommonUtilityDequeTests.suite());
 		suite.addTest(JptCommonUtilityEnumerationTests.suite());
 		suite.addTest(JptCommonUtilityExceptionTests.suite());
 		suite.addTest(JptCommonUtilityFactoryTests.suite());
@@ -48,7 +52,9 @@
 		suite.addTest(JptCommonUtilityModelTests.suite());
 		suite.addTest(JptCommonUtilityNodeTests.suite());
 		suite.addTest(JptCommonUtilityPredicateTests.suite());
+		suite.addTest(JptCommonUtilityQueueTests.suite());
 		suite.addTest(JptCommonUtilityReferenceTests.suite());
+		suite.addTest(JptCommonUtilityStackTests.suite());
 		suite.addTest(JptCommonUtilityTransformerTests.suite());
 
 		suite.addTestSuite(ArrayToolsTests.class);
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/AbstractRepeatingElementListTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/AbstractRepeatingElementListTests.java
index 6c8c23d..4170eb8 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/AbstractRepeatingElementListTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/AbstractRepeatingElementListTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -70,7 +70,7 @@
 
 		boolean exCaught = false;
 		try {
-			list.addAll(CollectionTools.collection("foo", "bar"));
+			list.addAll(CollectionTools.hashBag("foo", "bar"));
 			fail("bogus list: " + list);
 		} catch (UnsupportedOperationException ex) {
 			exCaught = true;
@@ -84,7 +84,7 @@
 
 		boolean exCaught = false;
 		try {
-			list.addAll(1, CollectionTools.collection("foo", "bar"));
+			list.addAll(1, CollectionTools.hashBag("foo", "bar"));
 			fail("bogus list: " + list);
 		} catch (UnsupportedOperationException ex) {
 			exCaught = true;
@@ -168,6 +168,9 @@
 		List<String> list = this.buildList(3);
 		assertEquals(0, list.indexOf(this.getElement()));
 		assertEquals(-1, list.indexOf(new Object()));
+
+		list = this.buildList(0);
+		assertEquals(-1, list.indexOf(this.getElement()));
 	}
 
 	public void testIsEmpty() {
@@ -207,6 +210,10 @@
 		List<String> list = this.buildList(3);
 		assertEquals(2, list.lastIndexOf(this.getElement()));
 		assertEquals(-1, list.lastIndexOf(new Object()));
+
+		list = this.buildList(0);
+		assertEquals(-1, list.indexOf(this.getElement()));
+		assertEquals(-1, list.lastIndexOf(new Object()));
 	}
 
 	public void testListIterator() {
@@ -474,6 +481,19 @@
 		assertNull(array[20]);
 	}
 
+	public void testToString() {
+		List<String> list1 = this.buildList(3);
+		List<String> list2 = new ArrayList<String>();
+		list2.add(this.getElement());
+		list2.add(this.getElement());
+		list2.add(this.getElement());
+		assertEquals(list2.toString(), list1.toString());
+
+		list1 = this.buildList(0);
+		list2 = new ArrayList<String>();
+		assertEquals(list2.toString(), list1.toString());
+	}
+
 	public abstract List<String> buildList(int size);
 
 	public abstract String getElement();
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayStackTests.java
deleted file mode 100644
index 10b863c..0000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayStackTests.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012, 2015 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.tests.internal.collection;
-
-import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.ArrayStack;
-import org.eclipse.jpt.common.utility.internal.collection.StackTools;
-import org.eclipse.jpt.common.utility.tests.internal.TestTools;
-
-@SuppressWarnings("nls")
-public class ArrayStackTests
-	extends StackTests
-{
-	public ArrayStackTests(String name) {
-		super(name);
-	}
-
-	@Override
-	Stack<String> buildStack() {
-		return new ArrayStack<String>();
-	}
-
-	public void testCollectionConstructor() {
-		ArrayList<String> c = new ArrayList<String>();
-		c.add("first");
-		c.add("second");
-		c.add("third");
-		c.add("fourth");
-		c.add("fifth");
-		c.add("sixth");
-		c.add("seventh");
-		c.add("eighth");
-		c.add("ninth");
-		c.add("tenth"); // force some free space
-		Stack<String> stack = StackTools.arrayStack(c);
-
-		assertFalse(stack.isEmpty());
-		assertEquals("tenth", stack.peek());
-		stack.push("eleventh");
-		stack.push("twelfth");
-
-		assertEquals("twelfth", stack.peek());
-		assertEquals("twelfth", stack.pop());
-		assertEquals("eleventh", stack.pop());
-		assertEquals("tenth", stack.peek());
-		assertEquals("tenth", stack.pop());
-		assertEquals("ninth", stack.pop());
-		assertFalse(stack.isEmpty());
-		assertEquals("eighth", stack.peek());
-		assertEquals("eighth", stack.pop());
-		assertEquals("seventh", stack.pop());
-		assertEquals("sixth", stack.pop());
-		assertEquals("fifth", stack.pop());
-		assertEquals("fourth", stack.pop());
-		assertEquals("third", stack.pop());
-		assertEquals("second", stack.pop());
-		assertEquals("first", stack.pop());
-		assertTrue(stack.isEmpty());
-	}
-
-	public void testSerialization_fullArray() throws Exception {
-		Stack<String> stack = new ArrayStack<String>(3);
-		stack.push("first");
-		stack.push("second");
-		stack.push("third");
-
-		this.verifyClone(stack, TestTools.serialize(stack));
-	}
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/BagTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/BagTests.java
index 8f72bab..42682e3 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/BagTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/BagTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -9,76 +9,813 @@
  ******************************************************************************/
 package org.eclipse.jpt.common.utility.tests.internal.collection;
 
-import junit.framework.TestCase;
-
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
 import org.eclipse.jpt.common.utility.collection.Bag;
-import org.eclipse.jpt.common.utility.internal.collection.EmptyBag;
-import org.eclipse.jpt.common.utility.internal.collection.HashBag;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
+//subclass MultiThreadedTestCase for subclasses of this class
 @SuppressWarnings("nls")
-public class BagTests extends TestCase {
+public abstract class BagTests
+	extends MultiThreadedTestCase
+{
+	private Bag<String> bag;
 
-	public BagTests(String name) {
+	protected BagTests(String name) {
 		super(name);
 	}
 
-	public void testEmptyBag_iterator() throws Exception {
-		assertFalse(EmptyBag.instance().iterator().hasNext());
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.bag = this.buildBag();
 	}
 
-	public void testEmptyBag_size() throws Exception {
-		assertEquals(0, EmptyBag.instance().size());
+	protected Bag<String> buildBag() {
+		Bag<String> b = this.buildBag_();
+		b.add(null);
+		b.add(new String("one"));
+		b.add(new String("two"));
+		b.add(new String("two"));
+		b.add(new String("three"));
+		b.add(new String("three"));
+		b.add(new String("three"));
+		b.add(new String("four"));
+		b.add(new String("four"));
+		b.add(new String("four"));
+		b.add(new String("four"));
+		return b;
 	}
 
-	public void testEmptyBag_uniqueIterator() throws Exception {
-		assertFalse(EmptyBag.instance().uniqueIterator().hasNext());
+	protected abstract Bag<String> buildBag_();
+
+	protected abstract Bag<String> buildBag(Collection<String> c);
+
+	protected abstract Bag<String> buildBag(int initialCapacity, float loadFactor);
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
 	}
 
-	public void testEmptyBag_uniqueCount() throws Exception {
-		assertEquals(0, EmptyBag.instance().uniqueCount());
+	private Collection<String> buildCollection() {
+		Collection<String> c = new ArrayList<String>();
+		c.add(new String("foo"));
+		c.add(new String("foo"));
+		c.add(new String("bar"));
+		c.add(new String("bar"));
+		c.add(new String("bar"));
+		return c;
 	}
 
-	public void testEmptyBag_count() throws Exception {
-		assertEquals(0, EmptyBag.instance().count("foo"));
+	public void testCtorCollection() {
+		Collection<String> c = this.buildCollection();
+		Bag<String> b = this.buildBag(c);
+		for (String s : c) {
+			assertTrue(b.contains(s));
+		}
 	}
 
-	public void testEmptyBag_entries() throws Exception {
-		assertFalse(EmptyBag.instance().entries().hasNext());
-	}
+	public void testCtorIntFloat() {
+		boolean exCaught;
 
-	public void testEmptyBag_remove() throws Exception {
-		assertFalse(EmptyBag.instance().remove("foo", 3));
-	}
-
-	public void testEmptyBag_add() throws Exception {
-		boolean exCaught = false;
+		exCaught = false;
 		try {
-			EmptyBag.instance().add("foo", 3);
-			fail();
-		} catch (UnsupportedOperationException ex) {
+			this.bag = this.buildBag(-20, 0.66f);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			this.bag = this.buildBag(20, -0.66f);
+		} catch (IllegalArgumentException ex) {
 			exCaught = true;
 		}
 		assertTrue(exCaught);
 	}
 
-	public void testEmptyBag_equals() throws Exception {
-		assertTrue(EmptyBag.instance().equals(EmptyBag.instance()));
-		assertFalse(EmptyBag.instance().equals("foo"));
+	public void testAdd() {
+		// the other adds took place in setUp
+		assertTrue(this.bag.add("five"));
 
-		Bag<Object> bag = new HashBag<Object>();
-		assertTrue(EmptyBag.instance().equals(bag));
-		bag.add("foo");
-		assertFalse(EmptyBag.instance().equals(bag));
+		assertTrue(this.bag.contains("one"));
+		assertTrue(this.bag.contains("two"));
+		assertTrue(this.bag.contains("three"));
+		assertTrue(this.bag.contains("four"));
+		assertTrue(this.bag.contains("five"));
 	}
 
-	public void testEmptyBag_hashCode() throws Exception {
-		assertEquals(0, EmptyBag.instance().hashCode());
+	public void testAddCount() {
+		// the other adds took place in setUp
+		this.bag.add("minus3", -3);
+		this.bag.add("zero", 0);
+		this.bag.add("five", 5);
+
+		assertFalse(this.bag.contains("minus3"));
+		assertFalse(this.bag.contains("zero"));
+		assertEquals(1, this.bag.count("one"));
+		assertEquals(2, this.bag.count("two"));
+		assertEquals(3, this.bag.count("three"));
+		assertEquals(4, this.bag.count("four"));
+		assertEquals(5, this.bag.count("five"));
+
+		this.bag.add("three", 2);
+		assertEquals(5, this.bag.count("three"));
 	}
 
-	public void testEmptyBag_serialization() throws Exception {
-		Bag<?> xxx = TestTools.serialize(EmptyBag.instance());
-		assertSame(EmptyBag.instance(), xxx);
+	public void testAddAll() {
+		Collection<String> c = this.buildCollection();
+		assertTrue(this.bag.addAll(c));
+		for (String s : c) {
+			assertTrue(this.bag.contains(s));
+		}
+	}
+
+	public void testClear() {
+		assertTrue(this.bag.contains("one"));
+		assertTrue(this.bag.contains("two"));
+		assertTrue(this.bag.contains("three"));
+		assertTrue(this.bag.contains("four"));
+		assertTrue(this.bag.contains(null));
+		assertEquals(11, this.bag.size());
+		this.bag.clear();
+		assertFalse(this.bag.contains("one"));
+		assertFalse(this.bag.contains("two"));
+		assertFalse(this.bag.contains("three"));
+		assertFalse(this.bag.contains("four"));
+		assertFalse(this.bag.contains(null));
+		assertEquals(0, this.bag.size());
+	}
+
+	public void testClone() {
+		@SuppressWarnings("unchecked")
+		Bag<String> bag2 = (Bag<String>) ObjectTools.execute(this.bag, "clone");
+		assertTrue(this.bag != bag2);
+		assertEquals(this.bag, bag2);
+		assertTrue(this.bag.hashCode() == bag2.hashCode());
+	}
+
+	public void testContains() {
+		assertTrue(this.bag.contains(null));
+		assertTrue(this.bag.contains("one"));
+		assertTrue(this.bag.contains("two"));
+		assertTrue(this.bag.contains("three"));
+		assertTrue(this.bag.contains("four"));
+		assertTrue(this.bag.contains(new String("four")));
+		assertTrue(this.bag.contains("fo" + "ur"));
+		assertFalse(this.bag.contains("five"));
+	}
+
+	public void testContainsAll() {
+		Collection<String> c = new ArrayList<String>();
+		c.add(null);
+		c.add(new String("one"));
+		c.add(new String("two"));
+		c.add(new String("three"));
+		c.add(new String("four"));
+		assertTrue(this.bag.containsAll(c));
+	}
+
+	public void testCount() {
+		assertEquals(0, this.bag.count("zero"));
+		assertEquals(1, this.bag.count("one"));
+		assertEquals(2, this.bag.count("two"));
+		assertEquals(3, this.bag.count("three"));
+		assertEquals(4, this.bag.count("four"));
+		assertEquals(0, this.bag.count("five"));
+	}
+
+	public void testEqualsObject() {
+		Bag<String> bag2 = this.buildBag();
+		assertEquals(this.bag, this.bag);
+		assertEquals(this.bag, bag2);
+
+		bag2.add("four");
+		assertFalse(this.bag.equals(bag2)); // same unique counts; different sizes
+		bag2.remove("four");
+
+		bag2.add("five");
+		bag2.remove("four");
+		assertFalse(this.bag.equals(bag2)); // same sizes; different unique counts
+		bag2.remove("five");
+		bag2.add("four");
+
+		bag2.remove("two");
+		bag2.add("four");
+		assertFalse(this.bag.equals(bag2)); // same sizes; same unique counts
+
+		Collection<String> c = new ArrayList<String>(this.bag);
+		assertFalse(this.bag.equals(c));
+	}
+
+	public void testHashCode() {
+		Bag<String> bag2 = this.buildBag();
+		assertEquals(this.bag.hashCode(), bag2.hashCode());
+	}
+
+	public void testIsEmpty() {
+		assertFalse(this.bag.isEmpty());
+		this.bag.clear();
+		assertTrue(this.bag.isEmpty());
+		this.bag.add("foo");
+		assertFalse(this.bag.isEmpty());
+	}
+
+	public void testEmptyIterator() {
+		this.bag.clear();
+		Iterator<String> iterator = this.bag.iterator();
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIterator() {
+		int i = 0;
+		Iterator<String> iterator = this.bag.iterator();
+		assertTrue(iterator.hasNext());
+		while (iterator.hasNext()) {
+			iterator.next();
+			i++;
+		}
+		assertEquals(11, i);
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		iterator.remove();
+		assertEquals(10, this.bag.size());
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		// start over
+		iterator = this.bag.iterator();
+		this.bag.add("five");
+		exCaught = false;
+		try {
+			iterator.next();
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIterator_remove_all() {
+		assertEquals(4, this.bag.count("four"));
+		Iterator<String> iterator = this.bag.iterator();
+		String next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if ((next != null) && next.equals("four")) {
+				iterator.remove();
+			}
+		}
+		assertEquals(0, this.bag.count("four"));
+	}
+
+	public void testIterator_remove_CME() {
+		Iterator<String> iterator = this.bag.iterator();
+		assertTrue(iterator.hasNext());
+		boolean exCaught = false;
+		try {
+			String next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.equals("four")) {
+					this.bag.remove("two");
+					iterator.remove();
+				}
+			}
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyUniqueIterator() {
+		this.bag.clear();
+		Iterator<String> iterator = this.bag.uniqueIterator();
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testUniqueIterator() {
+		int i = 0;
+		Iterator<String> iterator = this.bag.uniqueIterator();
+		assertTrue(iterator.hasNext());
+		while (iterator.hasNext()) {
+			iterator.next();
+			i++;
+		}
+		assertEquals(5, i);
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		// start over
+		iterator = this.bag.uniqueIterator();
+		Object next = null;
+		while (iterator.hasNext() && !"four".equals(next)) {
+			next = iterator.next();
+		}
+		iterator.remove();
+		assertEquals(7, this.bag.size());
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		// start over
+		iterator = this.bag.uniqueIterator();
+		this.bag.add("five");
+		exCaught = false;
+		try {
+			iterator.next();
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyEntries() {
+		this.bag.clear();
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEntries() {
+		int i = 0;
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertTrue(iterator.hasNext());
+		while (iterator.hasNext()) {
+			iterator.next();
+			i++;
+		}
+		assertEquals(5, i);
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		// start over
+		iterator = this.bag.entries();
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				iterator.remove();
+				break;
+			}
+		}
+		assertEquals(7, this.bag.size());
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		// start over
+		iterator = this.bag.entries();
+		this.bag.add("five");
+		exCaught = false;
+		try {
+			iterator.next();
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEntries_remove_CME() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertTrue(iterator.hasNext());
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals("four")) {
+					this.bag.remove("two");
+					iterator.remove();
+				}
+			}
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEntry_setCount_increase() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count("four"));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				assertEquals(4, next.setCount(42));
+				break;
+			}
+		}
+		assertEquals(42, this.bag.count("four"));
+		assertEquals(49, this.bag.size());
+	}
+
+	public void testEntry_setCount_same() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count("four"));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				assertEquals(4, next.setCount(4));
+				break;
+			}
+		}
+		assertEquals(4, this.bag.count("four"));
+		assertEquals(11, this.bag.size());
+	}
+
+	public void testEntry_setCount_derease() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count("four"));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				assertEquals(4, next.setCount(2));
+				break;
+			}
+		}
+		assertEquals(2, this.bag.count("four"));
+		assertEquals(9, this.bag.size());
+	}
+
+	public void testEntry_setCount_IAE1() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals("four")) {
+					next.setCount(0);
+					fail(next.toString());
+				}
+			}
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEntry_setCount_IAE2() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals("four")) {
+					next.setCount(-33);
+					fail(next.toString());
+				}
+			}
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_equalsObject() {
+		Iterator<Bag.Entry<String>> iterator1 = this.bag.entries();
+		Bag<String> bag2 = this.buildBag();
+		Bag.Entry<String> next1 = null;
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals("four")) {
+				break;
+			}
+		}
+		assertFalse(next1.equals("four"));
+		Iterator<Bag.Entry<String>> iterator2 = bag2.entries();
+		Bag.Entry<String> next2 = null;
+		while (iterator2.hasNext()) {
+			next2 = iterator2.next();
+			if (next2.getElement().equals("four")) {
+				break;
+			}
+		}
+		assertEquals(next1, next2);
+
+		bag2.remove("four");
+		iterator1 = this.bag.entries();
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals("four")) {
+				break;
+			}
+		}
+		iterator2 = bag2.entries();
+		while (iterator2.hasNext()) {
+			next2 = iterator2.next();
+			if (next2.getElement().equals("four")) {
+				break;
+			}
+		}
+		assertEquals(next1.getElement(), next2.getElement());
+		assertFalse(next1.equals(next2));
+
+		iterator1 = this.bag.entries();
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals("three")) {
+				break;
+			}
+		}
+		assertEquals(next1.getCount(), next2.getCount());
+		assertFalse(next1.equals(next2));
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_hashCode() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				break;
+			}
+		}
+		assertEquals(4 * "four".hashCode(), next.hashCode());
+
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement() == null) {
+				break;
+			}
+		}
+		assertEquals(0, next.hashCode());
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_toString() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals("four")) {
+				break;
+			}
+		}
+		assertEquals("four=>4", next.toString());
+	}
+
+	public void testRemove() {
+		assertTrue(this.bag.remove("one"));
+		assertFalse(this.bag.contains("one"));
+		assertFalse(this.bag.remove("one"));
+
+		assertTrue(this.bag.remove("two"));
+		assertTrue(this.bag.remove("two"));
+		assertFalse(this.bag.contains("two"));
+		assertFalse(this.bag.remove("two"));
+	}
+
+	public void testRemoveCount() {
+		assertFalse(this.bag.remove("one", 0));
+		assertTrue(this.bag.contains("one"));
+
+		assertTrue(this.bag.remove("one", 1));
+		assertFalse(this.bag.contains("one"));
+		assertFalse(this.bag.remove("one"));
+
+		assertFalse(this.bag.remove("two", -3));
+		assertTrue(this.bag.remove("two", 1));
+		assertTrue(this.bag.contains("two"));
+
+		assertTrue(this.bag.remove("two", 1));
+		assertFalse(this.bag.contains("two"));
+		assertFalse(this.bag.remove("two"));
+
+		assertTrue(this.bag.remove("three", 3));
+		assertFalse(this.bag.contains("three"));
+		assertFalse(this.bag.remove("three"));
+	}
+
+	public void testRemoveAll() {
+		Collection<String> c = new ArrayList<String>();
+		c.add("one");
+		c.add("three");
+		assertTrue(this.bag.removeAll(c));
+		assertFalse(this.bag.contains("one"));
+		assertFalse(this.bag.contains("three"));
+		assertFalse(this.bag.remove("one"));
+		assertFalse(this.bag.remove("three"));
+		assertFalse(this.bag.removeAll(c));
+	}
+
+	public void testRetainAll() {
+		Collection<String> c = new ArrayList<String>();
+		c.add("one");
+		c.add("three");
+		assertTrue(this.bag.retainAll(c));
+		assertTrue(this.bag.contains("one"));
+		assertTrue(this.bag.contains("three"));
+		assertFalse(this.bag.contains("two"));
+		assertFalse(this.bag.contains("four"));
+		assertFalse(this.bag.remove("two"));
+		assertFalse(this.bag.remove("four"));
+		assertFalse(this.bag.retainAll(c));
+	}
+
+	public void testSize() {
+		assertTrue(this.bag.size() == 11);
+		this.bag.add("five");
+		this.bag.add("five");
+		this.bag.add("five");
+		this.bag.add("five");
+		this.bag.add("five");
+		assertEquals(16, this.bag.size());
+	}
+
+	public void testSerialization() throws Exception {
+		Bag<String> bag2 = TestTools.serialize(this.bag);
+
+		assertTrue("same object?", this.bag != bag2);
+		assertEquals(11, bag2.size());
+		assertEquals(this.bag, bag2);
+		// look for similar elements
+		assertTrue(bag2.contains(null));
+		assertTrue(bag2.contains("one"));
+		assertTrue(bag2.contains("two"));
+		assertTrue(bag2.contains("three"));
+		assertTrue(bag2.contains("four"));
+
+		int nullCount = 0, oneCount = 0, twoCount = 0, threeCount = 0, fourCount = 0;
+		for (String s : bag2) {
+			if (s == null) {
+				nullCount++;
+			} else if (s.equals("one")) {
+				oneCount++;
+			} else if (s.equals("two")) {
+				twoCount++;
+			} else if (s.equals("three")) {
+				threeCount++;
+			} else if (s.equals("four")) {
+				fourCount++;
+			}
+		}
+		assertEquals(1, nullCount);
+		assertEquals(1, oneCount);
+		assertEquals(2, twoCount);
+		assertEquals(3, threeCount);
+		assertEquals(4, fourCount);
+	}
+
+	public void testSerialization_empty() throws Exception {
+		this.bag.clear();
+		Bag<String> bag2 = TestTools.serialize(this.bag);
+
+		assertTrue("same object?", this.bag != bag2);
+		assertEquals(0, bag2.size());
+		assertEquals(this.bag, bag2);
+	}
+
+	public void testToArray() {
+		Object[] a = this.bag.toArray();
+		assertEquals(11, a.length);
+		assertTrue(ArrayTools.contains(a, null));
+		assertTrue(ArrayTools.contains(a, "one"));
+		assertTrue(ArrayTools.contains(a, "two"));
+		assertTrue(ArrayTools.contains(a, "three"));
+		assertTrue(ArrayTools.contains(a, "four"));
+	}
+
+	public void testToArrayObjectArray() {
+		String[] a = new String[12];
+		a[11] = "not null";
+		String[] b = this.bag.toArray(a);
+		assertEquals(a, b);
+		assertEquals(12, a.length);
+		assertTrue(ArrayTools.contains(a, null));
+		assertTrue(ArrayTools.contains(a, "one"));
+		assertTrue(ArrayTools.contains(a, "two"));
+		assertTrue(ArrayTools.contains(a, "three"));
+		assertTrue(ArrayTools.contains(a, "four"));
+		assertTrue(a[11] == null);
+	}
+
+	public void testToString() {
+		String s = this.bag.toString();
+		assertTrue(s.startsWith("["));
+		assertTrue(s.endsWith("]"));
+		int commaCount = 0;
+		for (int i = 0; i < s.length(); i++) {
+			if (s.charAt(i) == ',') {
+				commaCount++;
+			}
+		}
+		assertEquals(10, commaCount);
+		assertTrue(s.indexOf("one") != -1);
+		assertTrue(s.indexOf("two") != -1);
+		assertTrue(s.indexOf("three") != -1);
+		assertTrue(s.indexOf("four") != -1);
+		assertTrue(s.indexOf("null") != -1);
 	}
 
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/CollectionToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/CollectionToolsTests.java
index d198057..a9f30d1 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/CollectionToolsTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/CollectionToolsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -20,17 +20,18 @@
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.Vector;
-import junit.framework.TestCase;
 import org.eclipse.jpt.common.utility.collection.Bag;
 import org.eclipse.jpt.common.utility.internal.ClassTools;
 import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
-import org.eclipse.jpt.common.utility.internal.collection.EmptyBag;
+import org.eclipse.jpt.common.utility.internal.collection.IdentityHashBag;
+import org.eclipse.jpt.common.utility.internal.collection.SynchronizedBag;
 import org.eclipse.jpt.common.utility.internal.comparator.ComparatorTools;
 import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable;
 import org.eclipse.jpt.common.utility.internal.iterator.EmptyIterator;
 import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
 import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
 import org.eclipse.jpt.common.utility.tests.internal.ArrayToolsTests;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
 public class CollectionToolsTests
@@ -164,7 +165,7 @@
 		String[] a = this.buildStringArray1();
 		assertTrue(CollectionTools.addAll(list, a));
 		assertEquals(6, list.size());
-		assertTrue(list.containsAll(CollectionTools.collection(a)));
+		assertTrue(list.containsAll(CollectionTools.hashBag(a)));
 	}
 
 	public void testAddAllCollectionObjectArray_StringListEmptyArray() {
@@ -177,7 +178,7 @@
 		String[] a = this.buildStringArray1();
 		assertFalse(CollectionTools.addAll(set, a));
 		assertEquals(3, set.size());
-		assertTrue(set.containsAll(CollectionTools.collection(a)));
+		assertTrue(set.containsAll(CollectionTools.hashBag(a)));
 
 		assertFalse(CollectionTools.addAll(set, new String[0]));
 	}
@@ -193,7 +194,7 @@
 
 		assertTrue(CollectionTools.addAll(list, a));
 		assertEquals(6, list.size());
-		assertTrue(list.containsAll(CollectionTools.collection(a)));
+		assertTrue(list.containsAll(CollectionTools.hashBag(a)));
 	}
 
 	public void testAddAllCollectionObjectArray_ObjectUnmodified() {
@@ -201,118 +202,81 @@
 		Set<Object> set = this.buildObjectSet1();
 		assertFalse(CollectionTools.addAll(set, a));
 		assertEquals(3, set.size());
-		assertTrue(set.containsAll(CollectionTools.collection(a)));
+		assertTrue(set.containsAll(CollectionTools.hashBag(a)));
 	}
 
 
-	// ********** bag **********
+	// ********** hash bag **********
 
-	public void testBagIterable() {
+	public void testHashBagIntFloat() {
+		Collection<String> c = CollectionTools.hashBag(42, 0.88f);
+		assertEquals(0, c.size());
+		assertTrue(c.isEmpty());
+	}
+
+	public void testHashBagIterable() {
 		Iterable<String> iterable = this.buildStringList1();
-		Bag<String> b = CollectionTools.bag(iterable);
-		assertEquals(3, b.size());
-		assertTrue(b.containsAll(this.buildStringList1()));
+		Collection<String> c = CollectionTools.hashBag(iterable);
+		assertEquals(3, c.size());
+		assertTrue(c.containsAll(this.buildStringList1()));
 	}
 
-	public void testBagIterableInt() {
+	public void testHashBagIterableInt() {
 		Iterable<String> iterable = this.buildStringList1();
-		Bag<String> b = CollectionTools.bag(iterable, 3);
-		assertEquals(3, b.size());
-		assertTrue(b.containsAll(this.buildStringList1()));
-	}
-
-	public void testBagIterator_String() {
-		Bag<String> b = CollectionTools.bag(this.buildStringList1().iterator());
-		assertEquals(3, b.size());
-		assertTrue(b.containsAll(this.buildStringList1()));
-	}
-
-	public void testBagIterator_StringObject() {
-		Collection<String> c = new ArrayList<String>();
-		c.add("zero");
-		c.add("one");
-		c.add("two");
-		c.add("three");
-		Bag<Object> b = CollectionTools.<Object>bag(c.iterator());
-		assertEquals(4, b.size());
-		assertTrue(b.containsAll(c));
-	}
-
-	public void testBagIterator_Empty() {
-		Bag<String> b = CollectionTools.bag(EmptyIterator.<String>instance());
-		assertEquals(0, b.size());
-	}
-
-	public void testBagIteratorInt() {
-		Bag<String> b = CollectionTools.bag(this.buildStringList1().iterator(), 3);
-		assertEquals(3, b.size());
-		assertTrue(b.containsAll(this.buildStringList1()));
-	}
-
-	public void testBagIteratorInt_Empty() {
-		Bag<String> b = CollectionTools.bag(EmptyIterator.<String>instance(), 3);
-		assertEquals(0, b.size());
-	}
-
-	public void testBagObjectArray() {
-		Bag<String> b = CollectionTools.bag(this.buildStringArray1());
-		assertEquals(3, b.size());
-		assertTrue(CollectionTools.containsAll(b, (Object[]) this.buildStringArray1()));
-	}
-
-	public void testBagObjectArray_Vararg() {
-		Bag<String> b = CollectionTools.bag("foo", "bar", "baz");
-		assertEquals(3, b.size());
-		assertTrue(CollectionTools.containsAll(b, new Object[]{"foo", "bar", "baz"}));
-	}
-
-	public void testBagObjectArray_Empty() {
-		Bag<String> b = CollectionTools.bag(EmptyBag.<String>instance());
-		assertEquals(0, b.size());
-	}
-
-
-	// ********** collection **********
-
-	public void testCollectionIterable() {
-		Iterable<String> iterable = this.buildStringList1();
-		Collection<String> c = CollectionTools.collection(iterable);
+		Collection<String> c = CollectionTools.hashBag(iterable, 3);
 		assertEquals(3, c.size());
 		assertTrue(c.containsAll(this.buildStringList1()));
 	}
 
-	public void testCollectionIterableInt() {
-		Iterable<String> iterable = this.buildStringList1();
-		Collection<String> c = CollectionTools.collection(iterable, 3);
+	public void testHashBagIterator() {
+		Collection<String> c = CollectionTools.hashBag(this.buildStringList1().iterator());
 		assertEquals(3, c.size());
 		assertTrue(c.containsAll(this.buildStringList1()));
 	}
 
-	public void testCollectionIterator() {
-		Collection<String> c = CollectionTools.collection(this.buildStringList1().iterator());
+	public void testHashBagIterator_ObjectString() {
+		Collection<Object> c = CollectionTools.<Object>hashBag(this.buildStringList1().iterator());
 		assertEquals(3, c.size());
 		assertTrue(c.containsAll(this.buildStringList1()));
 	}
 
-	public void testCollectionIterator_ObjectString() {
-		Collection<Object> c = CollectionTools.<Object>collection(this.buildStringList1().iterator());
+	public void testHashBagIteratorInt() {
+		Collection<String> c = CollectionTools.hashBag(this.buildStringList1().iterator(), 3);
 		assertEquals(3, c.size());
 		assertTrue(c.containsAll(this.buildStringList1()));
 	}
 
-	public void testCollectionIteratorInt() {
-		Collection<String> c = CollectionTools.collection(this.buildStringList1().iterator(), 3);
-		assertEquals(3, c.size());
-		assertTrue(c.containsAll(this.buildStringList1()));
-	}
-
-	public void testCollectionObjectArray() {
-		Collection<String> c = CollectionTools.collection(this.buildStringArray1());
+	public void testHashBagObjectArray() {
+		Collection<String> c = CollectionTools.hashBag(this.buildStringArray1());
 		assertEquals(3, c.size());
 		assertTrue(CollectionTools.containsAll(c, (Object[]) this.buildStringArray1()));
 	}
 
 
+	// ********** synchronized bag **********
+
+	public void testSynchronizedBagObject() {
+		Object mutex = "foo";
+		SynchronizedBag<String> sBag = CollectionTools.synchronizedBag(mutex);
+		assertEquals(mutex, sBag.getMutex());
+	}
+
+	public void testSynchronizedBagBagObject() {
+		Bag<String> bag = CollectionTools.hashBag();
+		Object mutex = "foo";
+		SynchronizedBag<String> sBag = CollectionTools.synchronizedBag(bag, mutex);
+		assertEquals(mutex, sBag.getMutex());
+	}
+
+
+	// ********** identity hash bag **********
+
+	public void testIdentityHashBagIntFloat() {
+		IdentityHashBag<String> bag = CollectionTools.identityHashBag(42, 0.88f);
+		assertTrue(bag.isEmpty());
+	}
+
+
 	// ********** contains all **********
 
 	public void testContainsAllCollectionIterable() {
@@ -348,22 +312,50 @@
 	// ********** filter **********
 
 	public void testFilterCollectionFilter() {
-		Collection<String> c = CollectionTools.collection(new String[] { "zero", "one", "two", "three", "four" });
+		Collection<String> c = CollectionTools.hashBag(new String[] { "zero", "one", "two", "three", "four" });
 		Collection<String> actual = CollectionTools.filter(c, new ArrayToolsTests.StringLengthEquals(3));
-		Collection<String> expected = CollectionTools.collection(new String[] { "one", "two" });
+		Collection<String> expected = CollectionTools.hashBag(new String[] { "one", "two" });
 		assertEquals(expected, actual);
 	}
 
 	public void testFilterCollectionFilterTransparent() {
-		Collection<String> c = CollectionTools.collection(new String[] { "zero", "one", "two", "three", "four" });
+		Collection<String> c = CollectionTools.hashBag(new String[] { "zero", "one", "two", "three", "four" });
 		Collection<String> actual = CollectionTools.filter(c, PredicateTools.<String>true_());
-		Collection<String> expected = CollectionTools.collection(new String[] { "zero", "one", "two", "three", "four" });
+		Collection<String> expected = CollectionTools.hashBag(new String[] { "zero", "one", "two", "three", "four" });
 		assertEquals(expected, actual);
 		assertNotSame(expected, actual);
 	}
 
+	// ********** identity bag **********
+
+	// tested in IdentityHashBagTests
+
 	// ********** partition **********
 
+	public void testPartitionCollectionInt_negative() {
+		this.verifyPartitionCollectionException(-3);
+	}
+
+	public void testPartitionCollectionInt_0() {
+		this.verifyPartitionCollectionException(0);
+	}
+
+	public void testPartitionCollectionInt_tooMany() {
+		this.verifyPartitionCollectionException(6);
+	}
+
+	public void verifyPartitionCollectionException(int count) {
+		Collection<String> c = Arrays.asList(new String[] { "zero", "one", "two", "three", "four" });
+		boolean exCaught = false;
+		try {
+			ArrayList<ArrayList<String>> actual = CollectionTools.partition(c, count);
+			fail("bogus partition: " + actual);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testPartitionCollectionInt_1() {
 		Collection<String> c = Arrays.asList(new String[] { "zero", "one", "two", "three", "four" });
 		ArrayList<ArrayList<String>> actual = CollectionTools.partition(c, 1);
@@ -792,6 +784,18 @@
 	}
 
 
+	// ********** to array fix **********
+
+	public void testToArrayCollectionClass() {
+		List<String> list = Arrays.asList(new String[] { "zero", "one", "two" });
+		String[] actual = CollectionTools.toArray(list, String.class);
+		assertEquals(3, actual.length);
+		assertEquals("zero", actual[0]);
+		assertEquals("one", actual[1]);
+		assertEquals("two", actual[2]);
+	}
+
+
 	// ********** transform **********
 
 	public void testTransformCollectionTransformer() {
@@ -804,23 +808,23 @@
 	}
 
 
-	// ********** set **********
+	// ********** hash set **********
 
-	public void testSetIterable() {
+	public void testHashSetIterable() {
 		Iterable<String> iterable = this.buildStringSet1();
-		assertEquals(this.buildStringSet1(), CollectionTools.set(iterable));
+		assertEquals(this.buildStringSet1(), CollectionTools.hashSet(iterable));
 	}
 
-	public void testSetIterableInt() {
+	public void testHashSetIterableInt() {
 		Iterable<String> iterable = this.buildStringSet1();
-		assertEquals(this.buildStringSet1(), CollectionTools.set(iterable, 22));
+		assertEquals(this.buildStringSet1(), CollectionTools.hashSet(iterable, 22));
 	}
 
-	public void testSetIterator_String() {
-		assertEquals(this.buildStringSet1(), CollectionTools.set(this.buildStringSet1().iterator()));
+	public void testHashSetIterator_String() {
+		assertEquals(this.buildStringSet1(), CollectionTools.hashSet(this.buildStringSet1().iterator()));
 	}
 
-	public void testSetIterator_Object() {
+	public void testHashSetIterator_Object() {
 		List<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("1");
@@ -833,21 +837,21 @@
 		Set<String> set = new HashSet<String>();
 		set.addAll(list);
 
-		assertEquals(set, CollectionTools.<Object>set(list.iterator()));
+		assertEquals(set, CollectionTools.<Object>hashSet(list.iterator()));
 	}
 
-	public void testSetIteratorInt() {
-		assertEquals(this.buildStringSet1(), CollectionTools.set(this.buildStringSet1().iterator(), 3));
+	public void testHashSetIteratorInt() {
+		assertEquals(this.buildStringSet1(), CollectionTools.hashSet(this.buildStringSet1().iterator(), 3));
 	}
 
-	public void testSetObjectArray() {
-		assertEquals(this.buildStringSet1(), CollectionTools.set(this.buildStringSet1().toArray()));
+	public void testHashSetObjectArray() {
+		assertEquals(this.buildStringSet1(), CollectionTools.hashSet(this.buildStringSet1().toArray()));
 	}
 
 
-	// ********** sorted set **********
+	// ********** tree set **********
 
-	public void testSortedSetIterable() {
+	public void testTreeSetIterable() {
 		ArrayList<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("2");
@@ -858,11 +862,11 @@
 		ss1.addAll(list);
 
 		Iterable<String> iterable = list;
-		SortedSet<String> ss2 = CollectionTools.<String>sortedSet(iterable);
+		SortedSet<String> ss2 = CollectionTools.<String>treeSet(iterable);
 		assertEquals(ss1, ss2);
 	}
 
-	public void testSortedSetIterableInt() {
+	public void testTreeSetIterableInt() {
 		ArrayList<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("2");
@@ -873,11 +877,11 @@
 		ss1.addAll(list);
 
 		Iterable<String> iterable = list;
-		SortedSet<String> ss2 = CollectionTools.<String>sortedSet(iterable, 5);
+		SortedSet<String> ss2 = CollectionTools.<String>treeSet(iterable, 5);
 		assertEquals(ss1, ss2);
 	}
 
-	public void testSortedSetIterableComparator() {
+	public void testTreeSetIterableComparator() {
 		ArrayList<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("2");
@@ -888,11 +892,11 @@
 		ss1.addAll(list);
 
 		Iterable<String> iterable = list;
-		SortedSet<String> ss2 = CollectionTools.<String>sortedSet(iterable, ComparatorTools.<String>reverseComparator());
+		SortedSet<String> ss2 = CollectionTools.<String>treeSet(iterable, ComparatorTools.<String>reverseComparator());
 		assertEquals(ss1, ss2);
 	}
 
-	public void testSortedSetIterableComparatorInt() {
+	public void testTreeSetIterableComparatorInt() {
 		ArrayList<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("2");
@@ -903,34 +907,34 @@
 		ss1.addAll(list);
 
 		Iterable<String> iterable = list;
-		SortedSet<String> ss2 = CollectionTools.<String>sortedSet(iterable, ComparatorTools.<String>reverseComparator(), 5);
+		SortedSet<String> ss2 = CollectionTools.<String>treeSet(iterable, ComparatorTools.<String>reverseComparator(), 5);
 		assertEquals(ss1, ss2);
 	}
 
-	public void testSortedSetIterator() {
-		assertEquals(this.buildSortedStringSet1(), CollectionTools.sortedSet(this.buildSortedStringSet1().iterator()));
+	public void testTreeSetIterator() {
+		assertEquals(this.buildSortedStringSet1(), CollectionTools.treeSet(this.buildSortedStringSet1().iterator()));
 	}
 
-	public void testSortedSetIterator_TreeSet() {
+	public void testTreeSetIterator_TreeSet() {
 		SortedSet<String> ss1 = new TreeSet<String>();
 		ss1.add("0");
 		ss1.add("2");
 		ss1.add("3");
 		ss1.add("1");
 
-		SortedSet<String> set2 = CollectionTools.<String>sortedSet(ss1.iterator());
+		SortedSet<String> set2 = CollectionTools.<String>treeSet(ss1.iterator());
 		assertEquals(ss1, set2);
 	}
 
-	public void testSortedSetIteratorInt() {
-		assertEquals(this.buildSortedStringSet1(), CollectionTools.sortedSet(this.buildSortedStringSet1().iterator(), 8));
+	public void testTreeSetIteratorInt() {
+		assertEquals(this.buildSortedStringSet1(), CollectionTools.treeSet(this.buildSortedStringSet1().iterator(), 8));
 	}
 
-	public void testSortedSetObjectArray() {
-		assertEquals(this.buildSortedStringSet1(), CollectionTools.sortedSet(this.buildStringSet1().toArray(new String[0])));
+	public void testTreeSetObjectArray() {
+		assertEquals(this.buildSortedStringSet1(), CollectionTools.treeSet(this.buildStringSet1().toArray(new String[0])));
 	}
 
-	public void testSortedSetObjectArrayComparator() {
+	public void testTreeSetObjectArrayComparator() {
 		ArrayList<String> list = new ArrayList<String>();
 		list.add("0");
 		list.add("2");
@@ -941,11 +945,12 @@
 		ss1.addAll(list);
 
 		String[] array = list.toArray(new String[list.size()]);
-		SortedSet<String> ss2 = CollectionTools.<String>sortedSet(array, ComparatorTools.<String>reverseComparator());
+		SortedSet<String> ss2 = CollectionTools.<String>treeSet(array, ComparatorTools.<String>reverseComparator());
 		assertEquals(ss1, ss2);
 	}
 
 
+
 	// ********** Old School Vector **********
 
 	public void testVectorIterable() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/EmptyBagTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/EmptyBagTests.java
new file mode 100644
index 0000000..685e1a3
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/EmptyBagTests.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2010, 2015 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.tests.internal.collection;
+
+import org.eclipse.jpt.common.utility.collection.Bag;
+import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.collection.HashBag;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class EmptyBagTests
+	extends TestCase
+{
+	public EmptyBagTests(String name) {
+		super(name);
+	}
+
+	public void testEmptyBag_iterator() throws Exception {
+		assertFalse(CollectionTools.emptyBag().iterator().hasNext());
+	}
+
+	public void testEmptyBag_size() throws Exception {
+		assertEquals(0, CollectionTools.emptyBag().size());
+	}
+
+	public void testEmptyBag_uniqueIterator() throws Exception {
+		assertFalse(CollectionTools.emptyBag().uniqueIterator().hasNext());
+	}
+
+	public void testEmptyBag_uniqueCount() throws Exception {
+		assertEquals(0, CollectionTools.emptyBag().uniqueCount());
+	}
+
+	public void testEmptyBag_count() throws Exception {
+		assertEquals(0, CollectionTools.emptyBag().count("foo"));
+	}
+
+	public void testEmptyBag_entries() throws Exception {
+		assertFalse(CollectionTools.emptyBag().entries().hasNext());
+	}
+
+	public void testEmptyBag_remove() throws Exception {
+		assertFalse(CollectionTools.emptyBag().remove("foo", 3));
+	}
+
+	public void testEmptyBag_add() throws Exception {
+		boolean exCaught = false;
+		try {
+			CollectionTools.emptyBag().add("foo", 3);
+			fail();
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyBag_equals() throws Exception {
+		assertTrue(CollectionTools.emptyBag().equals(CollectionTools.emptyBag()));
+		assertFalse(CollectionTools.emptyBag().equals("foo"));
+
+		Bag<Object> bag = new HashBag<Object>();
+		assertTrue(CollectionTools.emptyBag().equals(bag));
+		bag.add("foo");
+		assertFalse(CollectionTools.emptyBag().equals(bag));
+	}
+
+	public void testEmptyBag_hashCode() throws Exception {
+		assertEquals(0, CollectionTools.emptyBag().hashCode());
+	}
+
+	public void testEmptyBag_serialization() throws Exception {
+		Bag<?> xxx = TestTools.serialize(CollectionTools.emptyBag());
+		assertSame(CollectionTools.emptyBag(), xxx);
+	}
+
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/HashBagTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/HashBagTests.java
index a03d98e..a17bfa7 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/HashBagTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/HashBagTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2010 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -9,379 +9,37 @@
  ******************************************************************************/
 package org.eclipse.jpt.common.utility.tests.internal.collection;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.ConcurrentModificationException;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-import junit.framework.TestCase;
-
 import org.eclipse.jpt.common.utility.collection.Bag;
-import org.eclipse.jpt.common.utility.internal.ArrayTools;
 import org.eclipse.jpt.common.utility.internal.SystemTools;
 import org.eclipse.jpt.common.utility.internal.collection.HashBag;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
 @SuppressWarnings("nls")
-public class HashBagTests extends TestCase {
-	private HashBag<String> bag;
-
+public class HashBagTests
+	extends BagTests
+{
 	public HashBagTests(String name) {
 		super(name);
 	}
 
 	@Override
-	protected void setUp() throws Exception {
-		super.setUp();
-		this.bag = this.buildBag();
-	}
-
-	private HashBag<String> buildBag() {
-		HashBag<String> b = new HashBag<String>();
-		b.add(null);
-		b.add(new String("one"));
-		b.add(new String("two"));
-		b.add(new String("two"));
-		b.add(new String("three"));
-		b.add(new String("three"));
-		b.add(new String("three"));
-		b.add(new String("four"));
-		b.add(new String("four"));
-		b.add(new String("four"));
-		b.add(new String("four"));
-		return b;
+	protected Bag<String> buildBag_() {
+		return new HashBag<String>();
 	}
 
 	@Override
-	protected void tearDown() throws Exception {
-		TestTools.clear(this);
-		super.tearDown();
+	protected Bag<String> buildBag(Collection<String> c) {
+		return new HashBag<String>(c);
 	}
 
-	private Collection<String> buildCollection() {
-		Collection<String> c = new ArrayList<String>();
-		c.add(new String("foo"));
-		c.add(new String("foo"));
-		c.add(new String("bar"));
-		c.add(new String("bar"));
-		c.add(new String("bar"));
-		return c;
-	}
-
-	public void testCtorCollection() {
-		Collection<String> c = this.buildCollection();
-		Bag<String> b = new HashBag<String>(c);
-		for (String s : c) {
-			assertTrue(b.contains(s));
-		}
-	}
-
-	public void testCtorIntFloat() {
-		boolean exCaught;
-
-		exCaught = false;
-		try {
-			this.bag = new HashBag<String>(-20, 0.66f);
-		} catch (IllegalArgumentException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		exCaught = false;
-		try {
-			this.bag = new HashBag<String>(20, -0.66f);
-		} catch (IllegalArgumentException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-	}
-
-	public void testAdd() {
-		// the other adds took place in setUp
-		assertTrue(this.bag.add("five"));
-
-		assertTrue(this.bag.contains("one"));
-		assertTrue(this.bag.contains("two"));
-		assertTrue(this.bag.contains("three"));
-		assertTrue(this.bag.contains("four"));
-		assertTrue(this.bag.contains("five"));
-	}
-
-	public void testAddCount() {
-		// the other adds took place in setUp
-		this.bag.add("minus3", -3);
-		this.bag.add("zero", 0);
-		this.bag.add("five", 5);
-
-		assertFalse(this.bag.contains("minus3"));
-		assertFalse(this.bag.contains("zero"));
-		assertEquals(1, this.bag.count("one"));
-		assertEquals(2, this.bag.count("two"));
-		assertEquals(3, this.bag.count("three"));
-		assertEquals(4, this.bag.count("four"));
-		assertEquals(5, this.bag.count("five"));
-
-		this.bag.add("three", 2);
-		assertEquals(5, this.bag.count("three"));
-	}
-
-	public void testAddAll() {
-		Collection<String> c = this.buildCollection();
-		assertTrue(this.bag.addAll(c));
-		for (String s : c) {
-			assertTrue(this.bag.contains(s));
-		}
-	}
-
-	public void testClear() {
-		assertTrue(this.bag.contains("one"));
-		assertTrue(this.bag.contains("two"));
-		assertTrue(this.bag.contains("three"));
-		assertTrue(this.bag.contains("four"));
-		assertTrue(this.bag.contains(null));
-		assertEquals(11, this.bag.size());
-		this.bag.clear();
-		assertFalse(this.bag.contains("one"));
-		assertFalse(this.bag.contains("two"));
-		assertFalse(this.bag.contains("three"));
-		assertFalse(this.bag.contains("four"));
-		assertFalse(this.bag.contains(null));
-		assertEquals(0, this.bag.size());
-	}
-
-	public void testClone() {
-		Bag<String> bag2 = this.bag.clone();
-		assertTrue(this.bag != bag2);
-		assertEquals(this.bag, bag2);
-		assertTrue(this.bag.hashCode() == bag2.hashCode());
-	}
-
-	public void testContains() {
-		assertTrue(this.bag.contains(null));
-		assertTrue(this.bag.contains("one"));
-		assertTrue(this.bag.contains("two"));
-		assertTrue(this.bag.contains("three"));
-		assertTrue(this.bag.contains("four"));
-		assertTrue(this.bag.contains(new String("four")));
-		assertTrue(this.bag.contains("fo" + "ur"));
-		assertFalse(this.bag.contains("five"));
-	}
-
-	public void testContainsAll() {
-		Collection<String> c = new ArrayList<String>();
-		c.add(null);
-		c.add(new String("one"));
-		c.add(new String("two"));
-		c.add(new String("three"));
-		c.add(new String("four"));
-		assertTrue(this.bag.containsAll(c));
-	}
-
-	public void testCount() {
-		assertEquals(0, this.bag.count("zero"));
-		assertEquals(1, this.bag.count("one"));
-		assertEquals(2, this.bag.count("two"));
-		assertEquals(3, this.bag.count("three"));
-		assertEquals(4, this.bag.count("four"));
-		assertEquals(0, this.bag.count("five"));
-	}
-
-	public void testEquals() {
-		Bag<String> bag2 = this.buildBag();
-		assertEquals(this.bag, bag2);
-		bag2.add("five");
-		assertFalse(this.bag.equals(bag2));
-		Collection<String> c = new ArrayList<String>(this.bag);
-		assertFalse(this.bag.equals(c));
-	}
-
-	public void testHashCode() {
-		Bag<String> bag2 = this.buildBag();
-		assertEquals(this.bag.hashCode(), bag2.hashCode());
-	}
-
-	public void testIsEmpty() {
-		assertFalse(this.bag.isEmpty());
-		this.bag.clear();
-		assertTrue(this.bag.isEmpty());
-		this.bag.add("foo");
-		assertFalse(this.bag.isEmpty());
-	}
-
-	public void testEmptyIterator() {
-		this.bag.clear();
-		Iterator<String> iterator = this.bag.iterator();
-		assertFalse(iterator.hasNext());
-
-		boolean exCaught = false;
-		Object element = null;
-		try {
-			element = iterator.next();
-			fail(element.toString());
-		} catch (NoSuchElementException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		exCaught = false;
-		try {
-			iterator.remove();
-		} catch (IllegalStateException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-	}
-
-	public void testIterator() {
-		int i = 0;
-		Iterator<String> iterator = this.bag.iterator();
-		assertTrue(iterator.hasNext());
-		while (iterator.hasNext()) {
-			iterator.next();
-			i++;
-		}
-		assertEquals(11, i);
-		assertFalse(iterator.hasNext());
-
-		boolean exCaught = false;
-		Object element = null;
-		try {
-			element = iterator.next();
-			fail(element.toString());
-		} catch (NoSuchElementException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		iterator.remove();
-		assertEquals(10, this.bag.size());
-
-		exCaught = false;
-		try {
-			iterator.remove();
-		} catch (IllegalStateException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		// start over
-		iterator = this.bag.iterator();
-		this.bag.add("five");
-		exCaught = false;
-		try {
-			iterator.next();
-		} catch (ConcurrentModificationException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-	}
-
-	public void testUniqueIterator() {
-		int i = 0;
-		Iterator<String> iterator = this.bag.uniqueIterator();
-		assertTrue(iterator.hasNext());
-		while (iterator.hasNext()) {
-			iterator.next();
-			i++;
-		}
-		assertEquals(5, i);
-		assertFalse(iterator.hasNext());
-
-		boolean exCaught = false;
-		Object element = null;
-		try {
-			element = iterator.next();
-			fail(element.toString());
-		} catch (NoSuchElementException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		// start over
-		iterator = this.bag.uniqueIterator();
-		Object next = null;
-		while (iterator.hasNext() && !"four".equals(next)) {
-			next = iterator.next();
-		}
-		iterator.remove();
-		assertEquals(7, this.bag.size());
-
-		exCaught = false;
-		try {
-			iterator.remove();
-		} catch (IllegalStateException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		// start over
-		iterator = this.bag.uniqueIterator();
-		this.bag.add("five");
-		exCaught = false;
-		try {
-			iterator.next();
-		} catch (ConcurrentModificationException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-	}
-
-	public void testEntries() {
-		int i = 0;
-		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
-		assertTrue(iterator.hasNext());
-		while (iterator.hasNext()) {
-			iterator.next();
-			i++;
-		}
-		assertEquals(5, i);
-		assertFalse(iterator.hasNext());
-
-		boolean exCaught = false;
-		Object element = null;
-		try {
-			element = iterator.next();
-			fail(element.toString());
-		} catch (NoSuchElementException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		// start over
-		iterator = this.bag.entries();
-		Bag.Entry<String> next = null;
-		while (iterator.hasNext()) {
-			next = iterator.next();
-			if (next.getElement().equals("four")) {
-				iterator.remove();
-				break;
-			}
-		}
-		assertEquals(7, this.bag.size());
-
-		exCaught = false;
-		try {
-			iterator.remove();
-		} catch (IllegalStateException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
-
-		// start over
-		iterator = this.bag.entries();
-		this.bag.add("five");
-		exCaught = false;
-		try {
-			iterator.next();
-		} catch (ConcurrentModificationException ex) {
-			exCaught = true;
-		}
-		assertTrue(exCaught);
+	@Override
+	protected Bag<String> buildBag(int initialCapacity, float loadFactor) {
+		return new HashBag<String>(initialCapacity, loadFactor);
 	}
 
 	public void testHashingDistribution() throws Exception {
-		Bag<String> bigBag = new HashBag<String>();
+		Bag<String> bigBag = this.buildBag();
 		for (int i = 0; i < 10000; i++) {
 			bigBag.add("object" + i);
 		}
@@ -408,149 +66,4 @@
 			}
 		}
 	}
-
-	public void testRemove() {
-		assertTrue(this.bag.remove("one"));
-		assertFalse(this.bag.contains("one"));
-		assertFalse(this.bag.remove("one"));
-
-		assertTrue(this.bag.remove("two"));
-		assertTrue(this.bag.remove("two"));
-		assertFalse(this.bag.contains("two"));
-		assertFalse(this.bag.remove("two"));
-	}
-
-	public void testRemoveCount() {
-		assertFalse(this.bag.remove("one", 0));
-		assertTrue(this.bag.contains("one"));
-
-		assertTrue(this.bag.remove("one", 1));
-		assertFalse(this.bag.contains("one"));
-		assertFalse(this.bag.remove("one"));
-
-		assertFalse(this.bag.remove("two", -3));
-		assertTrue(this.bag.remove("two", 1));
-		assertTrue(this.bag.contains("two"));
-
-		assertTrue(this.bag.remove("two", 1));
-		assertFalse(this.bag.contains("two"));
-		assertFalse(this.bag.remove("two"));
-
-		assertTrue(this.bag.remove("three", 3));
-		assertFalse(this.bag.contains("three"));
-		assertFalse(this.bag.remove("three"));
-	}
-
-	public void testRemoveAll() {
-		Collection<String> c = new ArrayList<String>();
-		c.add("one");
-		c.add("three");
-		assertTrue(this.bag.removeAll(c));
-		assertFalse(this.bag.contains("one"));
-		assertFalse(this.bag.contains("three"));
-		assertFalse(this.bag.remove("one"));
-		assertFalse(this.bag.remove("three"));
-		assertFalse(this.bag.removeAll(c));
-	}
-
-	public void testRetainAll() {
-		Collection<String> c = new ArrayList<String>();
-		c.add("one");
-		c.add("three");
-		assertTrue(this.bag.retainAll(c));
-		assertTrue(this.bag.contains("one"));
-		assertTrue(this.bag.contains("three"));
-		assertFalse(this.bag.contains("two"));
-		assertFalse(this.bag.contains("four"));
-		assertFalse(this.bag.remove("two"));
-		assertFalse(this.bag.remove("four"));
-		assertFalse(this.bag.retainAll(c));
-	}
-
-	public void testSize() {
-		assertTrue(this.bag.size() == 11);
-		this.bag.add("five");
-		this.bag.add("five");
-		this.bag.add("five");
-		this.bag.add("five");
-		this.bag.add("five");
-		assertEquals(16, this.bag.size());
-	}
-
-	public void testSerialization() throws Exception {
-		Bag<String> bag2 = TestTools.serialize(this.bag);
-
-		assertTrue("same object?", this.bag != bag2);
-		assertEquals(11, bag2.size());
-		assertEquals(this.bag, bag2);
-		// look for similar elements
-		assertTrue(bag2.contains(null));
-		assertTrue(bag2.contains("one"));
-		assertTrue(bag2.contains("two"));
-		assertTrue(bag2.contains("three"));
-		assertTrue(bag2.contains("four"));
-
-		int nullCount = 0, oneCount = 0, twoCount = 0, threeCount = 0, fourCount = 0;
-		for (String s : bag2) {
-			if (s == null) {
-				nullCount++;
-			} else if (s.equals("one")) {
-				oneCount++;
-			} else if (s.equals("two")) {
-				twoCount++;
-			} else if (s.equals("three")) {
-				threeCount++;
-			} else if (s.equals("four")) {
-				fourCount++;
-			}
-		}
-		assertEquals(1, nullCount);
-		assertEquals(1, oneCount);
-		assertEquals(2, twoCount);
-		assertEquals(3, threeCount);
-		assertEquals(4, fourCount);
-	}
-
-	public void testToArray() {
-		Object[] a = this.bag.toArray();
-		assertEquals(11, a.length);
-		assertTrue(ArrayTools.contains(a, null));
-		assertTrue(ArrayTools.contains(a, "one"));
-		assertTrue(ArrayTools.contains(a, "two"));
-		assertTrue(ArrayTools.contains(a, "three"));
-		assertTrue(ArrayTools.contains(a, "four"));
-	}
-
-	public void testToArrayObjectArray() {
-		String[] a = new String[12];
-		a[11] = "not null";
-		String[] b = this.bag.toArray(a);
-		assertEquals(a, b);
-		assertEquals(12, a.length);
-		assertTrue(ArrayTools.contains(a, null));
-		assertTrue(ArrayTools.contains(a, "one"));
-		assertTrue(ArrayTools.contains(a, "two"));
-		assertTrue(ArrayTools.contains(a, "three"));
-		assertTrue(ArrayTools.contains(a, "four"));
-		assertTrue(a[11] == null);
-	}
-
-	public void testToString() {
-		String s = this.bag.toString();
-		assertTrue(s.startsWith("["));
-		assertTrue(s.endsWith("]"));
-		int commaCount = 0;
-		for (int i = 0; i < s.length(); i++) {
-			if (s.charAt(i) == ',') {
-				commaCount++;
-			}
-		}
-		assertEquals(10, commaCount);
-		assertTrue(s.indexOf("one") != -1);
-		assertTrue(s.indexOf("two") != -1);
-		assertTrue(s.indexOf("three") != -1);
-		assertTrue(s.indexOf("four") != -1);
-		assertTrue(s.indexOf("null") != -1);
-	}
-
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashBagTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashBagTests.java
index 23aa0f1..1fb037c 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashBagTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashBagTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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,17 +14,19 @@
 import java.util.ConcurrentModificationException;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-
-import junit.framework.TestCase;
-
+import org.eclipse.jpt.common.utility.collection.Bag;
 import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.internal.StringTools;
 import org.eclipse.jpt.common.utility.internal.SystemTools;
 import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
 import org.eclipse.jpt.common.utility.internal.collection.IdentityHashBag;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
-public class IdentityHashBagTests extends TestCase {
+public class IdentityHashBagTests
+	extends TestCase
+{
 	private IdentityHashBag<String> bag;
 	private String one = "one";
 	private String two = "two";
@@ -44,19 +46,23 @@
 	}
 	
 	protected IdentityHashBag<String> buildBag() {
-		IdentityHashBag<String> result = new IdentityHashBag<String>();
-		result.add(null);
-		result.add(this.one);
-		result.add(this.two);
-		result.add(this.two);
-		result.add(this.three);
-		result.add(this.three);
-		result.add(this.three);
-		result.add(this.four);
-		result.add(this.four);
-		result.add(this.four);
-		result.add(this.four);
-		return result;
+		return CollectionTools.identityHashBag(this.buildBagContents());
+	}
+	
+	protected Collection<String> buildBagContents() {
+		ArrayList<String> c = new ArrayList<String>();
+		c.add(null);
+		c.add(this.one);
+		c.add(this.two);
+		c.add(this.two);
+		c.add(this.three);
+		c.add(this.three);
+		c.add(this.three);
+		c.add(this.four);
+		c.add(this.four);
+		c.add(this.four);
+		c.add(this.four);
+		return c;
 	}
 	
 	@Override
@@ -199,17 +205,32 @@
 		assertEquals(0, this.bag.count("five"));
 	}
 	
-	public void testEquals() {
-		IdentityHashBag<String> bag2 = this.buildBag();
+	public void testEqualsObject() {
+		assertEquals(this.bag, this.bag);
+		IdentityHashBag<String> bag2 = CollectionTools.identityHashBag(this.buildBagContents(), 20);
 		assertEquals(this.bag, bag2);
-		bag2.add("five");
-		assertFalse(this.bag.equals(bag2));
+
+		bag2.add(this.four);
+		assertFalse(this.bag.equals(bag2)); // same unique counts; different sizes
+		bag2.remove(this.four);
+
+		String five = "five";
+		bag2.add(five);
+		bag2.remove(this.four);
+		assertFalse(this.bag.equals(bag2)); // same sizes; different unique counts
+		bag2.remove(five);
+		bag2.add(this.four);
+
+		bag2.remove(this.two);
+		bag2.add(this.four);
+		assertFalse(this.bag.equals(bag2)); // same sizes; same unique counts
+
 		Collection<String> c = new ArrayList<String>(this.bag);
 		assertFalse(this.bag.equals(c));
 	}
 	
 	public void testHashCode() {
-		IdentityHashBag<String> bag2 = this.buildBag();
+		IdentityHashBag<String> bag2 = CollectionTools.identityHashBag(this.buildBagContents().toArray(StringTools.EMPTY_STRING_ARRAY));
 		assertEquals(this.bag.hashCode(), bag2.hashCode());
 	}
 	
@@ -287,6 +308,30 @@
 		assertTrue("ConcurrentModificationException not thrown", exCaught);
 	}
 	
+	public void testEmptyUniqueIterator() {
+		this.bag.clear();
+		Iterator<String> iterator = this.bag.uniqueIterator();
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testUniqueIterator() {
 		int i = 0;
 		Iterator<String> iterator = this.bag.uniqueIterator();
@@ -338,6 +383,30 @@
 		assertTrue(exCaught);
 	}
 
+	public void testEmptyEntries() {
+		this.bag.clear();
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertFalse(iterator.hasNext());
+
+		boolean exCaught = false;
+		Object element = null;
+		try {
+			element = iterator.next();
+			fail(element.toString());
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			iterator.remove();
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testEntries() {
 		int i = 0;
 		Iterator<org.eclipse.jpt.common.utility.collection.Bag.Entry<String>> iterator = this.bag.entries();
@@ -392,6 +461,25 @@
 		assertTrue(exCaught);
 	}
 
+	public void testEntries_remove_CME() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertTrue(iterator.hasNext());
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals(this.four)) {
+					this.bag.remove(this.two);
+					iterator.remove();
+				}
+			}
+		} catch (ConcurrentModificationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testHashingDistribution() throws Exception {
 		IdentityHashBag<String> bigBag = new IdentityHashBag<String>();
 		for (int i = 0; i < 10000; i++) {
@@ -501,13 +589,13 @@
 	
 		assertTrue("same object?", this.bag != bag2);
 		assertEquals(11, bag2.size());
-		assertEquals(CollectionTools.bag(this.bag.iterator()), CollectionTools.bag(bag2.iterator()));
+		assertEquals(CollectionTools.hashBag(this.bag.iterator()), CollectionTools.hashBag(bag2.iterator()));
 		// look for similar elements
-		assertTrue(CollectionTools.bag(bag2.iterator()).contains(null));
-		assertTrue(CollectionTools.bag(bag2.iterator()).contains("one"));
-		assertTrue(CollectionTools.bag(bag2.iterator()).contains("two"));
-		assertTrue(CollectionTools.bag(bag2.iterator()).contains("three"));
-		assertTrue(CollectionTools.bag(bag2.iterator()).contains("four"));
+		assertTrue(CollectionTools.hashBag(bag2.iterator()).contains(null));
+		assertTrue(CollectionTools.hashBag(bag2.iterator()).contains("one"));
+		assertTrue(CollectionTools.hashBag(bag2.iterator()).contains("two"));
+		assertTrue(CollectionTools.hashBag(bag2.iterator()).contains("three"));
+		assertTrue(CollectionTools.hashBag(bag2.iterator()).contains("four"));
 	
 		int nullCount = 0, oneCount = 0, twoCount = 0, threeCount = 0, fourCount = 0;
 		for (String next : bag2) {
@@ -528,6 +616,15 @@
 		assertEquals(3, threeCount);
 		assertEquals(4, fourCount);
 	}
+
+	public void testSerialization_empty() throws Exception {
+		this.bag.clear();
+		Bag<String> bag2 = TestTools.serialize(this.bag);
+
+		assertTrue("same object?", this.bag != bag2);
+		assertEquals(0, bag2.size());
+		assertEquals(this.bag, bag2);
+	}
 	
 	public void testToArray() {
 		Object[] a = this.bag.toArray();
@@ -571,4 +668,169 @@
 		assertTrue(s.indexOf("null") != -1);
 	}
 
+	public void testEntry_setCount_increase() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count(this.four));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals(this.four)) {
+				assertEquals(4, next.setCount(42));
+				break;
+			}
+		}
+		assertEquals(42, this.bag.count(this.four));
+		assertEquals(49, this.bag.size());
+	}
+
+	public void testEntry_setCount_same() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count(this.four));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals(this.four)) {
+				assertEquals(4, next.setCount(4));
+				break;
+			}
+		}
+		assertEquals(4, this.bag.count(this.four));
+		assertEquals(11, this.bag.size());
+	}
+
+	public void testEntry_setCount_derease() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		assertEquals(4, this.bag.count(this.four));
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals(this.four)) {
+				assertEquals(4, next.setCount(2));
+				break;
+			}
+		}
+		assertEquals(2, this.bag.count(this.four));
+		assertEquals(9, this.bag.size());
+	}
+
+	public void testEntry_setCount_IAE1() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals(this.four)) {
+					next.setCount(0);
+					fail(next.toString());
+				}
+			}
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEntry_setCount_IAE2() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		boolean exCaught = false;
+		try {
+			Bag.Entry<String> next = null;
+			while (iterator.hasNext()) {
+				next = iterator.next();
+				if (next.getElement().equals(this.four)) {
+					next.setCount(-33);
+					fail(next.toString());
+				}
+			}
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_equalsObject() {
+		Iterator<Bag.Entry<String>> iterator1 = this.bag.entries();
+		Bag<String> bag2 = this.buildBag();
+		Bag.Entry<String> next1 = null;
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		assertFalse(next1.equals(this.four));
+		Iterator<Bag.Entry<String>> iterator2 = bag2.entries();
+		Bag.Entry<String> next2 = null;
+		while (iterator2.hasNext()) {
+			next2 = iterator2.next();
+			if (next2.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		assertEquals(next1, next2);
+
+		bag2.remove(this.four);
+		iterator1 = this.bag.entries();
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		iterator2 = bag2.entries();
+		while (iterator2.hasNext()) {
+			next2 = iterator2.next();
+			if (next2.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		assertEquals(next1.getElement(), next2.getElement());
+		assertFalse(next1.equals(next2));
+
+		iterator1 = this.bag.entries();
+		while (iterator1.hasNext()) {
+			next1 = iterator1.next();
+			if (next1.getElement().equals(this.three)) {
+				break;
+			}
+		}
+		assertEquals(next1.getCount(), next2.getCount());
+		assertFalse(next1.equals(next2));
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_hashCode() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		assertEquals(4 * this.four.hashCode(), next.hashCode());
+
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement() == null) {
+				break;
+			}
+		}
+		assertEquals(0, next.hashCode());
+	}
+
+	@SuppressWarnings("null")
+	public void testEntry_toString() {
+		Iterator<Bag.Entry<String>> iterator = this.bag.entries();
+		Bag.Entry<String> next = null;
+		while (iterator.hasNext()) {
+			next = iterator.next();
+			if (next.getElement().equals(this.four)) {
+				break;
+			}
+		}
+		assertEquals("four=>4", next.toString());
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashSetTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashSetTests.java
index 5dab6f4..6702469 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashSetTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/IdentityHashSetTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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.
@@ -12,13 +12,14 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import junit.framework.TestCase;
 import org.eclipse.jpt.common.utility.internal.ArrayTools;
 import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
 import org.eclipse.jpt.common.utility.internal.collection.IdentityHashSet;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
 public class IdentityHashSetTests
@@ -83,8 +84,10 @@
 	}
 
 	public void testCtorInt() {
-		boolean exCaught;
+		this.set = new IdentityHashSet<String>(20);
+		assertNotNull(this.set);
 
+		boolean exCaught;
 		exCaught = false;
 		try {
 			this.set = new IdentityHashSet<String>(-20);
@@ -161,6 +164,7 @@
 	}
 
 	public void testEquals() {
+		assertEquals(this.set, this.set);
 		IdentityHashSet<String> set2 = this.buildSet();
 		assertEquals(this.set, set2);
 		set2.add("five");
@@ -169,6 +173,13 @@
 		assertFalse(this.set.equals(c));
 	}
 
+	public void testEquals_set() {
+		HashSet<String> set2 = new HashSet<String>(this.set);
+		assertEquals(this.set, set2);
+		set2.add("five");
+		assertFalse(this.set.equals(set2));
+	}
+
 	public void testHashCode() {
 		IdentityHashSet<String> set2 = this.buildSet();
 		assertEquals(this.set.hashCode(), set2.hashCode());
@@ -291,6 +302,21 @@
 		assertFalse(this.set.retainAll(c));
 	}
 
+	public void testRetainAll_IHS() {
+		Collection<String> c = new IdentityHashSet<String>();
+		c.add(this.one);
+		c.add(new String(this.two));
+		c.add(this.three);
+		assertTrue(this.set.retainAll(c));
+		assertTrue(this.set.contains(this.one));
+		assertFalse(this.set.contains(this.two));
+		assertTrue(this.set.contains(this.three));
+		assertFalse(this.set.contains(this.four));
+		assertFalse(this.set.remove(this.two));
+		assertFalse(this.set.remove(this.four));
+		assertFalse(this.set.retainAll(c));
+	}
+
 	public void testSize() {
 		assertEquals(5, this.set.size());
 		String five = "five";
@@ -307,13 +333,13 @@
 
 		assertTrue("same object?", this.set != set2);
 		assertEquals(5, set2.size());
-		assertEquals(CollectionTools.set(this.set.iterator()), CollectionTools.set(set2.iterator()));
+		assertEquals(CollectionTools.hashSet(this.set.iterator()), CollectionTools.hashSet(set2.iterator()));
 		// look for similar elements
-		assertTrue(CollectionTools.set(set2.iterator()).contains(null));
-		assertTrue(CollectionTools.set(set2.iterator()).contains("one"));
-		assertTrue(CollectionTools.set(set2.iterator()).contains("two"));
-		assertTrue(CollectionTools.set(set2.iterator()).contains("three"));
-		assertTrue(CollectionTools.set(set2.iterator()).contains("four"));
+		assertTrue(CollectionTools.hashSet(set2.iterator()).contains(null));
+		assertTrue(CollectionTools.hashSet(set2.iterator()).contains("one"));
+		assertTrue(CollectionTools.hashSet(set2.iterator()).contains("two"));
+		assertTrue(CollectionTools.hashSet(set2.iterator()).contains("three"));
+		assertTrue(CollectionTools.hashSet(set2.iterator()).contains("four"));
 
 		int nullCount = 0, oneCount = 0, twoCount = 0, threeCount = 0, fourCount = 0;
 		for (String next : set2) {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/JptCommonUtilityCollectionTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/JptCommonUtilityCollectionTests.java
index 67a7c49..77363e4 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/JptCommonUtilityCollectionTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/JptCommonUtilityCollectionTests.java
@@ -20,25 +20,17 @@
 	public static Test suite() {
 		TestSuite suite = new TestSuite(JptCommonUtilityCollectionTests.class.getPackage().getName());
 
-		suite.addTestSuite(ArrayQueueTests.class);
-		suite.addTestSuite(ArrayStackTests.class);
-		suite.addTestSuite(BagTests.class);
 		suite.addTestSuite(CollectionToolsTests.class);
-		suite.addTestSuite(FixedSizeArrayQueueTests.class);
-		suite.addTestSuite(FixedSizeArrayStackTests.class);
+		suite.addTestSuite(EmptyBagTests.class);
 		suite.addTestSuite(HashBagTests.class);
 		suite.addTestSuite(IdentityHashBagTests.class);
 		suite.addTestSuite(IdentityHashSetTests.class);
-		suite.addTestSuite(LinkedQueueTests.class);
-		suite.addTestSuite(LinkedStackTests.class);
-		suite.addTestSuite(ListQueueTests.class);
-		suite.addTestSuite(ListStackTests.class);
 		suite.addTestSuite(ListToolsTests.class);
 		suite.addTestSuite(MapToolsTests.class);
 		suite.addTestSuite(NullElementListTests.class);
+		suite.addTestSuite(NullListTests.class);
 		suite.addTestSuite(RepeatingElementListTests.class);
-		suite.addTestSuite(SynchronizedQueueTests.class);
-		suite.addTestSuite(SynchronizedStackTests.class);
+		suite.addTestSuite(SynchronizedBagTests.class);
 		suite.addTestSuite(TightMapTests.class);
 
 		return suite;
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedQueueTests.java
deleted file mode 100644
index 31ec036..0000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedQueueTests.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012, 2015 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.tests.internal.collection;
-
-import java.util.Arrays;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedQueue;
-
-@SuppressWarnings("nls")
-public class LinkedQueueTests
-	extends QueueTests
-{
-	public LinkedQueueTests(String name) {
-		super(name);
-	}
-
-	@Override
-	Queue<String> buildQueue() {
-		return new LinkedQueue<String>();
-	}
-
-	public void testSize() {
-		Queue<String> queue = this.buildQueue();
-		String first = "first";
-		String second = "second";
-		String third = "third";
-
-		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
-		queue.enqueue(first);
-		queue.enqueue(second);
-		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
-		queue.enqueue(third);
-		assertEquals(3, ((Integer) ObjectTools.execute(queue, "size")).intValue());
-		queue.dequeue();
-		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
-		queue.dequeue();
-		queue.dequeue();
-		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
-	}
-
-	public void testBuildElements() {
-		Queue<String> queue = this.buildQueue();
-		String first = "first";
-		String second = "second";
-		String third = "third";
-		queue.enqueue(first);
-		queue.enqueue(second);
-		queue.enqueue(third);
-
-		Object[] elements = new Object[] { first, second, third };
-		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(queue, "buildElements"))));
-	}
-
-	public void testNodeCache() {
-		Queue<String> queue = new LinkedQueue<String>(2);
-		String first = "first";
-		String second = "second";
-		String third = "third";
-		String fourth = "fourth";
-		String fifth = "fifth";
-
-		Object factory = ObjectTools.get(queue, "nodeFactory");
-
-		this.verifyNodeCache(0, factory);
-		queue.enqueue(first);
-		this.verifyNodeCache(0, factory);
-		queue.enqueue(second);
-		queue.enqueue(third);
-		queue.enqueue(fourth);
-		queue.enqueue(fifth);
-		this.verifyNodeCache(0, factory);
-		assertNull(ObjectTools.get(factory, "cacheHead"));
-
-		queue.dequeue();
-		this.verifyNodeCache(1, factory);
-		queue.dequeue();
-		this.verifyNodeCache(2, factory);
-		queue.dequeue();
-		this.verifyNodeCache(2, factory);
-		queue.dequeue();
-		this.verifyNodeCache(2, factory);
-		queue.dequeue();
-		this.verifyNodeCache(2, factory);
-		queue.enqueue(first);
-		this.verifyNodeCache(1, factory);
-		queue.enqueue(second);
-		this.verifyNodeCache(0, factory);
-		queue.enqueue(third);
-		this.verifyNodeCache(0, factory);
-	}
-
-	public void verifyNodeCache(int size, Object factory) {
-		assertEquals(size, ((Integer) ObjectTools.get(factory, "cacheSize")).intValue());
-		int nodeCount = 0;
-		for (Object node = ObjectTools.get(factory, "cacheHead"); node != null; node = ObjectTools.get(node, "next")) {
-			nodeCount++;
-		}
-		assertEquals(size, nodeCount);
-	}
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedStackTests.java
deleted file mode 100644
index b1dd06d..0000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/LinkedStackTests.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2012, 2015 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.tests.internal.collection;
-
-import java.util.Arrays;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedStack;
-
-@SuppressWarnings("nls")
-public class LinkedStackTests
-	extends StackTests
-{
-	public LinkedStackTests(String name) {
-		super(name);
-	}
-
-	@Override
-	Stack<String> buildStack() {
-		return new LinkedStack<String>();
-	}
-
-	public void testSize() {
-		Stack<String> stack = this.buildStack();
-		String first = "first";
-		String second = "second";
-		String third = "third";
-
-		assertEquals(0, ((Integer) ObjectTools.execute(stack, "size")).intValue());
-		stack.push(first);
-		stack.push(second);
-		assertEquals(2, ((Integer) ObjectTools.execute(stack, "size")).intValue());
-		stack.push(third);
-		assertEquals(3, ((Integer) ObjectTools.execute(stack, "size")).intValue());
-		stack.pop();
-		assertEquals(2, ((Integer) ObjectTools.execute(stack, "size")).intValue());
-		stack.pop();
-		stack.pop();
-		assertEquals(0, ((Integer) ObjectTools.execute(stack, "size")).intValue());
-	}
-
-	public void testBuildElements() {
-		Stack<String> stack = this.buildStack();
-		String first = "first";
-		String second = "second";
-		String third = "third";
-		stack.push(first);
-		stack.push(second);
-		stack.push(third);
-
-		Object[] elements = new Object[] { third, second, first };
-		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(stack, "buildElements"))));
-	}
-
-	public void testNodeCache() {
-		Stack<String> stack = new LinkedStack<String>(2);
-		String first = "first";
-		String second = "second";
-		String third = "third";
-		String fourth = "fourth";
-		String fifth = "fifth";
-
-		Object factory = ObjectTools.get(stack, "nodeFactory");
-
-		this.verifyNodeCache(0, factory);
-		stack.push(first);
-		this.verifyNodeCache(0, factory);
-		stack.push(second);
-		stack.push(third);
-		stack.push(fourth);
-		stack.push(fifth);
-		this.verifyNodeCache(0, factory);
-		assertNull(ObjectTools.get(factory, "cacheHead"));
-
-		stack.pop();
-		this.verifyNodeCache(1, factory);
-		stack.pop();
-		this.verifyNodeCache(2, factory);
-		stack.pop();
-		this.verifyNodeCache(2, factory);
-		stack.pop();
-		this.verifyNodeCache(2, factory);
-		stack.pop();
-		this.verifyNodeCache(2, factory);
-		stack.push(first);
-		this.verifyNodeCache(1, factory);
-		stack.push(second);
-		this.verifyNodeCache(0, factory);
-		stack.push(third);
-		this.verifyNodeCache(0, factory);
-	}
-
-	public void verifyNodeCache(int size, Object factory) {
-		assertEquals(size, ((Integer) ObjectTools.get(factory, "cacheSize")).intValue());
-		int nodeCount = 0;
-		for (Object node = ObjectTools.get(factory, "cacheHead"); node != null; node = ObjectTools.get(node, "next")) {
-			nodeCount++;
-		}
-		assertEquals(size, nodeCount);
-	}
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListToolsTests.java
index d8045a0..7dd8f7d 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListToolsTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListToolsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -18,11 +18,11 @@
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.ListIterator;
 import java.util.Random;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.Vector;
-import junit.framework.TestCase;
 import org.eclipse.jpt.common.utility.internal.ClassTools;
 import org.eclipse.jpt.common.utility.internal.Range;
 import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
@@ -31,7 +31,10 @@
 import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable;
 import org.eclipse.jpt.common.utility.internal.iterator.EmptyIterator;
 import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
+import org.eclipse.jpt.common.utility.iterable.ListIterable;
 import org.eclipse.jpt.common.utility.tests.internal.ArrayToolsTests;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
 public class ListToolsTests
@@ -40,6 +43,9 @@
 	public ListToolsTests(String name) {
 		super(name);
 	}
+
+	// ********** add all **********
+
 	public void testAddAllListIntObjectArray() {
 		List<String> list = this.buildStringList1();
 		ListTools.addAll(list, 2, new String[] { "X", "X", "X" });
@@ -171,7 +177,7 @@
 
 	// ********** diff **********
 
-	public void testIndexOfDifference() {
+	public void testIndexOfDifference_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -183,7 +189,78 @@
 		assertEquals(3, ListTools.indexOfDifference(list1, list2));
 	}
 
-	public void testLastIndexOfDifference() {
+	public void testIndexOfDifference_none_null() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add(null);
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(null);
+		list2.add(new String("c"));
+		assertEquals(3, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testIndexOfDifference_first() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("b"));
+		list2.add(new String("c"));
+		assertEquals(0, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testIndexOfDifference_middle() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("X"));
+		list2.add(new String("c"));
+		assertEquals(1, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testIndexOfDifference_middle_null() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add(null);
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("X"));
+		list2.add(new String("c"));
+		assertEquals(1, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testIndexOfDifference_last() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("b"));
+		list2.add(new String("X"));
+		assertEquals(2, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testIndexOfDifference_last_size() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("b"));
+		assertEquals(2, ListTools.indexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -195,7 +272,90 @@
 		assertEquals(-1, ListTools.lastIndexOfDifference(list1, list2));
 	}
 
-	public void testDifferenceRange() {
+	public void testLastIndexOfDifference_none_null() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add(null);
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(null);
+		list2.add(new String("c"));
+		assertEquals(-1, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_first() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("b"));
+		list2.add(new String("X"));
+		assertEquals(2, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_first_size() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("b"));
+		assertEquals(2, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_middle() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("X"));
+		list2.add(new String("c"));
+		assertEquals(1, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_middle_null1() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add(null);
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(new String("b"));
+		list2.add(new String("c"));
+		assertEquals(1, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_middle_null2() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add(null);
+		list2.add(new String("c"));
+		assertEquals(1, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testLastIndexOfDifference_last() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("b"));
+		list2.add(new String("c"));
+		assertEquals(0, ListTools.lastIndexOfDifference(list1, list2));
+	}
+
+	public void testDifferenceRange_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -207,6 +367,42 @@
 		assertNull(ListTools.differenceRange(list1, list2));
 	}
 
+	public void testDifferenceRange_single() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("b"));
+		list2.add(new String("c"));
+		assertEquals(new Range(0, 0), ListTools.differenceRange(list1, list2));
+	}
+
+	public void testDifferenceRange_some() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("Y"));
+		list2.add(new String("c"));
+		assertEquals(new Range(0, 1), ListTools.differenceRange(list1, list2));
+	}
+
+	public void testDifferenceRange_all() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("Y"));
+		list2.add(new String("Z"));
+		assertEquals(new Range(0, 2), ListTools.differenceRange(list1, list2));
+	}
+
 
 	// ********** filter **********
 
@@ -228,7 +424,7 @@
 
 	// ********** identity diff **********
 
-	public void testIndexOfIdentityDifference() {
+	public void testIndexOfIdentityDifference_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -240,7 +436,31 @@
 		assertEquals(3, ListTools.indexOfIdentityDifference(list1, list2));
 	}
 
-	public void testLastIndexOfIdentityDifference() {
+	public void testIndexOfIdentityDifference_zero() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add("b");
+		list2.add("c");
+		assertEquals(0, ListTools.indexOfIdentityDifference(list1, list2));
+	}
+
+	public void testIndexOfIdentityDifference_last() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add("a");
+		list2.add("b");
+		list2.add(new String("c"));
+		assertEquals(2, ListTools.indexOfIdentityDifference(list1, list2));
+	}
+
+	public void testLastIndexOfIdentityDifference_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -252,7 +472,42 @@
 		assertEquals(-1, ListTools.lastIndexOfIdentityDifference(list1, list2));
 	}
 
-	public void testIdentityDifferenceRange() {
+	public void testLastIndexOfIdentityDifference_zero() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("a"));
+		list2.add("b");
+		list2.add("c");
+		assertEquals(0, ListTools.lastIndexOfIdentityDifference(list1, list2));
+	}
+
+	public void testLastIndexOfIdentityDifference_first() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add("a");
+		list2.add("b");
+		list2.add(new String("c"));
+		assertEquals(2, ListTools.lastIndexOfIdentityDifference(list1, list2));
+	}
+
+	public void testLastIndexOfIdentityDifference_size() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add("a");
+		list2.add("b");
+		assertEquals(2, ListTools.lastIndexOfIdentityDifference(list1, list2));
+	}
+
+	public void testIdentityDifferenceRange_none() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("a");
 		list1.add("b");
@@ -264,6 +519,42 @@
 		assertNull(ListTools.identityDifferenceRange(list1, list2));
 	}
 
+	public void testIdentityDifferenceRange_single() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add("b");
+		list2.add("c");
+		assertEquals(new Range(0, 0), ListTools.identityDifferenceRange(list1, list2));
+	}
+
+	public void testIdentityDifferenceRange_some() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("Y"));
+		list2.add("c");
+		assertEquals(new Range(0, 1), ListTools.identityDifferenceRange(list1, list2));
+	}
+
+	public void testIdentityDifferenceRange_all() {
+		List<String> list1 = new ArrayList<String>();
+		list1.add("a");
+		list1.add("b");
+		list1.add("c");
+		List<String> list2 = new ArrayList<String>();
+		list2.add(new String("X"));
+		list2.add(new String("Y"));
+		list2.add(new String("Z"));
+		assertEquals(new Range(0, 2), ListTools.identityDifferenceRange(list1, list2));
+	}
+
 
 	// ********** index of **********
 
@@ -273,6 +564,7 @@
 		assertEquals(1, ListTools.indexOf(list, "B", 1));
 		assertEquals(-1, ListTools.indexOf(list, "B", 2));
 		assertEquals(-1, ListTools.indexOf(list, "B", 22));
+		assertEquals(-1, ListTools.indexOf(new ArrayList<String>(), "B", 1));
 	}
 
 	public void testIndexOfListObjectInt_Null() {
@@ -287,9 +579,12 @@
 		String s = "B";
 		List<String> list = Arrays.asList(new String[] { "A", s, "C", "D" });
 		assertEquals(1, ListTools.identityIndexOf(list, s, -11));
+		assertEquals(1, ListTools.identityIndexOf(list, s, 0));
 		assertEquals(1, ListTools.identityIndexOf(list, s, 1));
 		assertEquals(-1, ListTools.identityIndexOf(list, s, 2));
 		assertEquals(-1, ListTools.identityIndexOf(list, s, 22));
+		assertEquals(-1, ListTools.identityIndexOf(list, s, 4));
+		assertEquals(-1, ListTools.identityIndexOf(new ArrayList<String>(), s, 1));
 	}
 
 	public void testIdentityIndexOfListObjectInt_NotFound() {
@@ -395,7 +690,12 @@
 		assertEquals(-1, ListTools.lastIndexOf(list, "B", -11));
 		assertEquals(1, ListTools.lastIndexOf(list, "B", 1));
 		assertEquals(1, ListTools.lastIndexOf(list, "B", 2));
+		assertEquals(1, ListTools.lastIndexOf(list, "B", 4));
+		assertEquals(-1, ListTools.lastIndexOf(list, null, 4));
 		assertEquals(1, ListTools.lastIndexOf(list, "B", 22));
+		assertEquals(0, ListTools.lastIndexOf(list, "A", 22));
+		assertEquals(-1, ListTools.lastIndexOf(list, "XXXs", 22));
+		assertEquals(-1, ListTools.lastIndexOf(new ArrayList<String>(), "XXXs", 22));
 	}
 
 	public void testLastIndexOfListObjectInt_Null() {
@@ -404,6 +704,8 @@
 		assertEquals(1, ListTools.lastIndexOf(list, null, 1));
 		assertEquals(1, ListTools.lastIndexOf(list, null, 2));
 		assertEquals(1, ListTools.lastIndexOf(list, null, 22));
+		list = Arrays.asList(new String[] { null, "A", "C", "D" });
+		assertEquals(0, ListTools.lastIndexOf(list, null, 22));
 	}
 
 	public void testLastIdentityIndexOfListObjectInt() {
@@ -412,7 +714,9 @@
 		assertEquals(-1, ListTools.lastIdentityIndexOf(list, s, -11));
 		assertEquals(1, ListTools.lastIdentityIndexOf(list, s, 1));
 		assertEquals(1, ListTools.lastIdentityIndexOf(list, s, 2));
+		assertEquals(1, ListTools.lastIdentityIndexOf(list, s, 4));
 		assertEquals(1, ListTools.lastIdentityIndexOf(list, s, 22));
+		assertEquals(-1, ListTools.lastIdentityIndexOf(new ArrayList<String>(), s, 22));
 	}
 
 	public void testLastIdentityIndexOfListObjectInt_NotFound() {
@@ -426,49 +730,49 @@
 	}
 
 
-	// ********** list **********
+	// ********** array list **********
 
-	public void testListIterable() {
+	public void testArrayListIterable() {
 		Iterable<String> iterable = this.buildStringList1();
-		assertEquals(this.buildStringList1(), ListTools.list(iterable));
+		assertEquals(this.buildStringList1(), ListTools.arrayList(iterable));
 	}
 
-	public void testListIterableInt() {
+	public void testArrayListIterableInt() {
 		Iterable<String> iterable = this.buildStringList1();
-		assertEquals(this.buildStringList1(), ListTools.list(iterable, 3));
+		assertEquals(this.buildStringList1(), ListTools.arrayList(iterable, 3));
 	}
 
-	public void testListIterator_String() {
-		List<String> list = ListTools.list(this.buildStringList1().iterator());
+	public void testArrayListIterator_String() {
+		List<String> list = ListTools.arrayList(this.buildStringList1().iterator());
 		assertEquals(this.buildStringList1(), list);
 	}
 
-	public void testListIterator_StringObject() {
+	public void testArrayListIterator_StringObject() {
 		List<String> list1 = new ArrayList<String>();
 		list1.add("0");
 		list1.add("1");
 		list1.add("2");
 		list1.add("3");
 
-		List<Object> list2 = ListTools.<Object>list(list1.iterator());
+		List<Object> list2 = ListTools.<Object>arrayList(list1.iterator());
 		assertEquals(list1, list2);
 	}
 
-	public void testListIterator_Empty() {
-		assertEquals(0, ListTools.list(EmptyIterator.instance()).size());
+	public void testArrayListIterator_Empty() {
+		assertEquals(0, ListTools.arrayList(EmptyIterator.instance()).size());
 	}
 
-	public void testListIteratorInt() {
-		List<String> list = ListTools.list(this.buildStringList1().iterator(), 3);
+	public void testArrayListIteratorInt() {
+		List<String> list = ListTools.arrayList(this.buildStringList1().iterator(), 3);
 		assertEquals(this.buildStringList1(), list);
 	}
 
-	public void testListIteratorInt_Empty() {
-		assertEquals(0, ListTools.list(EmptyIterator.instance(), 5).size());
+	public void testArrayListIteratorInt_Empty() {
+		assertEquals(0, ListTools.arrayList(EmptyIterator.instance(), 5).size());
 	}
 
-	public void testListObjectArray() {
-		List<String> list = ListTools.list(this.buildStringArray1());
+	public void testArrayListObjectArray() {
+		List<String> list = ListTools.arrayList(this.buildStringArray1());
 		assertEquals(this.buildStringList1(), list);
 	}
 
@@ -712,6 +1016,16 @@
 		}
 	}
 
+	public void testReverseList() {
+		List<String> list = this.buildStringList1();
+		List<String> result = ListTools.reverse(list);
+		assertSame(list, result);
+		assertEquals("two", list.get(0));
+		assertEquals("one", list.get(1));
+		assertEquals("zero", list.get(2));
+		assertEquals(3, list.size());
+	}
+
 	public void testShuffleList() {
 		List<String> list = this.buildStringList1();
 		List<String> result = ListTools.shuffle(list);
@@ -730,6 +1044,22 @@
 		ss.addAll(list);
 		List<String> result = ListTools.sort(list);
 		assertSame(list, result);
+		Iterator<String> ssIterator = ss.iterator();
+		for (Iterator<String> listIterator = list.iterator(); listIterator.hasNext(); ) {
+			assertEquals(ssIterator.next(), listIterator.next());
+		}
+	}
+
+	public void testSortListComparator() {
+		List<String> list = this.buildStringList1();
+		SortedSet<String> ss = new TreeSet<String>(ComparatorTools.<String>reverseComparator());
+		ss.addAll(list);
+		List<String> result = ListTools.sort(list, ComparatorTools.<String>reverseComparator());
+		assertSame(list, result);
+		Iterator<String> ssIterator = ss.iterator();
+		for (Iterator<String> listIterator = list.iterator(); listIterator.hasNext(); ) {
+			assertEquals(ssIterator.next(), listIterator.next());
+		}
 	}
 
 	public void testSwapListIntInt() {
@@ -743,6 +1073,87 @@
 	}
 
 
+	// ********** transformers **********
+
+	public void testListIteratorTransformer() {
+		Transformer<List<String>, ListIterator<String>> transformer = ListTools.listIteratorTransformer();
+		assertNotNull(transformer);
+		assertNotNull(transformer.toString());
+		List<String> list = this.buildStringList1();
+		ListIterator<String> iterator = transformer.transform(list);
+		assertNotNull(iterator);
+		assertEquals("zero", iterator.next());
+		assertEquals("one", iterator.next());
+		iterator.set("XXX");
+		assertEquals("two", iterator.next());
+		assertFalse(iterator.hasNext());
+		assertEquals("XXX", list.get(1));
+	}
+
+	public void testReadOnlyListIteratorTransformer() {
+		Transformer<List<? extends String>, ListIterator<String>> transformer = ListTools.readOnlyListIteratorTransformer();
+		assertNotNull(transformer);
+		assertNotNull(transformer.toString());
+		List<String> list = this.buildStringList1();
+		ListIterator<String> iterator = transformer.transform(list);
+		assertNotNull(iterator);
+		assertEquals("zero", iterator.next());
+		assertEquals("one", iterator.next());
+
+		boolean exCaught = false;
+		try {
+			iterator.set("XXX");
+			fail("bogus: " + iterator); //$NON-NLS-1$
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("two", iterator.next());
+		assertFalse(iterator.hasNext());
+		assertEquals("one", list.get(1));
+	}
+
+	public void testListIterableTransformer() {
+		Transformer<List<String>, ListIterable<String>> transformer = ListTools.listIterableTransformer();
+		assertNotNull(transformer);
+		assertNotNull(transformer.toString());
+		List<String> list = this.buildStringList1();
+		ListIterator<String> iterator = transformer.transform(list).iterator();
+		assertNotNull(iterator);
+		assertEquals("zero", iterator.next());
+		assertEquals("one", iterator.next());
+		iterator.set("XXX");
+		assertEquals("two", iterator.next());
+		assertFalse(iterator.hasNext());
+		assertEquals("XXX", list.get(1));
+	}
+
+	public void testReadOnlyListIterableTransformer() {
+		Transformer<List<? extends String>, ListIterable<String>> transformer = ListTools.readOnlyListIterableTransformer();
+		assertNotNull(transformer);
+		assertNotNull(transformer.toString());
+		List<String> list = this.buildStringList1();
+		ListIterator<String> iterator = transformer.transform(list).iterator();
+		assertNotNull(iterator);
+		assertEquals("zero", iterator.next());
+		assertEquals("one", iterator.next());
+
+		boolean exCaught = false;
+		try {
+			iterator.set("XXX");
+			fail("bogus: " + iterator); //$NON-NLS-1$
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("two", iterator.next());
+		assertFalse(iterator.hasNext());
+		assertEquals("one", list.get(1));
+	}
+
+
 	// ********** constructor **********
 
 	public void testConstructor() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/MapToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/MapToolsTests.java
index 03ec8d9..f257662 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/MapToolsTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/MapToolsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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.
@@ -9,24 +9,26 @@
  ******************************************************************************/
 package org.eclipse.jpt.common.utility.tests.internal.collection;
 
+import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import junit.framework.TestCase;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.factory.Factory;
 import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
 import org.eclipse.jpt.common.utility.internal.StringTools;
 import org.eclipse.jpt.common.utility.internal.collection.MapTools;
-import org.eclipse.jpt.common.utility.internal.collection.QueueTools;
-import org.eclipse.jpt.common.utility.internal.collection.StackTools;
 import org.eclipse.jpt.common.utility.internal.factory.FactoryTools;
 import org.eclipse.jpt.common.utility.internal.predicate.PredicateAdapter;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
 import org.eclipse.jpt.common.utility.internal.transformer.AbstractTransformer;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
 import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
 public class MapToolsTests
@@ -45,6 +47,15 @@
 		assertEquals(null, MapTools.get(map, "7", ""));
 	}
 
+	public void testGet_MapObjectObject() {
+		Map<String, String> map = this.buildMap();
+		assertEquals("one", MapTools.get_(map, "1", ""));
+		assertEquals("", MapTools.get_(map, "7", ""));
+		assertEquals("", map.get("7"));
+		map.put("7", null);
+		assertEquals("", MapTools.get_(map, "7", ""));
+	}
+
 	public void testGetMapObjectFactory() {
 		Factory<String> factory = FactoryTools.staticFactory("");
 		Map<String, String> map = this.buildMap();
@@ -55,6 +66,16 @@
 		assertEquals(null, MapTools.get(map, "7", factory));
 	}
 
+	public void testGet_MapObjectFactory() {
+		Factory<String> factory = FactoryTools.staticFactory("");
+		Map<String, String> map = this.buildMap();
+		assertEquals("one", MapTools.get_(map, "1", factory));
+		assertEquals("", MapTools.get_(map, "7", factory));
+		assertEquals("", map.get("7"));
+		map.put("7", null);
+		assertEquals("", MapTools.get_(map, "7", factory));
+	}
+
 	@SuppressWarnings("unchecked")
 	public void testGetMapObjectClass() {
 		ArrayList<String> list = new ArrayList<String>();
@@ -65,6 +86,36 @@
 		assertEquals(null, MapTools.get(map, "7", ArrayList.class));
 	}
 
+	@SuppressWarnings("unchecked")
+	public void testGet_MapObjectClass() {
+		ArrayList<String> list = new ArrayList<String>();
+		Map<String, ArrayList<String>> map = this.buildListMap();
+		assertEquals(list, MapTools.get_(map, "1", ArrayList.class));
+		assertEquals(list, MapTools.get_(map, "7", ArrayList.class));
+		map.put("7", null);
+		assertEquals(list, MapTools.get_(map, "7", ArrayList.class));
+	}
+
+	@SuppressWarnings("unchecked")
+	public void testGetMapObjectClassClassObject() {
+		ArrayList<String> list = new ArrayList<String>();
+		Map<String, ArrayList<String>> map = this.buildListMap();
+		assertEquals(list, MapTools.get(map, "1", ArrayList.class, Collection.class, new ArrayList<String>()));
+		assertEquals(list, MapTools.get(map, "7", ArrayList.class, Collection.class, new ArrayList<String>()));
+		map.put("7", null);
+		assertEquals(null, MapTools.get(map, "7", ArrayList.class, Collection.class, new ArrayList<String>()));
+	}
+
+	@SuppressWarnings("unchecked")
+	public void testGet_MapObjectClassClassObject() {
+		ArrayList<String> list = new ArrayList<String>();
+		Map<String, ArrayList<String>> map = this.buildListMap();
+		assertEquals(list, MapTools.get_(map, "1", ArrayList.class, Collection.class, new ArrayList<String>()));
+		assertEquals(list, MapTools.get_(map, "7", ArrayList.class, Collection.class, new ArrayList<String>()));
+		map.put("7", null);
+		assertEquals(new ArrayList<String>(), MapTools.get_(map, "7", ArrayList.class, Collection.class, new ArrayList<String>()));
+	}
+
 	public void testAddMapObjectTransformer() {
 		Map<String, String> map = new HashMap<String, String>();
 		assertEquals(null, MapTools.add(map, "one", REVERSE_STRING_TRANSFORMER));
@@ -96,7 +147,7 @@
 		strings.add("baz");
 		Queue<String> queue = QueueTools.arrayQueue(strings);
 		Map<String, String> map = new HashMap<String, String>();
-		MapTools.addAll(map, queue, REVERSE_STRING_TRANSFORMER);
+		QueueTools.drainTo(queue, map, REVERSE_STRING_TRANSFORMER);
 		assertEquals("foo", map.get("oof"));
 		assertEquals("bar", map.get("rab"));
 		assertEquals("baz", map.get("zab"));
@@ -109,7 +160,7 @@
 		strings.add("baz");
 		Stack<String> stack = StackTools.arrayStack(strings);
 		Map<String, String> map = new HashMap<String, String>();
-		MapTools.addAll(map, stack, REVERSE_STRING_TRANSFORMER);
+		StackTools.popAllTo(stack, map, REVERSE_STRING_TRANSFORMER);
 		assertEquals("foo", map.get("oof"));
 		assertEquals("bar", map.get("rab"));
 		assertEquals("baz", map.get("zab"));
@@ -142,7 +193,7 @@
 		strings.add("baz");
 		Queue<String> queue = QueueTools.arrayQueue(strings);
 		Map<String, String> map = new HashMap<String, String>();
-		MapTools.addAll(map, queue, REVERSE_STRING_TRANSFORMER, SORT_STRING_TRANSFORMER);
+		QueueTools.drainTo(queue, map, REVERSE_STRING_TRANSFORMER, SORT_STRING_TRANSFORMER);
 		assertEquals("foo", map.get("oof"));
 		assertEquals("abr", map.get("rab"));
 		assertEquals("abz", map.get("zab"));
@@ -155,7 +206,7 @@
 		strings.add("baz");
 		Stack<String> stack = StackTools.arrayStack(strings);
 		Map<String, String> map = new HashMap<String, String>();
-		MapTools.addAll(map, stack, REVERSE_STRING_TRANSFORMER, SORT_STRING_TRANSFORMER);
+		StackTools.popAllTo(stack, map, REVERSE_STRING_TRANSFORMER, SORT_STRING_TRANSFORMER);
 		assertEquals("foo", map.get("oof"));
 		assertEquals("abr", map.get("rab"));
 		assertEquals("abz", map.get("zab"));
@@ -175,12 +226,40 @@
 		assertEquals(this.buildMap(), map);
 	}
 
+	public void testPutAllMapListList_IAE() {
+		Map<String, String> map = new HashMap<String, String>();
+		boolean exCaught = false;
+		try {
+			List<String> values = this.buildValues();
+			values.remove(0);
+			MapTools.putAll(map, this.buildKeys(), values);
+			fail("bogus: " + map);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testPutAllMapArrayArray() {
 		Map<String, String> map = new HashMap<String, String>();
 		MapTools.putAll(map, this.buildKeys().toArray(StringTools.EMPTY_STRING_ARRAY), this.buildValues().toArray(StringTools.EMPTY_STRING_ARRAY));
 		assertEquals(this.buildMap(), map);
 	}
 
+	public void testPutAllMapArrayArray_IAE() {
+		Map<String, String> map = new HashMap<String, String>();
+		boolean exCaught = false;
+		try {
+			String[] values = this.buildValues().toArray(StringTools.EMPTY_STRING_ARRAY);
+			values = ArrayTools.removeElementAtIndex(values, 0);
+			MapTools.putAll(map, this.buildKeys().toArray(StringTools.EMPTY_STRING_ARRAY), values);
+			fail("bogus: " + map);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
 	public void testContainsAllKeysMapIterable() {
 		Map<String, String> map = this.buildMap();
 		Iterable<String> keys = this.buildKeys();
@@ -197,24 +276,6 @@
 		assertFalse(MapTools.containsAllKeys(map, (Object[]) keys));
 	}
 
-	public void testContainsAllKeysMapQueue() {
-		Map<String, String> map = this.buildMap();
-		Queue<String> keys = QueueTools.arrayQueue(this.buildKeys());
-		assertTrue(MapTools.containsAllKeys(map, keys));
-		map.remove("1");
-		keys = QueueTools.arrayQueue(this.buildKeys()); // rebuild queue
-		assertFalse(MapTools.containsAllKeys(map, keys));
-	}
-
-	public void testContainsAllKeysMapStack() {
-		Map<String, String> map = this.buildMap();
-		Stack<String> keys = StackTools.arrayStack(this.buildKeys());
-		assertTrue(MapTools.containsAllKeys(map, keys));
-		map.remove("1");
-		keys = StackTools.arrayStack(this.buildKeys()); // rebuild stack
-		assertFalse(MapTools.containsAllKeys(map, keys));
-	}
-
 	public void testContainsAllValuesMapIterable() {
 		Map<String, String> map = this.buildMap();
 		Iterable<String> values = this.buildValues();
@@ -231,24 +292,6 @@
 		assertFalse(MapTools.containsAllValues(map, (Object[]) values));
 	}
 
-	public void testContainsAllValuesMapQueue() {
-		Map<String, String> map = this.buildMap();
-		Queue<String> values = QueueTools.arrayQueue(this.buildValues());
-		assertTrue(MapTools.containsAllValues(map, values));
-		map.remove("1");
-		values = QueueTools.arrayQueue(this.buildValues()); // rebuild queue
-		assertFalse(MapTools.containsAllValues(map, values));
-	}
-
-	public void testContainsAllValuesMapStack() {
-		Map<String, String> map = this.buildMap();
-		Stack<String> values = StackTools.arrayStack(this.buildValues());
-		assertTrue(MapTools.containsAllValues(map, values));
-		map.remove("1");
-		values = StackTools.arrayStack(this.buildValues()); // rebuild stack
-		assertFalse(MapTools.containsAllValues(map, values));
-	}
-
 	public void testRemoveAllMapIterable() {
 		Map<String, String> map = this.buildMap();
 		Iterable<String> keys = this.buildKeys();
@@ -265,22 +308,6 @@
 		assertTrue(map.isEmpty());
 	}
 
-	public void testRemoveAllMapQueue() {
-		Map<String, String> map = this.buildMap();
-		Queue<String> keys = QueueTools.arrayQueue(this.buildKeys());
-		assertFalse(map.isEmpty());
-		MapTools.removeAll(map, keys);
-		assertTrue(map.isEmpty());
-	}
-
-	public void testRemoveAllMapStack() {
-		Map<String, String> map = this.buildMap();
-		Stack<String> keys = StackTools.arrayStack(this.buildKeys());
-		assertFalse(map.isEmpty());
-		MapTools.removeAll(map, keys);
-		assertTrue(map.isEmpty());
-	}
-
 	public void testRetainAllMapCollection() {
 		Map<String, String> map = this.buildMap();
 		Collection<String> keys = this.buildKeys();
@@ -321,6 +348,27 @@
 		assertTrue(map.isEmpty());
 	}
 
+	public void testRetainAllMapIterableInt() {
+		Map<String, String> map = this.buildMap();
+		Iterable<String> keys = this.buildKeys();
+		assertFalse(map.isEmpty());
+		MapTools.retainAll(map, keys, 77);
+		assertEquals(this.buildMap(), map);
+		Collection<String> temp = this.buildKeys();
+		temp.remove("3");
+		keys = temp;
+		MapTools.retainAll(map, keys);
+		assertFalse(map.containsKey("3"));
+	}
+
+	public void testRetainAllMapIterableInt_empty() {
+		Map<String, String> map = this.buildMap();
+		Iterable<String> keys = new ArrayList<String>();
+		assertFalse(map.isEmpty());
+		MapTools.retainAll(map, keys, 77);
+		assertTrue(map.isEmpty());
+	}
+
 	public void testRetainAllMapArray() {
 		Map<String, String> map = this.buildMap();
 		String[] keys = this.buildKeys().toArray(StringTools.EMPTY_STRING_ARRAY);
@@ -340,48 +388,6 @@
 		assertTrue(map.isEmpty());
 	}
 
-	public void testRetainAllMapQueue() {
-		Map<String, String> map = this.buildMap();
-		Queue<String> keys = QueueTools.arrayQueue(this.buildKeys());
-		assertFalse(map.isEmpty());
-		MapTools.retainAll(map, keys);
-		assertEquals(this.buildMap(), map);
-		Collection<String> temp = this.buildKeys();
-		temp.remove("3");
-		keys = QueueTools.arrayQueue(temp);
-		MapTools.retainAll(map, keys);
-		assertFalse(map.containsKey("3"));
-	}
-
-	public void testRetainAllMapQueue_empty() {
-		Map<String, String> map = this.buildMap();
-		Queue<String> keys = QueueTools.emptyQueue();
-		assertFalse(map.isEmpty());
-		MapTools.retainAll(map, keys);
-		assertTrue(map.isEmpty());
-	}
-
-	public void testRetainAllMapStack() {
-		Map<String, String> map = this.buildMap();
-		Stack<String> keys = StackTools.arrayStack(this.buildKeys());
-		assertFalse(map.isEmpty());
-		MapTools.retainAll(map, keys);
-		assertEquals(this.buildMap(), map);
-		Collection<String> temp = this.buildKeys();
-		temp.remove("3");
-		keys = StackTools.arrayStack(temp);
-		MapTools.retainAll(map, keys);
-		assertFalse(map.containsKey("3"));
-	}
-
-	public void testRetainAllMapStack_empty() {
-		Map<String, String> map = this.buildMap();
-		Stack<String> keys = StackTools.emptyStack();
-		assertFalse(map.isEmpty());
-		MapTools.retainAll(map, keys);
-		assertTrue(map.isEmpty());
-	}
-
 	public void testInvertMap() {
 		Map<String, String> map = this.buildMap();
 		map = MapTools.invert(map);
@@ -415,6 +421,21 @@
 		assertEquals("ruof", map.get("4"));
 	}
 
+	public void testConstructor() {
+		boolean exCaught = false;
+		try {
+			Object at = ClassTools.newInstance(MapTools.class);
+			fail("bogus: " + at); //$NON-NLS-1$
+		} catch (RuntimeException ex) {
+			if (ex.getCause() instanceof InvocationTargetException) {
+				if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+					exCaught = true;
+				}
+			}
+		}
+		assertTrue(exCaught);
+	}
+
 	private List<String> buildKeys() {
 		ArrayList<String> keys = new ArrayList<String>();
 		keys.add("0");
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/NullListTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/NullListTests.java
new file mode 100644
index 0000000..33c3397
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/NullListTests.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.collection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.ListIterator;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.collection.NullList;
+import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class NullListTests
+	extends TestCase
+{
+	public NullListTests(String name) {
+		super(name);
+	}
+
+	public void testAddObject() {
+		List<String> list = NullList.<String>instance();
+		assertFalse(list.add("foo"));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testAddIntObject() {
+		List<String> list = NullList.<String>instance();
+		list.add(0, "foo");
+		assertTrue(list.isEmpty());
+	}
+
+	public void testAddAllCollection() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.addAll(collection));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testAddAllIntCollection() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.addAll(0, collection));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testClear() {
+		List<String> list = NullList.<String>instance();
+		list.clear();
+		assertTrue(list.isEmpty());
+	}
+
+	public void testContainsObject() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.addAll(collection));
+		assertFalse(list.contains("foo"));
+		assertFalse(list.contains("bar"));
+		assertFalse(list.contains("XXX"));
+	}
+
+	public void testContainsAllCollection() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.addAll(collection));
+		assertFalse(list.containsAll(collection));
+		collection.clear();
+		assertTrue(list.containsAll(collection));
+	}
+
+	public void testGetInt() {
+		List<String> list = NullList.<String>instance();
+		boolean exCaught = false;
+		try {
+			list.get(0);
+			fail();
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIndexOfObject() {
+		List<String> list = NullList.<String>instance();
+		assertEquals(-1, list.indexOf("foo"));
+	}
+
+	public void testIsEmpty() {
+		List<String> list = NullList.<String>instance();
+		assertTrue(list.isEmpty());
+	}
+
+	public void testIterator() {
+		List<String> list = NullList.<String>instance();
+		assertTrue(IteratorTools.isEmpty(list.iterator()));
+	}
+
+	public void testLastIndexOfObject() {
+		List<String> list = NullList.<String>instance();
+		assertEquals(-1, list.lastIndexOf("foo"));
+	}
+
+	public void testListIterator() {
+		List<String> list = NullList.<String>instance();
+		assertTrue(IteratorTools.isEmpty(list.listIterator()));
+	}
+
+	public void testListIteratorInt() {
+		List<String> list = NullList.<String>instance();
+		ListIterator<String> iterator = list.listIterator(0);
+		assertTrue(IteratorTools.isEmpty(iterator));
+		boolean exCaught = false;
+		try {
+			iterator = list.listIterator(1);
+			fail("bogus list iterator: " + iterator);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testRemoveObject() {
+		List<String> list = NullList.<String>instance();
+		assertFalse(list.remove("foo"));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testRemoveInt() {
+		List<String> list = NullList.<String>instance();
+		boolean exCaught = false;
+		try {
+			String object = list.remove(0);
+			fail("bogus element: " + object);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+		assertTrue(list.isEmpty());
+	}
+
+	public void testRemoveAllCollection() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.removeAll(collection));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testRetainAllCollection() {
+		List<String> list = NullList.<String>instance();
+		Collection<String> collection = new ArrayList<String>();
+		collection.add("foo");
+		collection.add("bar");
+		assertFalse(list.retainAll(collection));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testSetIntObject() {
+		List<String> list = NullList.<String>instance();
+		boolean exCaught = false;
+		try {
+			String element = list.set(0, "foo");
+			fail("bogus set: " + element);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSize() {
+		List<String> list = NullList.<String>instance();
+		assertEquals(0, list.size());
+	}
+
+	public void testSubList() {
+		List<String> list = NullList.<String>instance();
+		List<String> subList = list.subList(0, 0);
+		assertTrue(subList.isEmpty());
+		boolean exCaught = false;
+		try {
+			subList = list.subList(0, 3);
+			fail("bogus sub list: " + subList);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			subList = list.subList(3, 0);
+			fail("bogus sub list: " + subList);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		exCaught = false;
+		try {
+			subList = list.subList(3, 3);
+			fail("bogus sub list: " + subList);
+		} catch (IndexOutOfBoundsException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		subList = list.subList(0, 0);
+		assertTrue(subList.isEmpty());
+	}
+
+	public void testToArray() {
+		List<String> list = NullList.<String>instance();
+		assertEquals(0, list.toArray().length);
+	}
+
+	public void testToArrayObjectArray() {
+		List<String> list = NullList.<String>instance();
+		assertEquals(0, list.toArray(ObjectTools.EMPTY_OBJECT_ARRAY).length);
+	}
+
+	public void testSerialization() throws Exception {
+		List<String> list = NullList.<String>instance();
+		assertSame(list, TestTools.serialize(list));
+	}
+
+	public void testToString() {
+		List<String> list = NullList.<String>instance();
+		assertEquals("[]", list.toString());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedBagTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedBagTests.java
new file mode 100644
index 0000000..011315b
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedBagTests.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.tests.internal.collection;
+
+import java.util.Collection;
+import org.eclipse.jpt.common.utility.collection.Bag;
+import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
+import org.eclipse.jpt.common.utility.internal.collection.HashBag;
+
+@SuppressWarnings("nls")
+public class SynchronizedBagTests
+	extends BagTests
+{
+	public SynchronizedBagTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected Bag<String> buildBag_() {
+		return CollectionTools.synchronizedBag();
+	}
+
+	@Override
+	protected Bag<String> buildBag(Collection<String> c) {
+		return CollectionTools.synchronizedBag(new HashBag<String>(c));
+	}
+
+	@Override
+	protected Bag<String> buildBag(int initialCapacity, float loadFactor) {
+		return CollectionTools.synchronizedBag(new HashBag<String>(initialCapacity, loadFactor));
+	}
+
+	@Override
+	public void testClone() {
+		// synchronized bag is not cloneable
+	}
+
+	public void testCtorBagObject_nullBag() {
+		boolean exCaught = false;
+		try {
+			Bag<String> bag = CollectionTools.synchronizedBag(null, "foo");
+			fail("bogus bag: " + bag);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testCtorBagObject_nullMutex() {
+		Bag<String> wrapped = CollectionTools.hashBag();
+		boolean exCaught = false;
+		try {
+			Bag<String> bag = CollectionTools.synchronizedBag(wrapped, null);
+			fail("bogus bag: " + bag);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testCtorBag_nullBag() {
+		boolean exCaught = false;
+		try {
+			Bag<String> bag = CollectionTools.synchronizedBag(null);
+			fail("bogus bag: " + bag);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedQueueTests.java
deleted file mode 100644
index 1973b5a..0000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedQueueTests.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009, 2012 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.tests.internal.collection;
-
-import java.util.NoSuchElementException;
-
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedQueue;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedQueue;
-
-@SuppressWarnings("nls")
-public class SynchronizedQueueTests
-	extends QueueTests
-{
-	private volatile SynchronizedQueue<String> sq;
-	volatile boolean timeoutOccurred;
-	volatile long startTime;
-	volatile long endTime;
-	volatile Object dequeuedObject;
-
-	static final String ITEM_1 = new String();
-	static final String ITEM_2 = new String();
-
-	public SynchronizedQueueTests(String name) {
-		super(name);
-	}
-
-	@Override
-	Queue<String> buildQueue() {
-		return new SynchronizedQueue<String>();
-	}
-
-	@Override
-	public void testClone() {
-		// synchronized queue is not cloneable
-	}
-
-	@Override
-	protected void setUp() throws Exception {
-		super.setUp();
-		this.sq = new SynchronizedQueue<String>();
-		this.timeoutOccurred = false;
-		this.startTime = 0;
-		this.endTime = 0;
-		this.dequeuedObject = null;
-	}
-
-	/**
-	 * test first with an unsynchronized queue,
-	 * then with a synchronized queue
-	 */
-	public void testConcurrentAccess() throws Exception {
-		this.verifyConcurrentAccess(new SlowLinkedQueue<String>(), "first");
-		this.verifyConcurrentAccess(new SlowSynchronizedQueue<String>(), "second");
-	}
-
-	private void verifyConcurrentAccess(SlowQueue<String> slowQueue, String expected) throws Exception {
-		slowQueue.enqueue("first");
-		slowQueue.enqueue("second");
-
-		Thread thread = this.buildThread(this.buildRunnable(slowQueue));
-		thread.start();
-		Thread.sleep(TWO_TICKS);
-
-		assertEquals(expected, slowQueue.dequeue());
-		thread.join();
-		assertTrue(slowQueue.isEmpty());
-	}
-
-	private Runnable buildRunnable(final SlowQueue<String> slowQueue) {
-		return new Runnable() {
-			public void run() {
-				slowQueue.slowDequeue();
-			}
-		};
-	}
-
-
-	private interface SlowQueue<E> extends Queue<E> {
-		Object slowDequeue();
-	}
-
-	private class SlowLinkedQueue<E> extends LinkedQueue<E> implements SlowQueue<E> {
-		private static final long serialVersionUID = 1L;
-		SlowLinkedQueue() {
-			super();
-		}
-		public Object slowDequeue() {
-			try {
-				Thread.sleep(5 * TICK);
-			} catch (InterruptedException ex) {
-				throw new RuntimeException(ex);
-			}
-			return this.dequeue();
-		}
-
-	}
-
-	private class SlowSynchronizedQueue<E> extends SynchronizedQueue<E> implements SlowQueue<E> {
-		private static final long serialVersionUID = 1L;
-		SlowSynchronizedQueue() {
-			super();
-		}
-		public synchronized Object slowDequeue() {
-			try {
-				Thread.sleep(5 * TICK);
-			} catch (InterruptedException ex) {
-				throw new RuntimeException(ex);
-			}
-			return this.dequeue();
-		}
-
-	}
-
-
-	// ********** waits **********
-
-	public void testWaitToDequeue() throws Exception {
-		this.verifyWaitToDequeue(0);
-		// no timeout occurs...
-		assertFalse(this.timeoutOccurred);
-		// ...and an item should have been dequeued by t2...
-		assertSame(ITEM_1, this.dequeuedObject);
-		// ...and the queue should be empty
-		assertTrue(this.sq.isEmpty());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() > TICK);
-	}
-
-	public void testWaitToDequeueTimeout() throws Exception {
-		this.verifyWaitToDequeue(TICK);
-		// timeout occurs...
-		assertTrue(this.timeoutOccurred);
-		// ...and the queue was never dequeued...
-		assertNull(this.dequeuedObject);
-		// ...and it still holds the item
-		assertSame(ITEM_1, this.sq.peek());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
-	}
-
-	private void verifyWaitToDequeue(long timeout) throws Exception {
-		Runnable r1 = this.buildRunnable(this.buildEnqueueCommand(), this.sq, TWO_TICKS);
-		Runnable r2 = this.buildRunnable(this.buildWaitToDequeueCommand(timeout), this.sq, 0);
-		Thread t1 = this.buildThread(r1);
-		Thread t2 = this.buildThread(r2);
-		t1.start();
-		t2.start();
-		t1.join();
-		t2.join();
-	}
-
-	public void testWaitToEnqueue() throws Exception {
-		this.verifyWaitToEnqueue(0);
-		// no timeout occurs...
-		assertFalse(this.timeoutOccurred);
-		// ...and the queue gets dequeued by t1...
-		assertSame(ITEM_1, this.dequeuedObject);
-		// ...and an item is enqueued on to the queue by t2
-		assertFalse(this.sq.isEmpty());
-		assertSame(ITEM_2, this.sq.peek());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() > TICK);
-	}
-
-	public void testWaitToEnqueueTimeout() throws Exception {
-		this.verifyWaitToEnqueue(TICK);
-		// timeout occurs...
-		assertTrue(this.timeoutOccurred);
-		// ...and the queue is eventually dequeued by t1...
-		assertSame(ITEM_1, this.dequeuedObject);
-		// ...but nothing is enqueued on to the queue by t2
-		assertTrue(this.sq.isEmpty());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
-	}
-
-	private void verifyWaitToEnqueue(long timeout) throws Exception {
-		this.sq.enqueue(ITEM_1);
-		Runnable r1 = this.buildRunnable(this.buildDequeueCommand(), this.sq, TWO_TICKS);
-		Runnable r2 = this.buildRunnable(this.buildWaitToEnqueueCommand(timeout), this.sq, 0);
-		Thread t1 = this.buildThread(r1);
-		Thread t2 = this.buildThread(r2);
-		t1.start();
-		t2.start();
-		t1.join();
-		t2.join();
-	}
-
-	private Command buildEnqueueCommand() {
-		return new Command() {
-			public void execute(SynchronizedQueue<String> synchronizedQueue) {
-				synchronizedQueue.enqueue(ITEM_1);
-			}
-		};
-	}
-
-	private Command buildWaitToDequeueCommand(final long timeout) {
-		return new Command() {
-			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
-				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
-				try {
-					SynchronizedQueueTests.this.dequeuedObject = synchronizedQueue.waitToDequeue(timeout);
-				} catch (NoSuchElementException ex) {
-					SynchronizedQueueTests.this.timeoutOccurred = true;
-				}
-				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
-			}
-		};
-	}
-
-	private Command buildDequeueCommand() {
-		return new Command() {
-			public void execute(SynchronizedQueue<String> synchronizedQueue) {
-				SynchronizedQueueTests.this.dequeuedObject = synchronizedQueue.dequeue();
-			}
-		};
-	}
-
-	private Command buildWaitToEnqueueCommand(final long timeout) {
-		return new Command() {
-			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
-				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
-				SynchronizedQueueTests.this.timeoutOccurred = ! synchronizedQueue.waitToEnqueue(ITEM_2, timeout);
-				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
-			}
-		};
-	}
-
-	private Runnable buildRunnable(final Command command, final SynchronizedQueue<String> synchronizedQueue, final long sleep) {
-		return new TestRunnable() {
-			@Override
-			protected void run_() throws Throwable {
-				if (sleep != 0) {
-					Thread.sleep(sleep);
-				}
-				command.execute(synchronizedQueue);
-			}
-		};
-	}
-
-	long calculateElapsedTime() {
-		return this.endTime - this.startTime;
-	}
-
-
-	// ********** Command interface **********
-
-	private interface Command {
-		void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException;
-	}
-
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedStackTests.java
deleted file mode 100644
index a0a923e..0000000
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/SynchronizedStackTests.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2007, 2012 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.tests.internal.collection;
-
-import java.util.EmptyStackException;
-
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedStack;
-import org.eclipse.jpt.common.utility.internal.collection.SynchronizedStack;
-
-@SuppressWarnings("nls")
-public class SynchronizedStackTests
-	extends StackTests
-{
-	private volatile SynchronizedStack<String> ss;
-	volatile boolean timeoutOccurred;
-	volatile long startTime;
-	volatile long endTime;
-	volatile Object poppedObject;
-
-	static final String ITEM_1 = new String();
-	static final String ITEM_2 = new String();
-
-	public SynchronizedStackTests(String name) {
-		super(name);
-	}
-
-	@Override
-	Stack<String> buildStack() {
-		return new SynchronizedStack<String>();
-	}
-
-	@Override
-	public void testClone() {
-		// synchronized stack is not cloneable
-	}
-
-	@Override
-	protected void setUp() throws Exception {
-		super.setUp();
-		this.ss = new SynchronizedStack<String>();
-		this.timeoutOccurred = false;
-		this.startTime = 0;
-		this.endTime = 0;
-		this.poppedObject = null;
-	}
-
-	/**
-	 * test first with an unsynchronized stack,
-	 * then with a synchronized stack
-	 */
-	public void testConcurrentAccess() throws Exception {
-		this.verifyConcurrentAccess(new SlowLinkedStack<String>(), "second");
-		this.verifyConcurrentAccess(new SlowSynchronizedStack<String>(), "first");
-	}
-
-	private void verifyConcurrentAccess(SlowStack<String> slowStack, String expected) throws Exception {
-		slowStack.push("first");
-		slowStack.push("second");
-
-		Thread thread = this.buildThread(this.buildRunnable(slowStack));
-		thread.start();
-		Thread.sleep(TWO_TICKS);
-
-		assertEquals(expected, slowStack.pop());
-		thread.join();
-		assertTrue(slowStack.isEmpty());
-	}
-
-	private Runnable buildRunnable(final SlowStack<String> slowStack) {
-		return new Runnable() {
-			public void run() {
-				slowStack.slowPop();
-			}
-		};
-	}
-
-
-	private interface SlowStack<E> extends Stack<E> {
-		Object slowPop();
-	}
-
-	private class SlowLinkedStack<E> extends LinkedStack<E> implements SlowStack<E> {
-		private static final long serialVersionUID = 1L;
-		SlowLinkedStack() {
-			super();
-		}
-		public Object slowPop() {
-			try {
-				Thread.sleep(5 * TICK);
-			} catch (InterruptedException ex) {
-				throw new RuntimeException(ex);
-			}
-			return this.pop();
-		}
-
-	}
-
-	private class SlowSynchronizedStack<E> extends SynchronizedStack<E> implements SlowStack<E> {
-		private static final long serialVersionUID = 1L;
-		SlowSynchronizedStack() {
-			super();
-		}
-		public synchronized Object slowPop() {
-			try {
-				Thread.sleep(5 * TICK);
-			} catch (InterruptedException ex) {
-				throw new RuntimeException(ex);
-			}
-			return this.pop();
-		}
-
-	}
-
-
-	// ********** waits **********
-
-	public void testWaitToPop() throws Exception {
-		this.verifyWaitToPop(0);
-		// no timeout occurs...
-		assertFalse(this.timeoutOccurred);
-		// ...and an item should have been popped by t2...
-		assertSame(ITEM_1, this.poppedObject);
-		// ...and the stack should be empty
-		assertTrue(this.ss.isEmpty());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() > TICK);
-	}
-
-	public void testWaitToPopTimeout() throws Exception {
-		this.verifyWaitToPop(TICK);
-		// timeout occurs...
-		assertTrue(this.timeoutOccurred);
-		// ...and the stack was never popped...
-		assertNull(this.poppedObject);
-		// ...and it still holds the item
-		assertSame(ITEM_1, this.ss.peek());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
-	}
-
-	private void verifyWaitToPop(long timeout) throws Exception {
-		Runnable r1 = this.buildRunnable(this.buildPushCommand(), this.ss, TWO_TICKS);
-		Runnable r2 = this.buildRunnable(this.buildWaitToPopCommand(timeout), this.ss, 0);
-		Thread t1 = this.buildThread(r1);
-		Thread t2 = this.buildThread(r2);
-		t1.start();
-		t2.start();
-		t1.join();
-		t2.join();
-	}
-
-	public void testWaitToPush() throws Exception {
-		this.verifyWaitToPush(0);
-		// no timeout occurs...
-		assertFalse(this.timeoutOccurred);
-		// ...and the stack gets popped by t1...
-		assertSame(ITEM_1, this.poppedObject);
-		// ...and an item is pushed on to the stack by t2
-		assertFalse(this.ss.isEmpty());
-		assertSame(ITEM_2, this.ss.peek());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() > TICK);
-	}
-
-	public void testWaitToPushTimeout() throws Exception {
-		this.verifyWaitToPush(TICK);
-		// timeout occurs...
-		assertTrue(this.timeoutOccurred);
-		// ...and the stack is eventually popped by t1...
-		assertSame(ITEM_1, this.poppedObject);
-		// ...but nothing is pushed on to the stack by t2
-		assertTrue(this.ss.isEmpty());
-		// make a reasonable guess about how long t2 took
-		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
-	}
-
-	private void verifyWaitToPush(long timeout) throws Exception {
-		this.ss.push(ITEM_1);
-		Runnable r1 = this.buildRunnable(this.buildPopCommand(), this.ss, TWO_TICKS);
-		Runnable r2 = this.buildRunnable(this.buildWaitToPushCommand(timeout), this.ss, 0);
-		Thread t1 = this.buildThread(r1);
-		Thread t2 = this.buildThread(r2);
-		t1.start();
-		t2.start();
-		t1.join();
-		t2.join();
-	}
-
-	private Command buildPushCommand() {
-		return new Command() {
-			public void execute(SynchronizedStack<String> synchronizedStack) {
-				synchronizedStack.push(ITEM_1);
-			}
-		};
-	}
-
-	private Command buildWaitToPopCommand(final long timeout) {
-		return new Command() {
-			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
-				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
-				try {
-					SynchronizedStackTests.this.poppedObject = synchronizedStack.waitToPop(timeout);
-				} catch (EmptyStackException ex) {
-					SynchronizedStackTests.this.timeoutOccurred = true;
-				}
-				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
-			}
-		};
-	}
-
-	private Command buildPopCommand() {
-		return new Command() {
-			public void execute(SynchronizedStack<String> synchronizedStack) {
-				SynchronizedStackTests.this.poppedObject = synchronizedStack.pop();
-			}
-		};
-	}
-
-	private Command buildWaitToPushCommand(final long timeout) {
-		return new Command() {
-			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
-				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
-				SynchronizedStackTests.this.timeoutOccurred = ! synchronizedStack.waitToPush(ITEM_2, timeout);
-				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
-			}
-		};
-	}
-
-	private Runnable buildRunnable(final Command command, final SynchronizedStack<String> synchronizedStack, final long sleep) {
-		return new TestRunnable() {
-			@Override
-			protected void run_() throws Throwable {
-				if (sleep != 0) {
-					Thread.sleep(sleep);
-				}
-				command.execute(synchronizedStack);
-			}
-		};
-	}
-
-	long calculateElapsedTime() {
-		return this.endTime - this.startTime;
-	}
-
-
-	// ********** Command interface **********
-
-	private interface Command {
-		void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException;
-	}
-
-}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/TightMapTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/TightMapTests.java
index c243a8d..0722e2a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/TightMapTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/TightMapTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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.
@@ -18,7 +18,6 @@
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
-import junit.framework.TestCase;
 import org.eclipse.jpt.common.utility.internal.ArrayTools;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
 import org.eclipse.jpt.common.utility.internal.StringTools;
@@ -26,6 +25,7 @@
 import org.eclipse.jpt.common.utility.internal.collection.TightMap;
 import org.eclipse.jpt.common.utility.internal.iterator.IteratorTools;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
 
 @SuppressWarnings("nls")
 public class TightMapTests
@@ -64,6 +64,13 @@
 		super.tearDown();
 	}
 
+	public void testCtorMap() {
+		Map<String, String> map2 = new HashMap<String, String>();
+		
+		this.map = new TightMap<String, String>(map2);
+		assertEquals(this.map, map2);
+	}
+
 	public void testSize() {
 		assertEquals(6, this.map.size());
 
@@ -200,6 +207,10 @@
 		assertFalse(this.map.containsKey("7"));
 		assertEquals(3, this.map.size());
 		assertFalse(this.map.containsValue("seven"));
+
+		assertEquals("one", this.map.remove("1"));
+		assertEquals("two", this.map.remove("2"));
+		assertEquals("four", this.map.remove("4"));
 	}
 
 	public void testPutAll() {
@@ -740,14 +751,14 @@
 		Collection<String> values = this.map.values();
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
-		assertTrue(CollectionTools.bag(values).equals(CollectionTools.bag(map2.values())));
+		assertTrue(CollectionTools.hashBag(values).equals(CollectionTools.hashBag(map2.values())));
 	}
 
 	public void testValues_hashCode() {
 		Collection<String> values = this.map.values();
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
-		assertEquals(CollectionTools.bag(values).hashCode(), CollectionTools.bag(map2.values()).hashCode());
+		assertEquals(CollectionTools.hashBag(values).hashCode(), CollectionTools.hashBag(map2.values()).hashCode());
 	}
 
 	public void testValues_removeAll() {
@@ -763,7 +774,7 @@
 		Collection<String> values2 = map2.values();
 		assertTrue(values2.removeAll(remove));
 
-		assertEquals(CollectionTools.bag(values2), CollectionTools.bag(values));
+		assertEquals(CollectionTools.hashBag(values2), CollectionTools.hashBag(values));
 	}
 
 	public void testValues_add() {
@@ -821,7 +832,7 @@
 		Collection<String> values2 = map2.values();
 		assertTrue(values2.retainAll(retain));
 
-		assertEquals(CollectionTools.bag(values2), CollectionTools.bag(values));
+		assertEquals(CollectionTools.hashBag(values2), CollectionTools.hashBag(values));
 	}
 
 	public void testValues_toArray() {
@@ -1017,12 +1028,58 @@
 		assertTrue(exCaught);
 	}
 
+	public void testEntrySet_iterator_entry_setValueObject() {
+		assertEquals(6, this.map.size());
+		assertTrue(this.map.containsKey("2"));
+		assertTrue(this.map.containsValue("two"));
+		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
+		assertEquals(6, entrySet.size());
+		for (Iterator<Map.Entry<String, String>> stream = entrySet.iterator(); stream.hasNext(); ) {
+			Map.Entry<String, String> entry = stream.next();
+			if (ObjectTools.equals(entry.getKey(), "2")) {
+				entry.setValue("XXX");
+			}
+		}
+		assertEquals(6, entrySet.size());
+		assertTrue(this.map.containsKey("2"));
+		assertFalse(this.map.containsValue("two"));
+		assertEquals("XXX", this.map.get("2"));
+		assertTrue(this.map.containsValue("XXX"));
+		assertEquals(6, this.map.size());
+	}
+
+	public void testEntrySet_iterator_entry_equalsObject() {
+		assertEquals(6, this.map.size());
+		assertTrue(this.map.containsKey("2"));
+		assertTrue(this.map.containsValue("two"));
+		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
+		assertEquals(6, entrySet.size());
+		for (Iterator<Map.Entry<String, String>> stream = entrySet.iterator(); stream.hasNext(); ) {
+			Map.Entry<String, String> entry = stream.next();
+			if (ObjectTools.equals(entry.getKey(), "2")) {
+				assertFalse(entry.equals("XXX"));
+			}
+		}
+	}
+
+	public void testEntrySet_iterator_entry_equalsObject2() {
+		Map<String, String> map1 = new TightMap<String, String>();
+		map1.put("foo", "bar");
+		Map<String, String> map2 = new TightMap<String, String>();
+		map2.put("foo", "XXX");
+		Set<Map.Entry<String, String>> entrySet1 = map1.entrySet();
+		Set<Map.Entry<String, String>> entrySet2 = map2.entrySet();
+		Map.Entry<String, String> entry1 = entrySet1.iterator().next();
+		Map.Entry<String, String> entry2 = entrySet2.iterator().next();
+		assertFalse(entry1.equals(entry2));
+	}
+
 	public void testEntrySet_size() {
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
 		assertEquals(6, entrySet.size());
 	}
 
-	public void testEntrySet_contains() {
+	public void testEntrySet_contains1() {
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
@@ -1031,6 +1088,26 @@
 		}
 	}
 
+	public void testEntrySet_contains2() {
+		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
+		HashMap<String, String> map2 = new HashMap<String, String>();
+		this.populateMap(map2);
+		map2.put("xxx", "XXX");
+		for (Map.Entry<String, String> entry : map2.entrySet()) {
+			String key = entry.getKey();
+			if ((key != null) && key.equals("xxx")) {
+				assertFalse(entrySet.contains(entry));
+			} else {
+				assertTrue(entrySet.contains(entry));
+			}
+		}
+	}
+
+	public void testEntrySet_contains3() {
+		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
+		assertFalse(entrySet.contains("XXX"));
+	}
+
 	@SuppressWarnings("null")
 	public void testEntrySet_remove1() {
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
@@ -1063,6 +1140,20 @@
 		assertEquals(6, this.map.size());
 	}
 
+	public void testEntrySet_remove3() {
+		Map<String, String> map1 = new TightMap<String, String>();
+		Set<Map.Entry<String, String>> entrySet1 = map1.entrySet();
+
+		Map<String, String> map2 = new TightMap<String, String>();
+		map2.put("foo", "FOO");
+		Set<Map.Entry<String, String>> entrySet2 = map2.entrySet();
+		Map.Entry<String, String> entry2 = entrySet2.iterator().next();
+
+		assertFalse(entrySet1.remove(entry2));
+		map1.put("foo", "XXX");
+		assertFalse(entrySet1.remove(entry2));
+	}
+
 	public void testEntrySet_clear() {
 		assertEquals(6, this.map.size());
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
@@ -1076,14 +1167,14 @@
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
-		assertTrue(CollectionTools.bag(entrySet).equals(CollectionTools.bag(map2.entrySet())));
+		assertTrue(CollectionTools.hashBag(entrySet).equals(CollectionTools.hashBag(map2.entrySet())));
 	}
 
 	public void testEntrySet_hashCode() {
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
-		assertEquals(CollectionTools.bag(entrySet).hashCode(), CollectionTools.bag(map2.entrySet()).hashCode());
+		assertEquals(CollectionTools.hashBag(entrySet).hashCode(), CollectionTools.hashBag(map2.entrySet()).hashCode());
 	}
 
 	public void testEntrySet_removeAll() {
@@ -1106,7 +1197,7 @@
 		assertTrue(entrySet.removeAll(remove));
 		assertTrue(entrySet2.removeAll(remove));
 
-		assertEquals(CollectionTools.bag(entrySet2), CollectionTools.bag(entrySet));
+		assertEquals(CollectionTools.hashBag(entrySet2), CollectionTools.hashBag(entrySet));
 	}
 
 	public void testEntrySet_add() {
@@ -1198,7 +1289,7 @@
 		Set<Map.Entry<String, String>> entrySet = this.map.entrySet();
 		assertTrue(entrySet.retainAll(retain));
 		assertTrue(entrySet2.retainAll(retain));
-		assertEquals(CollectionTools.bag(entrySet2), CollectionTools.bag(entrySet));
+		assertEquals(CollectionTools.hashBag(entrySet2), CollectionTools.hashBag(entrySet));
 	}
 
 	public void testEntrySet_toArray() {
@@ -1287,6 +1378,17 @@
 		assertTrue(this.map.equals(map2));
 	}
 
+	public void testEquals7() {
+		TightMap<String, String> map1 = new TightMap<String, String>();
+		map1.put("null", null);
+		HashMap<String, String> map2 = new HashMap<String, String>();
+		assertFalse(map1.equals(map2));
+		map2.put("null", "null");
+		assertFalse(map1.equals(map2));
+		map2.put("null", null);
+		assertTrue(map1.equals(map2));
+	}
+
 	public void testHashCode1() {
 		HashMap<String, String> map2 = new HashMap<String, String>();
 		this.populateMap(map2);
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/AbstractPriorityDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/AbstractPriorityDequeTests.java
new file mode 100644
index 0000000..7a47c60
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/AbstractPriorityDequeTests.java
@@ -0,0 +1,370 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.deque.AbstractPriorityDeque;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public abstract class AbstractPriorityDequeTests
+	extends TestCase
+{
+	public AbstractPriorityDequeTests(String name) {
+		super(name);
+	}
+
+	abstract <E extends Comparable<E>> AbstractPriorityDeque<E> buildDeque();
+
+	abstract <E extends Comparable<E>> AbstractPriorityDeque<E> buildDeque(int capacity);
+
+	abstract <E extends Comparable<E>> AbstractPriorityDeque<E> buildDeque(Comparator<E> comparator, int capacity);
+
+	public void testIsEmpty_head() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		assertTrue(deque.isEmpty());
+		deque.enqueue("first");
+		assertFalse(deque.isEmpty());
+		deque.enqueue("second");
+		assertFalse(deque.isEmpty());
+		deque.dequeueHead();
+		assertFalse(deque.isEmpty());
+		deque.dequeueHead();
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testIsEmpty_tail() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		assertTrue(deque.isEmpty());
+		deque.enqueue("first");
+		assertFalse(deque.isEmpty());
+		deque.enqueue("second");
+		assertFalse(deque.isEmpty());
+		deque.dequeueTail();
+		assertFalse(deque.isEmpty());
+		deque.dequeueTail();
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testEnqueueAndDequeueHead() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueueTail(second);
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.dequeueHead());
+	}
+
+	public void testEnqueueAndDequeueTail() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(second, deque.dequeueTail());
+		assertEquals(first, deque.dequeueTail());
+	}
+
+	public void testEnqueueAndPeekHead() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(first, deque.peekHead());
+		assertEquals(first, deque.peekHead());
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.peekHead());
+		assertEquals(second, deque.peekHead());
+		assertEquals(second, deque.dequeueHead());
+	}
+
+	public void testEnqueueAndPeekTail() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String zzzz = "zzzz";
+
+		deque.enqueue(second);
+		deque.enqueue(zzzz);
+		deque.enqueue(third);
+		deque.enqueue(first);
+		assertEquals(zzzz, deque.peekTail());
+		assertEquals(zzzz, deque.peekTail());
+		assertEquals(zzzz, deque.dequeueTail());
+		assertEquals(third, deque.peekTail());
+		assertEquals(third, deque.peekTail());
+		assertEquals(third, deque.dequeueTail());
+		assertEquals(second, deque.peekTail());
+		assertEquals(second, deque.peekTail());
+		assertEquals(second, deque.dequeueTail());
+		assertEquals(first, deque.peekTail());
+		assertEquals(first, deque.peekTail());
+		assertEquals(first, deque.dequeueTail());
+	}
+
+	public void testEmptyQueueExceptionPeekHead() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(first, deque.peekHead());
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.peekHead());
+		assertEquals(second, deque.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			deque.peekHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyQueueExceptionPeekTail() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(second, deque.peekTail());
+		assertEquals(second, deque.dequeueTail());
+		assertEquals(first, deque.peekTail());
+		assertEquals(first, deque.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			deque.peekTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyQueueExceptionDequeueHead() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(first, deque.peekHead());
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.peekHead());
+		assertEquals(second, deque.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			deque.dequeueHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyQueueExceptionDequeueTail() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueue(second);
+		assertEquals(second, deque.peekTail());
+		assertEquals(second, deque.dequeueTail());
+		assertEquals(first, deque.peekTail());
+		assertEquals(first, deque.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			deque.dequeueTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testClone() {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		deque.enqueue("first");
+		deque.enqueue("second");
+		deque.enqueue("third");
+
+		@SuppressWarnings("unchecked")
+		AbstractPriorityDeque<String> clone = (AbstractPriorityDeque<String>) ObjectTools.execute(deque, "clone");
+		this.verifyClone(deque, clone);
+	}
+
+	public void testSerialization() throws Exception {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		deque.enqueue("first");
+		deque.enqueue("second");
+		deque.enqueue("third");
+
+		this.verifyClone(deque, TestTools.serialize(deque));
+	}
+
+	protected void verifyClone(AbstractPriorityDeque<String> original, AbstractPriorityDeque<String> clone) {
+		assertNotSame(original, clone);
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertEquals(original.peekTail(), clone.peekTail());
+		assertEquals(original.dequeueTail(), clone.dequeueTail());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testToString() throws Exception {
+		AbstractPriorityDeque<String> deque = this.buildDeque();
+		assertEquals("[]", deque.toString());
+		deque.enqueue("first");
+		assertEquals("[first]", deque.toString());
+		deque.enqueue("second");
+		assertEquals("[first, second]", deque.toString());
+		deque.enqueue("third");
+		assertEquals("[first, second, third]", deque.toString());
+	}
+
+	public void testMultipleSizes() throws Exception {
+		int maxSize = 50;
+		Random random = new Random();
+		for (int size = 1; size <= maxSize; size++) {
+			int[] values = new int[size];
+			for (int i = 0; i < values.length; i++) {
+				values[i] = random.nextInt();
+			}
+			AbstractPriorityDeque<Integer> deque = this.buildDeque(size);
+			for (int value : values) {
+				deque.enqueue(Integer.valueOf(value));
+			}
+			Integer currentHead = deque.dequeueHead();
+			int i = 1;
+			Integer currentTail = null;
+			if ( ! deque.isEmpty()) {
+				currentTail = deque.dequeueTail();
+				i++;
+			}
+			do {
+				if ( ! deque.isEmpty()) {
+					Integer nextHead = deque.dequeueHead();
+					i++;
+					assertTrue(currentHead.intValue() <= nextHead.intValue());
+					currentHead = nextHead;
+				}
+				if ( ! deque.isEmpty()) {
+					Integer nextTail = deque.dequeueTail();
+					i++;
+					assertTrue((currentTail != null) && (currentTail.intValue() >= nextTail.intValue()));
+					currentTail = nextTail;
+				}
+			} while ( ! deque.isEmpty());
+			assertEquals(size, i);
+		}
+	}
+
+	public void testSomethingBig() throws Exception {
+		int size = 500000;
+		AbstractPriorityDeque<Integer> deque = this.buildDeque(size);
+		Random random = new Random();
+		for (int i = size; i-- > 0; ) {
+			deque.enqueue(Integer.valueOf(random.nextInt()));
+		}
+		Integer currentHead = deque.dequeueHead();
+		int i = 1;
+		Integer currentTail = null;
+		if ( ! deque.isEmpty()) {
+			currentTail = deque.dequeueTail();
+			i++;
+		}
+		do {
+			if ( ! deque.isEmpty()) {
+				Integer nextHead = deque.dequeueHead();
+				i++;
+				assertTrue(currentHead.intValue() <= nextHead.intValue());
+				currentHead = nextHead;
+			}
+			if ( ! deque.isEmpty()) {
+				Integer nextTail = deque.dequeueTail();
+				i++;
+				assertTrue((currentTail != null) && (currentTail.intValue() >= nextTail.intValue()));
+				currentTail = nextTail;
+			}
+		} while ( ! deque.isEmpty());
+		assertEquals(size, i);
+	}
+
+	public void testConstructor_nullComparator() throws Exception {
+		boolean exCaught = false;
+		try {
+			AbstractPriorityDeque<String> deque = this.buildDeque(null, 3);
+			fail("bogus deque: " + deque);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructor_negativeCapacity() throws Exception {
+		boolean exCaught = false;
+		try {
+			AbstractPriorityDeque<String> deque = this.buildDeque(-7);
+			fail("bogus deque: " + deque);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSerialization_fullArray() throws Exception {
+		AbstractPriorityDeque<String> deque = this.buildDeque(3);
+		deque.enqueue("first");
+		deque.enqueue("second");
+		deque.enqueue("third");
+
+		this.verifyClone(deque, TestTools.serialize(deque));
+	}
+
+	public void testSerialization_empty() throws Exception {
+		AbstractPriorityDeque<String> original = this.buildDeque();
+		AbstractPriorityDeque<String> clone = TestTools.serialize(original);
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("foo");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ArrayDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ArrayDequeTests.java
new file mode 100644
index 0000000..24b318b
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ArrayDequeTests.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.ArrayList;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.deque.ArrayDeque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+@SuppressWarnings("nls")
+public class ArrayDequeTests
+	extends DequeTests
+{
+	public ArrayDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Deque<String> buildDeque() {
+		return DequeTools.arrayDeque();
+	}
+
+	public void testConstructor_IAE() {
+		boolean exCaught = false;
+		try {
+			Deque<String> queue = DequeTools.arrayDeque(-1);
+			fail("bogus deque: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEnsureCapacity() {
+		ArrayDeque<String> queue = DequeTools.arrayDeque(0);
+		queue.ensureCapacity(7);
+		assertEquals(7, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testTrimToSize() {
+		ArrayDeque<String> queue = DequeTools.arrayDeque(10);
+		queue.enqueueTail("foo");
+		queue.enqueueTail("bar");
+		queue.trimToSize();
+		assertEquals(2, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testTrimToSize_noChange() {
+		ArrayDeque<String> queue = DequeTools.arrayDeque(2);
+		queue.enqueueTail("foo");
+		queue.enqueueTail("bar");
+		queue.trimToSize();
+		assertEquals(2, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testCollectionConstructor() {
+		ArrayList<String> c = new ArrayList<String>();
+		c.add("first");
+		c.add("second");
+		c.add("third");
+		c.add("fourth");
+		c.add("fifth");
+		c.add("sixth");
+		c.add("seventh");
+		c.add("eighth");
+		c.add("ninth");
+		c.add("tenth"); // force some free space
+		Deque<String> queue = DequeTools.arrayDeque(c);
+
+		assertFalse(queue.isEmpty());
+		assertEquals("first", queue.peekHead());
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+
+		assertEquals("first", queue.peekHead());
+		assertEquals("first", queue.dequeueHead());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.peekHead());
+		assertEquals("third", queue.dequeueHead());
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testWrappedElementsTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+
+		// make room for 11 and 12
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testWrappedElementsHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+
+		// make room for 11 and 12
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+		queue.enqueueHead("eleventh");
+		queue.enqueueHead("twelfth");
+
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertEquals("eleventh", queue.dequeueTail());
+		assertEquals("twelfth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+		queue.enqueueHead("eleventh");
+		queue.enqueueHead("twelfth");
+
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertEquals("eleventh", queue.dequeueTail());
+		assertEquals("twelfth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededWithWrappedElementsTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+		queue.enqueueTail("thirteenth");
+		queue.enqueueTail("fourteenth");
+		queue.enqueueTail("fifteenth");
+
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertEquals("thirteenth", queue.dequeueHead());
+		assertEquals("fourteenth", queue.dequeueHead());
+		assertEquals("fifteenth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededWithWrappedElementsHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+		queue.enqueueHead("eleventh");
+		queue.enqueueHead("twelfth");
+		queue.enqueueHead("thirteenth");
+		queue.enqueueHead("fourteenth");
+		queue.enqueueHead("fifteenth");
+
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertEquals("eleventh", queue.dequeueTail());
+		assertEquals("twelfth", queue.dequeueTail());
+		assertEquals("thirteenth", queue.dequeueTail());
+		assertEquals("fourteenth", queue.dequeueTail());
+		assertEquals("fifteenth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testSerialization_empty() throws Exception {
+		Deque<String> original = new ArrayDeque<String>(3);
+		Deque<String> clone = TestTools.serialize(original);
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueueTail("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testSerialization_fullArray() throws Exception {
+		Deque<String> queue = new ArrayDeque<String>(3);
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+
+	public void testSerialization_wrappedArray() throws Exception {
+		Deque<String> queue = new ArrayDeque<String>(3);
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+		queue.dequeueHead();
+		queue.enqueueTail("fourth");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeTests.java
new file mode 100644
index 0000000..cbdf797
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeTests.java
@@ -0,0 +1,290 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+// subclass MultiThreadedTestCase for subclasses of this class
+@SuppressWarnings("nls")
+public abstract class DequeTests
+	extends MultiThreadedTestCase
+{
+	public DequeTests(String name) {
+		super(name);
+	}
+
+	abstract Deque<String> buildDeque();
+
+	public void testIsEmpty() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("zero");
+		assertFalse(queue.isEmpty());
+		queue.dequeueHead();
+		assertFalse(queue.isEmpty());
+		queue.dequeueHead();
+		assertFalse(queue.isEmpty());
+		queue.dequeueTail();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueTailAndDequeueHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.dequeueHead());
+	}
+
+	public void testEnqueueHeadAndDequeueTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.dequeueTail());
+	}
+
+	public void testEnqueueAndDequeue() {
+		Deque<String> queue = this.buildDeque();
+		String negative = "negative";
+		String zero = "zero";
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		queue.enqueueHead(zero);
+		queue.enqueueHead(negative);
+		assertEquals(negative, queue.dequeueHead());
+		assertEquals(second, queue.dequeueTail());
+		assertEquals(zero, queue.dequeueHead());
+		assertEquals(first, queue.dequeueTail());
+
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueTailAndPeekHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+	}
+
+	public void testEnqueueHeadAndPeekTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+	}
+
+	public void testEnqueueAndPeek() {
+		Deque<String> queue = this.buildDeque();
+		String negative = "negative";
+		String zero = "zero";
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		queue.enqueueHead(zero);
+		queue.enqueueHead(negative);
+		assertEquals(negative, queue.peekHead());
+		assertEquals(negative, queue.peekHead());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.peekTail());
+
+		assertEquals(negative, queue.dequeueHead());
+		assertEquals(zero, queue.peekHead());
+		assertEquals(zero, queue.peekHead());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.peekTail());
+
+		assertEquals(second, queue.dequeueTail());
+		assertEquals(zero, queue.peekHead());
+		assertEquals(first, queue.peekTail());
+
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(zero, queue.peekHead());
+		assertEquals(zero, queue.peekTail());
+
+		assertEquals(zero, queue.dequeueTail());
+
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEmptyDequeExceptionPeekHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			queue.peekHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionPeekTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			queue.peekTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionDequeueHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			queue.dequeueHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionDequeueTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			queue.dequeueTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testClone() {
+		Deque<String> queue = this.buildDeque();
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+
+		@SuppressWarnings("unchecked")
+		Deque<String> clone = (Deque<String>) ObjectTools.execute(queue, "clone");
+		this.verifyClone(queue, clone);
+	}
+
+	public void testSerialization() throws Exception {
+		Deque<String> queue = this.buildDeque();
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+
+	protected void verifyClone(Deque<String> original, Deque<String> clone) {
+		assertNotSame(original, clone);
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+		assertEquals(original.peekTail(), clone.peekTail());
+		assertEquals(original.dequeueTail(), clone.dequeueTail());
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueueTail("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testToString() throws Exception {
+		Deque<String> queue = this.buildDeque();
+		assertEquals("[]", queue.toString());
+		queue.enqueueTail("first");
+		assertEquals("[first]", queue.toString());
+		queue.enqueueTail("second");
+		assertEquals("[first, second]", queue.toString());
+		queue.enqueueTail("third");
+		assertEquals("[first, second, third]", queue.toString());
+		queue.enqueueHead("foo");
+		assertEquals("[foo, first, second, third]", queue.toString());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeToolsTests.java
new file mode 100644
index 0000000..c30026b
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/DequeToolsTests.java
@@ -0,0 +1,832 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.StringTools;
+import org.eclipse.jpt.common.utility.internal.comparator.ComparatorTools;
+import org.eclipse.jpt.common.utility.internal.deque.ArrayDeque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.LinkedDeque;
+import org.eclipse.jpt.common.utility.internal.deque.PriorityDeque;
+import org.eclipse.jpt.common.utility.internal.deque.SynchronizedDeque;
+import org.eclipse.jpt.common.utility.internal.queue.ArrayQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.stack.ArrayStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class DequeToolsTests
+	extends TestCase
+{
+	public DequeToolsTests(String name) {
+		super(name);
+	}
+
+	// ********** enqueue all **********
+
+	public void testEnqueueTailAllIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueTailAll(deque, iterable));
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testEnqueueTailAllIterable_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.enqueueTailAll(deque, iterable));
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueHeadAll(deque, iterable));
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testEnqueueHeadAllIterable_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.enqueueHeadAll(deque, iterable));
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testEnqueueTailAllIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueTailAll(deque, iterable.iterator()));
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testEnqueueHeadAllIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueHeadAll(deque, iterable.iterator()));
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testEnqueueTailAllArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueTailAll(deque, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testEnqueueTailAllArray_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.enqueueTailAll(deque, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertTrue(DequeTools.enqueueHeadAll(deque, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testEnqueueHeadAllArray_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.enqueueHeadAll(deque, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertTrue(deque.isEmpty());
+	}
+
+
+	// ********** drain **********
+
+	public void testDrainHead() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayList<String> list = DequeTools.drainHead(d);
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainTail() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayList<String> list = DequeTools.drainTail(d);
+		assertEquals("one", list.get(2));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(0));
+	}
+
+	public void testDrainHeadToCollection() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(DequeTools.drainHeadTo(d, list));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainHeadToCollection_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(DequeTools.drainHeadTo(d, list));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainTailToCollection() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(DequeTools.drainTailTo(d, list));
+		assertEquals("one", list.get(2));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(0));
+	}
+
+	public void testDrainTailToCollection_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(DequeTools.drainTailTo(d, list));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainHeadToListIndex() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		deque.enqueueTail("aaa");
+		deque.enqueueTail("bbb");
+		deque.enqueueTail("ccc");
+		assertTrue(DequeTools.drainHeadTo(deque, list, 2));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("aaa", list.get(2));
+		assertEquals("bbb", list.get(3));
+		assertEquals("ccc", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainHeadToListIndex_end() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		deque.enqueueTail("aaa");
+		deque.enqueueTail("bbb");
+		deque.enqueueTail("ccc");
+		assertTrue(DequeTools.drainHeadTo(deque, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+		assertEquals("aaa", list.get(3));
+		assertEquals("bbb", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testDrainHeadToListIndex_empty() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.drainHeadTo(deque, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainTailToListIndex() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		deque.enqueueTail("aaa");
+		deque.enqueueTail("bbb");
+		deque.enqueueTail("ccc");
+		assertTrue(DequeTools.drainTailTo(deque, list, 2));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("bbb", list.get(3));
+		assertEquals("aaa", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainTailToListIndex_end() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		deque.enqueueTail("aaa");
+		deque.enqueueTail("bbb");
+		deque.enqueueTail("ccc");
+		assertTrue(DequeTools.drainTailTo(deque, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+		assertEquals("ccc", list.get(3));
+		assertEquals("bbb", list.get(4));
+		assertEquals("aaa", list.get(5));
+	}
+
+	public void testDrainTailToListIndex_empty() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Deque<String> deque = DequeTools.arrayDeque();
+		assertFalse(DequeTools.drainTailTo(deque, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainHeadToStack() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertTrue(DequeTools.drainHeadTo(d, stack));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testDrainHeadToStack_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertFalse(DequeTools.drainHeadTo(d, stack));
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainTailToStack() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertTrue(DequeTools.drainTailTo(d, stack));
+		assertEquals("one", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("three", stack.pop());
+	}
+
+	public void testDrainTailToStack_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertFalse(DequeTools.drainTailTo(d, stack));
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainHeadToQueue() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertTrue(DequeTools.drainHeadTo(d, queue));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testDrainHeadToQueue_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertFalse(DequeTools.drainHeadTo(d, queue));
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainTailToQueue() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertTrue(DequeTools.drainTailTo(d, queue));
+		assertEquals("three", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("one", queue.dequeue());
+	}
+
+	public void testDrainTailToQueue_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertFalse(DequeTools.drainTailTo(d, queue));
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainHeadToDeque() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayDeque<String> d2 = DequeTools.arrayDeque();
+		assertTrue(DequeTools.drainHeadTo(d, d2));
+		assertEquals("one", d2.dequeueHead());
+		assertEquals("two", d2.dequeueHead());
+		assertEquals("three", d2.dequeueHead());
+	}
+
+	public void testDrainHeadToDeque_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayDeque<String> d2 = DequeTools.arrayDeque();
+		assertFalse(DequeTools.drainHeadTo(d, d2));
+		assertTrue(d2.isEmpty());
+	}
+
+	public void testDrainTailToDeque() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		d.enqueueTail("three");
+		ArrayDeque<String> d2 = DequeTools.arrayDeque();
+		assertTrue(DequeTools.drainTailTo(d, d2));
+		assertEquals("one", d2.dequeueHead());
+		assertEquals("two", d2.dequeueHead());
+		assertEquals("three", d2.dequeueHead());
+	}
+
+	public void testDrainTailToDeque_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		ArrayDeque<String> d2 = DequeTools.arrayDeque();
+		assertFalse(DequeTools.drainTailTo(d, d2));
+		assertTrue(d2.isEmpty());
+	}
+
+	public void testDrainHeadToMapTransformer() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("zero");
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(DequeTools.drainHeadTo(d, map, FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainHeadToMapTransformer_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(DequeTools.drainHeadTo(d, map, FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainTailToMapTransformer() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("zero");
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(DequeTools.drainTailTo(d, map, FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainTailToMapTransformer_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(DequeTools.drainTailTo(d, map, FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainHeadToMapTransformerTransformer() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("zero");
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(DequeTools.drainHeadTo(d, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainHeadToMapTransformerTransformer_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(DequeTools.drainHeadTo(d, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainTailToMapTransformerTransformer() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		d.enqueueTail("zero");
+		d.enqueueTail("one");
+		d.enqueueTail("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(DequeTools.drainTailTo(d, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainTailToMapTransformerTransformer_empty() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(DequeTools.drainTailTo(d, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+
+	public static final Transformer<String, String> FIRST_LETTER_TRANSFORMER = new FirstLetterTransformer();
+
+	/* CU private */ static class FirstLetterTransformer
+		implements Transformer<String, String>
+	{
+		public String transform(String string) {
+			return string.substring(0, 1);
+		}
+		@Override
+		public String toString() {
+			return this.getClass().getSimpleName();
+		}
+	}
+
+	public static final Transformer<String, String> EMPHASIZER = new StringTools.CharDelimiter('*');
+
+
+	// ********** array deque **********
+
+	public void testArrayDeque() {
+		ArrayDeque<String> d = DequeTools.arrayDeque();
+		assertTrue(d.isEmpty());
+	}
+
+	public void testArrayDequeInt() {
+		ArrayDeque<String> d = DequeTools.arrayDeque(20);
+		assertTrue(d.isEmpty());
+		assertEquals(20, ((Object[]) ObjectTools.get(d, "elements")).length);
+	}
+
+	public void testArrayDequeIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque(iterable);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testArrayDequeIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque(iterable, 5);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseArrayDequeIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseArrayDeque(iterable);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testReverseArrayDequeIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseArrayDeque(iterable, 77);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testArrayDequeIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque(iterable.iterator());
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testArrayDequeIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque(iterable.iterator(), 5);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseArrayDequeIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseArrayDeque(iterable.iterator());
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testReverseArrayDequeIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseArrayDeque(iterable.iterator(), 42);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testArrayDequeArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.arrayDeque(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseArrayDequeArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseArrayDeque(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	// ********** linked deque **********
+
+	public void testLinkedDeque() {
+		LinkedDeque<String> d = DequeTools.linkedDeque();
+		assertTrue(d.isEmpty());
+	}
+
+	public void testLinkedDequeInt() {
+		LinkedDeque<String> d = DequeTools.linkedDeque(20);
+		assertTrue(d.isEmpty());
+	}
+
+	public void testLinkedDequeIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.linkedDeque(iterable);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testLinkedDequeIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.linkedDeque(iterable, 5);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseLinkedDequeIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseLinkedDeque(iterable);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testReverseLinkedDequeIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseLinkedDeque(iterable, 77);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testLinkedDequeIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.linkedDeque(iterable.iterator());
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testLinkedDequeIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.linkedDeque(iterable.iterator(), 5);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseLinkedDequeIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseLinkedDeque(iterable.iterator());
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testReverseLinkedDequeIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseLinkedDeque(iterable.iterator(), 42);
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	public void testLinkedDequeArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.linkedDeque(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseLinkedDequeArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseLinkedDeque(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", deque.dequeueTail());
+		assertEquals("two", deque.dequeueTail());
+		assertEquals("three", deque.dequeueTail());
+	}
+
+	// ********** fixed-capacity array deque **********
+
+	public void testFixedCapacityArrayDequeCollection() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.fixedCapacityArrayDeque(iterable);
+		assertEquals("one", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("three", deque.dequeueHead());
+	}
+
+	public void testReverseFixedCapacityArrayDequeCollection() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Deque<String> deque = DequeTools.reverseFixedCapacityArrayDeque(iterable);
+		assertEquals("three", deque.dequeueHead());
+		assertEquals("two", deque.dequeueHead());
+		assertEquals("one", deque.dequeueHead());
+	}
+
+	// ********** misc **********
+
+	public void testPriorityDequeComparator() {
+		PriorityDeque<String> deque = DequeTools.priorityDeque(ComparatorTools.<String>reverseComparator());
+		String first = "first";
+		String second = "second";
+
+		deque.enqueue(first);
+		deque.enqueueTail(second);
+		assertEquals(second, deque.dequeueHead());
+		assertEquals(first, deque.dequeueHead());
+	}
+
+	public void testSynchronizedDequeObject() {
+		Object lock = new Object();
+		SynchronizedDeque<String> deque = DequeTools.synchronizedDeque(lock);
+		String first = "first";
+		String second = "second";
+
+		deque.enqueueTail(first);
+		deque.enqueueTail(second);
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.dequeueHead());
+		assertEquals(lock, deque.getMutex());
+	}
+
+	public void testSynchronizedDequeDequeObject() {
+		Object lock = new Object();
+		Deque<String> innerDeque = DequeTools.arrayDeque();
+		String first = "first";
+		String second = "second";
+		innerDeque.enqueueTail(first);
+		innerDeque.enqueueTail(second);
+
+		SynchronizedDeque<String> deque = DequeTools.synchronizedDeque(innerDeque, lock);
+		assertEquals(first, deque.dequeueHead());
+		assertEquals(second, deque.dequeueHead());
+		assertEquals(lock, deque.getMutex());
+	}
+
+	public void testConstructor() {
+		boolean exCaught = false;
+		try {
+			Object at = ClassTools.newInstance(DequeTools.class);
+			fail("bogus: " + at);
+		} catch (RuntimeException ex) {
+			if (ex.getCause() instanceof InvocationTargetException) {
+				if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+					exCaught = true;
+				}
+			}
+		}
+		assertTrue(exCaught);
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/EmptyDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/EmptyDequeTests.java
new file mode 100644
index 0000000..0b525b0
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/EmptyDequeTests.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.EmptyDeque;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class EmptyDequeTests
+	extends TestCase
+{
+	public EmptyDequeTests(String name) {
+		super(name);
+	}
+
+	public void testEnqueueTail() {
+		Deque<String> deque = DequeTools.emptyDeque();
+		boolean exCaught = false;
+		try {
+			deque.enqueueTail("junk");
+			fail();
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEnqueueHead() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		boolean exCaught = false;
+		try {
+			deque.enqueueHead("junk");
+			fail();
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testDequeueHead() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = deque.dequeueHead();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testDequeueTail() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = deque.dequeueTail();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testPeekHead() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = deque.peekHead();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testPeekTail() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = deque.peekTail();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIsEmpty() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testToString() {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		assertEquals("[]", deque.toString());
+	}
+
+	public void testSerialization() throws Exception {
+		Deque<String> deque = EmptyDeque.<String>instance();
+		assertSame(deque, TestTools.serialize(deque));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityArrayDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityArrayDequeTests.java
new file mode 100644
index 0000000..b9014e1
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityArrayDequeTests.java
@@ -0,0 +1,341 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.FixedCapacityArrayDeque;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+@SuppressWarnings("nls")
+public class FixedCapacityArrayDequeTests
+	extends DequeTests
+{
+	public FixedCapacityArrayDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	FixedCapacityArrayDeque<String> buildDeque() {
+		return this.buildDeque(10);
+	}
+
+	FixedCapacityArrayDeque<String> buildDeque(int capacity) {
+		return DequeTools.fixedCapacityArrayDeque(capacity);
+	}
+
+	public void testInitialCapacityConstructor() {
+		boolean exCaught = false;
+		try {
+			Deque<String> queue = DequeTools.arrayDeque(-1);
+			fail("bogus deque: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIsFull() {
+		FixedCapacityArrayDeque<String> queue = this.buildDeque(3);
+		assertTrue(queue.isEmpty());
+		assertFalse(queue.isFull());
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+		assertFalse(queue.isEmpty());
+		assertTrue(queue.isFull());
+	}
+
+	public void testWrappedElementsTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+
+		// make room for 11 and 12
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testWrappedElementsHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+
+		// make room for 11 and 12
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+		queue.enqueueHead("eleventh");
+		queue.enqueueHead("twelfth");
+
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertEquals("eleventh", queue.dequeueTail());
+		assertEquals("twelfth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+
+		boolean exCaught = false;
+		try {
+			queue.enqueueTail("eleventh");
+			fail("bogus queue: " + queue);
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+
+		boolean exCaught = false;
+		try {
+			queue.enqueueHead("eleventh");
+			fail("bogus queue: " + queue);
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededWithWrappedElementsTail() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("third");
+		queue.enqueueTail("fourth");
+		queue.enqueueTail("fifth");
+		queue.enqueueTail("sixth");
+
+		assertEquals("first", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueHead());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueHead());
+
+		queue.enqueueTail("seventh");
+		queue.enqueueTail("eighth");
+		queue.enqueueTail("ninth");
+		queue.enqueueTail("tenth");
+		queue.enqueueTail("eleventh");
+		queue.enqueueTail("twelfth");
+		queue.enqueueTail("thirteenth");
+
+		boolean exCaught = false;
+		try {
+			queue.enqueueTail("fourteenth");
+			fail("bogus queue: " + queue);
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("fourth", queue.dequeueHead());
+		assertEquals("fifth", queue.dequeueHead());
+		assertEquals("sixth", queue.dequeueHead());
+		assertEquals("seventh", queue.dequeueHead());
+		assertEquals("eighth", queue.dequeueHead());
+		assertEquals("ninth", queue.dequeueHead());
+		assertEquals("tenth", queue.dequeueHead());
+		assertEquals("eleventh", queue.dequeueHead());
+		assertEquals("twelfth", queue.dequeueHead());
+		assertEquals("thirteenth", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayCapacityExceededWithWrappedElementsHead() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		queue.enqueueHead("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("second");
+		assertFalse(queue.isEmpty());
+		queue.enqueueHead("third");
+		queue.enqueueHead("fourth");
+		queue.enqueueHead("fifth");
+		queue.enqueueHead("sixth");
+
+		assertEquals("first", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("second", queue.dequeueTail());
+		assertFalse(queue.isEmpty());
+		assertEquals("third", queue.dequeueTail());
+
+		queue.enqueueHead("seventh");
+		queue.enqueueHead("eighth");
+		queue.enqueueHead("ninth");
+		queue.enqueueHead("tenth");
+		queue.enqueueHead("eleventh");
+		queue.enqueueHead("twelfth");
+		queue.enqueueHead("thirteenth");
+
+		boolean exCaught = false;
+		try {
+			queue.enqueueHead("fourteenth");
+			fail("bogus queue: " + queue);
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("fourth", queue.dequeueTail());
+		assertEquals("fifth", queue.dequeueTail());
+		assertEquals("sixth", queue.dequeueTail());
+		assertEquals("seventh", queue.dequeueTail());
+		assertEquals("eighth", queue.dequeueTail());
+		assertEquals("ninth", queue.dequeueTail());
+		assertEquals("tenth", queue.dequeueTail());
+		assertEquals("eleventh", queue.dequeueTail());
+		assertEquals("twelfth", queue.dequeueTail());
+		assertEquals("thirteenth", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testSerialization_empty() throws Exception {
+		Deque<String> original = new FixedCapacityArrayDeque<String>(3);
+		Deque<String> clone = TestTools.serialize(original);
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueueTail("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testSerialization_fullArray() throws Exception {
+		Deque<String> queue = new FixedCapacityArrayDeque<String>(3);
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+
+	public void testSerialization_wrappedArray() throws Exception {
+		Deque<String> queue = new FixedCapacityArrayDeque<String>(3);
+		queue.enqueueTail("first");
+		queue.enqueueTail("second");
+		queue.enqueueTail("third");
+		queue.dequeueHead();
+		queue.enqueueTail("fourth");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityPriorityDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityPriorityDequeTests.java
new file mode 100644
index 0000000..dec17f0
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/FixedCapacityPriorityDequeTests.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.Comparator;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.FixedCapacityPriorityDeque;
+
+@SuppressWarnings("nls")
+public class FixedCapacityPriorityDequeTests
+	extends AbstractPriorityDequeTests
+{
+	public FixedCapacityPriorityDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	<E extends Comparable<E>> FixedCapacityPriorityDeque<E> buildDeque() {
+		return DequeTools.<E>fixedCapacityPriorityDeque(10);
+	}
+
+	@Override
+	<E extends Comparable<E>> FixedCapacityPriorityDeque<E> buildDeque(int capacity) {
+		return DequeTools.fixedCapacityPriorityDeque(capacity);
+	}
+
+	@Override
+	<E extends Comparable<E>> FixedCapacityPriorityDeque<E> buildDeque(Comparator<E> comparator, int capacity) {
+		return DequeTools.fixedCapacityPriorityDeque(comparator, capacity);
+	}
+
+	public void testIsFull() throws Exception {
+		FixedCapacityPriorityDeque<String> deque = this.buildDeque();
+		assertFalse(deque.isFull());
+		deque.enqueue("first");
+		assertFalse(deque.isFull());
+		deque.enqueue("second");
+		assertFalse(deque.isFull());
+		deque.enqueue("third");
+		deque.enqueue("fourth");
+		deque.enqueue("fifth");
+		deque.enqueue("sixth");
+		deque.enqueue("seventh");
+		deque.enqueue("eighth");
+		deque.enqueue("ninth");
+		deque.enqueue("tenth");
+		assertTrue(deque.isFull());
+
+		deque.dequeueHead();
+		assertFalse(deque.isEmpty());
+		deque.dequeueHead();
+		deque.dequeueHead();
+		deque.dequeueHead();
+		deque.dequeueHead();
+		deque.dequeueHead();
+		deque.dequeueHead();
+		deque.dequeueHead();
+		assertFalse(deque.isFull());
+	}
+
+	public void testCapacityExceeded() {
+		FixedCapacityPriorityDeque<String> deque = this.buildDeque();
+		assertTrue(deque.isEmpty());
+		deque.enqueue("first");
+		assertFalse(deque.isEmpty());
+		deque.enqueue("second");
+		assertFalse(deque.isEmpty());
+		deque.enqueue("third");
+		deque.enqueue("fourth");
+		deque.enqueue("fifth");
+		deque.enqueue("sixth");
+		deque.enqueue("seventh");
+		deque.enqueue("eighth");
+		deque.enqueue("ninth");
+		deque.enqueue("tenth");
+
+		boolean exCaught = false;
+		try {
+			deque.enqueue("eleventh");
+			fail("bogus deque: " + deque);
+		} catch (IllegalStateException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+
+		assertEquals("eighth", deque.dequeueHead());
+		assertEquals("fifth", deque.dequeueHead());
+		assertEquals("first", deque.dequeueHead());
+		assertEquals("fourth", deque.dequeueHead());
+		assertFalse(deque.isEmpty());
+		assertEquals("ninth", deque.dequeueHead());
+		assertEquals("second", deque.dequeueHead());
+		assertEquals("seventh", deque.dequeueHead());
+		assertEquals("sixth", deque.dequeueHead());
+		assertFalse(deque.isEmpty());
+		assertEquals("tenth", deque.dequeueHead());
+		assertEquals("third", deque.dequeueHead());
+		assertTrue(deque.isEmpty());
+	}
+
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/JptCommonUtilityDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/JptCommonUtilityDequeTests.java
new file mode 100644
index 0000000..ac657e3
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/JptCommonUtilityDequeTests.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * decentralize test creation code
+ */
+public class JptCommonUtilityDequeTests {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite(JptCommonUtilityDequeTests.class.getPackage().getName());
+
+		suite.addTestSuite(ArrayDequeTests.class);
+		suite.addTestSuite(DequeToolsTests.class);
+		suite.addTestSuite(EmptyDequeTests.class);
+		suite.addTestSuite(FixedCapacityArrayDequeTests.class);
+		suite.addTestSuite(FixedCapacityPriorityDequeTests.class);
+		suite.addTestSuite(LinkedDequeTests.class);
+		suite.addTestSuite(ListDequeTests.class);
+		suite.addTestSuite(PriorityDequeTests.class);
+		suite.addTestSuite(ReverseDequeTests.class);
+		suite.addTestSuite(SynchronizedDequeTests.class);
+
+		return suite;
+	}
+
+	private JptCommonUtilityDequeTests() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/LinkedDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/LinkedDequeTests.java
new file mode 100644
index 0000000..2a809c5
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/LinkedDequeTests.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.Arrays;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.LinkedDeque;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+@SuppressWarnings("nls")
+public class LinkedDequeTests
+	extends DequeTests
+{
+	public LinkedDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Deque<String> buildDeque() {
+		return DequeTools.linkedDeque();
+	}
+
+	public void testConstructorInt_IAE() {
+		boolean exCaught = false;
+		try {
+			Deque<String> queue = DequeTools.linkedDeque(-3);
+			fail("bogus deque: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSize() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueueTail(third);
+		assertEquals(3, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeueHead();
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeueHead();
+		queue.dequeueHead();
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+	}
+
+	public void testSize_reverse() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueueHead(third);
+		assertEquals(3, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeueTail();
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeueTail();
+		queue.dequeueTail();
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+	}
+
+	public void testBuildElements() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		queue.enqueueTail(third);
+
+		Object[] elements = new Object[] { first, second, third };
+		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(queue, "buildElements"))));
+	}
+
+	public void testBuildElements_reverse() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.enqueueHead(first);
+		queue.enqueueHead(second);
+		queue.enqueueHead(third);
+
+		Object[] elements = new Object[] { third, second, first };
+		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(queue, "buildElements"))));
+	}
+
+	public void testNodeCache_max() {
+		Deque<String> queue = new LinkedDeque<String>(2);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		queue.enqueueTail(first);
+		this.verifyNodeCache(0, factory);
+		queue.enqueueTail(second);
+		queue.enqueueHead(third);
+		queue.enqueueHead(fourth);
+		queue.enqueueTail(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		queue.dequeueHead();
+		this.verifyNodeCache(1, factory);
+		queue.dequeueHead();
+		this.verifyNodeCache(2, factory);
+		queue.dequeueTail();
+		this.verifyNodeCache(2, factory);
+		queue.dequeueHead();
+		this.verifyNodeCache(2, factory);
+		queue.dequeueTail();
+		this.verifyNodeCache(2, factory);
+		queue.enqueueTail(first);
+		this.verifyNodeCache(1, factory);
+		queue.enqueueTail(second);
+		this.verifyNodeCache(0, factory);
+		queue.enqueueTail(third);
+		this.verifyNodeCache(0, factory);
+	}
+
+
+	public void testNodeCache_unlimited() {
+		Deque<String> queue = DequeTools.linkedDeque(-1);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		queue.enqueueTail(first);
+		this.verifyNodeCache(0, factory);
+		queue.enqueueTail(second);
+		queue.enqueueHead(third);
+		queue.enqueueHead(fourth);
+		queue.enqueueTail(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		queue.dequeueHead();
+		this.verifyNodeCache(1, factory);
+		queue.dequeueHead();
+		this.verifyNodeCache(2, factory);
+		queue.dequeueTail();
+		this.verifyNodeCache(3, factory);
+		queue.dequeueHead();
+		this.verifyNodeCache(4, factory);
+		queue.dequeueTail();
+		this.verifyNodeCache(5, factory);
+		queue.enqueueTail(first);
+		this.verifyNodeCache(4, factory);
+		queue.enqueueTail(second);
+		this.verifyNodeCache(3, factory);
+		queue.enqueueTail(third);
+		this.verifyNodeCache(2, factory);
+		queue.enqueueTail(fourth);
+		this.verifyNodeCache(1, factory);
+		queue.enqueueTail(fifth);
+		this.verifyNodeCache(0, factory);
+	}
+
+	public void verifyNodeCache(int size, Object factory) {
+		assertEquals(size, ((Integer) ObjectTools.get(factory, "cacheSize")).intValue());
+		int nodeCount = 0;
+		for (Object node = ObjectTools.get(factory, "cacheHead"); node != null; node = ObjectTools.get(node, "next")) {
+			nodeCount++;
+		}
+		assertEquals(size, nodeCount);
+	}
+
+	public void testNodeToString() {
+		Deque<String> queue = DequeTools.linkedDeque();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.enqueueTail(first);
+		queue.enqueueTail(second);
+		queue.enqueueHead(third);
+
+		Object head = ObjectTools.get(queue, "head");
+		assertTrue(head.toString().startsWith("LinkedDeque.Node"));
+		assertTrue(head.toString().endsWith("(third)"));
+	}
+
+	public void testSimpleNodeFactoryToString() {
+		Deque<String> queue = DequeTools.linkedDeque();
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertEquals("LinkedDeque.SimpleNodeFactory", factory.toString());
+	}
+
+	public void testCachingNodeFactoryToString() {
+		Deque<String> queue = DequeTools.linkedDeque(20);
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedDeque.CachingNodeFactory"));
+		assertTrue(factory.toString().endsWith("(0)"));
+	}
+
+	public void testClone_caching() throws Exception {
+		LinkedDeque<String> original = DequeTools.linkedDeque(20);
+		original.enqueueTail("first");
+
+		LinkedDeque<String> clone = original.clone();
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueueTail("second");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+
+		Object factory = ObjectTools.get(original, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedDeque.CachingNodeFactory"));
+	}
+
+	public void testSerialization_caching() throws Exception {
+		Deque<String> original = DequeTools.linkedDeque(20);
+		original.enqueueTail("first");
+
+		Deque<String> clone = TestTools.serialize(original);
+		assertEquals(original.peekHead(), clone.peekHead());
+		assertEquals(original.dequeueHead(), clone.dequeueHead());
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueueTail("second");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+
+		Object factory = ObjectTools.get(original, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedDeque.CachingNodeFactory"));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ListDequeTests.java
similarity index 63%
copy from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
copy to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ListDequeTests.java
index 4012ee2..24263cb 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ListDequeTests.java
@@ -7,22 +7,22 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.deque;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.ListStack;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
 
-public class ListStackTests
-	extends StackTests
+public class ListDequeTests
+	extends DequeTests
 {
-	public ListStackTests(String name) {
+	public ListDequeTests(String name) {
 		super(name);
 	}
 
 	@Override
-	Stack<String> buildStack() {
-		return new ListStack<String>(new ArrayList<String>());
+	Deque<String> buildDeque() {
+		return DequeTools.adapt(new ArrayList<String>());
 	}
 
 	@Override
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/PriorityDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/PriorityDequeTests.java
new file mode 100644
index 0000000..cf98335
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/PriorityDequeTests.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.Comparator;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.deque.AbstractPriorityDeque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.PriorityDeque;
+
+@SuppressWarnings("nls")
+public class PriorityDequeTests
+	extends AbstractPriorityDequeTests
+{
+	public PriorityDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	<E extends Comparable<E>> PriorityDeque<E> buildDeque() {
+		return DequeTools.<E>priorityDeque();
+	}
+
+	@Override
+	<E extends Comparable<E>> PriorityDeque<E> buildDeque(int capacity) {
+		return DequeTools.priorityDeque(capacity);
+	}
+
+	@Override
+	<E extends Comparable<E>> PriorityDeque<E> buildDeque(Comparator<E> comparator, int capacity) {
+		return DequeTools.priorityDeque(comparator, capacity);
+	}
+
+	public void testArrayCapacityExceeded() {
+		AbstractPriorityDeque<Integer> deque = this.buildDeque();
+		assertTrue(deque.isEmpty());
+		deque.enqueue(Integer.valueOf(1));
+		assertFalse(deque.isEmpty());
+		deque.enqueue(Integer.valueOf(2));
+		assertFalse(deque.isEmpty());
+		deque.enqueue(Integer.valueOf(3));
+		deque.enqueue(Integer.valueOf(10));
+		deque.enqueue(Integer.valueOf(11));
+		deque.enqueue(Integer.valueOf(12));
+		deque.enqueue(Integer.valueOf(4));
+		deque.enqueue(Integer.valueOf(4));
+		deque.enqueue(Integer.valueOf(7));
+		deque.enqueue(Integer.valueOf(8));
+		deque.enqueue(Integer.valueOf(9));
+		deque.enqueue(Integer.valueOf(5));
+		deque.enqueue(Integer.valueOf(6));
+		deque.enqueue(Integer.valueOf(9));
+
+		assertEquals(Integer.valueOf(1), deque.dequeueHead());
+		assertFalse(deque.isEmpty());
+		assertEquals(Integer.valueOf(2), deque.dequeueHead());
+		assertFalse(deque.isEmpty());
+		assertEquals(Integer.valueOf(3), deque.dequeueHead());
+		assertEquals(Integer.valueOf(4), deque.dequeueHead());
+		assertEquals(Integer.valueOf(12), deque.dequeueTail());
+		assertEquals(Integer.valueOf(4), deque.dequeueHead());
+		assertEquals(Integer.valueOf(5), deque.dequeueHead());
+		assertEquals(Integer.valueOf(6), deque.dequeueHead());
+		assertEquals(Integer.valueOf(7), deque.dequeueHead());
+		assertEquals(Integer.valueOf(11), deque.dequeueTail());
+		assertEquals(Integer.valueOf(8), deque.dequeueHead());
+		assertEquals(Integer.valueOf(10), deque.dequeueTail());
+		assertEquals(Integer.valueOf(9), deque.dequeueHead());
+		assertEquals(Integer.valueOf(9), deque.dequeueHead());
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testEnsureCapacity() throws Exception {
+		PriorityDeque<String> deque = this.buildDeque();
+		deque.enqueue("b");
+		deque.enqueue("c");
+		deque.enqueue("a");
+		assertEquals(11, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		deque.ensureCapacity(420);
+		assertEquals(421, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		assertEquals("a", deque.dequeueHead());
+		assertEquals("c", deque.dequeueTail());
+		assertEquals("b", deque.dequeueHead());
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testTrimToSize() throws Exception {
+		PriorityDeque<String> deque = this.buildDeque();
+		deque.enqueue("b");
+		deque.enqueue("c");
+		deque.enqueue("a");
+		assertEquals(11, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		deque.trimToSize();
+		assertEquals(4, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		assertEquals("a", deque.dequeueHead());
+		assertEquals("c", deque.dequeueTail());
+		assertEquals("b", deque.dequeueHead());
+		assertTrue(deque.isEmpty());
+	}
+
+	public void testTrimToSize_nop() throws Exception {
+		PriorityDeque<String> deque = this.buildDeque(3);
+		deque.enqueue("b");
+		deque.enqueue("c");
+		deque.enqueue("a");
+		assertEquals(4, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		deque.trimToSize();
+		assertEquals(4, ((Object[]) ObjectTools.get(deque, "elements")).length);
+		assertEquals("a", deque.dequeueHead());
+		assertEquals("c", deque.dequeueTail());
+		assertEquals("b", deque.dequeueHead());
+		assertTrue(deque.isEmpty());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ReverseDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ReverseDequeTests.java
new file mode 100644
index 0000000..ddc4c76
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/ReverseDequeTests.java
@@ -0,0 +1,282 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.tests.internal.deque;
+
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+
+@SuppressWarnings("nls")
+public class ReverseDequeTests
+	extends DequeTests
+{
+	private Deque<String> original;
+
+	public ReverseDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.original = DequeTools.arrayDeque();
+	}
+
+	@Override
+	public Deque<String> buildDeque() {
+		return DequeTools.reverse(this.original);
+	}
+
+	public void testIsEmpty_combo() {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.isEmpty());
+		this.original.enqueueTail("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueueTail("second");
+		assertFalse(queue.isEmpty());
+		this.original.enqueueHead("zero");
+		assertFalse(queue.isEmpty());
+		queue.dequeueHead();
+		assertFalse(queue.isEmpty());
+		queue.dequeueHead();
+		assertFalse(queue.isEmpty());
+		queue.dequeueTail();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueTailAndDequeueTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.dequeueTail());
+	}
+
+	public void testEnqueueHeadAndDequeueHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueHead(first);
+		this.original.enqueueHead(second);
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.dequeueHead());
+	}
+
+	public void testEnqueueAndDequeue_combo() {
+		Deque<String> queue = this.buildDeque();
+		String negative = "negative";
+		String zero = "zero";
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		this.original.enqueueHead(zero);
+		this.original.enqueueHead(negative);
+		assertEquals(negative, queue.dequeueTail());
+		assertEquals(second, queue.dequeueHead());
+		assertEquals(zero, queue.dequeueTail());
+		assertEquals(first, queue.dequeueHead());
+
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueTailAndPeekTail() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+	}
+
+	public void testEnqueueHeadAndPeekHead() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueHead(first);
+		this.original.enqueueHead(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+	}
+
+	public void testEnqueueAndPeek_combo() {
+		Deque<String> queue = this.buildDeque();
+		String negative = "negative";
+		String zero = "zero";
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		this.original.enqueueHead(zero);
+		this.original.enqueueHead(negative);
+		assertEquals(negative, queue.peekTail());
+		assertEquals(negative, queue.peekTail());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.peekHead());
+
+		assertEquals(negative, queue.dequeueTail());
+		assertEquals(zero, queue.peekTail());
+		assertEquals(zero, queue.peekTail());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.peekHead());
+
+		assertEquals(second, queue.dequeueHead());
+		assertEquals(zero, queue.peekTail());
+		assertEquals(first, queue.peekHead());
+
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(zero, queue.peekTail());
+		assertEquals(zero, queue.peekHead());
+
+		assertEquals(zero, queue.dequeueHead());
+
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEmptyDequeExceptionPeekTail_combo() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			queue.peekTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionPeekHead_combo() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueHead(first);
+		this.original.enqueueHead(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			queue.peekHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionDequeueTail_combo() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueTail(first);
+		this.original.enqueueTail(second);
+		assertEquals(first, queue.peekTail());
+		assertEquals(first, queue.dequeueTail());
+		assertEquals(second, queue.peekTail());
+		assertEquals(second, queue.dequeueTail());
+
+		boolean exCaught = false;
+		try {
+			queue.dequeueTail();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyDequeExceptionDequeueHead_combo() {
+		Deque<String> queue = this.buildDeque();
+		String first = "first";
+		String second = "second";
+
+		this.original.enqueueHead(first);
+		this.original.enqueueHead(second);
+		assertEquals(first, queue.peekHead());
+		assertEquals(first, queue.dequeueHead());
+		assertEquals(second, queue.peekHead());
+		assertEquals(second, queue.dequeueHead());
+
+		boolean exCaught = false;
+		try {
+			queue.dequeueHead();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	@Override
+	public void testClone() {
+		// unsupported
+	}
+
+	@Override
+	public void testToString() throws Exception {
+		Deque<String> queue = this.buildDeque();
+		assertTrue(queue.toString().startsWith("ReverseDeque"));
+		assertTrue(queue.toString().endsWith("([])"));
+		queue.enqueueTail("first");
+		assertTrue(queue.toString().startsWith("ReverseDeque"));
+		assertTrue(queue.toString().endsWith("([first])"));
+		queue.enqueueTail("second");
+		assertTrue(queue.toString().startsWith("ReverseDeque"));
+		assertTrue(queue.toString().endsWith("([second, first])"));
+		queue.enqueueTail("third");
+		assertTrue(queue.toString().startsWith("ReverseDeque"));
+		assertTrue(queue.toString().endsWith("([third, second, first])"));
+		queue.enqueueHead("foo");
+		assertTrue(queue.toString().startsWith("ReverseDeque"));
+		assertTrue(queue.toString().endsWith("([third, second, first, foo])"));
+	}
+
+	public void testCtor_nullDeque() {
+		boolean exCaught = false;
+		try {
+			Deque<String> deque = DequeTools.reverse(null);
+			fail("bogus deque: " + deque);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/SynchronizedDequeTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/SynchronizedDequeTests.java
new file mode 100644
index 0000000..2f916dd
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/deque/SynchronizedDequeTests.java
@@ -0,0 +1,1255 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.deque;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.deque.Deque;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.deque.LinkedDeque;
+import org.eclipse.jpt.common.utility.internal.deque.SynchronizedDeque;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
+
+@SuppressWarnings("nls")
+public class SynchronizedDequeTests
+	extends DequeTests
+{
+	private volatile SynchronizedDeque<String> syncDeque;
+	volatile boolean timeoutOccurred;
+	volatile long startTime;
+	volatile long endTime;
+	volatile Object dequeueHeadObject;
+	volatile Object dequeueTailObject;
+
+	boolean commandExecuted;
+
+	static final String ITEM_1 = new String();
+	static final String ITEM_2 = new String();
+
+	public SynchronizedDequeTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Deque<String> buildDeque() {
+		return DequeTools.synchronizedDeque();
+	}
+
+	@Override
+	public void testClone() {
+		// unsupported
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.syncDeque = DequeTools.synchronizedDeque();
+		this.timeoutOccurred = false;
+		this.startTime = 0;
+		this.endTime = 0;
+		this.dequeueHeadObject = null;
+	}
+
+	// ********** constructor **********
+
+	public void testConstructorDeque() throws Exception {
+		Deque<String> innerDeque = DequeTools.arrayDeque();
+		SynchronizedDeque<String> stack = DequeTools.synchronizedDeque(innerDeque);
+		assertNotNull(stack);
+		assertSame(stack, stack.getMutex());
+	}
+
+	public void testConstructorDeque_NPE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Deque<String> stack = DequeTools.synchronizedDeque(null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorDequeObject() throws Exception {
+		String mutex = "mutex";
+		Deque<String> innerDeque = DequeTools.arrayDeque();
+		SynchronizedDeque<String> stack = DequeTools.synchronizedDeque(innerDeque, mutex);
+		assertNotNull(stack);
+		assertSame(mutex, stack.getMutex());
+	}
+
+	public void testConstructorDequeObject_NPE1() throws Exception {
+		String mutex = "mutex";
+		boolean exCaught = false;
+		try {
+			Deque<String> stack = DequeTools.synchronizedDeque(null, mutex);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorDequeObject_NPE2() throws Exception {
+		Deque<String> innerDeque = DequeTools.arrayDeque();
+		boolean exCaught = false;
+		try {
+			Deque<String> stack = DequeTools.synchronizedDeque(innerDeque, null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	// ********** concurrent access **********
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentDequeueHead() throws Exception {
+		this.verifyConcurrentDequeueHead(new SlowLinkedDeque<String>(), "first");
+		this.verifyConcurrentDequeueHead(new SlowSynchronizedDeque<String>(), "second");
+	}
+
+	private void verifyConcurrentDequeueHead(SlowDeque<String> slowDeque, String expected) throws Exception {
+		slowDeque.enqueueTail("first");
+		slowDeque.enqueueTail("second");
+
+		Thread thread = this.buildThread(this.buildRunnableDequeueHead(slowDeque));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(expected, slowDeque.dequeueHead());
+		thread.join();
+		assertTrue(slowDeque.isEmpty());
+	}
+
+	private Runnable buildRunnableDequeueHead(final SlowDeque<String> slowDeque) {
+		return new Runnable() {
+			public void run() {
+				slowDeque.slowDequeueHead();
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentDequeueTail() throws Exception {
+		this.verifyConcurrentDequeueTail(new SlowLinkedDeque<String>(), "first");
+		this.verifyConcurrentDequeueTail(new SlowSynchronizedDeque<String>(), "second");
+	}
+
+	private void verifyConcurrentDequeueTail(SlowDeque<String> slowDeque, String expected) throws Exception {
+		slowDeque.enqueueHead("first");
+		slowDeque.enqueueHead("second");
+
+		Thread thread = this.buildThread(this.buildRunnableDequeueTail(slowDeque));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(expected, slowDeque.dequeueTail());
+		thread.join();
+		assertTrue(slowDeque.isEmpty());
+	}
+
+	private Runnable buildRunnableDequeueTail(final SlowDeque<String> slowDeque) {
+		return new Runnable() {
+			public void run() {
+				slowDeque.slowDequeueTail();
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentEnqueueTail() throws Exception {
+		this.verifyConcurrentEnqueueTail(new SlowLinkedDeque<String>(), "second", "first");
+		this.verifyConcurrentEnqueueTail(new SlowSynchronizedDeque<String>(), "first", "second");
+	}
+
+	private void verifyConcurrentEnqueueTail(SlowDeque<String> slowDeque, String first, String second) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnableEnqueueTail(slowDeque, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		slowDeque.enqueueTail("second");
+		thread.join();
+		assertEquals(first, slowDeque.dequeueHead());
+		assertEquals(second, slowDeque.dequeueHead());
+		assertTrue(slowDeque.isEmpty());
+	}
+
+	private Runnable buildRunnableEnqueueTail(final SlowDeque<String> slowDeque, final String element) {
+		return new Runnable() {
+			public void run() {
+				slowDeque.slowEnqueueTail(element);
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentEnqueueHead() throws Exception {
+		this.verifyConcurrentEnqueueHead(new SlowLinkedDeque<String>(), "second", "first");
+		this.verifyConcurrentEnqueueHead(new SlowSynchronizedDeque<String>(), "first", "second");
+	}
+
+	private void verifyConcurrentEnqueueHead(SlowDeque<String> slowDeque, String first, String second) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnableEnqueueHead(slowDeque, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		slowDeque.enqueueHead("second");
+		thread.join();
+		assertEquals(first, slowDeque.dequeueTail());
+		assertEquals(second, slowDeque.dequeueTail());
+		assertTrue(slowDeque.isEmpty());
+	}
+
+	private Runnable buildRunnableEnqueueHead(final SlowDeque<String> slowDeque, final String element) {
+		return new Runnable() {
+			public void run() {
+				slowDeque.slowEnqueueHead(element);
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentIsEmpty() throws Exception {
+		this.verifyConcurrentIsEmpty(new SlowLinkedDeque<String>(), true);
+		this.verifyConcurrentIsEmpty(new SlowSynchronizedDeque<String>(), false);
+	}
+
+	private void verifyConcurrentIsEmpty(SlowDeque<String> slowDeque, boolean empty) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnableEnqueueTail(slowDeque, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(empty, slowDeque.isEmpty());
+		thread.join();
+		assertEquals("first", slowDeque.dequeueHead());
+		assertTrue(slowDeque.isEmpty());
+	}
+
+
+	private interface SlowDeque<E> extends Deque<E> {
+		Object slowDequeueHead();
+		Object slowDequeueTail();
+		void slowEnqueueTail(E element);
+		void slowEnqueueHead(E element);
+	}
+
+	private class SlowLinkedDeque<E> extends LinkedDeque<E> implements SlowDeque<E> {
+		private static final long serialVersionUID = 1L;
+		SlowLinkedDeque() {
+			super();
+		}
+		public Object slowDequeueHead() {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			return this.dequeueHead();
+		}
+		public Object slowDequeueTail() {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			return this.dequeueTail();
+		}
+		public void slowEnqueueTail(E element) {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			this.enqueueTail(element);
+		}
+		public void slowEnqueueHead(E element) {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			this.enqueueHead(element);
+		}
+	}
+
+	private class SlowSynchronizedDeque<E> extends SynchronizedDeque<E> implements SlowDeque<E> {
+		private static final long serialVersionUID = 1L;
+		SlowSynchronizedDeque() {
+			super(DequeTools.<E>linkedDeque());
+		}
+		public Object slowDequeueHead() {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				return this.dequeueHead();
+			}
+		}
+		public Object slowDequeueTail() {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				return this.dequeueTail();
+			}
+		}
+		public void slowEnqueueTail(E element) {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				this.enqueueTail(element);
+			}
+		}
+		public void slowEnqueueHead(E element) {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				this.enqueueHead(element);
+			}
+		}
+	}
+
+
+	// ********** waits **********
+
+	public void testWaitUntilEmpty() throws Exception {
+		this.verifyWaitUntilEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmpty2() throws Exception {
+		this.verifyWaitUntilEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmptyTimeout() throws Exception {
+		this.verifyWaitUntilEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue was dequeueHead...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilEmpty(long timeout) throws Exception {
+		this.syncDeque.enqueueTail(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildDequeueHeadCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilEmptyCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				SynchronizedDequeTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedDeque.waitUntilEmpty();
+					return false;
+				}
+				return ! synchronizedDeque.waitUntilEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitUntilNotEmpty() throws Exception {
+		this.verifyWaitUntilNotEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been enqueueTail by t1...
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_1, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmpty2() throws Exception {
+		this.verifyWaitUntilNotEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been enqueueTail by t1...
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_1, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmptyTimeout() throws Exception {
+		this.verifyWaitUntilNotEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and an item should have been enqueueTail by t1...
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_1, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilNotEmpty(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildEnqueueTailCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilNotEmptyCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilNotEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				SynchronizedDequeTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedDeque.waitUntilNotEmpty();
+					return false;
+				}
+				return ! synchronizedDeque.waitUntilNotEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitToDequeueHead() throws Exception {
+		this.verifyWaitToDequeueHead(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueHead by t2...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeueHead2() throws Exception {
+		this.verifyWaitToDequeueHead(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueHead by t2...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeueHeadTimeout() throws Exception {
+		this.verifyWaitToDequeueHead(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue was never dequeueHead...
+		assertNull(this.dequeueHeadObject);
+		// ...and it still holds the item
+		assertSame(ITEM_1, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToDequeueHead(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildEnqueueTailCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToDequeueHeadCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToDequeueHeadCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				this.waitToDequeueHead(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private void waitToDequeueHead(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					SynchronizedDequeTests.this.dequeueHeadObject = synchronizedDeque.waitToDequeueHead();
+					return;
+				}
+				try {
+					SynchronizedDequeTests.this.dequeueHeadObject = synchronizedDeque.waitToDequeueHead(timeout);
+				} catch (NoSuchElementException ex) {
+					SynchronizedDequeTests.this.timeoutOccurred = true;
+				}
+			}
+		};
+	}
+
+	public void testWaitToDequeueTail() throws Exception {
+		this.verifyWaitToDequeueTail(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueTaild by t2...
+		assertSame(ITEM_1, this.dequeueTailObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeueTail2() throws Exception {
+		this.verifyWaitToDequeueTail(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeueTaild by t2...
+		assertSame(ITEM_1, this.dequeueTailObject);
+		// ...and the queue should be empty
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeueTailTimeout() throws Exception {
+		this.verifyWaitToDequeueTail(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue was never dequeueTaild...
+		assertNull(this.dequeueTailObject);
+		// ...and it still holds the item
+		assertSame(ITEM_1, this.syncDeque.peekTail());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToDequeueTail(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildEnqueueHeadCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToDequeueTailCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToDequeueTailCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				this.waitToDequeueTail(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private void waitToDequeueTail(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					SynchronizedDequeTests.this.dequeueTailObject = synchronizedDeque.waitToDequeueTail();
+					return;
+				}
+				try {
+					SynchronizedDequeTests.this.dequeueTailObject = synchronizedDeque.waitToDequeueTail(timeout);
+				} catch (NoSuchElementException ex) {
+					SynchronizedDequeTests.this.timeoutOccurred = true;
+				}
+			}
+		};
+	}
+
+	public void testWaitToEnqueueTail() throws Exception {
+		this.verifyWaitToEnqueueTail(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and an item is enqueueTail on to the queue by t2
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_2, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueueTail2() throws Exception {
+		this.verifyWaitToEnqueueTail(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and an item is enqueueTail on to the queue by t2
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_2, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueueTailTimeout() throws Exception {
+		this.verifyWaitToEnqueueTail(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue is eventually dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...but nothing is enqueueTail on to the queue by t2
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToEnqueueTail(long timeout) throws Exception {
+		this.syncDeque.enqueueTail(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildDequeueHeadCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToEnqueueTailCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToEnqueueTailCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				SynchronizedDequeTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedDeque.waitToEnqueueTail(ITEM_2);
+					return false;
+				}
+				return ! synchronizedDeque.waitToEnqueueTail(ITEM_2, timeout);
+			}
+		};
+	}
+
+	public void testWaitToEnqueueHead() throws Exception {
+		this.verifyWaitToEnqueueHead(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and an item is enqueueHead on to the queue by t2
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_2, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueueHead2() throws Exception {
+		this.verifyWaitToEnqueueHead(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...and an item is enqueueHead on to the queue by t2
+		assertFalse(this.syncDeque.isEmpty());
+		assertSame(ITEM_2, this.syncDeque.peekHead());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueueHeadTimeout() throws Exception {
+		this.verifyWaitToEnqueueHead(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue is eventually dequeueHead by t1...
+		assertSame(ITEM_1, this.dequeueHeadObject);
+		// ...but nothing is enqueueHead on to the queue by t2
+		assertTrue(this.syncDeque.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToEnqueueHead(long timeout) throws Exception {
+		this.syncDeque.enqueueHead(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildDequeueHeadCommand(), this.syncDeque, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToEnqueueHeadCommand(timeout), this.syncDeque, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToEnqueueHeadCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				SynchronizedDequeTests.this.startTime = System.currentTimeMillis();
+				SynchronizedDequeTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedDeque);
+				SynchronizedDequeTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedDeque.waitToEnqueueHead(ITEM_2);
+					return false;
+				}
+				return ! synchronizedDeque.waitToEnqueueHead(ITEM_2, timeout);
+			}
+		};
+	}
+
+	private Command buildEnqueueTailCommand() {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) {
+				synchronizedDeque.enqueueTail(ITEM_1);
+			}
+		};
+	}
+
+	private Command buildEnqueueHeadCommand() {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) {
+				synchronizedDeque.enqueueHead(ITEM_1);
+			}
+		};
+	}
+
+	private Command buildDequeueHeadCommand() {
+		return new Command() {
+			public void execute(SynchronizedDeque<String> synchronizedDeque) {
+				SynchronizedDequeTests.this.dequeueHeadObject = synchronizedDeque.dequeueHead();
+			}
+		};
+	}
+
+	private Runnable buildRunnable(final Command command, final SynchronizedDeque<String> synchronizedDeque, final long sleep) {
+		return new TestRunnable() {
+			@Override
+			protected void run_() throws Throwable {
+				if (sleep != 0) {
+					Thread.sleep(sleep);
+				}
+				command.execute(synchronizedDeque);
+			}
+		};
+	}
+
+	long calculateElapsedTime() {
+		return this.endTime - this.startTime;
+	}
+
+
+	// ********** Command interface **********
+
+	private interface Command {
+		void execute(SynchronizedDeque<String> synchronizedDeque) throws InterruptedException;
+	}
+
+
+	// ********** execute **********
+
+	public void testExecute() throws Exception {
+		org.eclipse.jpt.common.utility.command.Command command = new org.eclipse.jpt.common.utility.command.Command() {
+			public void execute() {
+				SynchronizedDequeTests.this.commandExecuted = true;
+			}
+		};
+		this.commandExecuted = false;
+		this.syncDeque.execute(command);
+		assertTrue(this.commandExecuted);
+	}
+
+
+	// ********** additional protocol **********
+
+	public void testEnqueueTailAllIterable() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		this.syncDeque.enqueueTailAll(list);
+		assertEquals("one", this.syncDeque.dequeueHead());
+		assertEquals("two", this.syncDeque.dequeueHead());
+		assertEquals("three", this.syncDeque.dequeueHead());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllIterable_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		this.syncDeque.enqueueTailAll(list);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllObjectArray() throws Exception {
+		this.syncDeque.enqueueTailAll(new String[] { "one", "two", "three" });
+		assertEquals("one", this.syncDeque.dequeueHead());
+		assertEquals("two", this.syncDeque.dequeueHead());
+		assertEquals("three", this.syncDeque.dequeueHead());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllObjectArray_empty() throws Exception {
+		this.syncDeque.enqueueTailAll(new String[0]);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllStack() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		this.syncDeque.enqueueTailAll(stack);
+		assertEquals("three", this.syncDeque.dequeueHead());
+		assertEquals("two", this.syncDeque.dequeueHead());
+		assertEquals("one", this.syncDeque.dequeueHead());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		this.syncDeque.enqueueTailAll(stack);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllDeque() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		queue.enqueueTail("one");
+		queue.enqueueTail("two");
+		queue.enqueueTail("three");
+		this.syncDeque.enqueueTailAll(queue);
+		assertEquals("one", this.syncDeque.dequeueHead());
+		assertEquals("two", this.syncDeque.dequeueHead());
+		assertEquals("three", this.syncDeque.dequeueHead());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueTailAllDeque_empty() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		this.syncDeque.enqueueTailAll(queue);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testDrainHead() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		ArrayList<String> list = this.syncDeque.drainHead();
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainHead_empty() throws Exception {
+		ArrayList<String> list = this.syncDeque.drainHead();
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainHeadToCollection() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(this.syncDeque.drainHeadTo(list));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainHeadToCollection_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(this.syncDeque.drainHeadTo(list));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainHeadToListInt() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.syncDeque.drainHeadTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("one", list.get(2));
+		assertEquals("two", list.get(3));
+		assertEquals("three", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testDrainHeadToListInt_end() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.syncDeque.drainHeadTo(list, 3));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("one", list.get(3));
+		assertEquals("two", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainHeadToListInt_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertFalse(this.syncDeque.drainHeadTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+	}
+
+	public void testDrainHeadToStack() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(this.syncDeque.drainHeadTo(stack));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainHeadToStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(this.syncDeque.drainHeadTo(stack));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainHeadToDeque() throws Exception {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("three");
+		Deque<String> queue = DequeTools.arrayDeque();
+		assertTrue(this.syncDeque.drainHeadTo(queue));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", queue.dequeueHead());
+		assertEquals("two", queue.dequeueHead());
+		assertEquals("three", queue.dequeueHead());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainHeadToDeque_empty() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		assertFalse(this.syncDeque.drainHeadTo(queue));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainHeadToMapTransformer() {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.syncDeque.drainHeadTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainHeadToMapTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.syncDeque.drainHeadTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainHeadToMapTransformerTransformer() {
+		this.syncDeque.enqueueTail("one");
+		this.syncDeque.enqueueTail("two");
+		this.syncDeque.enqueueTail("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.syncDeque.drainHeadTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainHeadToMapTransformerTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.syncDeque.drainHeadTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testEnqueueHeadAllIterable() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		this.syncDeque.enqueueHeadAll(list);
+		assertEquals("one", this.syncDeque.dequeueTail());
+		assertEquals("two", this.syncDeque.dequeueTail());
+		assertEquals("three", this.syncDeque.dequeueTail());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllIterable_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		this.syncDeque.enqueueHeadAll(list);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllObjectArray() throws Exception {
+		this.syncDeque.enqueueHeadAll(new String[] { "one", "two", "three" });
+		assertEquals("one", this.syncDeque.dequeueTail());
+		assertEquals("two", this.syncDeque.dequeueTail());
+		assertEquals("three", this.syncDeque.dequeueTail());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllObjectArray_empty() throws Exception {
+		this.syncDeque.enqueueHeadAll(new String[0]);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllStack() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		this.syncDeque.enqueueHeadAll(stack);
+		assertEquals("three", this.syncDeque.dequeueTail());
+		assertEquals("two", this.syncDeque.dequeueTail());
+		assertEquals("one", this.syncDeque.dequeueTail());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		this.syncDeque.enqueueHeadAll(stack);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllDeque() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		queue.enqueueHead("one");
+		queue.enqueueHead("two");
+		queue.enqueueHead("three");
+		this.syncDeque.enqueueHeadAll(queue);
+		assertEquals("one", this.syncDeque.dequeueTail());
+		assertEquals("two", this.syncDeque.dequeueTail());
+		assertEquals("three", this.syncDeque.dequeueTail());
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testEnqueueHeadAllDeque_empty() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		this.syncDeque.enqueueHeadAll(queue);
+		assertTrue(this.syncDeque.isEmpty());
+	}
+
+	public void testDrainTail() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		ArrayList<String> list = this.syncDeque.drainTail();
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainTail_empty() throws Exception {
+		ArrayList<String> list = this.syncDeque.drainTail();
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainTailToCollection() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(this.syncDeque.drainTailTo(list));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainTailToCollection_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(this.syncDeque.drainTailTo(list));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainTailToListInt() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.syncDeque.drainTailTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("one", list.get(2));
+		assertEquals("two", list.get(3));
+		assertEquals("three", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testDrainTailToListInt_end() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.syncDeque.drainTailTo(list, 3));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("one", list.get(3));
+		assertEquals("two", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainTailToListInt_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertFalse(this.syncDeque.drainTailTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+	}
+
+	public void testDrainTailToStack() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(this.syncDeque.drainTailTo(stack));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainTailToStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(this.syncDeque.drainTailTo(stack));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainTailToDeque() throws Exception {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("three");
+		Deque<String> queue = DequeTools.arrayDeque();
+		assertTrue(this.syncDeque.drainTailTo(queue));
+		assertTrue(this.syncDeque.isEmpty());
+		assertEquals("one", queue.dequeueTail());
+		assertEquals("two", queue.dequeueTail());
+		assertEquals("three", queue.dequeueTail());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainTailToDeque_empty() throws Exception {
+		Deque<String> queue = DequeTools.arrayDeque();
+		assertFalse(this.syncDeque.drainTailTo(queue));
+		assertTrue(this.syncDeque.isEmpty());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainTailToMapTransformer() {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.syncDeque.drainTailTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainTailToMapTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.syncDeque.drainTailTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainTailToMapTransformerTransformer() {
+		this.syncDeque.enqueueHead("one");
+		this.syncDeque.enqueueHead("two");
+		this.syncDeque.enqueueHead("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.syncDeque.drainTailTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainTailToMapTransformerTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.syncDeque.drainTailTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/eol/CheckWinEOL.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/eol/CheckWinEOL.java
index 7f362da..ca86f6b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/eol/CheckWinEOL.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/eol/CheckWinEOL.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 1998, 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
  * This program and the accompanying materials are made available under the 
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License
  * v1.0, both of which accompany this distribution.
@@ -47,7 +47,7 @@
 		Iterable<File> invalidJavaFiles = getAllJavaFilesWithInvalidWinEOL(rootDirectoryName);
 		int count = 0;
 		System.out.println("Java files with bogus EOL:");
-		for (String invalidFileName : CollectionTools.sortedSet(IterableTools.transform(invalidJavaFiles, FILE_ABSOLUTE_PATH_TRANSFORMER))) {
+		for (String invalidFileName : CollectionTools.treeSet(IterableTools.transform(invalidJavaFiles, FILE_ABSOLUTE_PATH_TRANSFORMER))) {
 			count++;
 			System.out.print('\t');
 			System.out.println(invalidFileName);
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/io/FileToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/io/FileToolsTests.java
index 2e2996f..500a313 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/io/FileToolsTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/io/FileToolsTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -54,22 +54,22 @@
 	}
 
 	public void testFilesIn() {
-		Collection<File> files = CollectionTools.collection(FileTools.files(this.tempDir.getPath()));
+		Collection<File> files = CollectionTools.hashBag(FileTools.files(this.tempDir.getPath()));
 		assertEquals("invalid file count", 3, files.size());
 	}
 
 	public void testDirectoriesIn() {
-		Collection<File> files = CollectionTools.collection(FileTools.directories(this.tempDir.getPath()));
+		Collection<File> files = CollectionTools.hashBag(FileTools.directories(this.tempDir.getPath()));
 		assertEquals("invalid directory count", 2, files.size());
 	}
 
 	public void testFilesInTree() {
-		Collection<File> files = CollectionTools.collection(FileTools.allFiles(this.tempDir.getPath()));
+		Collection<File> files = CollectionTools.hashBag(FileTools.allFiles(this.tempDir.getPath()));
 		assertEquals("invalid file count", 9, files.size());
 	}
 
 	public void testDirectoriesInTree() {
-		Collection<File> files = CollectionTools.collection(FileTools.allDirectories(this.tempDir.getPath()));
+		Collection<File> files = CollectionTools.hashBag(FileTools.allDirectories(this.tempDir.getPath()));
 		assertEquals("invalid directory count", 3, files.size());
 	}
 
@@ -159,7 +159,7 @@
 
 		FileFilter filter = this.buildFileFilter(prefix);
 		Iterator<File> filteredFilesIterator = FileTools.filter(FileTools.files(this.tempDir), filter);
-		Collection<File> filteredFiles = CollectionTools.collection(filteredFilesIterator);
+		Collection<File> filteredFiles = CollectionTools.hashBag(filteredFilesIterator);
 		assertEquals(2, filteredFiles.size());
 		assertTrue(filteredFiles.contains(testFile1));
 		assertTrue(filteredFiles.contains(testFile2));
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/GraphIterableTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/GraphIterableTests.java
index 679225a..95715ee 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/GraphIterableTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/GraphIterableTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -121,7 +121,7 @@
 		}
 
 		void setNeighbors(GraphNode[] neighbors) {
-			this.neighbors = ListTools.list(neighbors);
+			this.neighbors = ListTools.arrayList(neighbors);
 		}
 
 		public Iterable<GraphNode> getNeighbors() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/QueueIterableTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/QueueIterableTests.java
index 2695501..1d8ee7a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/QueueIterableTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/QueueIterableTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -10,10 +10,9 @@
 package org.eclipse.jpt.common.utility.tests.internal.iterable;
 
 import junit.framework.TestCase;
-
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedQueue;
 import org.eclipse.jpt.common.utility.internal.iterable.QueueIterable;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 @SuppressWarnings("nls")
 public class QueueIterableTests extends TestCase {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/StackIterableTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/StackIterableTests.java
index e28542f..3235a9a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/StackIterableTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterable/StackIterableTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -12,10 +12,9 @@
 import java.util.Iterator;
 
 import junit.framework.TestCase;
-
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedStack;
 import org.eclipse.jpt.common.utility.internal.iterable.StackIterable;
+import org.eclipse.jpt.common.utility.internal.stack.LinkedStack;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 @SuppressWarnings("nls")
 public class StackIterableTests extends TestCase {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/GraphIteratorTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/GraphIteratorTests.java
index bb47dbe..2779274 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/GraphIteratorTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/GraphIteratorTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2005, 2015 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.
@@ -141,7 +141,7 @@
 		}
 
 		void setNeighbors(GraphNode[] neighbors) {
-			this.neighbors = ListTools.list(neighbors);
+			this.neighbors = ListTools.arrayList(neighbors);
 		}
 
 		public Iterator<GraphNode> neighbors() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/ReadOnlyCompositeListIteratorTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/ReadOnlyCompositeListIteratorTests.java
index 72786c2..0776ef1 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/ReadOnlyCompositeListIteratorTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/iterator/ReadOnlyCompositeListIteratorTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -200,8 +200,8 @@
 		List<List<? extends Number>> list = new ArrayList<List<? extends Number>>();
 		list.add(integerList);
 		list.add(floatList);
-		Transformer<List<? extends Number>, ListIterator<? extends Number>> transformer = ListTools.readOnlyListIteratorTransformer();
-		ListIterator<ListIterator<? extends Number>> numberIterators = IteratorTools.transform(list.listIterator(), transformer);
+		Transformer<List<? extends Number>, ListIterator<Number>> transformer = ListTools.readOnlyListIteratorTransformer();
+		ListIterator<ListIterator<Number>> numberIterators = IteratorTools.transform(list.listIterator(), transformer);
 		ListIterator<Number> li = IteratorTools.concatenateReadOnly(numberIterators);
 		while (li.hasNext()) {
 			assertTrue(li.next().intValue() > 0);
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionAspectAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionAspectAdapterTests.java
index 977a946..b52a11b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionAspectAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionAspectAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -131,7 +131,7 @@
 	}
 
 	public void testSubjectHolder() {
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 		assertNull(this.event1);
 
 		this.subjectHolder1.setValue(this.subject2);
@@ -139,7 +139,7 @@
 		assertEquals(this.event1Type, CHANGE);
 		assertEquals(this.aa1, this.event1.getSource());
 		assertEquals(CollectionValueModel.VALUES, this.event1.getCollectionName());
-		assertEquals(this.subject2Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject2Names(), CollectionTools.hashBag(this.aa1.iterator()));
 		
 		this.event1 = null;
 		this.event1Type = null;
@@ -157,11 +157,11 @@
 		assertEquals(this.event1Type, CHANGE);
 		assertEquals(this.aa1, this.event1.getSource());
 		assertEquals(CollectionValueModel.VALUES, this.event1.getCollectionName());
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 	}
 
 	public void testAdd() {
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 		assertNull(this.event1);
 
 		this.subject1.addName("jam");
@@ -172,7 +172,7 @@
 		assertEquals("jam", ((CollectionAddEvent) this.event1).getItems().iterator().next());
 		Collection<String> namesPlus = this.subject1Names();
 		namesPlus.add("jam");
-		assertEquals(namesPlus, CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(namesPlus, CollectionTools.hashBag(this.aa1.iterator()));
 
 		this.event1 = null;
 		this.event1Type = null;
@@ -183,11 +183,11 @@
 		assertEquals(CollectionValueModel.VALUES, this.event1.getCollectionName());
 		assertEquals("jaz", ((CollectionAddEvent) this.event1).getItems().iterator().next());
 		namesPlus.add("jaz");
-		assertEquals(namesPlus, CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(namesPlus, CollectionTools.hashBag(this.aa1.iterator()));
 	}
 
 	public void testRemove() {
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 		assertNull(this.event1);
 
 		this.subject1.removeName("foo");
@@ -198,7 +198,7 @@
 		assertEquals("foo", ((CollectionRemoveEvent) this.event1).getItems().iterator().next());
 		Collection<String> namesMinus = this.subject1Names();
 		namesMinus.remove("foo");
-		assertEquals(namesMinus, CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(namesMinus, CollectionTools.hashBag(this.aa1.iterator()));
 
 		this.event1 = null;
 		this.event1Type = null;
@@ -209,11 +209,11 @@
 		assertEquals(CollectionValueModel.VALUES, this.event1.getCollectionName());
 		assertEquals("bar", ((CollectionRemoveEvent) this.event1).getItems().iterator().next());
 		namesMinus.remove("bar");
-		assertEquals(namesMinus, CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(namesMinus, CollectionTools.hashBag(this.aa1.iterator()));
 	}
 
 	public void testCollectionChange() {
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 		assertNull(this.event1);
 
 		this.subject1.addTwoNames("jam", "jaz");
@@ -224,12 +224,12 @@
 		Collection<String> namesPlus2 = this.subject1Names();
 		namesPlus2.add("jam");
 		namesPlus2.add("jaz");
-		assertEquals(namesPlus2, CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(namesPlus2, CollectionTools.hashBag(this.aa1.iterator()));
 	}
 
 	public void testIterator() {
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.subject1.names()));
-		assertEquals(this.subject1Names(), CollectionTools.bag(this.aa1.iterator()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.subject1.names()));
+		assertEquals(this.subject1Names(), CollectionTools.hashBag(this.aa1.iterator()));
 	}
 
 	public void testSize() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionListValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionListValueModelAdapterTests.java
index dbd9f43..659b3d1 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionListValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionListValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -73,7 +73,7 @@
 	}
 
 	private Collection<String> adapterCollection() {
-		return CollectionTools.collection(this.adapter.iterator());
+		return CollectionTools.hashBag(this.adapter.iterator());
 	}
 
 	public void testStaleValue() {
@@ -114,7 +114,7 @@
 
 		Collection<String> adapterCollection = this.adapterCollection();
 		assertEquals(this.wrappedCollection, adapterCollection);
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 	}
 
@@ -136,7 +136,7 @@
 
 		Collection<String> adapterCollection = this.adapterCollection();
 		assertEquals(this.wrappedCollection, adapterCollection);
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 	}
 
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
index 7f02e0d..bdf7a7e 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CollectionPropertyValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -56,7 +56,7 @@
 	}
 
 	private Collection<String> wrappedCollection() {
-		return CollectionTools.collection(this.wrappedCollectionHolder.iterator());
+		return CollectionTools.hashBag(this.wrappedCollectionHolder.iterator());
 	}
 
 	public void testValue() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeCollectionValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeCollectionValueModelTests.java
index 7827461..22dd60c 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeCollectionValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/CompositeCollectionValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -71,51 +71,51 @@
 		assertEquals(3, familiesSynch.size());
 		assertEquals(12, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(12, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		jetsons.removeMember(jetsons.memberNamed("Astro"));
 		assertEquals(3, familiesSynch.size());
 		assertEquals(11, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(11, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		jetsons.removeMember(jetsons.memberNamed("Judy"));
 		assertEquals(3, familiesSynch.size());
 		assertEquals(10, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(10, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		jetsons.addMember("Fido");
 		assertEquals(3, familiesSynch.size());
 		assertEquals(11, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(11, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		this.neighborhood.removeFamily(jetsons);
 		assertEquals(2, familiesSynch.size());
 		assertEquals(7, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(7, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		Family bears = this.neighborhood.addFamily("Bear");
 			bears.addMember("Yogi");
 		assertEquals(3, familiesSynch.size());
 		assertEquals(8, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(8, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		bears.addMember("Boo-Boo");
 		assertEquals(3, familiesSynch.size());
 		assertEquals(9, IteratorTools.size(this.neighborhood.allMembers()));
 		assertEquals(9, membersSynch.size());
-		assertEquals(CollectionTools.bag(this.neighborhood.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(this.neighborhood.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 
 		Neighborhood n2 = new Neighborhood("Hanna-Barbera 2");
 		this.neighborhoodHolder.setValue(n2);
@@ -123,8 +123,8 @@
 		assertEquals(3, familiesSynch.size());
 		assertEquals(12, IteratorTools.size(n2.allMembers()));
 		assertEquals(12, membersSynch.size());
-		assertEquals(CollectionTools.bag(n2.allMembers()), membersSynch);
-		assertEquals(membersSynch, CollectionTools.bag(compositeCVM.iterator()));
+		assertEquals(CollectionTools.hashBag(n2.allMembers()), membersSynch);
+		assertEquals(membersSynch, CollectionTools.hashBag(compositeCVM.iterator()));
 	}
 
 	public void testNoTransformer() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ExtendedListValueModelWrapperTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ExtendedListValueModelWrapperTests.java
index 604397e..2a356d3 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ExtendedListValueModelWrapperTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ExtendedListValueModelWrapperTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -103,7 +103,7 @@
 
 	public void testIterator() {
 		this.extendedListHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.buildListener());
-		assertEquals(this.buildExtendedList(), ListTools.list(this.extendedListHolder.iterator()));
+		assertEquals(this.buildExtendedList(), ListTools.arrayList(this.extendedListHolder.iterator()));
 	}
 
 	public void testSize() {
@@ -121,7 +121,7 @@
 	}
 
 	private boolean extendedListContainsAny(Collection<String> items) {
-		List<String> extendedList = ListTools.list(this.extendedListHolder.iterator());
+		List<String> extendedList = ListTools.arrayList(this.extendedListHolder.iterator());
 		for (Iterator<String> stream = items.iterator(); stream.hasNext(); ) {
 			if (extendedList.contains(stream.next())) {
 				return true;
@@ -226,7 +226,7 @@
 		this.eventType = null;
 		this.listHolder.addAll(0, this.buildList());
 		this.verifyEvent(ADD);
-		assertEquals(this.buildList(), ListTools.list(((ListAddEvent) this.event).getItems()));
+		assertEquals(this.buildList(), ListTools.arrayList(((ListAddEvent) this.event).getItems()));
 
 		this.event = null;
 		this.eventType = null;
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListAspectAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListAspectAdapterTests.java
index 2006775..df7106b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListAspectAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListAspectAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -134,14 +134,14 @@
 	}
 
 	public void testSubjectHolder() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		this.subjectHolder1.setValue(this.subject2);
 		assertNotNull(this.event1);
 		assertEquals(this.aa1, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
-		assertEquals(this.subject2Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject2Names(), ListTools.arrayList(this.aa1.listIterator()));
 		
 		this.event1 = null;
 		this.subjectHolder1.setValue(null);
@@ -155,11 +155,11 @@
 		assertNotNull(this.event1);
 		assertEquals(this.aa1, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testAdd() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		this.subject1.addName("jam");
@@ -170,7 +170,7 @@
 		assertEquals("jam", ((ListAddEvent) this.event1).getItems().iterator().next());
 		List<String> namesPlus = this.subject1Names();
 		namesPlus.add("jam");
-		assertEquals(namesPlus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesPlus, ListTools.arrayList(this.aa1.listIterator()));
 
 		this.event1 = null;
 		this.aa1.add(2, "jaz");
@@ -180,11 +180,11 @@
 		assertEquals(2, ((ListAddEvent) this.event1).getIndex());
 		assertEquals("jaz", ((ListAddEvent) this.event1).getItems().iterator().next());
 		namesPlus.add(2, "jaz");
-		assertEquals(namesPlus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesPlus, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testDefaultAdd() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		List<String> items = new ArrayList<String>();
@@ -202,11 +202,11 @@
 		assertEquals("jam", ((ListAddEvent) this.event1).getItems().iterator().next());
 		List<String> namesPlus = this.subject1Names();
 		namesPlus.addAll(2, items);
-		assertEquals(namesPlus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesPlus, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testRemove() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		String removedName = this.subject1.removeName(0);	// should be "foo"
@@ -217,7 +217,7 @@
 		assertEquals(removedName, ((ListRemoveEvent) this.event1).getItems().iterator().next());
 		List<String> namesMinus = this.subject1Names();
 		namesMinus.remove(0);
-		assertEquals(namesMinus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesMinus, ListTools.arrayList(this.aa1.listIterator()));
 
 		this.event1 = null;
 		Object removedItem = this.aa1.remove(0);	
@@ -227,11 +227,11 @@
 		assertEquals(0, ((ListRemoveEvent) this.event1).getIndex());
 		assertEquals(removedItem, ((ListRemoveEvent) this.event1).getItems().iterator().next());
 		namesMinus.remove(0);
-		assertEquals(namesMinus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesMinus, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testDefaultLength() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		List<String> items = new ArrayList<String>();
@@ -248,11 +248,11 @@
 		List<String> namesPlus = this.subject1Names();
 		namesPlus.remove(1);
 		namesPlus.remove(1);
-		assertEquals(namesPlus, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesPlus, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testReplace() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		String replacedName = this.subject1.setName(0, "jelly");	// should be "foo"
@@ -264,7 +264,7 @@
 		assertEquals(replacedName, ((ListReplaceEvent) this.event1).getOldItems().iterator().next());
 		List<String> namesChanged = this.subject1Names();
 		namesChanged.set(0, "jelly");
-		assertEquals(namesChanged, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesChanged, ListTools.arrayList(this.aa1.listIterator()));
 
 		this.event1 = null;
 		replacedName = this.subject1.setName(1, "roll");	// should be "bar"
@@ -277,11 +277,11 @@
 		namesChanged = this.subject1Names();
 		namesChanged.set(0, "jelly");
 		namesChanged.set(1, "roll");
-		assertEquals(namesChanged, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesChanged, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testListChange() {
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 		assertNull(this.event1);
 
 		this.subject1.addTwoNames("jam", "jaz");
@@ -291,12 +291,12 @@
 		List<String> namesPlus2 = this.subject1Names();
 		namesPlus2.add(0, "jaz");
 		namesPlus2.add(0, "jam");
-		assertEquals(namesPlus2, ListTools.list(this.aa1.listIterator()));
+		assertEquals(namesPlus2, ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testIterator() {
-		assertEquals(this.subject1Names(), ListTools.list(this.subject1.names()));
-		assertEquals(this.subject1Names(), ListTools.list(this.aa1.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.subject1.names()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.aa1.listIterator()));
 	}
 
 	public void testGet() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCollectionValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCollectionValueModelAdapterTests.java
index 9d82c24..a3e0d7f 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCollectionValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCollectionValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -54,7 +54,7 @@
 	}
 
 	private Collection<String> wrappedCollection() {
-		return CollectionTools.collection(this.wrappedList.iterator());
+		return CollectionTools.hashBag(this.wrappedList.iterator());
 	}
 
 	@Override
@@ -73,7 +73,7 @@
 		this.wrappedListHolder.add(0, "foo");
 		this.wrappedListHolder.add(1, "bar");
 		this.wrappedListHolder.add(2, "baz");
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(3, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 	}
@@ -87,17 +87,17 @@
 		this.wrappedListHolder.add(0, "foo");
 		this.wrappedListHolder.add(1, "bar");
 		this.wrappedListHolder.add(2, "baz");
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(3, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 
 		this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
-		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(0, adapterCollection.size());
 		assertEquals(new HashBag<String>(), adapterCollection);
 
 		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
-		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(3, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 	}
@@ -114,9 +114,9 @@
 		this.wrappedListHolder.add(5, "jaz");
 		assertEquals(6, this.wrappedList.size());
 
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(this.wrappedCollection(), adapterCollection);
-		assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection(), CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection(), synchCollection);
 	}
 
@@ -135,9 +135,9 @@
 		assertFalse(this.wrappedList.contains("foo"));
 		assertEquals(4, this.wrappedList.size());
 
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(this.wrappedCollection(), adapterCollection);
-		assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection(), CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection(), synchCollection);
 	}
 
@@ -164,7 +164,7 @@
 		assertFalse(this.wrappedList.contains("foo"));
 		assertEquals(4, this.wrappedList.size());
 
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 	}
 
@@ -182,7 +182,7 @@
 		this.wrappedListHolder.add(0, "foo");
 		this.wrappedListHolder.add(1, "bar");
 		this.wrappedListHolder.add(2, "baz");
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(3, adapterCollection.size());
 		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
 			@Override
@@ -198,7 +198,7 @@
 			}
 		});
 		this.wrappedListHolder.set(0, "joo");
-		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(3, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 	}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCuratorTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCuratorTests.java
index e667223..e345b5b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCuratorTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/ListCuratorTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -125,14 +125,14 @@
 	}
 
 	public void testSubjectHolder() {
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 		assertNull(this.event1);
 
 		this.subjectHolder1.setValue(this.subject2);
 		assertNotNull(this.event1);
 		assertEquals(this.curator, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
-		assertEquals(this.subject2Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject2Names(), ListTools.arrayList(this.curator.listIterator()));
 		
 		this.event1 = null;
 		this.subjectHolder1.setValue(null);
@@ -146,11 +146,11 @@
 		assertNotNull(this.event1);
 		assertEquals(this.curator, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 	}
 
 	public void testAdd() {
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 		assertNull(this.event1);
 
 		this.subject1.addString("echo");
@@ -161,7 +161,7 @@
 		assertEquals("echo", ((ListAddEvent) this.event1).getItems().iterator().next());
 		List<String> stringsPlus = this.subject1Names();
 		stringsPlus.add("echo");
-		assertEquals(stringsPlus, ListTools.list(this.curator.listIterator()));
+		assertEquals(stringsPlus, ListTools.arrayList(this.curator.listIterator()));
 
 		this.event1 = null;
 		this.subject1.addString(0, "zulu");
@@ -171,11 +171,11 @@
 		assertEquals(0, ((ListAddEvent) this.event1).getIndex());
 		assertEquals("zulu", ((ListAddEvent) this.event1).getItems().iterator().next());
 		stringsPlus.add(0, "zulu");
-		assertEquals(stringsPlus, ListTools.list(this.curator.listIterator()));
+		assertEquals(stringsPlus, ListTools.arrayList(this.curator.listIterator()));
 	}
 	
 	public void testRemove() {
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 		assertNull(this.event1);
 
 		String removedString = this.subject1.removeString(0);	// should be "alpha"
@@ -186,7 +186,7 @@
 		assertEquals(removedString, ((ListRemoveEvent) this.event1).getItems().iterator().next());
 		List<String> stringsMinus = this.subject1Names();
 		stringsMinus.remove(0);
-		assertEquals(stringsMinus, ListTools.list(this.curator.listIterator()));
+		assertEquals(stringsMinus, ListTools.arrayList(this.curator.listIterator()));
 		
 		removedString = this.subject1.removeString(2);	// should be "delta"
 		assertNotNull(this.event1);
@@ -195,11 +195,11 @@
 		assertEquals(2, ((ListRemoveEvent) this.event1).getIndex());
 		assertEquals(removedString, ((ListRemoveEvent) this.event1).getItems().iterator().next());
 		stringsMinus.remove(2);
-		assertEquals(stringsMinus, ListTools.list(this.curator.listIterator()));
+		assertEquals(stringsMinus, ListTools.arrayList(this.curator.listIterator()));
 	}
 	
 	public void testCompleteListChange() {
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 		assertNull(this.event1);
 		
 		this.subject1.setStrings(this.subject2Names());
@@ -207,20 +207,20 @@
 		assertEquals(this.curator, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
 		List<String> newStrings = this.subject2Names();
-		assertEquals(newStrings, ListTools.list(this.curator.listIterator()));
+		assertEquals(newStrings, ListTools.arrayList(this.curator.listIterator()));
 	}
 	
 	public void testPartialListChange() {
-		List<String> startingList = ListTools.list(this.curator.listIterator());
+		List<String> startingList = ListTools.arrayList(this.curator.listIterator());
 		assertEquals(this.subject1Names(), startingList);
 		assertNull(this.event1);
 		
 		String identicalString = startingList.get(1);  // should be "bravo"
 		String nonidenticalString = startingList.get(0); // should be "alpha"
-		List<String> newStrings = ListTools.list(new String[] {new String("bravo"), new String("alpha"), "echo", "delta", "foxtrot"});
+		List<String> newStrings = ListTools.arrayList(new String[] {new String("bravo"), new String("alpha"), "echo", "delta", "foxtrot"});
 		this.subject1.setStrings(newStrings);
 		
-		List<String> finalList = ListTools.list(this.curator.listIterator());
+		List<String> finalList = ListTools.arrayList(this.curator.listIterator());
 		assertNotNull(this.event1);
 		assertEquals(this.curator, this.event1.getSource());
 		assertEquals(ListValueModel.LIST_VALUES, this.event1.getListName());
@@ -230,8 +230,8 @@
 	}
 	
 	public void testIterator() {
-		assertEquals(this.subject1Names(), ListTools.list(this.subject1.strings()));
-		assertEquals(this.subject1Names(), ListTools.list(this.curator.listIterator()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.subject1.strings()));
+		assertEquals(this.subject1Names(), ListTools.arrayList(this.curator.listIterator()));
 	}
 	
 	public void testGet() {
@@ -339,7 +339,7 @@
 		}
 		
 		public void setStrings(String[] strings) {
-			this.strings = ListTools.list(strings);
+			this.strings = ListTools.arrayList(strings);
 			this.fireStateChanged();
 		}
 	}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyCollectionValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyCollectionValueModelAdapterTests.java
index 7ba6e13..c2c087d 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyCollectionValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyCollectionValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -50,7 +50,7 @@
 	}
 
 	private Collection<String> wrappedCollection() {
-		return CollectionTools.collection(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
+		return CollectionTools.hashBag(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
 	}
 
 	@Override
@@ -65,7 +65,7 @@
 			public void itemsAdded(CollectionAddEvent e) {/* OK */}
 		});
 		this.wrappedValueHolder.setValue("foo");
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(1, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 		assertEquals("foo", adapterCollection.iterator().next());
@@ -78,18 +78,18 @@
 		};
 		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
 		this.wrappedValueHolder.setValue("foo");
-		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		Collection<String> adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(1, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 		assertEquals("foo", adapterCollection.iterator().next());
 
 		this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
-		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(0, adapterCollection.size());
 		assertEquals(new HashBag<String>(), adapterCollection);
 
 		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
-		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		adapterCollection = CollectionTools.hashBag(this.adapter.iterator());
 		assertEquals(1, adapterCollection.size());
 		assertEquals(this.wrappedCollection(), adapterCollection);
 		assertEquals("foo", adapterCollection.iterator().next());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyListValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyListValueModelAdapterTests.java
index 4b34f92..d6b0aff 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyListValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/PropertyListValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -53,7 +53,7 @@
 	}
 
 	private Collection<String> wrappedList() {
-		return ListTools.list(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
+		return ListTools.arrayList(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
 	}
 
 	@Override
@@ -69,7 +69,7 @@
 		});
 		assertFalse(this.adapter.iterator().hasNext());
 		this.wrappedValueHolder.setValue("foo");
-		List<String> adapterList = ListTools.list(this.adapter.iterator());
+		List<String> adapterList = ListTools.arrayList(this.adapter.iterator());
 		assertEquals(1, adapterList.size());
 		assertEquals(this.wrappedList(), adapterList);
 		assertEquals("foo", adapterList.iterator().next());
@@ -108,18 +108,18 @@
 		};
 		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
 		this.wrappedValueHolder.setValue("foo");
-		List<String> adapterList = ListTools.list(this.adapter.iterator());
+		List<String> adapterList = ListTools.arrayList(this.adapter.iterator());
 		assertEquals(1, adapterList.size());
 		assertEquals(this.wrappedList(), adapterList);
 		assertEquals("foo", adapterList.iterator().next());
 
 		this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, listener);
-		adapterList = ListTools.list(this.adapter.iterator());
+		adapterList = ListTools.arrayList(this.adapter.iterator());
 		assertEquals(0, adapterList.size());
 		assertEquals(new ArrayList<String>(), adapterList);
 
 		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
-		adapterList = ListTools.list(this.adapter.iterator());
+		adapterList = ListTools.arrayList(this.adapter.iterator());
 		assertEquals(1, adapterList.size());
 		assertEquals(this.wrappedList(), adapterList);
 		assertEquals("foo", adapterList.iterator().next());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SetCollectionValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SetCollectionValueModelTests.java
index 0b72b43..411d8bc 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SetCollectionValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SetCollectionValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -297,21 +297,21 @@
 	}
 
 	private void verify(CollectionValueModel<String> cvm, String... expectedItems) {
-		Bag<String> actual = CollectionTools.bag(cvm);
-		Bag<String> expected = CollectionTools.bag(expectedItems);
+		Bag<String> actual = CollectionTools.hashBag(cvm);
+		Bag<String> expected = CollectionTools.hashBag(expectedItems);
 		assertEquals(expected, actual);
 	}
 
 	private void verifyEvent(CollectionAddEvent event, Object source, Object... expectedItems) {
 		assertEquals(source, event.getSource());
 		assertEquals(CollectionValueModel.VALUES, event.getCollectionName());
-		assertEquals(CollectionTools.bag(expectedItems), CollectionTools.bag(event.getItems()));
+		assertEquals(CollectionTools.hashBag(expectedItems), CollectionTools.hashBag(event.getItems()));
 	}
 
 	private void verifyEvent(CollectionRemoveEvent event, Object source, Object... expectedItems) {
 		assertEquals(source, event.getSource());
 		assertEquals(CollectionValueModel.VALUES, event.getCollectionName());
-		assertEquals(CollectionTools.bag(expectedItems), CollectionTools.bag(event.getItems()));
+		assertEquals(CollectionTools.hashBag(expectedItems), CollectionTools.hashBag(event.getItems()));
 	}
 
 	private void verifyEvent(CollectionClearEvent event, Object source) {
@@ -322,7 +322,7 @@
 	private void verifyEvent(CollectionChangeEvent event, Object source, Object... expectedItems) {
 		assertEquals(source, event.getSource());
 		assertEquals(CollectionValueModel.VALUES, event.getCollectionName());
-		assertEquals(CollectionTools.bag(expectedItems), CollectionTools.bag(event.getCollection()));
+		assertEquals(CollectionTools.hashBag(expectedItems), CollectionTools.hashBag(event.getCollection()));
 	}
 
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleCollectionValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleCollectionValueModelTests.java
index d4592b8..2960323 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleCollectionValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleCollectionValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -97,8 +97,8 @@
 	}
 
 	public void testIterator() {
-		assertEquals(this.buildBag(), CollectionTools.bag(this.bagHolder.iterator()));
-		assertEquals(this.buildSet(), CollectionTools.set(this.setHolder.iterator()));
+		assertEquals(this.buildBag(), CollectionTools.hashBag(this.bagHolder.iterator()));
+		assertEquals(this.buildSet(), CollectionTools.hashSet(this.setHolder.iterator()));
 	}
 
 	public void testSize() {
@@ -123,7 +123,7 @@
 	}
 
 	private boolean bagHolderContainsAny(Collection<String> items) {
-		Bag<String> bag = CollectionTools.bag(this.bagHolder.iterator());
+		Bag<String> bag = CollectionTools.hashBag(this.bagHolder.iterator());
 		for (String string : items) {
 			if (bag.contains(string)) {
 				return true;
@@ -133,7 +133,7 @@
 	}
 
 	private boolean setHolderContainsAny(Collection<String> items) {
-		Set<String> set = CollectionTools.set(this.setHolder.iterator());
+		Set<String> set = CollectionTools.hashSet(this.setHolder.iterator());
 		for (String string : items) {
 			if (set.contains(string)) {
 				return true;
@@ -291,7 +291,7 @@
 		this.bagEventType = null;
 		this.bagHolder.addAll(this.buildBag());
 		this.verifyBagEvent(ADD);
-		assertEquals(this.buildBag(), CollectionTools.bag(((CollectionAddEvent) this.bagEvent).getItems()));
+		assertEquals(this.buildBag(), CollectionTools.hashBag(((CollectionAddEvent) this.bagEvent).getItems()));
 	}
 
 	private void verifySetChange() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleListValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleListValueModelTests.java
index 2730490..f4ce67b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleListValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SimpleListValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -89,15 +89,15 @@
 	}
 
 	public void testIterator() {
-		assertEquals(this.buildList(), ListTools.list(this.listHolder.iterator()));
+		assertEquals(this.buildList(), ListTools.arrayList(this.listHolder.iterator()));
 	}
 
 	public void testListIterator() {
-		assertEquals(this.buildList(), ListTools.list(this.listHolder.listIterator()));
+		assertEquals(this.buildList(), ListTools.arrayList(this.listHolder.listIterator()));
 	}
 
 	public void testListIteratorInt() {
-		assertEquals(ListTools.list(this.buildList().listIterator(1)), ListTools.list(this.listHolder.listIterator(1)));
+		assertEquals(ListTools.arrayList(this.buildList().listIterator(1)), ListTools.arrayList(this.listHolder.listIterator(1)));
 	}
 
 	public void testSize() {
@@ -113,7 +113,7 @@
 	}
 
 	private boolean listContainsAny(Collection<String> items) {
-		Set<String> set = CollectionTools.set(this.listHolder.iterator());
+		Set<String> set = CollectionTools.hashSet(this.listHolder.iterator());
 		for (Iterator<String> stream = items.iterator(); stream.hasNext(); ) {
 			if (set.contains(stream.next())) {
 				return true;
@@ -287,7 +287,7 @@
 		this.eventType = null;
 		this.listHolder.addAll(0, this.buildList());
 		this.verifyEvent(ADD);
-		assertEquals(this.buildList(), ListTools.list(((ListAddEvent) this.event).getItems()));
+		assertEquals(this.buildList(), ListTools.arrayList(((ListAddEvent) this.event).getItems()));
 
 		this.event = null;
 		this.eventType = null;
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelAdapterTests.java
index 83752b4..060018b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -69,7 +69,7 @@
 		Collection<String> sortedSet = new TreeSet<String>(comparator);
 		sortedSet.addAll(expected);
 		List<String> expectedList = new ArrayList<String>(sortedSet);
-		List<String> actualList = ListTools.list(actual.iterator());
+		List<String> actualList = ListTools.arrayList(actual.iterator());
 		assertEquals(expectedList, actualList);
 	}
 
@@ -100,7 +100,7 @@
 		assertEquals(6, this.wrappedCollection.size());
 
 		this.verifyList(this.wrappedCollection, this.adapter);
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 	}
 
@@ -120,7 +120,7 @@
 		assertEquals(4, this.wrappedCollection.size());
 
 		this.verifyList(this.wrappedCollection, this.adapter);
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 	}
 
@@ -161,12 +161,12 @@
 		assertEquals(6, this.wrappedCollection.size());
 
 		this.verifyList(this.wrappedCollection, this.adapter);
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 
 		this.adapter.setComparator(ComparatorTools.<String>reverseComparator());
 		this.verifyList(this.wrappedCollection, this.adapter, ComparatorTools.<String>reverseComparator());
-		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, CollectionTools.hashBag(synchList.iterator()));
 		assertEquals(this.wrappedCollection, synchCollection);
 	}
 
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelWrapperTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelWrapperTests.java
index e2a384a..985de8b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelWrapperTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/SortedListValueModelWrapperTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -66,7 +66,7 @@
 		Collection<String> sortedSet = new TreeSet<String>(comparator);
 		sortedSet.addAll(expected);
 		List<String> expectedList = new ArrayList<String>(sortedSet);
-		List<String> actualList = ListTools.list(actual);
+		List<String> actualList = ListTools.arrayList(actual);
 		assertEquals(expectedList, actualList);
 	}
 
@@ -98,7 +98,7 @@
 
 		this.verifyList(this.list, this.sortedListModel);
 		assertEquals(this.list, synchList);
-		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+		assertEquals(ListTools.arrayList(this.sortedListModel), sortedSynchList);
 	}
 
 	public void testRemoveItem() {
@@ -118,7 +118,7 @@
 
 		this.verifyList(this.list, this.sortedListModel);
 		assertEquals(this.list, synchList);
-		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+		assertEquals(ListTools.arrayList(this.sortedListModel), sortedSynchList);
 	}
 
 	public void testReplaceItem() {
@@ -138,7 +138,7 @@
 
 		this.verifyList(this.list, this.sortedListModel);
 		assertEquals(this.list, synchList);
-		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+		assertEquals(ListTools.arrayList(this.sortedListModel), sortedSynchList);
 	}
 
 	public void testListSynch() {
@@ -179,7 +179,7 @@
 
 		this.verifyList(this.list, this.sortedListModel);
 		assertEquals(this.list, synchList);
-		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+		assertEquals(ListTools.arrayList(this.sortedListModel), sortedSynchList);
 
 		this.sortedListModel.setComparator(ComparatorTools.<String>reverseComparator());
 		this.verifyList(this.list, this.sortedListModel, ComparatorTools.<String>reverseComparator());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticCollectionValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticCollectionValueModelTests.java
index 43fcc46..dc88239 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticCollectionValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticCollectionValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -53,7 +53,7 @@
 	}
 
 	public void testIterator() {
-		assertEquals(buildCollection(), CollectionTools.bag(this.collectionHolder.iterator()));
+		assertEquals(buildCollection(), CollectionTools.hashBag(this.collectionHolder.iterator()));
 	}
 
 	public void testSize() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticListValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticListValueModelTests.java
index c02f54d..151b98b 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticListValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/StaticListValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2010 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -56,7 +56,7 @@
 	}
 
 	public void testIterator() {
-		assertEquals(buildList(), ListTools.list(this.listHolder.listIterator()));
+		assertEquals(buildList(), ListTools.arrayList(this.listHolder.listIterator()));
 	}
 
 	public void testSize() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/TransformationListValueModelTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/TransformationListValueModelTests.java
index ecc491f..4cd4659 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/TransformationListValueModelTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/TransformationListValueModelTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -126,16 +126,16 @@
 
 	public void testIterator() {
 		this.transformedListHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.buildListener());
-		assertEquals(this.buildTransformedList(), ListTools.list(this.transformedListHolder.iterator()));
+		assertEquals(this.buildTransformedList(), ListTools.arrayList(this.transformedListHolder.iterator()));
 	}
 
 	public void testStaleValues() {
 		ListChangeListener listener = this.buildListener();
 		this.transformedListHolder.addListChangeListener(ListValueModel.LIST_VALUES, listener);
-		assertEquals(this.buildTransformedList(), ListTools.list(this.transformedListHolder.iterator()));
+		assertEquals(this.buildTransformedList(), ListTools.arrayList(this.transformedListHolder.iterator()));
 
 		this.transformedListHolder.removeListChangeListener(ListValueModel.LIST_VALUES, listener);
-		assertEquals(Collections.EMPTY_LIST, ListTools.list(this.transformedListHolder.iterator()));
+		assertEquals(Collections.EMPTY_LIST, ListTools.arrayList(this.transformedListHolder.iterator()));
 	}
 
 	public void testSize() {
@@ -152,7 +152,7 @@
 	}
 
 	private boolean transformedListContainsAny(Collection<String> items) {
-		List<String> transformedList = ListTools.list(this.transformedListHolder.iterator());
+		List<String> transformedList = ListTools.arrayList(this.transformedListHolder.iterator());
 		for (Iterator<String> stream = items.iterator(); stream.hasNext(); ) {
 			if (transformedList.contains(stream.next())) {
 				return true;
@@ -229,7 +229,7 @@
 		this.eventType = null;
 		this.listHolder.addAll(0, this.buildList());
 		this.verifyEvent(ADD);
-		assertEquals(this.buildTransformedList(), ListTools.list(((ListAddEvent) this.event).getItems()));
+		assertEquals(this.buildTransformedList(), ListTools.arrayList(((ListAddEvent) this.event).getItems()));
 
 		this.event = null;
 		this.eventType = null;
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TableModelAdapterTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TableModelAdapterTests.java
index 82677aa..00f0b39 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TableModelAdapterTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TableModelAdapterTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -230,7 +230,7 @@
 	}
 
 	private List<String> sortedNames() {
-		return new ArrayList<String>(CollectionTools.sortedSet(this.crowd.peopleNames()));
+		return new ArrayList<String>(CollectionTools.treeSet(this.crowd.peopleNames()));
 	}
 
 	private TableModelListener buildSingleEventListener() {
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TreeModelAdapterUITest.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TreeModelAdapterUITest.java
index 04ebcba..69a3d40 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TreeModelAdapterUITest.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/model/value/swing/TreeModelAdapterUITest.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -242,7 +242,7 @@
 		if (stream == null) {
 			return Collections.emptyList();
 		}
-		return ListTools.list(new EnumerationIterator<TreePath>(stream));
+		return ListTools.arrayList(new EnumerationIterator<TreePath>(stream));
 	}
 
 	// ********** behavior **********
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ArrayQueueTests.java
similarity index 74%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayQueueTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ArrayQueueTests.java
index a6066d5..9329535 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ArrayQueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ArrayQueueTests.java
@@ -7,12 +7,13 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.ArrayQueue;
-import org.eclipse.jpt.common.utility.internal.collection.QueueTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.queue.ArrayQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
 @SuppressWarnings("nls")
@@ -25,7 +26,40 @@
 
 	@Override
 	Queue<String> buildQueue() {
-		return new ArrayQueue<String>();
+		return QueueTools.arrayQueue();
+	}
+
+	public void testConstructor_IAE() {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.arrayQueue(-1);
+			fail("bogus deque: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEnsureCapacity() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue(0);
+		queue.ensureCapacity(7);
+		assertEquals(7, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testTrimToSize() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue(10);
+		queue.enqueue("foo");
+		queue.enqueue("bar");
+		queue.trimToSize();
+		assertEquals(2, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testTrimToSize_noChange() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue(2);
+		queue.enqueue("foo");
+		queue.enqueue("bar");
+		queue.trimToSize();
+		assertEquals(2, ((Object[]) ObjectTools.get(queue, "elements")).length);
 	}
 
 	public void testCollectionConstructor() {
@@ -181,6 +215,19 @@
 		assertTrue(queue.isEmpty());
 	}
 
+	public void testSerialization_empty() throws Exception {
+		Queue<String> original = new ArrayQueue<String>(3);
+		Queue<String> clone = TestTools.serialize(original);
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
 	public void testSerialization_fullArray() throws Exception {
 		Queue<String> queue = new ArrayQueue<String>(3);
 		queue.enqueue("first");
@@ -189,4 +236,15 @@
 
 		this.verifyClone(queue, TestTools.serialize(queue));
 	}
+
+	public void testSerialization_wrappedArray() throws Exception {
+		Queue<String> queue = new ArrayQueue<String>(3);
+		queue.enqueue("first");
+		queue.enqueue("second");
+		queue.enqueue("third");
+		queue.dequeue();
+		queue.enqueue("fourth");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/DequeQueueTests.java
similarity index 63%
copy from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java
copy to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/DequeQueueTests.java
index ff60295..7bbc809 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/DequeQueueTests.java
@@ -7,22 +7,22 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
-import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.ListQueue;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
-public class ListQueueTests
+public class DequeQueueTests
 	extends QueueTests
 {
-	public ListQueueTests(String name) {
+	public DequeQueueTests(String name) {
 		super(name);
 	}
 
 	@Override
 	Queue<String> buildQueue() {
-		return new ListQueue<String>(new ArrayList<String>());
+		return QueueTools.adapt(DequeTools.<String>arrayDeque());
 	}
 
 	@Override
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/EmptyQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/EmptyQueueTests.java
new file mode 100644
index 0000000..e8ec2c3
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/EmptyQueueTests.java
@@ -0,0 +1,76 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.queue;
+
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.internal.queue.EmptyQueue;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class EmptyQueueTests
+	extends TestCase
+{
+	public EmptyQueueTests(String name) {
+		super(name);
+	}
+
+	public void testEnqueue() {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		boolean exCaught = false;
+		try {
+			queue.enqueue("junk");
+			fail();
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testDequeue() {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = queue.dequeue();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testPeek() {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = queue.peek();
+			fail(bogus);
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIsEmpty() {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testToString() {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		assertEquals("[]", queue.toString());
+	}
+
+	public void testSerialization() throws Exception {
+		Queue<String> queue = EmptyQueue.<String>instance();
+		assertSame(queue, TestTools.serialize(queue));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/FixedCapacityArrayQueueTests.java
similarity index 90%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayQueueTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/FixedCapacityArrayQueueTests.java
index e1f0bfa..51dde90 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayQueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/FixedCapacityArrayQueueTests.java
@@ -7,24 +7,24 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.FixedSizeArrayQueue;
-import org.eclipse.jpt.common.utility.internal.collection.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.FixedCapacityArrayQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 @SuppressWarnings("nls")
-public class FixedSizeArrayQueueTests
+public class FixedCapacityArrayQueueTests
 	extends QueueTests
 {
-	public FixedSizeArrayQueueTests(String name) {
+	public FixedCapacityArrayQueueTests(String name) {
 		super(name);
 	}
 
 	@Override
-	FixedSizeArrayQueue<String> buildQueue() {
-		return new FixedSizeArrayQueue<String>(10);
+	FixedCapacityArrayQueue<String> buildQueue() {
+		return QueueTools.fixedCapacityArrayQueue(10);
 	}
 
 	public void testCollectionConstructor() {
@@ -39,7 +39,7 @@
 		c.add("eighth");
 		c.add("ninth");
 		c.add("tenth");
-		Queue<String> queue = QueueTools.fixedSizeQueue(c);
+		Queue<String> queue = QueueTools.fixedCapacityArrayQueue(c);
 
 		assertFalse(queue.isEmpty());
 		assertEquals("first", queue.peek());
@@ -59,7 +59,7 @@
 	}
 
 	public void testIsFull() {
-		FixedSizeArrayQueue<String> queue = this.buildQueue();
+		FixedCapacityArrayQueue<String> queue = this.buildQueue();
 		assertFalse(queue.isFull());
 		queue.enqueue("first");
 		assertFalse(queue.isFull());
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/JptCommonUtilityQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/JptCommonUtilityQueueTests.java
new file mode 100644
index 0000000..4bf7ac7
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/JptCommonUtilityQueueTests.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.queue;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * decentralize test creation code
+ */
+public class JptCommonUtilityQueueTests {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite(JptCommonUtilityQueueTests.class.getPackage().getName());
+
+		suite.addTestSuite(ArrayQueueTests.class);
+		suite.addTestSuite(DequeQueueTests.class);
+		suite.addTestSuite(EmptyQueueTests.class);
+		suite.addTestSuite(FixedCapacityArrayQueueTests.class);
+		suite.addTestSuite(LinkedQueueTests.class);
+		suite.addTestSuite(ListQueueTests.class);
+		suite.addTestSuite(PriorityQueueTests.class);
+		suite.addTestSuite(QueueToolsTests.class);
+		suite.addTestSuite(StackQueueTests.class);
+		suite.addTestSuite(SynchronizedQueueTests.class);
+
+		return suite;
+	}
+
+	private JptCommonUtilityQueueTests() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/LinkedQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/LinkedQueueTests.java
new file mode 100644
index 0000000..3795806
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/LinkedQueueTests.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.tests.internal.queue;
+
+import java.util.Arrays;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+@SuppressWarnings("nls")
+public class LinkedQueueTests
+	extends QueueTests
+{
+	public LinkedQueueTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Queue<String> buildQueue() {
+		return QueueTools.linkedQueue();
+	}
+
+	public void testConstructorInt_IAE() {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.linkedQueue(-3);
+			fail("bogus queue: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSize() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.enqueue(third);
+		assertEquals(3, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeue();
+		assertEquals(2, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+		queue.dequeue();
+		queue.dequeue();
+		assertEquals(0, ((Integer) ObjectTools.execute(queue, "size")).intValue());
+	}
+
+	public void testBuildElements() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.enqueue(first);
+		queue.enqueue(second);
+		queue.enqueue(third);
+
+		Object[] elements = new Object[] { first, second, third };
+		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(queue, "buildElements"))));
+	}
+
+	public void testNodeCache_max() {
+		Queue<String> queue = new LinkedQueue<String>(2);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		queue.enqueue(first);
+		this.verifyNodeCache(0, factory);
+		queue.enqueue(second);
+		queue.enqueue(third);
+		queue.enqueue(fourth);
+		queue.enqueue(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		queue.dequeue();
+		this.verifyNodeCache(1, factory);
+		queue.dequeue();
+		this.verifyNodeCache(2, factory);
+		queue.dequeue();
+		this.verifyNodeCache(2, factory);
+		queue.dequeue();
+		this.verifyNodeCache(2, factory);
+		queue.dequeue();
+		this.verifyNodeCache(2, factory);
+		queue.enqueue(first);
+		this.verifyNodeCache(1, factory);
+		queue.enqueue(second);
+		this.verifyNodeCache(0, factory);
+		queue.enqueue(third);
+		this.verifyNodeCache(0, factory);
+	}
+
+	public void testNodeCache_unlimited() {
+		Queue<String> queue = new LinkedQueue<String>(-1);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		queue.enqueue(first);
+		this.verifyNodeCache(0, factory);
+		queue.enqueue(second);
+		queue.enqueue(third);
+		queue.enqueue(fourth);
+		queue.enqueue(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		queue.dequeue();
+		this.verifyNodeCache(1, factory);
+		queue.dequeue();
+		this.verifyNodeCache(2, factory);
+		queue.dequeue();
+		this.verifyNodeCache(3, factory);
+		queue.dequeue();
+		this.verifyNodeCache(4, factory);
+		queue.dequeue();
+		this.verifyNodeCache(5, factory);
+		queue.enqueue(first);
+		this.verifyNodeCache(4, factory);
+		queue.enqueue(second);
+		this.verifyNodeCache(3, factory);
+		queue.enqueue(third);
+		this.verifyNodeCache(2, factory);
+		queue.enqueue(fourth);
+		this.verifyNodeCache(1, factory);
+		queue.enqueue(fifth);
+		this.verifyNodeCache(0, factory);
+	}
+
+	public void verifyNodeCache(int size, Object factory) {
+		assertEquals(size, ((Integer) ObjectTools.get(factory, "cacheSize")).intValue());
+		int nodeCount = 0;
+		for (Object node = ObjectTools.get(factory, "cacheHead"); node != null; node = ObjectTools.get(node, "next")) {
+			nodeCount++;
+		}
+		assertEquals(size, nodeCount);
+	}
+
+	public void testNodeToString() {
+		Queue<String> queue = QueueTools.linkedQueue();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.enqueue(first);
+		queue.enqueue(second);
+		queue.enqueue(third);
+
+		Object head = ObjectTools.get(queue, "head");
+		assertTrue(head.toString().startsWith("LinkedQueue.Node"));
+		assertTrue(head.toString().endsWith("(first)"));
+	}
+
+	public void testSimpleNodeFactoryToString() {
+		Queue<String> queue = QueueTools.linkedQueue();
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertEquals("LinkedQueue.SimpleNodeFactory", factory.toString());
+	}
+
+	public void testCachingNodeFactoryToString() {
+		Queue<String> queue = QueueTools.linkedQueue(20);
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedQueue.CachingNodeFactory"));
+		assertTrue(factory.toString().endsWith("(0)"));
+	}
+
+	public void testClone_caching() throws Exception {
+		LinkedQueue<String> original = QueueTools.linkedQueue(20);
+		original.enqueue("first");
+
+		LinkedQueue<String> clone = original.clone();
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.dequeue(), clone.dequeue());
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("second");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+
+		Object factory = ObjectTools.get(original, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedQueue.CachingNodeFactory"));
+	}
+
+	public void testSerialization_caching() throws Exception {
+		Queue<String> original = QueueTools.linkedQueue(20);
+		original.enqueue("first");
+
+		Queue<String> clone = TestTools.serialize(original);
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.dequeue(), clone.dequeue());
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("second");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+
+		Object factory = ObjectTools.get(original, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedQueue.CachingNodeFactory"));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ListQueueTests.java
similarity index 80%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ListQueueTests.java
index ff60295..563e6f4 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListQueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/ListQueueTests.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.collection.ListQueue;
+import org.eclipse.jpt.common.utility.internal.queue.ListQueue;
+import org.eclipse.jpt.common.utility.queue.Queue;
 
 public class ListQueueTests
 	extends QueueTests
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/PriorityQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/PriorityQueueTests.java
new file mode 100644
index 0000000..4f84c69
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/PriorityQueueTests.java
@@ -0,0 +1,444 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.queue;
+
+import java.util.Comparator;
+import java.util.NoSuchElementException;
+import java.util.Random;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.StringTools;
+import org.eclipse.jpt.common.utility.internal.queue.PriorityQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class PriorityQueueTests
+	extends TestCase
+{
+	public PriorityQueueTests(String name) {
+		super(name);
+	}
+
+	private Queue<String> buildQueue() {
+		return QueueTools.priorityQueue();
+	}
+
+	public void testIsEmpty() {
+		Queue<String> queue = this.buildQueue();
+		assertTrue(queue.isEmpty());
+		queue.enqueue("first");
+		assertFalse(queue.isEmpty());
+		queue.enqueue("second");
+		assertFalse(queue.isEmpty());
+		queue.dequeue();
+		assertFalse(queue.isEmpty());
+		queue.dequeue();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueAndDequeue() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.dequeue());
+	}
+
+	public void testEnqueueAndPeek() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.peek());
+		assertEquals(second, queue.peek());
+		assertEquals(second, queue.dequeue());
+	}
+
+	public void testEmptyQueueExceptionPeek() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.peek());
+		assertEquals(second, queue.dequeue());
+
+		boolean exCaught = false;
+		try {
+			queue.peek();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testEmptyQueueExceptionDequeue() {
+		Queue<String> queue = this.buildQueue();
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.peek());
+		assertEquals(second, queue.dequeue());
+
+		boolean exCaught = false;
+		try {
+			queue.dequeue();
+			fail();
+		} catch (NoSuchElementException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testClone() {
+		Queue<String> queue = this.buildQueue();
+		queue.enqueue("first");
+		queue.enqueue("second");
+		queue.enqueue("third");
+
+		@SuppressWarnings("unchecked")
+		Queue<String> clone = (Queue<String>) ObjectTools.execute(queue, "clone");
+		this.verifyClone(queue, clone);
+	}
+
+	public void testSerialization() throws Exception {
+		Queue<String> queue = this.buildQueue();
+		queue.enqueue("first");
+		queue.enqueue("second");
+		queue.enqueue("third");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+
+	protected void verifyClone(Queue<String> original, Queue<String> clone) {
+		assertNotSame(original, clone);
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.dequeue(), clone.dequeue());
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.dequeue(), clone.dequeue());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.dequeue(), clone.dequeue());
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("fourth");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testToString() throws Exception {
+		Queue<String> queue = this.buildQueue();
+		assertEquals("[]", queue.toString());
+		queue.enqueue("first");
+		assertEquals("[first]", queue.toString());
+		queue.enqueue("second");
+		assertEquals("[first, second]", queue.toString());
+		queue.enqueue("third");
+		assertEquals("[first, second, third]", queue.toString());
+	}
+
+	public void testArrayCapacityExceeded() {
+		Queue<Integer> queue = QueueTools.priorityQueue();
+		assertTrue(queue.isEmpty());
+		queue.enqueue(Integer.valueOf(1));
+		assertFalse(queue.isEmpty());
+		queue.enqueue(Integer.valueOf(2));
+		assertFalse(queue.isEmpty());
+		queue.enqueue(Integer.valueOf(3));
+		queue.enqueue(Integer.valueOf(10));
+		queue.enqueue(Integer.valueOf(11));
+		queue.enqueue(Integer.valueOf(12));
+		queue.enqueue(Integer.valueOf(4));
+		queue.enqueue(Integer.valueOf(4));
+		queue.enqueue(Integer.valueOf(7));
+		queue.enqueue(Integer.valueOf(8));
+		queue.enqueue(Integer.valueOf(9));
+		queue.enqueue(Integer.valueOf(5));
+		queue.enqueue(Integer.valueOf(6));
+		queue.enqueue(Integer.valueOf(9));
+
+		assertEquals(Integer.valueOf(1), queue.dequeue());
+		assertFalse(queue.isEmpty());
+		assertEquals(Integer.valueOf(2), queue.dequeue());
+		assertFalse(queue.isEmpty());
+		assertEquals(Integer.valueOf(3), queue.dequeue());
+		assertEquals(Integer.valueOf(4), queue.dequeue());
+		assertEquals(Integer.valueOf(4), queue.dequeue());
+		assertEquals(Integer.valueOf(5), queue.dequeue());
+		assertEquals(Integer.valueOf(6), queue.dequeue());
+		assertEquals(Integer.valueOf(7), queue.dequeue());
+		assertEquals(Integer.valueOf(8), queue.dequeue());
+		assertEquals(Integer.valueOf(9), queue.dequeue());
+		assertEquals(Integer.valueOf(9), queue.dequeue());
+		assertEquals(Integer.valueOf(10), queue.dequeue());
+		assertEquals(Integer.valueOf(11), queue.dequeue());
+		assertEquals(Integer.valueOf(12), queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testMultipleSizes() throws Exception {
+		int maxSize = 50;
+		Random random = new Random();
+		for (int size = 1; size <= maxSize; size++) {
+			Queue<Integer> queue = QueueTools.priorityQueue(size);
+			for (int i = size; i-- > 0; ) {
+				queue.enqueue(Integer.valueOf(random.nextInt()));
+			}
+			Integer current = queue.dequeue();
+			int i = 1;
+			do {
+				if ( ! queue.isEmpty()) {
+					Integer next = queue.dequeue();
+					i++;
+					assertTrue(current.intValue() <= next.intValue());
+					current = next;
+				}
+			} while ( ! queue.isEmpty());
+			assertEquals(size, i);
+		}
+	}
+
+	// instance variable access appears to be slightly faster(!)
+//	public void testLocalVariablePerformance() throws Exception {
+//		int minSize = 5000000;
+//		int executionCount = 10;
+//		Random random = new Random();
+//		for (int x = 0; x < executionCount; x++) {
+//			int size = minSize + random.nextInt(minSize / 2);
+//			Integer[] values = new Integer[size];
+//			for (int i = size; i-- > 0; ) {
+//				values[i] = Integer.valueOf(random.nextInt());
+//			}
+//			PriorityQueue<Integer> queue;
+//			queue = QueueTools.priorityQueue(size);
+//			for (Integer value : values) {
+//				queue.enqueue(value);
+//			}
+//			long start = System.currentTimeMillis();
+//			while ( ! queue.isEmpty()) {
+//				queue.dequeue();
+//			}
+//			long execTime = System.currentTimeMillis() - start;
+//			System.out.println("execution time (local var):    " + (execTime / 1000.0));
+//			assertTrue(queue.isEmpty());
+//
+//			queue = QueueTools.priorityQueue(size);
+//			for (Integer value : values) {
+//				queue.enqueue(value);
+//			}
+//			start = System.currentTimeMillis();
+//			while ( ! queue.isEmpty()) {
+//				queue.dequeueIV();
+//			}
+//			execTime = System.currentTimeMillis() - start;
+//			System.out.println("execution time (instance var): " + (execTime / 1000.0));
+//			System.out.println();
+//			assertTrue(queue.isEmpty());
+//		}
+//	}
+//
+	public void testSomethingBig() throws Exception {
+		int size = 500000;
+		Queue<Integer> queue = QueueTools.priorityQueue(size);
+		Random random = new Random();
+		for (int i = size; i-- > 0; ) {
+			queue.enqueue(Integer.valueOf(random.nextInt()));
+		}
+		Integer current = queue.dequeue();
+		int i = 1;
+		do {
+			if ( ! queue.isEmpty()) {
+				Integer next = queue.dequeue();
+				i++;
+				assertTrue(current.intValue() <= next.intValue());
+				current = next;
+			}
+		} while ( ! queue.isEmpty());
+		assertEquals(size, i);
+	}
+
+	public void testEnsureCapacity() throws Exception {
+		PriorityQueue<String> queue = QueueTools.priorityQueue();
+		queue.enqueue("b");
+		queue.enqueue("c");
+		queue.enqueue("a");
+		assertEquals(11, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		queue.ensureCapacity(420);
+		assertEquals(421, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		assertEquals("a", queue.dequeue());
+		assertEquals("b", queue.dequeue());
+		assertEquals("c", queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testTrimToSize() throws Exception {
+		PriorityQueue<String> queue = QueueTools.priorityQueue();
+		queue.enqueue("b");
+		queue.enqueue("c");
+		queue.enqueue("a");
+		assertEquals(11, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		queue.trimToSize();
+		assertEquals(4, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		assertEquals("a", queue.dequeue());
+		assertEquals("b", queue.dequeue());
+		assertEquals("c", queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testTrimToSize_nop() throws Exception {
+		PriorityQueue<String> queue = QueueTools.priorityQueue(3);
+		queue.enqueue("b");
+		queue.enqueue("c");
+		queue.enqueue("a");
+		assertEquals(4, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		queue.trimToSize();
+		assertEquals(4, ((Object[]) ObjectTools.get(queue, "elements")).length);
+		assertEquals("a", queue.dequeue());
+		assertEquals("b", queue.dequeue());
+		assertEquals("c", queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testConstructor_nullComparator() throws Exception {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue((Comparator<String>) null, 3);
+			fail("bogus queue: " + queue);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructor_negativeCapacity() throws Exception {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue(-7);
+			fail("bogus queue: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSerialization_fullArray() throws Exception {
+		Queue<String> queue = QueueTools.priorityQueue(3);
+		queue.enqueue("first");
+		queue.enqueue("second");
+		queue.enqueue("third");
+
+		this.verifyClone(queue, TestTools.serialize(queue));
+	}
+
+	public void testSerialization_empty() throws Exception {
+		Queue<String> original = QueueTools.priorityQueue();
+		Queue<String> clone = TestTools.serialize(original);
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.enqueue("foo");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testConstructorComparatorObjectArrayInt() throws Exception {
+		int maxSize = 100;
+		Integer[] array = new Integer[maxSize + 1];
+		Random random = new Random();
+		for (int size = 1; size <= maxSize; size++) {
+			ArrayTools.fill(array, null);
+			for (int i = size + 1; i-- > 1; ) {
+				array[i] = Integer.valueOf(random.nextInt());
+			}
+			Queue<Integer> queue = QueueTools.priorityQueue(array, size);
+			Integer current = queue.dequeue();
+			int i = 1;
+			do {
+				if ( ! queue.isEmpty()) {
+					Integer next = queue.dequeue();
+					i++;
+					assertTrue(current.intValue() <= next.intValue());
+					current = next;
+				}
+			} while ( ! queue.isEmpty());
+			assertEquals(size, i);
+		}
+	}
+
+	public void testConstructorComparatorObjectArrayInt_nullComparator() throws Exception {
+		String[] array = new String[5];
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue(null, array, 3);
+			fail("bogus queue: " + queue);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorComparatorObjectArrayInt_nullArray() throws Exception {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue((String[]) null, 3);
+			fail("bogus queue: " + queue);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorComparatorObjectArrayInt_emptyArray() throws Exception {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue(StringTools.EMPTY_STRING_ARRAY, 3);
+			fail("bogus queue: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorComparatorObjectArrayInt_negativeSize() throws Exception {
+		String[] array = new String[5];
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.priorityQueue(array, -7);
+			fail("bogus queue: " + queue);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueTests.java
similarity index 89%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueTests.java
index 9cd09a4..e150362 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueTests.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
 import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
 import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
@@ -146,4 +146,15 @@
 		// clone should still be empty
 		assertTrue(clone.isEmpty());
 	}
+
+	public void testToString() throws Exception {
+		Queue<String> queue = this.buildQueue();
+		assertEquals("[]", queue.toString());
+		queue.enqueue("first");
+		assertEquals("[first]", queue.toString());
+		queue.enqueue("second");
+		assertEquals("[first, second]", queue.toString());
+		queue.enqueue("third");
+		assertEquals("[first, second, third]", queue.toString());
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueToolsTests.java
new file mode 100644
index 0000000..1796eb0
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/QueueToolsTests.java
@@ -0,0 +1,506 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.queue;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.StringTools;
+import org.eclipse.jpt.common.utility.internal.comparator.ComparatorTools;
+import org.eclipse.jpt.common.utility.internal.queue.ArrayQueue;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.ListQueue;
+import org.eclipse.jpt.common.utility.internal.queue.PriorityQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
+import org.eclipse.jpt.common.utility.internal.stack.ArrayStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class QueueToolsTests
+	extends TestCase
+{
+	public QueueToolsTests(String name) {
+		super(name);
+	}
+
+	// ********** enqueue all **********
+
+	public void testEnqueueAllIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertTrue(QueueTools.enqueueAll(queue, iterable));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testEnqueueAllIterable_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertFalse(QueueTools.enqueueAll(queue, iterable));
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testEnqueueAllIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertTrue(QueueTools.enqueueAll(queue, iterable.iterator()));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testEnqueueAllArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertTrue(QueueTools.enqueueAll(queue, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testEnqueueAllArray_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertFalse(QueueTools.enqueueAll(queue, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertTrue(queue.isEmpty());
+	}
+
+
+	// ********** drain **********
+
+	public void testDrain() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("one");
+		queue.enqueue("two");
+		queue.enqueue("three");
+		ArrayList<String> list = QueueTools.drain(queue);
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainToCollection() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("one");
+		queue.enqueue("two");
+		queue.enqueue("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(QueueTools.drainTo(queue, list));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainToCollection_empty() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(QueueTools.drainTo(queue, list));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainToListIndex() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("aaa");
+		queue.enqueue("bbb");
+		queue.enqueue("ccc");
+		assertTrue(QueueTools.drainTo(queue, list, 2));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("aaa", list.get(2));
+		assertEquals("bbb", list.get(3));
+		assertEquals("ccc", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainToListIndex_end() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("aaa");
+		queue.enqueue("bbb");
+		queue.enqueue("ccc");
+		assertTrue(QueueTools.drainTo(queue, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+		assertEquals("aaa", list.get(3));
+		assertEquals("bbb", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testDrainToListIndex_empty() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertFalse(QueueTools.drainTo(queue, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainToStack() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("one");
+		queue.enqueue("two");
+		queue.enqueue("three");
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertTrue(QueueTools.drainTo(queue, stack));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testDrainToStack_empty() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		ArrayStack<String> stack = StackTools.arrayStack();
+		assertFalse(QueueTools.drainTo(queue, stack));
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainToQueue() {
+		ArrayQueue<String> queue1 = QueueTools.arrayQueue();
+		queue1.enqueue("one");
+		queue1.enqueue("two");
+		queue1.enqueue("three");
+		ArrayQueue<String> queue2 = QueueTools.arrayQueue();
+		assertTrue(QueueTools.drainTo(queue1, queue2));
+		assertEquals("one", queue2.dequeue());
+		assertEquals("two", queue2.dequeue());
+		assertEquals("three", queue2.dequeue());
+	}
+
+	public void testDrainToQueue_empty() {
+		ArrayQueue<String> queue1 = QueueTools.arrayQueue();
+		ArrayQueue<String> queue2 = QueueTools.arrayQueue();
+		assertFalse(QueueTools.drainTo(queue1, queue2));
+		assertTrue(queue2.isEmpty());
+	}
+
+	public void testDrainToMapTransformer() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("zero");
+		queue.enqueue("one");
+		queue.enqueue("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(QueueTools.drainTo(queue, map, FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainToMapTransformer_empty() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(QueueTools.drainTo(queue, map, FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainToMapTransformerTransformer() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("zero");
+		queue.enqueue("one");
+		queue.enqueue("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(QueueTools.drainTo(queue, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainToMapTransformerTransformer_empty() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(QueueTools.drainTo(queue, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+
+	public static final Transformer<String, String> FIRST_LETTER_TRANSFORMER = new FirstLetterTransformer();
+
+	/* CU private */ static class FirstLetterTransformer
+		implements Transformer<String, String>
+	{
+		public String transform(String string) {
+			return string.substring(0, 1);
+		}
+		@Override
+		public String toString() {
+			return this.getClass().getSimpleName();
+		}
+	}
+
+	public static final Transformer<String, String> EMPHASIZER = new StringTools.CharDelimiter('*');
+
+
+	// ********** array queue **********
+
+	public void testArrayQueue() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testArrayQueueInt() {
+		ArrayQueue<String> queue = QueueTools.arrayQueue(20);
+		assertTrue(queue.isEmpty());
+		assertEquals(20, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testArrayQueueIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue(iterable);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testArrayQueueIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue(iterable, 5);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testArrayQueueIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue(iterable.iterator());
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testArrayQueueIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue(iterable.iterator(), 5);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testArrayQueueArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.arrayQueue(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	// ********** linked queue **********
+
+	public void testLinkedQueue() {
+		LinkedQueue<String> queue = QueueTools.linkedQueue();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testLinkedQueueInt() {
+		LinkedQueue<String> queue = QueueTools.linkedQueue(20);
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testLinkedQueueIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.linkedQueue(iterable);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testLinkedQueueIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.linkedQueue(iterable, 5);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testLinkedQueueIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.linkedQueue(iterable.iterator());
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testLinkedQueueIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.linkedQueue(iterable.iterator(), 5);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testLinkedQueueArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.linkedQueue(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	// ********** fixed-capacity array queue **********
+
+	public void testFixedCapacityArrayQueueCollection() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Queue<String> queue = QueueTools.fixedCapacityArrayQueue(iterable);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	// ********** misc **********
+
+	public void testPriorityQueueComparator() {
+		PriorityQueue<String> queue = QueueTools.priorityQueue(ComparatorTools.<String>reverseComparator());
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.dequeue());
+	}
+
+	public void testPriorityQueueObjectArray() {
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String[] array = new String[] { null, second, first, third };
+		PriorityQueue<String> queue = QueueTools.priorityQueue(array);
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.dequeue());
+		assertEquals(third, queue.dequeue());
+	}
+
+	public void testPriorityQueueComparatorObjectArray() {
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String[] array = new String[] { null, first, second, third };
+		PriorityQueue<String> queue = QueueTools.priorityQueue(ComparatorTools.<String>reverseComparator(), array);
+		assertEquals(third, queue.dequeue());
+		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.dequeue());
+	}
+
+	public void testSynchronizedQueueObject() {
+		Object lock = new Object();
+		SynchronizedQueue<String> queue = QueueTools.synchronizedQueue(lock);
+		String first = "first";
+		String second = "second";
+
+		queue.enqueue(first);
+		queue.enqueue(second);
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.dequeue());
+		assertEquals(lock, queue.getMutex());
+	}
+
+	public void testSynchronizedQueueQueueObject() {
+		Object lock = new Object();
+		Queue<String> innerQueue = QueueTools.arrayQueue();
+		String first = "first";
+		String second = "second";
+		innerQueue.enqueue(first);
+		innerQueue.enqueue(second);
+
+		SynchronizedQueue<String> queue = QueueTools.synchronizedQueue(innerQueue, lock);
+		assertEquals(first, queue.dequeue());
+		assertEquals(second, queue.dequeue());
+		assertEquals(lock, queue.getMutex());
+	}
+
+	public void testAdaptList() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		ListQueue<String> queue = QueueTools.adapt(list);
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+	}
+
+	public void testEmptyQueue() {
+		Queue<String> queue = QueueTools.emptyQueue();
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testConstructor() {
+		boolean exCaught = false;
+		try {
+			Object at = ClassTools.newInstance(QueueTools.class);
+			fail("bogus: " + at);
+		} catch (RuntimeException ex) {
+			if (ex.getCause() instanceof InvocationTargetException) {
+				if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+					exCaught = true;
+				}
+			}
+		}
+		assertTrue(exCaught);
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/StackQueueTests.java
similarity index 74%
copy from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java
copy to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/StackQueueTests.java
index 9cd09a4..b00d3a2 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/QueueTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/StackQueueTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2015 Oracle. All rights reserved.
+ * Copyright (c) 2015 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.
@@ -7,24 +7,38 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.queue;
 
-import java.util.NoSuchElementException;
-import org.eclipse.jpt.common.utility.collection.Queue;
-import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
+import java.util.EmptyStackException;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
 
 // subclass MultiThreadedTestCase for subclasses of this class
 @SuppressWarnings("nls")
-public abstract class QueueTests
-	extends MultiThreadedTestCase
+public class StackQueueTests
+	extends TestCase
 {
-	public QueueTests(String name) {
+	public StackQueueTests(String name) {
 		super(name);
 	}
 
-	abstract Queue<String> buildQueue();
+	private Queue<String> buildQueue() {
+		return QueueTools.stackQueue();
+	}
+
+	public void testConstructor_NPE() {
+		boolean exCaught = false;
+		try {
+			Queue<String> queue = QueueTools.adapt((Stack<String>) null);
+			fail("bogus queue: " + queue);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
 
 	public void testIsEmpty() {
 		Queue<String> queue = this.buildQueue();
@@ -46,8 +60,8 @@
 
 		queue.enqueue(first);
 		queue.enqueue(second);
-		assertEquals(first, queue.dequeue());
 		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.dequeue());
 	}
 
 	public void testEnqueueAndPeek() {
@@ -57,12 +71,12 @@
 
 		queue.enqueue(first);
 		queue.enqueue(second);
-		assertEquals(first, queue.peek());
-		assertEquals(first, queue.peek());
-		assertEquals(first, queue.dequeue());
 		assertEquals(second, queue.peek());
 		assertEquals(second, queue.peek());
 		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
 	}
 
 	public void testEmptyQueueExceptionPeek() {
@@ -72,16 +86,16 @@
 
 		queue.enqueue(first);
 		queue.enqueue(second);
-		assertEquals(first, queue.peek());
-		assertEquals(first, queue.dequeue());
 		assertEquals(second, queue.peek());
 		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
 
 		boolean exCaught = false;
 		try {
-			queue.peek();
-			fail();
-		} catch (NoSuchElementException ex) {
+			String string = queue.peek();
+			fail("bogus element: " + string);
+		} catch (EmptyStackException ex) {
 			exCaught = true;
 		}
 		assertTrue(exCaught);
@@ -94,32 +108,21 @@
 
 		queue.enqueue(first);
 		queue.enqueue(second);
-		assertEquals(first, queue.peek());
-		assertEquals(first, queue.dequeue());
 		assertEquals(second, queue.peek());
 		assertEquals(second, queue.dequeue());
+		assertEquals(first, queue.peek());
+		assertEquals(first, queue.dequeue());
 
 		boolean exCaught = false;
 		try {
-			queue.dequeue();
-			fail();
-		} catch (NoSuchElementException ex) {
+			String string = queue.dequeue();
+			fail("bogus element: " + string);
+		} catch (EmptyStackException ex) {
 			exCaught = true;
 		}
 		assertTrue(exCaught);
 	}
 
-	public void testClone() {
-		Queue<String> queue = this.buildQueue();
-		queue.enqueue("first");
-		queue.enqueue("second");
-		queue.enqueue("third");
-
-		@SuppressWarnings("unchecked")
-		Queue<String> clone = (Queue<String>) ObjectTools.execute(queue, "clone");
-		this.verifyClone(queue, clone);
-	}
-
 	public void testSerialization() throws Exception {
 		Queue<String> queue = this.buildQueue();
 		queue.enqueue("first");
@@ -146,4 +149,15 @@
 		// clone should still be empty
 		assertTrue(clone.isEmpty());
 	}
+
+	public void testToString() throws Exception {
+		Queue<String> queue = this.buildQueue();
+		assertEquals("[]", queue.toString());
+		queue.enqueue("first");
+		assertEquals("[first]", queue.toString());
+		queue.enqueue("second");
+		assertEquals("[second, first]", queue.toString());
+		queue.enqueue("third");
+		assertEquals("[third, second, first]", queue.toString());
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/SynchronizedQueueTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/SynchronizedQueueTests.java
new file mode 100644
index 0000000..a058941
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/queue/SynchronizedQueueTests.java
@@ -0,0 +1,793 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2015 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.tests.internal.queue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import org.eclipse.jpt.common.utility.internal.queue.LinkedQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.queue.SynchronizedQueue;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.tests.internal.deque.DequeToolsTests;
+
+@SuppressWarnings("nls")
+public class SynchronizedQueueTests
+	extends QueueTests
+{
+	private volatile SynchronizedQueue<String> sq;
+	volatile boolean timeoutOccurred;
+	volatile long startTime;
+	volatile long endTime;
+	volatile Object dequeuedObject;
+
+	boolean commandExecuted;
+
+	static final String ITEM_1 = new String();
+	static final String ITEM_2 = new String();
+
+	public SynchronizedQueueTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Queue<String> buildQueue() {
+		return QueueTools.synchronizedQueue();
+	}
+
+	@Override
+	public void testClone() {
+		// synchronized queue is not cloneable
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.sq = QueueTools.synchronizedQueue();
+		this.timeoutOccurred = false;
+		this.startTime = 0;
+		this.endTime = 0;
+		this.dequeuedObject = null;
+	}
+
+	// ********** constructor **********
+
+	public void testConstructorQueue() throws Exception {
+		Queue<String> innerQueue = QueueTools.arrayQueue();
+		SynchronizedQueue<String> stack = QueueTools.synchronizedQueue(innerQueue);
+		assertNotNull(stack);
+		assertSame(stack, stack.getMutex());
+	}
+
+	public void testConstructorQueue_NPE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Queue<String> stack = QueueTools.synchronizedQueue(null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorQueueObject() throws Exception {
+		String mutex = "mutex";
+		Queue<String> innerQueue = QueueTools.arrayQueue();
+		SynchronizedQueue<String> stack = QueueTools.synchronizedQueue(innerQueue, mutex);
+		assertNotNull(stack);
+		assertSame(mutex, stack.getMutex());
+	}
+
+	public void testConstructorQueueObject_NPE1() throws Exception {
+		String mutex = "mutex";
+		boolean exCaught = false;
+		try {
+			Queue<String> stack = QueueTools.synchronizedQueue(null, mutex);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorQueueObject_NPE2() throws Exception {
+		Queue<String> innerQueue = QueueTools.arrayQueue();
+		boolean exCaught = false;
+		try {
+			Queue<String> stack = QueueTools.synchronizedQueue(innerQueue, null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	// ********** concurrent access **********
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentDequeue() throws Exception {
+		this.verifyConcurrentDequeue(new SlowLinkedQueue<String>(), "first");
+		this.verifyConcurrentDequeue(new SlowSynchronizedQueue<String>(), "second");
+	}
+
+	private void verifyConcurrentDequeue(SlowQueue<String> slowQueue, String expected) throws Exception {
+		slowQueue.enqueue("first");
+		slowQueue.enqueue("second");
+
+		Thread thread = this.buildThread(this.buildRunnableDequeue(slowQueue));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(expected, slowQueue.dequeue());
+		thread.join();
+		assertTrue(slowQueue.isEmpty());
+	}
+
+	private Runnable buildRunnableDequeue(final SlowQueue<String> slowQueue) {
+		return new Runnable() {
+			public void run() {
+				slowQueue.slowDequeue();
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentEnqueue() throws Exception {
+		this.verifyConcurrentEnqueue(new SlowLinkedQueue<String>(), "second", "first");
+		this.verifyConcurrentEnqueue(new SlowSynchronizedQueue<String>(), "first", "second");
+	}
+
+	private void verifyConcurrentEnqueue(SlowQueue<String> slowQueue, String first, String second) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnableEnqueue(slowQueue, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		slowQueue.enqueue("second");
+		thread.join();
+		assertEquals(first, slowQueue.dequeue());
+		assertEquals(second, slowQueue.dequeue());
+		assertTrue(slowQueue.isEmpty());
+	}
+
+	private Runnable buildRunnableEnqueue(final SlowQueue<String> slowQueue, final String element) {
+		return new Runnable() {
+			public void run() {
+				slowQueue.slowEnqueue(element);
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized queue,
+	 * then with a synchronized queue
+	 */
+	public void testConcurrentIsEmpty() throws Exception {
+		this.verifyConcurrentIsEmpty(new SlowLinkedQueue<String>(), true);
+		this.verifyConcurrentIsEmpty(new SlowSynchronizedQueue<String>(), false);
+	}
+
+	private void verifyConcurrentIsEmpty(SlowQueue<String> slowQueue, boolean empty) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnableEnqueue(slowQueue, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(empty, slowQueue.isEmpty());
+		thread.join();
+		assertEquals("first", slowQueue.dequeue());
+		assertTrue(slowQueue.isEmpty());
+	}
+
+
+	private interface SlowQueue<E> extends Queue<E> {
+		Object slowDequeue();
+		void slowEnqueue(E element);
+	}
+
+	private class SlowLinkedQueue<E> extends LinkedQueue<E> implements SlowQueue<E> {
+		private static final long serialVersionUID = 1L;
+		SlowLinkedQueue() {
+			super();
+		}
+		public Object slowDequeue() {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			return this.dequeue();
+		}
+		public void slowEnqueue(E element) {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			this.enqueue(element);
+		}
+	}
+
+	private class SlowSynchronizedQueue<E> extends SynchronizedQueue<E> implements SlowQueue<E> {
+		private static final long serialVersionUID = 1L;
+		SlowSynchronizedQueue() {
+			super(QueueTools.<E>linkedQueue());
+		}
+		public Object slowDequeue() {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				return this.dequeue();
+			}
+		}
+		public void slowEnqueue(E element) {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				this.enqueue(element);
+			}
+		}
+	}
+
+
+	// ********** waits **********
+
+	public void testWaitUntilEmpty() throws Exception {
+		this.verifyWaitUntilEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeued by t1...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and the queue should be empty
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmpty2() throws Exception {
+		this.verifyWaitUntilEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeued by t1...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and the queue should be empty
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmptyTimeout() throws Exception {
+		this.verifyWaitUntilEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue was dequeued...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and the queue should be empty
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilEmpty(long timeout) throws Exception {
+		this.sq.enqueue(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildDequeueCommand(), this.sq, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilEmptyCommand(timeout), this.sq, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
+				SynchronizedQueueTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedQueue);
+				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedQueue.waitUntilEmpty();
+					return false;
+				}
+				return ! synchronizedQueue.waitUntilEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitUntilNotEmpty() throws Exception {
+		this.verifyWaitUntilNotEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been enqueued by t1...
+		assertFalse(this.sq.isEmpty());
+		assertSame(ITEM_1, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmpty2() throws Exception {
+		this.verifyWaitUntilNotEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been enqueued by t1...
+		assertFalse(this.sq.isEmpty());
+		assertSame(ITEM_1, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmptyTimeout() throws Exception {
+		this.verifyWaitUntilNotEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and an item should have been enqueued by t1...
+		assertFalse(this.sq.isEmpty());
+		assertSame(ITEM_1, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilNotEmpty(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildEnqueueCommand(), this.sq, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilNotEmptyCommand(timeout), this.sq, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilNotEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
+				SynchronizedQueueTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedQueue);
+				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedQueue.waitUntilNotEmpty();
+					return false;
+				}
+				return ! synchronizedQueue.waitUntilNotEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitToDequeue() throws Exception {
+		this.verifyWaitToDequeue(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeued by t2...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and the queue should be empty
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeue2() throws Exception {
+		this.verifyWaitToDequeue(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been dequeued by t2...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and the queue should be empty
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToDequeueTimeout() throws Exception {
+		this.verifyWaitToDequeue(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue was never dequeued...
+		assertNull(this.dequeuedObject);
+		// ...and it still holds the item
+		assertSame(ITEM_1, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToDequeue(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildEnqueueCommand(), this.sq, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToDequeueCommand(timeout), this.sq, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToDequeueCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
+				this.waitToDequeue(synchronizedQueue);
+				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
+			}
+			private void waitToDequeue(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				if (timeout < 0) {
+					SynchronizedQueueTests.this.dequeuedObject = synchronizedQueue.waitToDequeue();
+					return;
+				}
+				try {
+					SynchronizedQueueTests.this.dequeuedObject = synchronizedQueue.waitToDequeue(timeout);
+				} catch (NoSuchElementException ex) {
+					SynchronizedQueueTests.this.timeoutOccurred = true;
+				}
+			}
+		};
+	}
+
+	public void testWaitToEnqueue() throws Exception {
+		this.verifyWaitToEnqueue(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeued by t1...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and an item is enqueued on to the queue by t2
+		assertFalse(this.sq.isEmpty());
+		assertSame(ITEM_2, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueue2() throws Exception {
+		this.verifyWaitToEnqueue(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the queue gets dequeued by t1...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...and an item is enqueued on to the queue by t2
+		assertFalse(this.sq.isEmpty());
+		assertSame(ITEM_2, this.sq.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToEnqueueTimeout() throws Exception {
+		this.verifyWaitToEnqueue(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the queue is eventually dequeued by t1...
+		assertSame(ITEM_1, this.dequeuedObject);
+		// ...but nothing is enqueued on to the queue by t2
+		assertTrue(this.sq.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToEnqueue(long timeout) throws Exception {
+		this.sq.enqueue(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildDequeueCommand(), this.sq, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToEnqueueCommand(timeout), this.sq, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToEnqueueCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				SynchronizedQueueTests.this.startTime = System.currentTimeMillis();
+				SynchronizedQueueTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedQueue);
+				SynchronizedQueueTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedQueue.waitToEnqueue(ITEM_2);
+					return false;
+				}
+				return ! synchronizedQueue.waitToEnqueue(ITEM_2, timeout);
+			}
+		};
+	}
+
+	private Command buildEnqueueCommand() {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) {
+				synchronizedQueue.enqueue(ITEM_1);
+			}
+		};
+	}
+
+	private Command buildDequeueCommand() {
+		return new Command() {
+			public void execute(SynchronizedQueue<String> synchronizedQueue) {
+				SynchronizedQueueTests.this.dequeuedObject = synchronizedQueue.dequeue();
+			}
+		};
+	}
+
+	private Runnable buildRunnable(final Command command, final SynchronizedQueue<String> synchronizedQueue, final long sleep) {
+		return new TestRunnable() {
+			@Override
+			protected void run_() throws Throwable {
+				if (sleep != 0) {
+					Thread.sleep(sleep);
+				}
+				command.execute(synchronizedQueue);
+			}
+		};
+	}
+
+	long calculateElapsedTime() {
+		return this.endTime - this.startTime;
+	}
+
+
+	// ********** Command interface **********
+
+	private interface Command {
+		void execute(SynchronizedQueue<String> synchronizedQueue) throws InterruptedException;
+	}
+
+
+	// ********** execute **********
+
+	public void testExecute() throws Exception {
+		org.eclipse.jpt.common.utility.command.Command command = new org.eclipse.jpt.common.utility.command.Command() {
+			public void execute() {
+				SynchronizedQueueTests.this.commandExecuted = true;
+			}
+		};
+		this.commandExecuted = false;
+		this.sq.execute(command);
+		assertTrue(this.commandExecuted);
+	}
+
+
+	// ********** additional protocol **********
+
+	public void testEnqueueAllIterable() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		this.sq.enqueueAll(list);
+		assertEquals("one", this.sq.dequeue());
+		assertEquals("two", this.sq.dequeue());
+		assertEquals("three", this.sq.dequeue());
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllIterable_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		this.sq.enqueueAll(list);
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllObjectArray() throws Exception {
+		this.sq.enqueueAll(new String[] { "one", "two", "three" });
+		assertEquals("one", this.sq.dequeue());
+		assertEquals("two", this.sq.dequeue());
+		assertEquals("three", this.sq.dequeue());
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllObjectArray_empty() throws Exception {
+		this.sq.enqueueAll(new String[0]);
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllStack() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		this.sq.enqueueAll(stack);
+		assertEquals("three", this.sq.dequeue());
+		assertEquals("two", this.sq.dequeue());
+		assertEquals("one", this.sq.dequeue());
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		this.sq.enqueueAll(stack);
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllQueue() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("one");
+		queue.enqueue("two");
+		queue.enqueue("three");
+		this.sq.enqueueAll(queue);
+		assertEquals("one", this.sq.dequeue());
+		assertEquals("two", this.sq.dequeue());
+		assertEquals("three", this.sq.dequeue());
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testEnqueueAllQueue_empty() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		this.sq.enqueueAll(queue);
+		assertTrue(this.sq.isEmpty());
+	}
+
+	public void testDrain() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		ArrayList<String> list = this.sq.drain();
+		assertTrue(this.sq.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrain_empty() throws Exception {
+		ArrayList<String> list = this.sq.drain();
+		assertTrue(this.sq.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainToCollection() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(this.sq.drainTo(list));
+		assertTrue(this.sq.isEmpty());
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testDrainToCollection_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(this.sq.drainTo(list));
+		assertTrue(this.sq.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testDrainToListInt() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.sq.drainTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("one", list.get(2));
+		assertEquals("two", list.get(3));
+		assertEquals("three", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testDrainToListInt_end() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.sq.drainTo(list, 3));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("one", list.get(3));
+		assertEquals("two", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testDrainToListInt_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertFalse(this.sq.drainTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+	}
+
+	public void testDrainToStack() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(this.sq.drainTo(stack));
+		assertTrue(this.sq.isEmpty());
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainToStack_empty() throws Exception {
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(this.sq.drainTo(stack));
+		assertTrue(this.sq.isEmpty());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testDrainToQueue() throws Exception {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertTrue(this.sq.drainTo(queue));
+		assertTrue(this.sq.isEmpty());
+		assertEquals("one", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("three", queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainToQueue_empty() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertFalse(this.sq.drainTo(queue));
+		assertTrue(this.sq.isEmpty());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testDrainToMapTransformer() {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.sq.drainTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testDrainToMapTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.sq.drainTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testDrainToMapTransformerTransformer() {
+		this.sq.enqueue("one");
+		this.sq.enqueue("two");
+		this.sq.enqueue("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.sq.drainTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testDrainToMapTransformerTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.sq.drainTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ArrayStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ArrayStackTests.java
new file mode 100644
index 0000000..0334b14
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ArrayStackTests.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.tests.internal.stack;
+
+import java.util.ArrayList;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.stack.ArrayStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+
+@SuppressWarnings("nls")
+public class ArrayStackTests
+	extends StackTests
+{
+	public ArrayStackTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Stack<String> buildStack() {
+		return new ArrayStack<String>();
+	}
+
+	public void testCollectionConstructor() {
+		ArrayList<String> c = new ArrayList<String>();
+		c.add("first");
+		c.add("second");
+		c.add("third");
+		c.add("fourth");
+		c.add("fifth");
+		c.add("sixth");
+		c.add("seventh");
+		c.add("eighth");
+		c.add("ninth");
+		c.add("tenth"); // force some free space
+		Stack<String> stack = StackTools.arrayStack(c);
+
+		assertFalse(stack.isEmpty());
+		assertEquals("tenth", stack.peek());
+		stack.push("eleventh");
+		stack.push("twelfth");
+
+		assertEquals("twelfth", stack.peek());
+		assertEquals("twelfth", stack.pop());
+		assertEquals("eleventh", stack.pop());
+		assertEquals("tenth", stack.peek());
+		assertEquals("tenth", stack.pop());
+		assertEquals("ninth", stack.pop());
+		assertFalse(stack.isEmpty());
+		assertEquals("eighth", stack.peek());
+		assertEquals("eighth", stack.pop());
+		assertEquals("seventh", stack.pop());
+		assertEquals("sixth", stack.pop());
+		assertEquals("fifth", stack.pop());
+		assertEquals("fourth", stack.pop());
+		assertEquals("third", stack.pop());
+		assertEquals("second", stack.pop());
+		assertEquals("first", stack.pop());
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testSerialization_fullArray() throws Exception {
+		Stack<String> stack = new ArrayStack<String>(3);
+		stack.push("first");
+		stack.push("second");
+		stack.push("third");
+
+		this.verifyClone(stack, TestTools.serialize(stack));
+	}
+
+	public void testEnsureCapacity() {
+		ArrayStack<String> queue = StackTools.arrayStack(0);
+		queue.ensureCapacity(7);
+		assertEquals(7, ((Object[]) ObjectTools.get(queue, "elements")).length);
+	}
+
+	public void testTrimToSize() throws Exception {
+		ArrayStack<String> stack = new ArrayStack<String>(5);
+		stack.push("first");
+		stack.push("second");
+		stack.push("third");
+
+		Object[] elements = (Object[]) ObjectTools.get(stack, "elements");
+		assertEquals(5, elements.length);
+
+		stack.trimToSize();
+		elements = (Object[]) ObjectTools.get(stack, "elements");
+		assertEquals(3, elements.length);
+	}
+
+	public void testTrimToSize_noChange() throws Exception {
+		ArrayStack<String> stack = new ArrayStack<String>(3);
+		stack.push("first");
+		stack.push("second");
+		stack.push("third");
+
+		Object[] elements = (Object[]) ObjectTools.get(stack, "elements");
+		assertEquals(3, elements.length);
+
+		stack.trimToSize();
+		elements = (Object[]) ObjectTools.get(stack, "elements");
+		assertEquals(3, elements.length);
+	}
+
+	public void testConstructorInt_IAE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.arrayStack(-3);
+			fail("bogus stack: " + stack);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testToString_empty() throws Exception {
+		Stack<String> stack = this.buildStack();
+		assertEquals("[]", stack.toString());
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/DequeStackTests.java
similarity index 63%
copy from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
copy to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/DequeStackTests.java
index 4012ee2..2e9ed5a 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/DequeStackTests.java
@@ -7,22 +7,22 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.stack;
 
-import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.ListStack;
+import org.eclipse.jpt.common.utility.internal.deque.DequeTools;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
-public class ListStackTests
+public class DequeStackTests
 	extends StackTests
 {
-	public ListStackTests(String name) {
+	public DequeStackTests(String name) {
 		super(name);
 	}
 
 	@Override
 	Stack<String> buildStack() {
-		return new ListStack<String>(new ArrayList<String>());
+		return StackTools.adapt(DequeTools.<String>arrayDeque());
 	}
 
 	@Override
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/EmptyStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/EmptyStackTests.java
new file mode 100644
index 0000000..6e7e606
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/EmptyStackTests.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.stack;
+
+import java.util.EmptyStackException;
+import org.eclipse.jpt.common.utility.internal.stack.EmptyStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.tests.internal.TestTools;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class EmptyStackTests
+	extends TestCase
+{
+	public EmptyStackTests(String name) {
+		super(name);
+	}
+
+	public void testPush() {
+		Stack<String> stack = StackTools.emptyStack();
+		boolean exCaught = false;
+		try {
+			stack.push("junk");
+			fail();
+		} catch (UnsupportedOperationException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testPop() {
+		Stack<String> stack = EmptyStack.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = stack.pop();
+			fail(bogus);
+		} catch (EmptyStackException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testPeek() {
+		Stack<String> stack = EmptyStack.<String>instance();
+		boolean exCaught = false;
+		try {
+			String bogus = stack.peek();
+			fail(bogus);
+		} catch (EmptyStackException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testIsEmpty() {
+		Stack<String> stack = EmptyStack.<String>instance();
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testToString() {
+		Stack<String> stack = EmptyStack.<String>instance();
+		assertEquals("[]", stack.toString());
+	}
+
+	public void testSerialization() throws Exception {
+		Stack<String> stack = EmptyStack.<String>instance();
+		assertSame(stack, TestTools.serialize(stack));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/FixedCapacityArrayStackTests.java
similarity index 76%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayStackTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/FixedCapacityArrayStackTests.java
index 53ba45f..315b4d6 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/FixedSizeArrayStackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/FixedCapacityArrayStackTests.java
@@ -7,25 +7,25 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.stack;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.FixedSizeArrayStack;
-import org.eclipse.jpt.common.utility.internal.collection.StackTools;
+import org.eclipse.jpt.common.utility.internal.stack.FixedCapacityArrayStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
 @SuppressWarnings("nls")
-public class FixedSizeArrayStackTests
+public class FixedCapacityArrayStackTests
 	extends StackTests
 {
-	public FixedSizeArrayStackTests(String name) {
+	public FixedCapacityArrayStackTests(String name) {
 		super(name);
 	}
 
 	@Override
-	FixedSizeArrayStack<String> buildStack() {
-		return new FixedSizeArrayStack<String>(10);
+	FixedCapacityArrayStack<String> buildStack() {
+		return StackTools.fixedCapacityArrayStack(10);
 	}
 
 	public void testCollectionConstructor() {
@@ -40,7 +40,7 @@
 		c.add("eighth");
 		c.add("ninth");
 		c.add("tenth");
-		Stack<String> stack = StackTools.fixedSizeStack(c);
+		Stack<String> stack = StackTools.fixedCapacityArrayStack(c);
 
 		assertFalse(stack.isEmpty());
 		assertEquals("tenth", stack.peek());
@@ -60,7 +60,7 @@
 	}
 
 	public void testIsFull() {
-		FixedSizeArrayStack<String> stack = this.buildStack();
+		FixedCapacityArrayStack<String> stack = this.buildStack();
 		assertFalse(stack.isFull());
 		stack.push("first");
 		assertFalse(stack.isFull());
@@ -131,11 +131,27 @@
 	}
 
 	public void testSerialization_fullArray() throws Exception {
-		Stack<String> stack = new FixedSizeArrayStack<String>(3);
+		Stack<String> stack = new FixedCapacityArrayStack<String>(3);
 		stack.push("first");
 		stack.push("second");
 		stack.push("third");
 
 		this.verifyClone(stack, TestTools.serialize(stack));
 	}
+
+	public void testConstructorInt_IAE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.fixedCapacityArrayStack(-3);
+			fail("bogus stack: " + stack);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testToString_empty() throws Exception {
+		Stack<String> stack = this.buildStack();
+		assertEquals("[]", stack.toString());
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/JptCommonUtilityStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/JptCommonUtilityStackTests.java
new file mode 100644
index 0000000..f1ff723
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/JptCommonUtilityStackTests.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2015 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.tests.internal.stack;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * decentralize test creation code
+ */
+public class JptCommonUtilityStackTests {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite(JptCommonUtilityStackTests.class.getPackage().getName());
+
+		suite.addTestSuite(ArrayStackTests.class);
+		suite.addTestSuite(DequeStackTests.class);
+		suite.addTestSuite(EmptyStackTests.class);
+		suite.addTestSuite(FixedCapacityArrayStackTests.class);
+		suite.addTestSuite(LinkedStackTests.class);
+		suite.addTestSuite(ListStackTests.class);
+		suite.addTestSuite(StackToolsTests.class);
+		suite.addTestSuite(SynchronizedStackTests.class);
+
+		return suite;
+	}
+
+	private JptCommonUtilityStackTests() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/LinkedStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/LinkedStackTests.java
new file mode 100644
index 0000000..74e8569
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/LinkedStackTests.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Copyright (c) 2012, 2015 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.tests.internal.stack;
+
+import java.util.Arrays;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.stack.LinkedStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
+
+@SuppressWarnings("nls")
+public class LinkedStackTests
+	extends StackTests
+{
+	public LinkedStackTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Stack<String> buildStack() {
+		return StackTools.linkedStack();
+	}
+
+	public void testConstructorInt_IAE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.linkedStack(-3);
+			fail("bogus stack: " + stack);
+		} catch (IllegalArgumentException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testSize() {
+		Stack<String> stack = this.buildStack();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+
+		assertEquals(0, ((Integer) ObjectTools.execute(stack, "size")).intValue());
+		stack.push(first);
+		stack.push(second);
+		assertEquals(2, ((Integer) ObjectTools.execute(stack, "size")).intValue());
+		stack.push(third);
+		assertEquals(3, ((Integer) ObjectTools.execute(stack, "size")).intValue());
+		stack.pop();
+		assertEquals(2, ((Integer) ObjectTools.execute(stack, "size")).intValue());
+		stack.pop();
+		stack.pop();
+		assertEquals(0, ((Integer) ObjectTools.execute(stack, "size")).intValue());
+	}
+
+	public void testBuildElements() {
+		Stack<String> stack = this.buildStack();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		stack.push(first);
+		stack.push(second);
+		stack.push(third);
+
+		Object[] elements = new Object[] { third, second, first };
+		assertTrue(Arrays.equals(elements, ((Object[]) ObjectTools.execute(stack, "buildElements"))));
+	}
+
+	public void testNodeCache_max() {
+		Stack<String> stack = new LinkedStack<String>(2);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(stack, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		stack.push(first);
+		this.verifyNodeCache(0, factory);
+		stack.push(second);
+		stack.push(third);
+		stack.push(fourth);
+		stack.push(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		stack.pop();
+		this.verifyNodeCache(1, factory);
+		stack.pop();
+		this.verifyNodeCache(2, factory);
+		stack.pop();
+		this.verifyNodeCache(2, factory);
+		stack.pop();
+		this.verifyNodeCache(2, factory);
+		stack.pop();
+		this.verifyNodeCache(2, factory);
+		stack.push(first);
+		this.verifyNodeCache(1, factory);
+		stack.push(second);
+		this.verifyNodeCache(0, factory);
+		stack.push(third);
+		this.verifyNodeCache(0, factory);
+	}
+
+	public void testNodeCache_unlimited() {
+		Stack<String> stack = new LinkedStack<String>(-1);
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		String fourth = "fourth";
+		String fifth = "fifth";
+
+		Object factory = ObjectTools.get(stack, "nodeFactory");
+
+		this.verifyNodeCache(0, factory);
+		stack.push(first);
+		this.verifyNodeCache(0, factory);
+		stack.push(second);
+		stack.push(third);
+		stack.push(fourth);
+		stack.push(fifth);
+		this.verifyNodeCache(0, factory);
+		assertNull(ObjectTools.get(factory, "cacheHead"));
+
+		stack.pop();
+		this.verifyNodeCache(1, factory);
+		stack.pop();
+		this.verifyNodeCache(2, factory);
+		stack.pop();
+		this.verifyNodeCache(3, factory);
+		stack.pop();
+		this.verifyNodeCache(4, factory);
+		stack.pop();
+		this.verifyNodeCache(5, factory);
+		stack.push(first);
+		this.verifyNodeCache(4, factory);
+		stack.push(second);
+		this.verifyNodeCache(3, factory);
+		stack.push(third);
+		this.verifyNodeCache(2, factory);
+		stack.push(fourth);
+		this.verifyNodeCache(1, factory);
+		stack.push(fifth);
+		this.verifyNodeCache(0, factory);
+	}
+
+	public void verifyNodeCache(int size, Object factory) {
+		assertEquals(size, ((Integer) ObjectTools.get(factory, "cacheSize")).intValue());
+		int nodeCount = 0;
+		for (Object node = ObjectTools.get(factory, "cacheHead"); node != null; node = ObjectTools.get(node, "next")) {
+			nodeCount++;
+		}
+		assertEquals(size, nodeCount);
+	}
+
+	public void testNodeToString() {
+		Stack<String> queue = StackTools.linkedStack();
+		String first = "first";
+		String second = "second";
+		String third = "third";
+		queue.push(first);
+		queue.push(second);
+		queue.push(third);
+
+		Object head = ObjectTools.get(queue, "head");
+		assertTrue(head.toString().startsWith("LinkedStack.Node"));
+		assertTrue(head.toString().endsWith("(third)"));
+	}
+
+	public void testToString_empty() throws Exception {
+		Stack<String> stack = this.buildStack();
+		assertEquals("[]", stack.toString());
+	}
+
+	public void testSimpleNodeFactoryToString() {
+		Stack<String> queue = StackTools.linkedStack();
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertEquals("LinkedStack.SimpleNodeFactory", factory.toString());
+	}
+
+	public void testCachingNodeFactoryToString() {
+		Stack<String> queue = StackTools.linkedStack(20);
+		Object factory = ObjectTools.get(queue, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedStack.CachingNodeFactory"));
+		assertTrue(factory.toString().endsWith("(0)"));
+	}
+
+	public void testClone_caching() throws Exception {
+		LinkedStack<String> original = StackTools.linkedStack(20);
+		original.push("first");
+
+		LinkedStack<String> clone = original.clone();
+		assertEquals(original.peek(), clone.peek());
+		assertEquals(original.pop(), clone.pop());
+		assertNotSame(original, clone);
+		assertTrue(original.isEmpty());
+		assertEquals(original.isEmpty(), clone.isEmpty());
+
+		original.push("second");
+		assertFalse(original.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+
+		Object factory = ObjectTools.get(original, "nodeFactory");
+		assertTrue(factory.toString().startsWith("LinkedStack.CachingNodeFactory"));
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ListStackTests.java
similarity index 75%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ListStackTests.java
index 4012ee2..2c0c3e6 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/ListStackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/ListStackTests.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.stack;
 
 import java.util.ArrayList;
-import org.eclipse.jpt.common.utility.collection.Stack;
-import org.eclipse.jpt.common.utility.internal.collection.ListStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 
 public class ListStackTests
 	extends StackTests
@@ -22,7 +22,7 @@
 
 	@Override
 	Stack<String> buildStack() {
-		return new ListStack<String>(new ArrayList<String>());
+		return StackTools.adapt(new ArrayList<String>());
 	}
 
 	@Override
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/StackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackTests.java
similarity index 85%
rename from common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/StackTests.java
rename to common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackTests.java
index ad755fe..54fc775 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/collection/StackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackTests.java
@@ -7,11 +7,11 @@
  * Contributors:
  *     Oracle - initial API and implementation
  ******************************************************************************/
-package org.eclipse.jpt.common.utility.tests.internal.collection;
+package org.eclipse.jpt.common.utility.tests.internal.stack;
 
 import java.util.EmptyStackException;
-import org.eclipse.jpt.common.utility.collection.Stack;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.stack.Stack;
 import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
 import org.eclipse.jpt.common.utility.tests.internal.TestTools;
 
@@ -147,4 +147,23 @@
 		assertTrue(clone.isEmpty());
 	}
 
+	public void testSerialization_empty() throws Exception {
+		Stack<String> stack = this.buildStack();
+		Stack<String> clone = TestTools.serialize(stack);
+		assertNotSame(stack, clone);
+		assertTrue(clone.isEmpty());
+		stack.push("fourth");
+		assertFalse(stack.isEmpty());
+		// clone should still be empty
+		assertTrue(clone.isEmpty());
+	}
+
+	public void testToString() throws Exception {
+		Stack<String> stack = this.buildStack();
+		stack.push("first");
+		stack.push("second");
+		stack.push("third");
+
+		assertEquals("[third, second, first]", stack.toString());
+	}
 }
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackToolsTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackToolsTests.java
new file mode 100644
index 0000000..79d0c86
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/StackToolsTests.java
@@ -0,0 +1,465 @@
+/*******************************************************************************
+ * Copyright (c) 2015 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.tests.internal.stack;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.internal.ClassTools;
+import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.StringTools;
+import org.eclipse.jpt.common.utility.internal.queue.ArrayQueue;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.stack.ArrayStack;
+import org.eclipse.jpt.common.utility.internal.stack.LinkedStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.internal.stack.SynchronizedStack;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.transformer.Transformer;
+import junit.framework.TestCase;
+
+@SuppressWarnings("nls")
+public class StackToolsTests
+	extends TestCase
+{
+	public StackToolsTests(String name) {
+		super(name);
+	}
+
+	// ********** push all **********
+
+	public void testPushAllIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(StackTools.pushAll(stack, iterable));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testPushAllIterable_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(StackTools.pushAll(stack, iterable));
+		assertTrue(stack.isEmpty());
+	}
+
+	public void testPushAllIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(StackTools.pushAll(stack, iterable.iterator()));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testPushAllArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertTrue(StackTools.pushAll(stack, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testPushAllArray_empty() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(StackTools.pushAll(stack, iterable.toArray(StringTools.EMPTY_STRING_ARRAY)));
+		assertTrue(stack.isEmpty());
+	}
+
+
+	// ********** pop all **********
+
+	public void testPopAll() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		ArrayList<String> list = StackTools.popAll(stack);
+		assertEquals("three", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("one", list.get(2));
+	}
+
+	public void testPopAllToCollection() {
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(StackTools.popAllTo(stack, list));
+		assertEquals("three", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("one", list.get(2));
+	}
+
+	public void testPopAllToCollection_empty() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(StackTools.popAllTo(stack, list));
+		assertTrue(list.isEmpty());
+	}
+
+	public void testPopAllToListIndex() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("aaa");
+		stack.push("bbb");
+		stack.push("ccc");
+		assertTrue(StackTools.popAllTo(stack, list, 2));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("bbb", list.get(3));
+		assertEquals("aaa", list.get(4));
+		assertEquals("three", list.get(5));
+	}
+
+	public void testPopAllToListIndex_end() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		stack.push("aaa");
+		stack.push("bbb");
+		stack.push("ccc");
+		assertTrue(StackTools.popAllTo(stack, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+		assertEquals("ccc", list.get(3));
+		assertEquals("bbb", list.get(4));
+		assertEquals("aaa", list.get(5));
+	}
+
+	public void testPopAllToListIndex_empty() {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		Stack<String> stack = StackTools.arrayStack();
+		assertFalse(StackTools.popAllTo(stack, list, 3));
+		assertEquals("one", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("three", list.get(2));
+	}
+
+	public void testPopAllToStack() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		ArrayStack<String> stack2 = StackTools.arrayStack();
+		assertTrue(StackTools.popAllTo(stack, stack2));
+		assertEquals("one", stack2.pop());
+		assertEquals("two", stack2.pop());
+		assertEquals("three", stack2.pop());
+	}
+
+	public void testPopAllToStack_empty() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		ArrayStack<String> stack2 = StackTools.arrayStack();
+		assertFalse(StackTools.popAllTo(stack, stack2));
+		assertTrue(stack2.isEmpty());
+	}
+
+	public void testPopAllToQueue() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		stack.push("one");
+		stack.push("two");
+		stack.push("three");
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertTrue(StackTools.popAllTo(stack, queue));
+		assertEquals("three", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("one", queue.dequeue());
+	}
+
+	public void testPopAllToQueue_empty() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		ArrayQueue<String> queue = QueueTools.arrayQueue();
+		assertFalse(StackTools.popAllTo(stack, queue));
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testPopAllToMapTransformer() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		stack.push("zero");
+		stack.push("one");
+		stack.push("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(StackTools.popAllTo(stack, map, FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testPopAllToMapTransformer_empty() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(StackTools.popAllTo(stack, map, FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testPopAllToMapTransformerTransformer() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		stack.push("zero");
+		stack.push("one");
+		stack.push("two");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(StackTools.popAllTo(stack, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testPopAllToMapTransformerTransformer_empty() {
+		ArrayStack<String> stack = StackTools.arrayStack();
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(StackTools.popAllTo(stack, map, FIRST_LETTER_TRANSFORMER, EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+
+	public static final Transformer<String, String> FIRST_LETTER_TRANSFORMER = new FirstLetterTransformer();
+
+	/* CU private */ static class FirstLetterTransformer
+		implements Transformer<String, String>
+	{
+		public String transform(String string) {
+			return string.substring(0, 1);
+		}
+		@Override
+		public String toString() {
+			return this.getClass().getSimpleName();
+		}
+	}
+
+	public static final Transformer<String, String> EMPHASIZER = new StringTools.CharDelimiter('*');
+
+
+	// ********** array stack **********
+
+	public void testArrayStack() {
+		ArrayStack<String> d = StackTools.arrayStack();
+		assertTrue(d.isEmpty());
+	}
+
+	public void testArrayStackInt() {
+		ArrayStack<String> d = StackTools.arrayStack(20);
+		assertTrue(d.isEmpty());
+		assertEquals(20, ((Object[]) ObjectTools.get(d, "elements")).length);
+	}
+
+	public void testArrayStackIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack(iterable);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testArrayStackIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack(iterable, 5);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testArrayStackIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack(iterable.iterator());
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testArrayStackIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack(iterable.iterator(), 5);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testArrayStackArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.arrayStack(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	// ********** linked stack **********
+
+	public void testLinkedStack() {
+		LinkedStack<String> d = StackTools.linkedStack();
+		assertTrue(d.isEmpty());
+	}
+
+	public void testLinkedStackInt() {
+		LinkedStack<String> d = StackTools.linkedStack(20);
+		assertTrue(d.isEmpty());
+	}
+
+	public void testLinkedStackIterable() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testLinkedStackIterableInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable, 5);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testLinkedStackIterator() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable.iterator());
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testLinkedStackIteratorInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable.iterator(), 5);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testLinkedStackArray() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable.toArray(StringTools.EMPTY_STRING_ARRAY));
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	public void testLinkedStackArrayInt() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.linkedStack(iterable.toArray(StringTools.EMPTY_STRING_ARRAY), 2);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	// ********** fixed-capacity array stack **********
+
+	public void testFixedCapacityArrayStackCollection() {
+		ArrayList<String> iterable = new ArrayList<String>();
+		iterable.add("one");
+		iterable.add("two");
+		iterable.add("three");
+		Stack<String> stack = StackTools.fixedCapacityArrayStack(iterable);
+		assertEquals("three", stack.pop());
+		assertEquals("two", stack.pop());
+		assertEquals("one", stack.pop());
+	}
+
+	// ********** misc **********
+
+	public void testSynchronizedStackObject() {
+		Object lock = new Object();
+		SynchronizedStack<String> stack = StackTools.synchronizedStack(lock);
+		String first = "first";
+		String second = "second";
+
+		stack.push(first);
+		stack.push(second);
+		assertEquals(second, stack.pop());
+		assertEquals(first, stack.pop());
+		assertEquals(lock, stack.getMutex());
+	}
+
+	public void testSynchronizedStackStackObject() {
+		Object lock = new Object();
+		Stack<String> innerStack = StackTools.arrayStack();
+		String first = "first";
+		String second = "second";
+		innerStack.push(first);
+		innerStack.push(second);
+
+		SynchronizedStack<String> stack = StackTools.synchronizedStack(innerStack, lock);
+		assertEquals(second, stack.pop());
+		assertEquals(first, stack.pop());
+		assertEquals(lock, stack.getMutex());
+	}
+
+	public void testConstructor() {
+		boolean exCaught = false;
+		try {
+			Object at = ClassTools.newInstance(StackTools.class);
+			fail("bogus: " + at);
+		} catch (RuntimeException ex) {
+			if (ex.getCause() instanceof InvocationTargetException) {
+				if (ex.getCause().getCause() instanceof UnsupportedOperationException) {
+					exCaught = true;
+				}
+			}
+		}
+		assertTrue(exCaught);
+	}
+}
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/SynchronizedStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/SynchronizedStackTests.java
new file mode 100644
index 0000000..d8bf228
--- /dev/null
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/SynchronizedStackTests.java
@@ -0,0 +1,792 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2015 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.tests.internal.stack;
+
+import java.util.ArrayList;
+import java.util.EmptyStackException;
+import java.util.HashMap;
+import java.util.Map;
+import org.eclipse.jpt.common.utility.internal.queue.QueueTools;
+import org.eclipse.jpt.common.utility.internal.stack.LinkedStack;
+import org.eclipse.jpt.common.utility.internal.stack.StackTools;
+import org.eclipse.jpt.common.utility.internal.stack.SynchronizedStack;
+import org.eclipse.jpt.common.utility.queue.Queue;
+import org.eclipse.jpt.common.utility.stack.Stack;
+import org.eclipse.jpt.common.utility.tests.internal.deque.DequeToolsTests;
+
+@SuppressWarnings("nls")
+public class SynchronizedStackTests
+	extends StackTests
+{
+	private volatile SynchronizedStack<String> ss;
+	volatile boolean timeoutOccurred;
+	volatile long startTime;
+	volatile long endTime;
+	volatile Object poppedObject;
+
+	boolean commandExecuted;
+
+	static final String ITEM_1 = new String();
+	static final String ITEM_2 = new String();
+
+	public SynchronizedStackTests(String name) {
+		super(name);
+	}
+
+	@Override
+	Stack<String> buildStack() {
+		return StackTools.synchronizedStack();
+	}
+
+	@Override
+	public void testClone() {
+		// synchronized stack is not cloneable
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.ss = StackTools.synchronizedStack();
+		this.timeoutOccurred = false;
+		this.startTime = 0;
+		this.endTime = 0;
+		this.poppedObject = null;
+	}
+
+	// ********** constructor **********
+
+	public void testConstructorStack() throws Exception {
+		Stack<String> innerStack = StackTools.arrayStack();
+		SynchronizedStack<String> stack = StackTools.synchronizedStack(innerStack);
+		assertNotNull(stack);
+		assertSame(stack, stack.getMutex());
+	}
+
+	public void testConstructorStack_NPE() throws Exception {
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.synchronizedStack(null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorStackObject() throws Exception {
+		String mutex = "mutex";
+		Stack<String> innerStack = StackTools.arrayStack();
+		SynchronizedStack<String> stack = StackTools.synchronizedStack(innerStack, mutex);
+		assertNotNull(stack);
+		assertSame(mutex, stack.getMutex());
+	}
+
+	public void testConstructorStackObject_NPE1() throws Exception {
+		String mutex = "mutex";
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.synchronizedStack(null, mutex);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	public void testConstructorStackObject_NPE2() throws Exception {
+		Stack<String> innerStack = StackTools.arrayStack();
+		boolean exCaught = false;
+		try {
+			Stack<String> stack = StackTools.synchronizedStack(innerStack, null);
+			fail("bogus stack: " + stack);
+		} catch (NullPointerException ex) {
+			exCaught = true;
+		}
+		assertTrue(exCaught);
+	}
+
+	// ********** concurrent access **********
+
+	/**
+	 * test first with an unsynchronized stack,
+	 * then with a synchronized stack
+	 */
+	public void testConcurrentPop() throws Exception {
+		this.verifyConcurrentPop(new SlowLinkedStack<String>(), "second");
+		this.verifyConcurrentPop(new SlowSynchronizedStack<String>(), "first");
+	}
+
+	private void verifyConcurrentPop(SlowStack<String> slowStack, String expected) throws Exception {
+		slowStack.push("first");
+		slowStack.push("second");
+
+		Thread thread = this.buildThread(this.buildRunnablePop(slowStack));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(expected, slowStack.pop());
+		thread.join();
+		assertTrue(slowStack.isEmpty());
+	}
+
+	private Runnable buildRunnablePop(final SlowStack<String> slowStack) {
+		return new Runnable() {
+			public void run() {
+				slowStack.slowPop();
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized stack,
+	 * then with a synchronized stack
+	 */
+	public void testConcurrentPush() throws Exception {
+		this.verifyConcurrentPush(new SlowLinkedStack<String>(), "first", "second");
+		this.verifyConcurrentPush(new SlowSynchronizedStack<String>(), "second", "first");
+	}
+
+	private void verifyConcurrentPush(SlowStack<String> slowStack, String first, String second) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnablePush(slowStack, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		slowStack.push("second");
+		thread.join();
+		assertEquals(first, slowStack.pop());
+		assertEquals(second, slowStack.pop());
+		assertTrue(slowStack.isEmpty());
+	}
+
+	private Runnable buildRunnablePush(final SlowStack<String> slowStack, final String element) {
+		return new Runnable() {
+			public void run() {
+				slowStack.slowPush(element);
+			}
+		};
+	}
+
+	/**
+	 * test first with an unsynchronized stack,
+	 * then with a synchronized stack
+	 */
+	public void testConcurrentIsEmpty() throws Exception {
+		this.verifyConcurrentIsEmpty(new SlowLinkedStack<String>(), true);
+		this.verifyConcurrentIsEmpty(new SlowSynchronizedStack<String>(), false);
+	}
+
+	private void verifyConcurrentIsEmpty(SlowStack<String> slowStack, boolean empty) throws Exception {
+		Thread thread = this.buildThread(this.buildRunnablePush(slowStack, "first"));
+		thread.start();
+		Thread.sleep(TWO_TICKS);
+
+		assertEquals(empty, slowStack.isEmpty());
+		thread.join();
+		assertEquals("first", slowStack.pop());
+		assertTrue(slowStack.isEmpty());
+	}
+
+
+	private interface SlowStack<E> extends Stack<E> {
+		Object slowPop();
+		void slowPush(E element);
+	}
+
+	private class SlowLinkedStack<E> extends LinkedStack<E> implements SlowStack<E> {
+		private static final long serialVersionUID = 1L;
+		SlowLinkedStack() {
+			super();
+		}
+		public Object slowPop() {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			return this.pop();
+		}
+		public void slowPush(E element) {
+			try {
+				Thread.sleep(5 * TICK);
+			} catch (InterruptedException ex) {
+				throw new RuntimeException(ex);
+			}
+			this.push(element);
+		}
+	}
+
+	private class SlowSynchronizedStack<E> extends SynchronizedStack<E> implements SlowStack<E> {
+		private static final long serialVersionUID = 1L;
+		SlowSynchronizedStack() {
+			super(StackTools.<E>linkedStack());
+		}
+		public Object slowPop() {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				return this.pop();
+			}
+		}
+		public void slowPush(E element) {
+			synchronized (this.getMutex()) {
+				try {
+					Thread.sleep(5 * TICK);
+				} catch (InterruptedException ex) {
+					throw new RuntimeException(ex);
+				}
+				this.push(element);
+			}
+		}
+	}
+
+	// ********** waits **********
+
+	public void testWaitUntilEmpty() throws Exception {
+		this.verifyWaitUntilEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been popped by t1...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and the stack should be empty
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmpty2() throws Exception {
+		this.verifyWaitUntilEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been popped by t1...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and the stack should be empty
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilEmptyTimeout() throws Exception {
+		this.verifyWaitUntilEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the stack was popped...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and the stack should be empty
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilEmpty(long timeout) throws Exception {
+		this.ss.push(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildPopCommand(), this.ss, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilEmptyCommand(timeout), this.ss, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
+				SynchronizedStackTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedStack);
+				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedStack.waitUntilEmpty();
+					return false;
+				}
+				return ! synchronizedStack.waitUntilEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitUntilNotEmpty() throws Exception {
+		this.verifyWaitUntilNotEmpty(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been pushed by t1...
+		assertFalse(this.ss.isEmpty());
+		assertSame(ITEM_1, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmpty2() throws Exception {
+		this.verifyWaitUntilNotEmpty(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been pushed by t1...
+		assertFalse(this.ss.isEmpty());
+		assertSame(ITEM_1, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitUntilNotEmptyTimeout() throws Exception {
+		this.verifyWaitUntilNotEmpty(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and an item should have been pushed by t1...
+		assertFalse(this.ss.isEmpty());
+		assertSame(ITEM_1, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitUntilNotEmpty(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildPushCommand(), this.ss, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitUntilNotEmptyCommand(timeout), this.ss, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitUntilNotEmptyCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
+				SynchronizedStackTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedStack);
+				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedStack.waitUntilNotEmpty();
+					return false;
+				}
+				return ! synchronizedStack.waitUntilNotEmpty(timeout);
+			}
+		};
+	}
+
+	public void testWaitToPop() throws Exception {
+		this.verifyWaitToPop(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been popped by t2...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and the stack should be empty
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToPop2() throws Exception {
+		this.verifyWaitToPop(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and an item should have been popped by t2...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and the stack should be empty
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToPopTimeout() throws Exception {
+		this.verifyWaitToPop(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the stack was never popped...
+		assertNull(this.poppedObject);
+		// ...and it still holds the item
+		assertSame(ITEM_1, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToPop(long timeout) throws Exception {
+		Runnable r1 = this.buildRunnable(this.buildPushCommand(), this.ss, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToPopCommand(timeout), this.ss, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToPopCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
+				this.waitToPop(synchronizedStack);
+				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
+			}
+			private void waitToPop(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				if (timeout < 0) {
+					SynchronizedStackTests.this.poppedObject = synchronizedStack.waitToPop();
+					return;
+				}
+				try {
+					SynchronizedStackTests.this.poppedObject = synchronizedStack.waitToPop(timeout);
+				} catch (EmptyStackException ex) {
+					SynchronizedStackTests.this.timeoutOccurred = true;
+				}
+			}
+		};
+	}
+
+	public void testWaitToPush() throws Exception {
+		this.verifyWaitToPush(-1);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the stack gets popped by t1...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and an item is pushed on to the stack by t2
+		assertFalse(this.ss.isEmpty());
+		assertSame(ITEM_2, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToPush2() throws Exception {
+		this.verifyWaitToPush(0);
+		// no timeout occurs...
+		assertFalse(this.timeoutOccurred);
+		// ...and the stack gets popped by t1...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...and an item is pushed on to the stack by t2
+		assertFalse(this.ss.isEmpty());
+		assertSame(ITEM_2, this.ss.peek());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() > TICK);
+	}
+
+	public void testWaitToPushTimeout() throws Exception {
+		this.verifyWaitToPush(TICK);
+		// timeout occurs...
+		assertTrue(this.timeoutOccurred);
+		// ...and the stack is eventually popped by t1...
+		assertSame(ITEM_1, this.poppedObject);
+		// ...but nothing is pushed on to the stack by t2
+		assertTrue(this.ss.isEmpty());
+		// make a reasonable guess about how long t2 took
+		assertTrue(this.calculateElapsedTime() < THREE_TICKS);
+	}
+
+	private void verifyWaitToPush(long timeout) throws Exception {
+		this.ss.push(ITEM_1);
+		Runnable r1 = this.buildRunnable(this.buildPopCommand(), this.ss, TWO_TICKS);
+		Runnable r2 = this.buildRunnable(this.buildWaitToPushCommand(timeout), this.ss, 0);
+		Thread t1 = this.buildThread(r1);
+		Thread t2 = this.buildThread(r2);
+		t1.start();
+		t2.start();
+		t1.join();
+		t2.join();
+	}
+
+	private Command buildWaitToPushCommand(final long timeout) {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				SynchronizedStackTests.this.startTime = System.currentTimeMillis();
+				SynchronizedStackTests.this.timeoutOccurred = this.timeoutOccurred(synchronizedStack);
+				SynchronizedStackTests.this.endTime = System.currentTimeMillis();
+			}
+			private boolean timeoutOccurred(SynchronizedStack<String> synchronizedStack) throws InterruptedException {
+				if (timeout < 0) {
+					synchronizedStack.waitToPush(ITEM_2);
+					return false;
+				}
+				return ! synchronizedStack.waitToPush(ITEM_2, timeout);
+			}
+		};
+	}
+
+	private Command buildPushCommand() {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) {
+				synchronizedStack.push(ITEM_1);
+			}
+		};
+	}
+
+	private Command buildPopCommand() {
+		return new Command() {
+			public void execute(SynchronizedStack<String> synchronizedStack) {
+				SynchronizedStackTests.this.poppedObject = synchronizedStack.pop();
+			}
+		};
+	}
+
+	private Runnable buildRunnable(final Command command, final SynchronizedStack<String> synchronizedStack, final long sleep) {
+		return new TestRunnable() {
+			@Override
+			protected void run_() throws Throwable {
+				if (sleep != 0) {
+					Thread.sleep(sleep);
+				}
+				command.execute(synchronizedStack);
+			}
+		};
+	}
+
+	long calculateElapsedTime() {
+		return this.endTime - this.startTime;
+	}
+
+
+	// ********** Command interface **********
+
+	private interface Command {
+		void execute(SynchronizedStack<String> synchronizedStack) throws InterruptedException;
+	}
+
+
+	// ********** execute **********
+
+	public void testExecute() throws Exception {
+		org.eclipse.jpt.common.utility.command.Command command = new org.eclipse.jpt.common.utility.command.Command() {
+			public void execute() {
+				SynchronizedStackTests.this.commandExecuted = true;
+			}
+		};
+		this.commandExecuted = false;
+		this.ss.execute(command);
+		assertTrue(this.commandExecuted);
+	}
+
+
+	// ********** additional protocol **********
+
+	public void testPushAllIterable() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("one");
+		list.add("two");
+		list.add("three");
+		this.ss.pushAll(list);
+		assertEquals("three", this.ss.pop());
+		assertEquals("two", this.ss.pop());
+		assertEquals("one", this.ss.pop());
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllIterable_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		this.ss.pushAll(list);
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllObjectArray() throws Exception {
+		this.ss.pushAll(new String[] { "one", "two", "three" });
+		assertEquals("three", this.ss.pop());
+		assertEquals("two", this.ss.pop());
+		assertEquals("one", this.ss.pop());
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllObjectArray_empty() throws Exception {
+		this.ss.pushAll(new String[0]);
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllStack() throws Exception {
+		Stack<String> s2 = StackTools.arrayStack();
+		s2.push("one");
+		s2.push("two");
+		s2.push("three");
+		this.ss.pushAll(s2);
+		assertEquals("one", this.ss.pop());
+		assertEquals("two", this.ss.pop());
+		assertEquals("three", this.ss.pop());
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllStack_empty() throws Exception {
+		Stack<String> s2 = StackTools.arrayStack();
+		this.ss.pushAll(s2);
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllQueue() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		queue.enqueue("one");
+		queue.enqueue("two");
+		queue.enqueue("three");
+		this.ss.pushAll(queue);
+		assertEquals("three", this.ss.pop());
+		assertEquals("two", this.ss.pop());
+		assertEquals("one", this.ss.pop());
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPushAllQueue_empty() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		this.ss.pushAll(queue);
+		assertTrue(this.ss.isEmpty());
+	}
+
+	public void testPopAll() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		ArrayList<String> list = this.ss.popAll();
+		assertTrue(this.ss.isEmpty());
+		assertEquals("three", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("one", list.get(2));
+	}
+
+	public void testPopAll_empty() throws Exception {
+		ArrayList<String> list = this.ss.popAll();
+		assertTrue(this.ss.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testPopAllToCollection() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		ArrayList<String> list = new ArrayList<String>();
+		assertTrue(this.ss.popAllTo(list));
+		assertTrue(this.ss.isEmpty());
+		assertEquals("three", list.get(0));
+		assertEquals("two", list.get(1));
+		assertEquals("one", list.get(2));
+	}
+
+	public void testPopAllToCollection_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		assertFalse(this.ss.popAllTo(list));
+		assertTrue(this.ss.isEmpty());
+		assertTrue(list.isEmpty());
+	}
+
+	public void testPopAllToListInt() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.ss.popAllTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("three", list.get(2));
+		assertEquals("two", list.get(3));
+		assertEquals("one", list.get(4));
+		assertEquals("ccc", list.get(5));
+	}
+
+	public void testPopAllToListInt_end() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertTrue(this.ss.popAllTo(list, 3));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+		assertEquals("three", list.get(3));
+		assertEquals("two", list.get(4));
+		assertEquals("one", list.get(5));
+	}
+
+	public void testPopAllToListInt_empty() throws Exception {
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("aaa");
+		list.add("bbb");
+		list.add("ccc");
+		assertFalse(this.ss.popAllTo(list, 2));
+		assertEquals("aaa", list.get(0));
+		assertEquals("bbb", list.get(1));
+		assertEquals("ccc", list.get(2));
+	}
+
+	public void testPopAllToStack() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		Stack<String> s2 = StackTools.arrayStack();
+		assertTrue(this.ss.popAllTo(s2));
+		assertTrue(this.ss.isEmpty());
+		assertEquals("one", s2.pop());
+		assertEquals("two", s2.pop());
+		assertEquals("three", s2.pop());
+		assertTrue(s2.isEmpty());
+	}
+
+	public void testPopAllToStack_empty() throws Exception {
+		Stack<String> s2 = StackTools.arrayStack();
+		assertFalse(this.ss.popAllTo(s2));
+		assertTrue(this.ss.isEmpty());
+		assertTrue(s2.isEmpty());
+	}
+
+	public void testPopAllToQueue() throws Exception {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("three");
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertTrue(this.ss.popAllTo(queue));
+		assertTrue(this.ss.isEmpty());
+		assertEquals("three", queue.dequeue());
+		assertEquals("two", queue.dequeue());
+		assertEquals("one", queue.dequeue());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testPopAllToQueue_empty() throws Exception {
+		Queue<String> queue = QueueTools.arrayQueue();
+		assertFalse(this.ss.popAllTo(queue));
+		assertTrue(this.ss.isEmpty());
+		assertTrue(queue.isEmpty());
+	}
+
+	public void testPopAllToMapTransformer() {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.ss.popAllTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertEquals("one", map.get("o"));
+		assertEquals("two", map.get("t"));
+		assertEquals("zero", map.get("z"));
+	}
+
+	public void testPopAllToMapTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.ss.popAllTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER));
+		assertTrue(map.isEmpty());
+	}
+
+	public void testPopAllToMapTransformerTransformer() {
+		this.ss.push("one");
+		this.ss.push("two");
+		this.ss.push("zero");
+		Map<String, String>map = new HashMap<String, String>();
+		assertTrue(this.ss.popAllTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertEquals("*one*", map.get("o"));
+		assertEquals("*two*", map.get("t"));
+		assertEquals("*zero*", map.get("z"));
+	}
+
+	public void testPopAllToMapTransformerTransformer_empty() {
+		Map<String, String>map = new HashMap<String, String>();
+		assertFalse(this.ss.popAllTo(map, DequeToolsTests.FIRST_LETTER_TRANSFORMER, DequeToolsTests.EMPHASIZER));
+		assertTrue(map.isEmpty());
+	}
+}
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/AbstractJaxbNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/AbstractJaxbNode.java
index 313eff6..05ff36c 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/AbstractJaxbNode.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/AbstractJaxbNode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -309,7 +309,7 @@
 		 * <em>updated</em> (<code>false</code>).
 		 */
 		protected void sync(boolean sync) {
-			HashSet<C> contextElements = CollectionTools.set(this.getContextElements());
+			HashSet<C> contextElements = CollectionTools.hashSet(this.getContextElements());
 			int resourceIndex = 0;
 
 			for (R resourceElement : this.getResourceElements()) {
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/SchemaLibraryImpl.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/SchemaLibraryImpl.java
index c5c5bcb..3989aff 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/SchemaLibraryImpl.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/SchemaLibraryImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -54,7 +54,7 @@
 	
 	public List<String> getSchemaLocations() {
 		return Collections.unmodifiableList(
-				ListTools.list(
+				ListTools.arrayList(
 						IterableTools.transform(this.schemaEntries, SchemaEntry.LOCATION_TRANSFORMER)));
 	}
 	
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/AbstractJaxbContextRoot.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/AbstractJaxbContextRoot.java
index c5fcbcd..d8a1490 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/AbstractJaxbContextRoot.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/AbstractJaxbContextRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -93,7 +93,7 @@
 		Set<String> totalTypeNames = new HashSet<String>();
 		
 		// process types with annotations and in jaxb.index files
-		for (String typeName: CollectionTools.set(calculateInitialTypeNames())) {  // ensure iterable is unique
+		for (String typeName: CollectionTools.hashSet(calculateInitialTypeNames())) {  // ensure iterable is unique
 			totalTypeNames.add(typeName);
 			addType_(buildType(typeName));
 		}
@@ -122,18 +122,18 @@
 		super.update();
 		
 		// keep a master list of these so that objects are updated only once
-		final Set<String> packagesToUpdate = CollectionTools.<String>set();
-		final Set<String> typesToUpdate = CollectionTools.<String>set();
+		final Set<String> packagesToUpdate = CollectionTools.<String>hashSet();
+		final Set<String> typesToUpdate = CollectionTools.<String>hashSet();
 		
 		// keep a (shrinking) running list of these so that we know which ones we do eventually need to remove
-		final Set<String> packagesToRemove = CollectionTools.set(this.packages.keySet());
-		final Set<String> typesToRemove = CollectionTools.set(this.types.keySet());
+		final Set<String> packagesToRemove = CollectionTools.hashSet(this.packages.keySet());
+		final Set<String> typesToRemove = CollectionTools.hashSet(this.types.keySet());
 		
 		// keep a master list of all types that we've processed so we don't process them again
-		final Set<String> totalTypes = CollectionTools.<String>set();
+		final Set<String> totalTypes = CollectionTools.<String>hashSet();
 		
 		// keep a running list of types that we need to scan for further referenced types
-		final Set<String> typesToScan = CollectionTools.<String>set();
+		final Set<String> typesToScan = CollectionTools.<String>hashSet();
 		
 		// process packages with annotations first
 		for (String pkg : calculateInitialPackageNames()) {
@@ -148,7 +148,7 @@
 		
 		// calculate initial types (annotated or listed in jaxb.index files)
 		final Set<String> resourceTypesToProcess 
-				= CollectionTools.set(calculateInitialTypeNames());
+				= CollectionTools.hashSet(calculateInitialTypeNames());
 		
 		// store set of types that are referenced (and should therefore be default mapped)
 		final Set<String> referencedTypes = new HashSet<String>();
@@ -215,7 +215,7 @@
 	 * calculate set of packages that can be determined purely by presence of package annotations
 	 */
 	protected Set<String> calculateInitialPackageNames() {
-		return CollectionTools.set(
+		return CollectionTools.hashSet(
 				IterableTools.transform(getJaxbProject().getAnnotatedJavaResourcePackages(), JavaResourcePackage.NAME_TRANSFORMER));
 	}
 	
@@ -223,7 +223,7 @@
 	 * calculate set of packages that can be determined from type names
 	 */
 	protected Set<String> calculatePackageNames(Set<String> typeNames) {
-		Set<String> packageNames = CollectionTools.<String>set();
+		Set<String> packageNames = CollectionTools.<String>hashSet();
 		for (String typeName : typeNames) {
 			JavaType jaxbType = this.types.get(typeName);
 			if (jaxbType != null) {
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/ContextContainerTools.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/ContextContainerTools.java
index 1cfff80..fda2038 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/ContextContainerTools.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/ContextContainerTools.java
@@ -1,3 +1,12 @@
+/*******************************************************************************

+ * Copyright (c) 2010, 2015 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.jaxb.core.internal.context;

 

 import java.util.ArrayList;

@@ -86,7 +95,7 @@
 	 * <em>updated</em> (<code>false</code>).

 	 */

 	protected static <C extends JaxbContextNode, R> void sync(Adapter<C, R> adapter, boolean sync) {

-		HashSet<C> contextElements = CollectionTools.set(adapter.getContextElements());

+		HashSet<C> contextElements = CollectionTools.hashSet(adapter.getContextElements());

 		ArrayList<C> contextElementsToSync = new ArrayList<C>(contextElements.size());

 		int resourceIndex = 0;

 		

diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaAttributesContainer.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaAttributesContainer.java
index 1da4952..7becc89 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaAttributesContainer.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaAttributesContainer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -137,7 +137,7 @@
 	 */
 	private void initializePublicMemberAccessAttributes() {
 		this.initializeFieldAttributes(JavaResourceField.IS_RELEVANT_FOR_PUBLIC_MEMBER_ACCESS);
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all persistable resource method getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -169,7 +169,7 @@
 	private void intializePropertyAccessAttributes() {
 		this.initializeFieldAttributes(JavaResourceAnnotatedElement.IS_ANNOTATED);
 		
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -245,7 +245,7 @@
 	}
 	
 	private void initializeAnnotatedPropertyAttributes() {
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -312,11 +312,11 @@
 	 * 4. all annotated methods (some will have a matching getter/setter, some will be standalone)
 	 */
 	private void syncPublicMemberAccessAttributes() {
-		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 		
 		this.syncFieldAttributes(contextAttributes, JavaResourceField.IS_RELEVANT_FOR_PUBLIC_MEMBER_ACCESS);
 		
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all persistable resource method getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -347,7 +347,7 @@
 	 * 2. all annotated methods getters/setters
 	 */
 	private void syncFieldAccessAttributes() {
-		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 		
 		this.syncFieldAttributes(contextAttributes, JavaResourceField.IS_RELEVANT_FOR_FIELD_ACCESS);
 		this.syncAnnotatedPropertyAttributes(contextAttributes);
@@ -360,11 +360,11 @@
 	 * 3. all annotated methods getters/setters that don't have a matching pair
 	 */
 	private void syncPropertyAccessAttributes() {
-		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 		
 		this.syncFieldAttributes(contextAttributes, JavaResourceAnnotatedElement.IS_ANNOTATED);
 		
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -395,14 +395,14 @@
 	 * 2. all annotated methods getters/setters (some will have a matching getter/setter, some will be standalone)
 	 */
 	private void syncNoneAccessAttributes() {
-		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 		
 		this.syncFieldAttributes(contextAttributes, JavaResourceAnnotatedElement.IS_ANNOTATED);
 		this.syncAnnotatedPropertyAttributes(contextAttributes);
 	}
 	
 	private void syncAnnotatedPropertyAttributes(HashSet<JavaPersistentAttribute> contextAttributes) {
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaClassMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaClassMapping.java
index ac5290d..9e52c22 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaClassMapping.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaClassMapping.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -532,8 +532,8 @@
 	
 	protected void updateIncludedAttributes() {
 		HashSet<JaxbClassMapping> oldSuperclasses 
-				= CollectionTools.set(this.includedAttributesContainers.keySet());
-		Set<JaxbPersistentAttribute> oldAttributes = CollectionTools.set(getIncludedAttributes());
+				= CollectionTools.hashSet(this.includedAttributesContainers.keySet());
+		Set<JaxbPersistentAttribute> oldAttributes = CollectionTools.hashSet(getIncludedAttributes());
 		
 		if (! isXmlTransient()) {
 			JaxbClassMapping superclass = this.superclass;
@@ -554,7 +554,7 @@
 			this.includedAttributesContainers.remove(oldSuperclass);
 		}
 		
-		Set<JaxbPersistentAttribute> newAttributes = CollectionTools.set(getIncludedAttributes());
+		Set<JaxbPersistentAttribute> newAttributes = CollectionTools.hashSet(getIncludedAttributes());
 		if (IterableTools.elementsAreDifferent(oldAttributes, newAttributes)) {
 			fireCollectionChanged(INCLUDED_ATTRIBUTES_COLLECTION, newAttributes);
 		}
@@ -773,7 +773,7 @@
 		// no nonexistent attributes (attributes mapped otherwise allowed) ...
 		// *except* no transient attributes allowed
 		
-		Bag<String> props = CollectionTools.bag(getPropOrder());
+		Bag<String> props = CollectionTools.hashBag(getPropOrder());
 		Set<String> allAttributes = new HashSet<String>();
 		Set<String> requiredAttributes = new HashSet<String>();
 		Set<String> transientAttributes = new HashSet<String>();
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaXmlNs.java b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaXmlNs.java
index aa3b732..bfac5bb 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaXmlNs.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.core/src/org/eclipse/jpt/jaxb/core/internal/context/java/GenericJavaXmlNs.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -133,7 +133,7 @@
 		if (schema != null) { 
 			result = IterableTools.concatenate(result, schema.getNamespaceProposals());
 		}
-		return CollectionTools.set(result);
+		return CollectionTools.hashSet(result);
 	}
 	
 	
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/ELJaxbContextRootImpl.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/ELJaxbContextRootImpl.java
index fb28815..7b48dee 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/ELJaxbContextRootImpl.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/ELJaxbContextRootImpl.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -204,7 +204,7 @@
 	
 	protected void updateOxmFiles() {
 		Collection<JptXmlResource> 
-				unmatchedOxmResources = CollectionTools.collection(getJaxbProject().getOxmResources());
+				unmatchedOxmResources = CollectionTools.hashBag(getJaxbProject().getOxmResources());
 		
 		for (OxmFile oxmFile : getOxmFiles()) {
 			JptXmlResource oxmResource = oxmFile.getOxmResource();
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java
index d78f11b..13b36a8 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2012, 2015 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.
@@ -159,7 +159,7 @@
 										StringTools.JAVA_STRING_LITERAL_CONTENT_TRANSFORMER));
 			}
 			
-			return CollectionTools.sortedSet(result);
+			return CollectionTools.treeSet(result);
 		}
 		
 		return EmptyIterable.instance();
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.ui/src/org/eclipse/jpt/jaxb/ui/internal/properties/JaxbSchemasPropertiesPage.java b/jaxb/plugins/org.eclipse.jpt.jaxb.ui/src/org/eclipse/jpt/jaxb/ui/internal/properties/JaxbSchemasPropertiesPage.java
index e9c9804..8992ee6 100644
--- a/jaxb/plugins/org.eclipse.jpt.jaxb.ui/src/org/eclipse/jpt/jaxb/ui/internal/properties/JaxbSchemasPropertiesPage.java
+++ b/jaxb/plugins/org.eclipse.jpt.jaxb.ui/src/org/eclipse/jpt/jaxb/ui/internal/properties/JaxbSchemasPropertiesPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -574,7 +574,7 @@
 		
 		@Override
 		protected Collection<Schema> getAspectValue() {
-			return CollectionTools.collection(iterator());
+			return CollectionTools.hashBag(iterator());
 		}
 		
 		
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/AbstractJpaContextModel.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/AbstractJpaContextModel.java
index 5260660..4bdbb22 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/AbstractJpaContextModel.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/AbstractJpaContextModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -461,7 +461,7 @@
 		 */
 		protected void sync(boolean sync) {
 			@SuppressWarnings("unchecked")
-			HashSet<C> contextElements = (HashSet<C>) CollectionTools.set(this.elements.toArray());
+			HashSet<C> contextElements = (HashSet<C>) CollectionTools.hashSet(this.elements.toArray());
 			ArrayList<C> contextElementsToSync = new ArrayList<C>(contextElements.size());
 			int resourceIndex = 0;
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/ContextContainerTools.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/ContextContainerTools.java
index 747df14..7604c53 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/ContextContainerTools.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/ContextContainerTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2010 Oracle. All rights reserved.
+ * Copyright (c) 2010, 2015 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.
@@ -94,7 +94,7 @@
 	 * <em>updated</em> (<code>false</code>).
 	 */
 	protected static <C extends JpaContextModel, R> void sync(Adapter<C, R> adapter, boolean sync) {
-		HashSet<C> contextElements = CollectionTools.set(adapter.getContextElements());
+		HashSet<C> contextElements = CollectionTools.hashSet(adapter.getContextElements());
 		ArrayList<C> contextElementsToSync = new ArrayList<C>(contextElements.size());
 		int resourceIndex = 0;
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/MappingTools.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/MappingTools.java
index be06988..ff0de46 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/MappingTools.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/MappingTools.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2015 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.
@@ -535,7 +535,7 @@
 	 * Returns the names of basic array types.
 	 */
 	public static Iterable<String> getBasicArrayTypeNames() {
-		return ListTools.list(BASIC_ARRAY_TYPE_NAMES);
+		return ListTools.arrayList(BASIC_ARRAY_TYPE_NAMES);
 	}
 	
 	
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java
index 9761487..ee47c33 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2015 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.
@@ -445,7 +445,7 @@
 	private void intializePropertyAccessAttributes() {
 		this.initializeFieldAttributes(JavaResourceAnnotatedElement.IS_ANNOTATED);
 
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -459,7 +459,7 @@
 	}
 
 	private void initializeAnnotatedPropertyAttributes() {
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -503,7 +503,7 @@
 	 * 2. all annotated methods(getters/setters)
 	 */
 	private void syncFieldAccessAttributes() {
-		HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 
 		this.syncFieldAttributes(contextAttributes, JavaResourceField.IS_RELEVANT_FOR_FIELD_ACCESS);
 		this.syncAnnotatedPropertyAttributes(contextAttributes);
@@ -516,11 +516,11 @@
 	 * 3. all annotated methods getters/setters that don't have a matching pair
 	 */
 	private void syncPropertyAccessAttributes() {
-		HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.set(this.getAttributes());
+		HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
 
 		this.syncFieldAttributes(contextAttributes, JavaResourceAnnotatedElement.IS_ANNOTATED);
 
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -546,7 +546,7 @@
 	}
 
 	private void syncAnnotatedPropertyAttributes(HashSet<JavaSpecifiedPersistentAttribute> contextAttributes) {
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java
index 8563422..60d7de6 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -199,8 +199,8 @@
 
 	protected boolean hintsAreEquivalentTo(Query other) {
 		// get fixed lists of the hints
-		ArrayList<JavaQueryHint> hints1 = ListTools.list(this.getHints());
-		ArrayList<? extends QueryHint> hints2 = ListTools.list(other.getHints());
+		ArrayList<JavaQueryHint> hints1 = ListTools.arrayList(this.getHints());
+		ArrayList<? extends QueryHint> hints2 = ListTools.arrayList(other.getHints());
 		if (hints1.size() != hints2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmQuery.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmQuery.java
index 6c0cbb7..99b1f54 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmQuery.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmQuery.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -219,8 +219,8 @@
 
 	protected boolean hintsAreEquivalentTo(Query other) {
 		// get fixed lists of the hints
-		ArrayList<OrmQueryHint> hints1 = ListTools.list(this.getHints());
-		ArrayList<? extends QueryHint> hints2 = ListTools.list(other.getHints());
+		ArrayList<OrmQueryHint> hints1 = ListTools.arrayList(this.getHints());
+		ArrayList<? extends QueryHint> hints2 = ListTools.arrayList(other.getHints());
 		if (hints1.size() != hints2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java
index 363f4e1..ed3c32f 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2015 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.
@@ -619,7 +619,7 @@
 	 * </ol>
 	 */
 	private void syncFieldAccessDefaultAttributes() {
-		HashSet<OrmPersistentAttribute> contextAttributes = CollectionTools.set(this.getDefaultAttributes());
+		HashSet<OrmPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getDefaultAttributes());
 
 		this.syncFieldDefaultAttributes(contextAttributes, this.buildResourceFieldIsRelevant());
 		if ( ! this.mapping.isMetadataComplete()) {
@@ -640,13 +640,13 @@
 	 * </ol>
 	 */
 	private void syncPropertyAccessDefaultAttributes() {
-		HashSet<OrmPersistentAttribute> contextAttributes = CollectionTools.set(this.getDefaultAttributes());
+		HashSet<OrmPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getDefaultAttributes());
 
 		if ( ! this.mapping.isMetadataComplete()) {
 			this.syncFieldDefaultAttributes(contextAttributes, JavaResourceAnnotatedElement.IS_ANNOTATED);
 		}
 
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getJavaResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getJavaResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getJavaResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
@@ -688,7 +688,7 @@
 	}
 
 	private void syncAnnotatedPropertyDefaultAttributes(HashSet<OrmPersistentAttribute> contextAttributes) {
-		Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getJavaResourceMethods());
+		Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getJavaResourceMethods());
 		//iterate through all resource methods searching for persistable getters
 		for (JavaResourceMethod getterMethod : this.getJavaResourcePropertyGetters()) {
 			JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/persistence/AbstractPersistenceUnit.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/persistence/AbstractPersistenceUnit.java
index 714e219..bec46f3 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/persistence/AbstractPersistenceUnit.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/persistence/AbstractPersistenceUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -1564,7 +1564,7 @@
 	}
 
 	public Iterable<String> getUniqueGeneratorNames() {
-		return CollectionTools.set(this.getNonEmptyGeneratorNames(), this.getGeneratorsSize());
+		return CollectionTools.hashSet(this.getNonEmptyGeneratorNames(), this.getGeneratorsSize());
 	}
 
 	protected Iterable<String> getNonEmptyGeneratorNames() {
@@ -1584,7 +1584,7 @@
 	 * @see #buildQueries()
 	 */
 	protected Iterable<Generator> buildGenerators() {
-		ArrayList<Generator> result = ListTools.list(this.getMappingFileGenerators());
+		ArrayList<Generator> result = ListTools.arrayList(this.getMappingFileGenerators());
 
 		HashSet<String> mappingFileGeneratorNames = this.convertToNames(result);
 		HashMap<String, ArrayList<Generator>> allJavaGenerators = this.mapByName(this.getAllJavaGenerators());
@@ -1664,7 +1664,7 @@
 	 * or multiple, non-overridden Java queries with the same name.
 	 */
 	protected Iterable<Query> buildQueries() {
-		ArrayList<Query> result = ListTools.list(this.getMappingFileQueries());
+		ArrayList<Query> result = ListTools.arrayList(this.getMappingFileQueries());
 
 		HashSet<String> mappingFileQueryNames = this.convertToNames(result);
 		HashMap<String, ArrayList<Query>> allJavaQueries = this.mapByName(this.getAllJavaQueries());
@@ -1984,7 +1984,7 @@
 	 * type mappings (by full qualified class name).
 	 */
 	protected Iterable<TypeMapping> getActiveTypeMappings(){
-		ArrayList<TypeMapping> result = ListTools.list(this.getMappingFileTypeMappings());
+		ArrayList<TypeMapping> result = ListTools.arrayList(this.getMappingFileTypeMappings());
 
 		HashSet<String> mappingFileClassNames = this.convertToClassNames(result);
 		HashMap<String, ArrayList<TypeMapping>> javaTypeMappings = this.mapTypeMappingsByClassName(this.getJavaTypeMappings());
@@ -2047,7 +2047,7 @@
 		SubMonitor sm = SubMonitor.convert(monitor, 4);
 
 		// gather up all the annotated Java types and types listed in the mapping files
-		HashSet<JavaResourceAbstractType> newClasses = CollectionTools.set(this.getJpaProject().getPotentialJavaSourceTypes());
+		HashSet<JavaResourceAbstractType> newClasses = CollectionTools.hashSet(this.getJpaProject().getPotentialJavaSourceTypes());
 		HashSet<String> mappingFileTypeNames = this.getMappingFileTypeNames();
 
 		// calculate the class refs to be removed
@@ -2245,7 +2245,7 @@
 	protected <M extends JpaNamedContextModel> ArrayList<M> extractConvertibleJavaModels(Iterable<M> allJavaModels, Iterable<M> mappingFileModels) {
 		ArrayList<M> convertibleModels = new ArrayList<M>();
 
-		HashSet<String> mappingFileModelNames = this.convertToNames(ListTools.list(mappingFileModels));
+		HashSet<String> mappingFileModelNames = this.convertToNames(ListTools.arrayList(mappingFileModels));
 		HashMap<String, ArrayList<M>> allJavaModelsByName = this.mapByName(allJavaModels);
 		for (Map.Entry<String, ArrayList<M>> entry : allJavaModelsByName.entrySet()) {
 			String javaModelName = entry.getKey();
@@ -2300,7 +2300,7 @@
 	}
 
 	protected void checkForMultiplePersistenceUnitMetadata(List<IMessage> messages) {
-		ArrayList<MappingFileRef> pumdMappingFileRefs = ListTools.list(this.getPersistenceUnitMetadataMappingFileRefs());
+		ArrayList<MappingFileRef> pumdMappingFileRefs = ListTools.arrayList(this.getPersistenceUnitMetadataMappingFileRefs());
 		if (pumdMappingFileRefs.size() > 1) {
 			for (MappingFileRef mappingFileRef : pumdMappingFileRefs) {
 				messages.add(
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/facet/JpaFacetDataModelProvider.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/facet/JpaFacetDataModelProvider.java
index 03788c2..4c71c2c 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/facet/JpaFacetDataModelProvider.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/facet/JpaFacetDataModelProvider.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -481,7 +481,7 @@
 	 * put a null entry at the top of the list (for <none>)
 	 */
 	protected List<String> buildValidConnectionNames() {
-		List<String> connectionNames = ListTools.sort(ListTools.list(this.getConnectionProfileNames()));
+		List<String> connectionNames = ListTools.sort(ListTools.arrayList(this.getConnectionProfileNames()));
 		connectionNames.add(0, null);
 		return connectionNames;
 	}
@@ -518,7 +518,7 @@
 	 * put an entry for the default at the top of the list
 	 */
 	protected List<String> buildValidStrings(Iterable<String> strings, String defaultString) {
-		List<String> validStrings = ListTools.list(strings);
+		List<String> validStrings = ListTools.arrayList(strings);
 		if ((defaultString != null) && ! validStrings.contains(defaultString)) {
 			validStrings.add(0, defaultString);
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/GenericContextRoot.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/GenericContextRoot.java
index c681173..26a6320 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/GenericContextRoot.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/GenericContextRoot.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -277,7 +277,7 @@
 		}
 
 		PersistenceUnit persistenceUnit = persistence.getPersistenceUnits().iterator().next();
-		HashBag<JavaResourceAbstractType> annotatedTypes = CollectionTools.bag(this.jpaProject.getAnnotatedJavaSourceTypes());
+		HashBag<JavaResourceAbstractType> annotatedTypes = CollectionTools.hashBag(this.jpaProject.getAnnotatedJavaSourceTypes());
 		HashBag<JavaResourceAbstractType> orphans = annotatedTypes.clone();
 		for (JavaResourceAbstractType jrat : annotatedTypes) {
 			if (persistenceUnit.specifiesManagedType(jrat.getTypeBinding().getQualifiedName())) {
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/java/GenericJavaTableGenerator.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/java/GenericJavaTableGenerator.java
index 2ffa72e..9a6051b 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/java/GenericJavaTableGenerator.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/java/GenericJavaTableGenerator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -567,8 +567,8 @@
 
 	protected boolean uniqueConstraintsAreEquivalentTo(TableGenerator generator) {
 		// get fixed lists of the unique constraints
-		ArrayList<JavaSpecifiedUniqueConstraint> uniqueConstraints1 = ListTools.list(this.getUniqueConstraints());
-		ArrayList<SpecifiedUniqueConstraint> uniqueConstraints2 = ListTools.list(generator.getUniqueConstraints());
+		ArrayList<JavaSpecifiedUniqueConstraint> uniqueConstraints1 = ListTools.arrayList(this.getUniqueConstraints());
+		ArrayList<SpecifiedUniqueConstraint> uniqueConstraints2 = ListTools.arrayList(generator.getUniqueConstraints());
 		if (uniqueConstraints1.size() != uniqueConstraints2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/orm/GenericOrmTableGenerator.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/orm/GenericOrmTableGenerator.java
index 4c02e68..a6820ef 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/orm/GenericOrmTableGenerator.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa1/context/orm/GenericOrmTableGenerator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -441,8 +441,8 @@
 
 	protected boolean uniqueConstraintsAreEquivalentTo(TableGenerator generator) {
 		// get fixed lists of the unique constraints
-		ArrayList<OrmSpecifiedUniqueConstraint> uniqueConstraints1 = ListTools.list(this.getUniqueConstraints());
-		ArrayList<SpecifiedUniqueConstraint> uniqueConstraints2 = ListTools.list(generator.getUniqueConstraints());
+		ArrayList<OrmSpecifiedUniqueConstraint> uniqueConstraints1 = ListTools.arrayList(this.getUniqueConstraints());
+		ArrayList<SpecifiedUniqueConstraint> uniqueConstraints2 = ListTools.arrayList(generator.getUniqueConstraints());
 		if (uniqueConstraints1.size() != uniqueConstraints2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2/GenericMetamodelSynchronizer2_0.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2/GenericMetamodelSynchronizer2_0.java
index 456e7da..d65e767 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2/GenericMetamodelSynchronizer2_0.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2/GenericMetamodelSynchronizer2_0.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2009, 2015 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.
@@ -24,7 +24,7 @@
 import org.eclipse.jpt.common.core.utility.BodySourceWriter;
 import org.eclipse.jpt.common.utility.internal.ClassNameTools;
 import org.eclipse.jpt.common.utility.internal.ObjectTools;
-import org.eclipse.jpt.common.utility.internal.collection.LinkedStack;
+import org.eclipse.jpt.common.utility.internal.stack.LinkedStack;
 import org.eclipse.jpt.common.utility.io.IndentingPrintWriter;
 import org.eclipse.jpt.jpa.core.context.AttributeMapping;
 import org.eclipse.jpt.jpa.core.context.PersistentType;
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/java/GenericJavaNamedStoredProcedureQuery2_1.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/java/GenericJavaNamedStoredProcedureQuery2_1.java
index 09b9bc8..6d4fc0f 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/java/GenericJavaNamedStoredProcedureQuery2_1.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/java/GenericJavaNamedStoredProcedureQuery2_1.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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.
@@ -296,8 +296,8 @@
 
 	protected boolean parametersAreEquivalentTo(NamedStoredProcedureQuery2_1 other) {
 		// get fixed lists of the stored procedure parameters
-		ArrayList<JavaStoredProcedureParameter2_1> parameter1 = ListTools.list(this.getParameters());
-		ArrayList<? extends StoredProcedureParameter2_1> parameter2 = ListTools.list(other.getParameters());
+		ArrayList<JavaStoredProcedureParameter2_1> parameter1 = ListTools.arrayList(this.getParameters());
+		ArrayList<? extends StoredProcedureParameter2_1> parameter2 = ListTools.arrayList(other.getParameters());
 		if (parameter1.size() != parameter2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/orm/GenericOrmNamedStoredProcedureQuery2_1.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/orm/GenericOrmNamedStoredProcedureQuery2_1.java
index 6986664..ff89d27 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/orm/GenericOrmNamedStoredProcedureQuery2_1.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/jpa2_1/context/orm/GenericOrmNamedStoredProcedureQuery2_1.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 Oracle. All rights reserved.
+ * Copyright (c) 2013, 2015 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.
@@ -309,8 +309,8 @@
 
 	protected boolean parametersAreEquivalentTo(NamedStoredProcedureQuery2_1 other) {
 		// get fixed lists of the stored procedure parameters
-		ArrayList<OrmStoredProcedureParameter2_1> parameter1 = ListTools.list(this.getParameters());
-		ArrayList<? extends StoredProcedureParameter2_1> parameter2 = ListTools.list(other.getParameters());
+		ArrayList<OrmStoredProcedureParameter2_1> parameter1 = ListTools.arrayList(this.getParameters());
+		ArrayList<? extends StoredProcedureParameter2_1> parameter2 = ListTools.arrayList(other.getParameters());
 		if (parameter1.size() != parameter2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaMapping.java
index 12d2009..10f6043 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaMapping.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/jpql/spi/JpaMapping.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 Oracle. All rights reserved.
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
  * which accompanies this distribution.
@@ -103,7 +103,7 @@
 	protected ITypeDeclaration[] buildGenericTypeDeclarations() {
 		JavaSpecifiedPersistentAttribute javaPersistentAttribute = mapping.getPersistentAttribute().getJavaPersistentAttribute();
 		JavaResourceAttribute resource = javaPersistentAttribute == null ? null : javaPersistentAttribute.getResourceAttribute();
-		List<ITypeDeclaration> declarations = ListTools.list(buildGenericTypeDeclarations(resource));
+		List<ITypeDeclaration> declarations = ListTools.arrayList(buildGenericTypeDeclarations(resource));
 		return declarations.toArray(new ITypeDeclaration[declarations.size()]);
 	}
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/context/persistence/EclipseLinkPersistenceUnit.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/context/persistence/EclipseLinkPersistenceUnit.java
index 66c734d..902a23f 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/context/persistence/EclipseLinkPersistenceUnit.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/context/persistence/EclipseLinkPersistenceUnit.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -440,7 +440,7 @@
 	 * unit's scope, with duplicates removed.
 	 */
 	public Iterable<String> getUniqueConverterNames() {
-		return CollectionTools.set(this.getNonEmptyConverterNames(), this.getConvertersSize());
+		return CollectionTools.hashSet(this.getNonEmptyConverterNames(), this.getConvertersSize());
 	}
 
 	protected Iterable<String> getNonEmptyConverterNames() {
@@ -460,7 +460,7 @@
 	 * @see #buildQueries()
 	 */
 	protected Iterable<EclipseLinkConverter> buildConverters() {
-		ArrayList<EclipseLinkConverter> result = ListTools.list(this.getMappingFileConverters());
+		ArrayList<EclipseLinkConverter> result = ListTools.arrayList(this.getMappingFileConverters());
 
 		HashSet<String> mappingFileConverterNames = this.convertToNames(result);
 		HashMap<String, ArrayList<EclipseLinkConverter>> javaConverters = this.mapByName(this.getAllJavaConverters());
@@ -1370,7 +1370,7 @@
 	protected <M extends JpaNamedContextModel> HashMap<String, ArrayList<M>> extractEclipseLinkConvertibleJavaModels(Iterable<M> allJavaModels, Iterable<M> mappingFileModels, EquivalencyAdapter<M> adapter) {
 		HashMap<String, ArrayList<M>> convertibleModels = new HashMap<String, ArrayList<M>>();
 
-		HashSet<String> mappingFileModelNames = this.convertToNames(ListTools.list(mappingFileModels));
+		HashSet<String> mappingFileModelNames = this.convertToNames(ListTools.arrayList(mappingFileModels));
 		HashMap<String, ArrayList<M>> allJavaModelsByName = this.mapByName(allJavaModels);
 		for (Map.Entry<String, ArrayList<M>> entry : allJavaModelsByName.entrySet()) {
 			String javaModelName = entry.getKey();
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/java/EclipseLinkJavaObjectTypeConverter.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/java/EclipseLinkJavaObjectTypeConverter.java
index 5916887..ac65fd2 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/java/EclipseLinkJavaObjectTypeConverter.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/java/EclipseLinkJavaObjectTypeConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -299,8 +299,8 @@
 
 	protected boolean conversionValuesAreEquivalentTo(EclipseLinkObjectTypeConverter converter) {
 		// get fixed lists of the conversion values
-		ArrayList<EclipseLinkJavaConversionValue> conversionValues1 = ListTools.list(this.getConversionValues());
-		ArrayList<? extends EclipseLinkConversionValue> conversionValues2 = ListTools.list(converter.getConversionValues());
+		ArrayList<EclipseLinkJavaConversionValue> conversionValues1 = ListTools.arrayList(this.getConversionValues());
+		ArrayList<? extends EclipseLinkConversionValue> conversionValues2 = ListTools.arrayList(converter.getConversionValues());
 		if (conversionValues1.size() != conversionValues2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/orm/EclipseLinkOrmObjectTypeConverter.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/orm/EclipseLinkOrmObjectTypeConverter.java
index e4c0714..8dc5144 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/orm/EclipseLinkOrmObjectTypeConverter.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/orm/EclipseLinkOrmObjectTypeConverter.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -431,8 +431,8 @@
 
 	protected boolean conversionValuesAreEquivalentTo(EclipseLinkObjectTypeConverter converter) {
 		// get fixed lists of the conversion values
-		ArrayList<EclipseLinkOrmConversionValue> conversionValues1 = ListTools.list(this.getConversionValues());
-		ArrayList<? extends EclipseLinkConversionValue> conversionValues2 = ListTools.list(converter.getConversionValues());
+		ArrayList<EclipseLinkOrmConversionValue> conversionValues1 = ListTools.arrayList(this.getConversionValues());
+		ArrayList<? extends EclipseLinkConversionValue> conversionValues2 = ListTools.arrayList(converter.getConversionValues());
 		if (conversionValues1.size() != conversionValues2.size()) {
 			return false;
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkCustomization.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkCustomization.java
index 8cd1d0c..a77196b 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkCustomization.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkCustomization.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -96,7 +96,7 @@
 	}
 
 	private List<String> buildSessionCustomizers() {
-		return ListTools.list(this.convertToValues(this.getPropertiesSetWithPrefix(ECLIPSELINK_SESSION_CUSTOMIZER)));
+		return ListTools.arrayList(this.convertToValues(this.getPropertiesSetWithPrefix(ECLIPSELINK_SESSION_CUSTOMIZER)));
 	}
 
 	private Iterable<String> convertToValues(Iterable<PersistenceUnit.Property> properties) {
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkPersistenceUnitProperties.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkPersistenceUnitProperties.java
index 97e57fb..dbd316c 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkPersistenceUnitProperties.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.core/src/org/eclipse/jpt/jpa/eclipselink/core/internal/context/persistence/EclipseLinkPersistenceUnitProperties.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2011 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -30,7 +30,7 @@
 	// ******** Convenience methods ********
 	
 	protected Set<PersistenceUnit.Property> getPropertiesSetWithPrefix(String keyPrefix) {
-		return CollectionTools.set(this.getPersistenceUnit().getPropertiesWithNamePrefix(keyPrefix));
+		return CollectionTools.hashSet(this.getPersistenceUnit().getPropertiesWithNamePrefix(keyPrefix));
 	}
 
 	/**
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/details/EclipseLinkConversionValueDialog.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/details/EclipseLinkConversionValueDialog.java
index 32e3082..320f425 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/details/EclipseLinkConversionValueDialog.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/details/EclipseLinkConversionValueDialog.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2012 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -68,7 +68,7 @@
 	protected EclipseLinkConversionValueStateObject buildStateObject() {
 		String dataValue = null;
 		String objectValue = null;
-		Set<String> dataValues = CollectionTools.set(this.objectTypeConverter.getDataValues(), this.objectTypeConverter.getDataValuesSize());
+		Set<String> dataValues = CollectionTools.hashSet(this.objectTypeConverter.getDataValues(), this.objectTypeConverter.getDataValuesSize());
 		if (isEditDialog()) {
 			dataValue = this.conversionValue.getDataValue();
 			objectValue = this.conversionValue.getObjectValue();
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/customization/EclipseLinkProfilerClassChooser.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/customization/EclipseLinkProfilerClassChooser.java
index 6cf5bfd..a790902 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/customization/EclipseLinkProfilerClassChooser.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/customization/EclipseLinkProfilerClassChooser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -169,7 +169,7 @@
 
 	private CollectionValueModel<String> buildProfilersCollectionHolder() {
 		return new SimpleCollectionValueModel<String>(
-			CollectionTools.collection(this.buildProfilers())
+			CollectionTools.hashBag(this.buildProfilers())
 		);
 	}
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkLoggerClassChooser.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkLoggerClassChooser.java
index c793e89..376679f 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkLoggerClassChooser.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkLoggerClassChooser.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -175,7 +175,7 @@
 
 	private CollectionValueModel<String> buildLoggersCollectionHolder() {
 		return new SimpleCollectionValueModel<String>(
-			CollectionTools.collection(this.buildLoggers())
+			CollectionTools.hashBag(this.buildLoggers())
 		);
 	}
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkPersistenceUnitOptionsEditorPage.java b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkPersistenceUnitOptionsEditorPage.java
index 1aea403..db073d0 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkPersistenceUnitOptionsEditorPage.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.eclipselink.ui/src/org/eclipse/jpt/jpa/eclipselink/ui/internal/persistence/options/EclipseLinkPersistenceUnitOptionsEditorPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -505,7 +505,7 @@
 
 	private CollectionValueModel<String> buildTargetDatabasesCollectionHolder() {
 		return new SimpleCollectionValueModel<String>(
-			CollectionTools.collection(buildTargetDatabases())
+			CollectionTools.hashBag(buildTargetDatabases())
 		);
 	}
 
@@ -637,7 +637,7 @@
 
 	private CollectionValueModel<String> buildTargetServersCollectionHolder() {
 		return new SimpleCollectionValueModel<String>(
-			CollectionTools.collection(buildTargetServers())
+			CollectionTools.hashBag(buildTargetServers())
 		);
 	}
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaJavaCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaJavaCompletionProposalComputer.java
index ad8a244..e0fb302 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaJavaCompletionProposalComputer.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaJavaCompletionProposalComputer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -110,7 +110,7 @@
 			return Collections.emptyList();
 		}
 		
-		Collection<JpaStructureNode> rootStructureNodes = CollectionTools.collection(jpaFile.getRootStructureNodes());
+		Collection<JpaStructureNode> rootStructureNodes = CollectionTools.hashBag(jpaFile.getRootStructureNodes());
 		if (rootStructureNodes.isEmpty()) {
 			return Collections.emptyList();
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaXmlCompletionProposalComputer.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaXmlCompletionProposalComputer.java
index f228193..fa9e632 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaXmlCompletionProposalComputer.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/JpaXmlCompletionProposalComputer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2012 Oracle. All rights reserved.
+ * Copyright (c) 2012, 2015 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.
@@ -224,7 +224,7 @@
 		JpaFile jpaFile = (JpaFile) file.getAdapter(JpaFile.class);
 		if (jpaFile == null) return Collections.emptyList();
 
-		Collection<JpaStructureNode> rootStructureNodes = CollectionTools.collection(jpaFile.getRootStructureNodes());
+		Collection<JpaStructureNode> rootStructureNodes = CollectionTools.hashBag(jpaFile.getRootStructureNodes());
 		if (rootStructureNodes.isEmpty()) {
 			return Collections.emptyList();
 		}
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/BaseJoinColumnStateObject.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/BaseJoinColumnStateObject.java
index fee1d0c..657993f 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/BaseJoinColumnStateObject.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/BaseJoinColumnStateObject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2009 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -120,7 +120,7 @@
 		if (table == null) {
 			return EmptyListIterator.instance();
 		}
-		return ListTools.list(table.getSortedColumnIdentifiers()).listIterator();
+		return ListTools.arrayList(table.getSortedColumnIdentifiers()).listIterator();
 	}
 	
 	private static int columnsSize(Table table) {
@@ -340,8 +340,8 @@
 	}
 
 	public void setTable(String table) {
-		ArrayList<String> oldNames = ListTools.list(this.names());
-		ArrayList<String> oldRefColNames = ListTools.list(this.referenceColumnNames());
+		ArrayList<String> oldNames = ListTools.arrayList(this.names());
+		ArrayList<String> oldRefColNames = ListTools.arrayList(this.referenceColumnNames());
 		String oldTable = this.table;
 		this.table = table;
 		this.firePropertyChanged(TABLE_PROPERTY, oldTable, table);
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/JoinColumnInJoiningStrategyStateObject.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/JoinColumnInJoiningStrategyStateObject.java
index ce6c714..54618cb 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/JoinColumnInJoiningStrategyStateObject.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/JoinColumnInJoiningStrategyStateObject.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2010 Oracle. All rights reserved.
+ * Copyright (c) 2008, 2015 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.
@@ -56,7 +56,7 @@
 	@Override
 	public ListIterator<String> tables() {
 		Schema schema = getDbSchema();
-		return schema == null ? super.tables() : ListTools.list(schema.getSortedTableIdentifiers()).listIterator();
+		return schema == null ? super.tables() : ListTools.arrayList(schema.getSortedTableIdentifiers()).listIterator();
 	}
 	
 	protected Schema getDbSchema() {
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/TemporalTypeCombo.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/TemporalTypeCombo.java
index 2708942..f96cd0e 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/TemporalTypeCombo.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/details/TemporalTypeCombo.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2015 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.
@@ -90,7 +90,7 @@
 	}
 
 	private List<TemporalType> buildSortedTemporalTypeList() {
-		return ListTools.sort(ListTools.list(TemporalType.values()), this.buildTemporalTypeComparator());
+		return ListTools.sort(ListTools.arrayList(TemporalType.values()), this.buildTemporalTypeComparator());
 	}
 
 	private Comparator<TemporalType> buildTemporalTypeComparator() {
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/properties/JpaProjectPropertiesPage.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/properties/JpaProjectPropertiesPage.java
index 543daa5..ae844d2 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/properties/JpaProjectPropertiesPage.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/properties/JpaProjectPropertiesPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -1137,7 +1137,7 @@
 		}
 
 		void collectionChanged() {
-			this.fireCollectionChanged(CollectionValueModel.VALUES, CollectionTools.collection(this.iterator()));
+			this.fireCollectionChanged(CollectionValueModel.VALUES, CollectionTools.hashBag(this.iterator()));
 		}
 
 		public Iterator<String> iterator() {
@@ -1377,7 +1377,7 @@
 		private void processJavaProjectDelta(IJavaElementDelta delta) {
 			IJavaProject javaProject = (IJavaProject) delta.getElement();
 			if (javaProject.equals(this.subject.getJavaProject()) && this.classpathHasChanged(delta)) {
-				this.fireCollectionChanged(CollectionValueModel.VALUES, CollectionTools.collection(this.iterator()));
+				this.fireCollectionChanged(CollectionValueModel.VALUES, CollectionTools.hashBag(this.iterator()));
 			}
 		}
 
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/DatabaseGroup.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/DatabaseGroup.java
index 4286500..470f50d 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/DatabaseGroup.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/DatabaseGroup.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -210,7 +210,7 @@
 	}
 
 	private SortedSet<String> buildSortedConnectionProfileNames() {
-		return CollectionTools.sortedSet(this.getConnectionProfileNames());
+		return CollectionTools.treeSet(this.getConnectionProfileNames());
 	}
 
 	private Iterable<String> getConnectionProfileNames() {
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/TablesSelectorWizardPage.java b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/TablesSelectorWizardPage.java
index 68411e8..ced3577 100644
--- a/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/TablesSelectorWizardPage.java
+++ b/jpa/plugins/org.eclipse.jpt.jpa.ui/src/org/eclipse/jpt/jpa/ui/internal/wizards/gen/TablesSelectorWizardPage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -278,7 +278,7 @@
 		if(this.fetchTablesJobIsRunning()) {
 			return Collections.<Table> emptyList();
 		}
-		return CollectionTools.collection(schema.getTables());
+		return CollectionTools.hashBag(schema.getTables());
 	}
 
 	private Collection<Table> possibleTables() {
@@ -636,7 +636,7 @@
 							schema.getName()));
 					subMonitor.worked(20);
 
-					tables.addAll(CollectionTools.collection(schema.getTables()));
+					tables.addAll(CollectionTools.hashBag(schema.getTables()));
 					
 					subMonitor.worked(95);
 				}
diff --git a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/java/JavaAttributeOverrideTests.java b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/java/JavaAttributeOverrideTests.java
index 7fa854a..f0d98e7 100644
--- a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/java/JavaAttributeOverrideTests.java
+++ b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/java/JavaAttributeOverrideTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -180,7 +180,7 @@
 		assertEquals("id", attributeOverride.getColumn().getDefaultName());
 		
 		
-		JavaPersistentType mappedSuperclass = ListTools.list(getPersistenceUnit().getSpecifiedClassRefs()).get(1).getJavaPersistentType();
+		JavaPersistentType mappedSuperclass = ListTools.arrayList(getPersistenceUnit().getSpecifiedClassRefs()).get(1).getJavaPersistentType();
 		BasicMapping basicMapping = (BasicMapping) mappedSuperclass.getAttributeNamed("id").getMapping();
 		basicMapping.getColumn().setSpecifiedName("FOO");
 	
@@ -203,7 +203,7 @@
 		assertEquals("AnnotationTestTypeChild", attributeOverride.getColumn().getDefaultTableName());
 
 		
-		JavaPersistentType mappedSuperclass = ListTools.list(getPersistenceUnit().getSpecifiedClassRefs()).get(1).getJavaPersistentType();
+		JavaPersistentType mappedSuperclass = ListTools.arrayList(getPersistenceUnit().getSpecifiedClassRefs()).get(1).getJavaPersistentType();
 		BasicMapping basicMapping = (BasicMapping) mappedSuperclass.getAttributeNamed("id").getMapping();
 		basicMapping.getColumn().setSpecifiedTableName("BAR");
 	
diff --git a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/orm/OrmSecondaryTableTests.java b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/orm/OrmSecondaryTableTests.java
index 962bb10..d761800 100644
--- a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/orm/OrmSecondaryTableTests.java
+++ b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/context/orm/OrmSecondaryTableTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2007, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2007, 2015 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.
@@ -750,7 +750,7 @@
 		javaSecondaryTable.addUniqueConstraint().addColumnName("BAR");
 		javaSecondaryTable.addUniqueConstraint().addColumnName("BAZ");
 
-		List<UniqueConstraint> uniqueConstraints = ListTools.list(ormSecondaryTable.getUniqueConstraints());
+		List<UniqueConstraint> uniqueConstraints = ListTools.arrayList(ormSecondaryTable.getUniqueConstraints());
 		assertEquals(3, uniqueConstraints.size());
 		assertEquals("FOO", uniqueConstraints.get(0).getColumnName(0));
 		assertEquals("BAR", uniqueConstraints.get(1).getColumnName(0));
diff --git a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/jpa2/context/persistence/Generic2_0JpaMetadataConversionTests.java b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/jpa2/context/persistence/Generic2_0JpaMetadataConversionTests.java
index 61677e3..7f880fd 100644
--- a/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/jpa2/context/persistence/Generic2_0JpaMetadataConversionTests.java
+++ b/jpa/tests/org.eclipse.jpt.jpa.core.tests/src/org/eclipse/jpt/jpa/core/tests/internal/jpa2/context/persistence/Generic2_0JpaMetadataConversionTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -244,7 +244,7 @@
 		assertEquals(0, entity.getQueryContainer().getNamedNativeQueriesSize());
 		
 		// test the mapping file queries have correct values
-		Collection<OrmNamedNativeQuery> namedNativeQueries = CollectionTools.collection(entityMappings.getQueryContainer().getNamedNativeQueries());
+		Collection<OrmNamedNativeQuery> namedNativeQueries = CollectionTools.hashBag(entityMappings.getQueryContainer().getNamedNativeQueries());
 
 		// test the first mapping file query
 		OrmNamedNativeQuery nnq1 = selectModelNamed(namedNativeQueries, "nnq1");
@@ -407,7 +407,7 @@
 		assertEquals(0, mappedSuperclass.getQueryContainer().getNamedNativeQueriesSize());
 		
 		// test the mapping file queries have correct values
-		Collection<OrmNamedNativeQuery> namedNativeQueries = CollectionTools.collection(entityMappings.getQueryContainer().getNamedNativeQueries());
+		Collection<OrmNamedNativeQuery> namedNativeQueries = CollectionTools.hashBag(entityMappings.getQueryContainer().getNamedNativeQueries());
 
 		// test the first mapping file query
 		OrmNamedNativeQuery nnq1 = selectModelNamed(namedNativeQueries, "nnq1");
diff --git a/jpa/tests/org.eclipse.jpt.jpa.eclipselink.core.tests/src/org/eclipse/jpt/jpa/eclipselink/core/tests/internal/context/persistence/EclipseLink2_2JpaMetadataConversionTests.java b/jpa/tests/org.eclipse.jpt.jpa.eclipselink.core.tests/src/org/eclipse/jpt/jpa/eclipselink/core/tests/internal/context/persistence/EclipseLink2_2JpaMetadataConversionTests.java
index 1237aed..c810a9e 100644
--- a/jpa/tests/org.eclipse.jpt.jpa.eclipselink.core.tests/src/org/eclipse/jpt/jpa/eclipselink/core/tests/internal/context/persistence/EclipseLink2_2JpaMetadataConversionTests.java
+++ b/jpa/tests/org.eclipse.jpt.jpa.eclipselink.core.tests/src/org/eclipse/jpt/jpa/eclipselink/core/tests/internal/context/persistence/EclipseLink2_2JpaMetadataConversionTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2011, 2013 Oracle. All rights reserved.
+ * Copyright (c) 2011, 2015 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.
@@ -449,7 +449,7 @@
 		assertEquals(mapping.getConverterContainer().getConvertersSize(), 0);
 		
 		// test the mapping file converter have correct values
-		Collection<EclipseLinkOrmCustomConverter> customConverters = CollectionTools.collection(entityMappings.getConverterContainer().getCustomConverters());
+		Collection<EclipseLinkOrmCustomConverter> customConverters = CollectionTools.hashBag(entityMappings.getConverterContainer().getCustomConverters());
 		EclipseLinkCustomConverter custom1 = Generic2_0JpaMetadataConversionTests.selectModelNamed(customConverters, "custom1");
 		assertEquals("custom1", custom1.getName());
 		assertEquals("foo1", custom1.getConverterClass());