Losen up restriction so the Utility classes can access forbidden classes, such as Swing classes
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF b/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
index 6823e2a..8e995f3 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
+++ b/tools/org.eclipse.persistence.tools.utility.tests/META-INF/MANIFEST.MF
@@ -12,8 +12,10 @@
  org.eclipse.persistence.tools.utility.tests.model.listener,

  org.eclipse.persistence.tools.utility.tests.model.value,

  org.eclipse.persistence.tools.utility.tests.model.value.prefs,

+ org.eclipse.persistence.tools.utility.tests.model.value.swing,

  org.eclipse.persistence.tools.utility.tests.node,

  org.eclipse.persistence.tools.utility.tests.reference,

+ org.eclipse.persistence.tools.utility.tests.swing,

  org.eclipse.persistence.tools.utility.tests.transformer

 Bundle-RequiredExecutionEnvironment: JavaSE-1.6

 Require-Bundle: org.eclipse.persistence.tools.utility;bundle-version="2.5.0",

diff --git a/tools/org.eclipse.persistence.tools.utility.tests/pom.xml b/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
index 3eb6520..c161060 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
+++ b/tools/org.eclipse.persistence.tools.utility.tests/pom.xml
@@ -16,4 +16,18 @@
         <relativePath>../org.eclipse.persistence.tools.parent/pom.xml</relativePath>
     </parent>
 
+    <build>
+	   <plugins>
+	      <plugin>
+	         <groupId>org.eclipse.tycho</groupId>
+	         <artifactId>tycho-compiler-plugin</artifactId>
+	         <version>${tycho.version}</version>
+	         <configuration>
+	         	<!-- Remove the restriction to access restricted classes, such as Swing classes. -->
+	           <compilerArgument>-err:-forbidden</compilerArgument>
+	         </configuration>
+	       </plugin> 
+	    </plugins>
+    </build>
+
 </project>
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
index 8ec386b..e973368 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/CommonUtilityTests.java
@@ -81,8 +81,8 @@
 		suite.addTestSuite(SystemToolsTests.class);
 		suite.addTestSuite(TypeDeclarationToolsTests.class);
 		suite.addTestSuite(VersionComparatorTests.class);
-//		suite.addTestSuite(XMLToolsReadTests.class);
-//		suite.addTestSuite(XMLToolsWriteTests.class);
+		suite.addTestSuite(XMLToolsReadTests.class);
+		suite.addTestSuite(XMLToolsWriteTests.class);
 
 		return suite;
 	}
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java
new file mode 100644
index 0000000..fb6f19a
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsReadTests.java
@@ -0,0 +1,175 @@
+/*******************************************************************************

+ * Copyright (c) 2005, 2013 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 v. 1.0

+ * which accompanies this distribution.

+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ * http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *     Oracle - initial API and implementation

+ *

+ ******************************************************************************/

+package org.eclipse.persistence.tools.utility.tests;

+

+import java.io.StringReader;

+import junit.framework.TestCase;

+import org.eclipse.persistence.tools.utility.XMLTools;

+import org.eclipse.persistence.tools.utility.iterable.IterableTools;

+import org.w3c.dom.Document;

+import org.w3c.dom.Node;

+

+@SuppressWarnings("nls")

+public class XMLToolsReadTests

+	extends TestCase

+{

+	private Document testDocument;

+	private Node rootNode;

+

+

+	public XMLToolsReadTests(String name) {

+		super(name);

+	}

+

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		this.testDocument = this.buildTestDocument();

+		this.rootNode = XMLTools.getChild(this.testDocument, "root-element");

+	}

+

+	private Document buildTestDocument() {

+		return XMLTools.parse(new StringReader(this.buildTestDocumentString()));

+	}

+

+	private String buildTestDocumentString() {

+		StringBuffer sb = new StringBuffer(2000);

+		sb.append("<?xml version = '1.0' encoding = 'UTF-8'?>");

+		sb.append("<root-element>");

+		sb.append(		"<element-0>");

+		sb.append(			"<element-0-text-1>some text</element-0-text-1>");

+		sb.append(			"<element-0-text-2></element-0-text-2>");

+		sb.append(			"<element-0-text-3/>");

+		sb.append(			"<element-0-non-text>");

+		sb.append(				"<element-0-non-text-child>");

+		sb.append(				"</element-0-non-text-child>");

+		sb.append(			"</element-0-non-text>");

+		sb.append(		"</element-0>");

+		sb.append(		"<element-1>");

+		sb.append(			"<element-1-int>42</element-1-int>");

+		sb.append(			"<element-1-boolean-true-1>true</element-1-boolean-true-1>");

+		sb.append(			"<element-1-boolean-true-2>T</element-1-boolean-true-2>");

+		sb.append(			"<element-1-boolean-true-3>1</element-1-boolean-true-3>");

+		sb.append(			"<element-1-boolean-false-1>false</element-1-boolean-false-1>");

+		sb.append(			"<element-1-boolean-false-2>F</element-1-boolean-false-2>");

+		sb.append(			"<element-1-boolean-false-3>0</element-1-boolean-false-3>");

+		sb.append(		"</element-1>");

+		sb.append(		"<element-2>");

+		sb.append(			"<element-2.0>");

+		sb.append(			"</element-2.0>");

+		sb.append(			"<element-2.0>");

+		sb.append(			"</element-2.0>");

+		sb.append(			"<element-2.0>");

+		sb.append(			"</element-2.0>");

+		sb.append(		"</element-2>");

+		sb.append(		"<element-3>element 3 contents</element-3>");

+		sb.append("</root-element>");

+		return sb.toString();

+	}

+

+	@Override

+	protected void tearDown() throws Exception {

+		TestTools.clear(this);

+		super.tearDown();

+	}

+

+	public void testGetChild() {

+		assertEquals("element-1", XMLTools.getChild(this.rootNode, "element-1").getNodeName());

+		assertEquals("element-3", XMLTools.getChild(this.rootNode, "element-3").getNodeName());

+		assertEquals(null, XMLTools.getChild(this.rootNode, "element-1x"));

+	}

+

+	public void testGetChildren() {

+		Iterable<Node> children = XMLTools.getChildren(this.rootNode);

+		assertEquals(4, IterableTools.size(children));

+		for (int i = 1; i < 4; i++) {

+			assertEquals("element-" + i, IterableTools.get(children, i).getNodeName());

+		}

+	}

+

+	public void testGetChildrenNamed() {

+		Node element2Node = XMLTools.getChild(this.rootNode, "element-2");

+		Iterable<Node> children = XMLTools.getChildren(element2Node, "element-2.0");

+		assertEquals(3, IterableTools.size(children));

+		for (int i = 0; i < 3; i++) {

+			assertEquals("element-2.0", IterableTools.get(children, i).getNodeName());

+		}

+	}

+

+	public void testGetTextContent() {

+		Node node = XMLTools.getChild(this.rootNode, "element-0");

+		Node childNode = XMLTools.getChild(node, "element-0-text-1");

+		assertEquals("some text", XMLTools.getTextContent(childNode));

+

+		childNode = XMLTools.getChild(node, "element-0-text-2");

+		assertEquals("", XMLTools.getTextContent(childNode));

+

+		childNode = XMLTools.getChild(node, "element-0-text-3");

+		assertEquals("", XMLTools.getTextContent(childNode));

+

+		childNode = XMLTools.getChild(node, "element-0-non-text");

+		boolean exCaught = false;

+		try {

+			String text = XMLTools.getTextContent(childNode);

+			text = text.toString();

+		} catch (IllegalArgumentException ex) {

+			exCaught = true;

+		}

+		assertTrue(exCaught);

+	}

+

+	public void testGetChildTextContent() {

+		assertEquals("element 3 contents", XMLTools.getChildTextContent(this.rootNode, "element-3"));

+	}

+

+	public void testGetChildTextContentDefaultValue() {

+		assertEquals("element 3 contents", XMLTools.getChildTextContent(this.rootNode, "element-3", "default value 3"));

+		assertEquals("default value 4", XMLTools.getChildTextContent(this.rootNode, "element-4", "default value 4"));

+	}

+

+	public void testGetChildIntContent() {

+		Node node = XMLTools.getChild(this.rootNode, "element-1");

+		assertEquals(42, XMLTools.getChildIntContent(node, "element-1-int"));

+	}

+

+	public void testGetChildIntContentDefaultValue() {

+		Node node = XMLTools.getChild(this.rootNode, "element-1");

+		assertEquals(42, XMLTools.childIntContent(node, "element-1-int", 99));

+		assertEquals(99, XMLTools.childIntContent(node, "element-1-int-x", 99));

+	}

+

+	public void testGetChildBooleanContent() {

+		Node node = XMLTools.getChild(this.rootNode, "element-1");

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-1"));

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-2"));

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-3"));

+

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-1"));

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-2"));

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-3"));

+	}

+

+	public void testGetChildBooleanContentDefaultValue() {

+		Node node = XMLTools.getChild(this.rootNode, "element-1");

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-1", false));

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-2", false));

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-3", false));

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-true-bogus", false));

+

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-1", true));

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-2", true));

+		assertFalse(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-3", true));

+		assertTrue(XMLTools.getChildBooleanContent(node, "element-1-boolean-false-bogus", true));

+	}

+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java
new file mode 100644
index 0000000..46b3a5f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/XMLToolsWriteTests.java
@@ -0,0 +1,146 @@
+/*******************************************************************************

+ * Copyright (c) 2005, 2013 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 v. 1.0

+ * which accompanies this distribution.

+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html

+ * and the Eclipse Distribution License is available at

+ * http://www.eclipse.org/org/documents/edl-v10.php.

+ *

+ * Contributors:

+ *     Oracle - initial API and implementation

+ *

+ ******************************************************************************/

+package org.eclipse.persistence.tools.utility.tests;

+

+import java.io.ByteArrayOutputStream;

+import java.io.OutputStream;

+import junit.framework.TestCase;

+import org.eclipse.persistence.tools.utility.StringTools;

+import org.eclipse.persistence.tools.utility.SystemTools;

+import org.eclipse.persistence.tools.utility.XMLTools;

+import org.w3c.dom.Document;

+import org.w3c.dom.Node;

+

+/**

+ * these tests assume the XML will be formatted with appropriate

+ * indentation?

+ */

+@SuppressWarnings("nls")

+public class XMLToolsWriteTests

+	extends TestCase

+{

+	private Document testDocument;

+	private Node rootNode;

+	private static final String CR = System.getProperty("line.separator");

+

+

+	public XMLToolsWriteTests(String name) {

+		super(name);

+	}

+

+	@Override

+	protected void setUp() throws Exception {

+		super.setUp();

+		this.testDocument = XMLTools.newDocument();

+		this.rootNode = this.testDocument.createElement("root-element");

+		this.testDocument.appendChild(this.rootNode);

+		XMLTools.addSimpleTextNode(this.rootNode, "element-0", "foo");

+	}

+

+	@Override

+	protected void tearDown() throws Exception {

+		TestTools.clear(this);

+		super.tearDown();

+	}

+

+	private void verifyTestDocumentString(String string) throws Exception {

+		OutputStream stream = new ByteArrayOutputStream(2000);

+		XMLTools.print(this.testDocument, stream);

+		stream.close();

+		StringBuffer sb = new StringBuffer(2000);

+		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"");

+		if (SystemTools.jvmIsOracle() && SystemTools.javaSpecificationVersionIsGreaterThan("1.5")) {

+			sb.append(" standalone=\"no\"");

+		}

+		sb.append("?>");

+		if (SystemTools.jvmIsOracle() || (SystemTools.jvmIsIBM() && SystemTools.javaSpecificationVersionIsLessThanOrEqualTo("1.5"))) {

+			sb.append(CR);

+		}

+		sb.append("<root-element>");

+		sb.append(CR);

+		sb.append("<element-0>");

+		sb.append("foo");

+		sb.append("</element-0>");

+		sb.append(CR);

+		sb.append(string);

+		sb.append("</root-element>");

+		if (SystemTools.jvmIsOracle() || (SystemTools.jvmIsIBM() && SystemTools.javaSpecificationVersionIsLessThanOrEqualTo("1.5"))) {

+			sb.append(CR);

+		}

+		String expected = sb.toString();

+		String actual = stream.toString();

+		assertEquals(StringTools.compressWhitespace(expected), StringTools.compressWhitespace(actual));

+	}

+

+	public void testAddSimpleTextNode() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text");

+		this.verifyTestDocumentString("<element-1>some text</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodeDefaultValue1() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text", "some text");

+		this.verifyTestDocumentString("");

+	}

+

+	public void testAddSimpleTextNodeDefaultValue2() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", "some text", "default text");

+		this.verifyTestDocumentString("<element-1>some text</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodeInt() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42);

+		this.verifyTestDocumentString("<element-1>42</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodeIntDefaultValue1() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42, 42);

+		this.verifyTestDocumentString("");

+	}

+

+	public void testAddSimpleTextNodeIntDefaultValue2() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", 42, 43);

+		this.verifyTestDocumentString("<element-1>42</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodeBoolean() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", true);

+		this.verifyTestDocumentString("<element-1>true</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodeBooleanDefaultValue1() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", true, true);

+		this.verifyTestDocumentString("");

+	}

+

+	public void testAddSimpleTextNodeBooleanDefaultValue2() throws Exception {

+		XMLTools.addSimpleTextNode(this.rootNode, "element-1", false, true);

+		this.verifyTestDocumentString("<element-1>false</element-1>" + CR);

+	}

+

+	public void testAddSimpleTextNodes() throws Exception {

+		XMLTools.addSimpleTextNodes(this.rootNode, "element-1-collection", "element-1", new String[] {"text 1", "text 2", "text 3"});

+		StringBuffer sb = new StringBuffer(2000);

+		sb.append("<element-1-collection>");

+		sb.append(CR);

+		sb.append("<element-1>text 1</element-1>");

+		sb.append(CR);

+		sb.append("<element-1>text 2</element-1>");

+		sb.append(CR);

+		sb.append("<element-1>text 3</element-1>");

+		sb.append(CR);

+		sb.append("</element-1-collection>");

+		sb.append(CR);

+		this.verifyTestDocumentString(sb.toString());

+	}

+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java
new file mode 100644
index 0000000..d990942
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/Displayable.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model;
+
+import javax.swing.Icon;
+import org.eclipse.persistence.tools.utility.model.Model;
+
+/**
+ * Used by general-purpose UI models and renderers to cast
+ * application model objects to something displayable.
+ */
+@SuppressWarnings("nls")
+public interface Displayable
+	extends Model
+{
+	/**
+	 * Return a string that can be used to identify the model
+	 * in a textual UI setting (typically the object's name).
+	 * When the display string changes, the model should fire
+	 * the appropriate change notification:<pre>
+	 *     this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString);
+	 * </pre>
+	 */
+	String displayString();
+		String DISPLAY_STRING_PROPERTY = "displayString";
+
+	/**
+	 * Return an icon that can be used to identify the model
+	 * in a UI component that supports icons (the icon can be null).
+	 * When the icon changes, the model should fire
+	 * the appropriate change notification:<pre>
+	 *     this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon);
+	 * </pre>
+	 */
+	Icon icon();
+		String ICON_PROPERTY = "icon";
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java
new file mode 100644
index 0000000..6efa650
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/SimpleDisplayable.java
@@ -0,0 +1,175 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model;
+
+import javax.swing.Icon;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+
+/**
+ * This implementation of {@link Displayable} converts any {@link Object}
+ * to a {@link Displayable}. Subclass it to override {@link #displayString()} and
+ * {@link #icon()} if necessary. Change notification will be fired if the
+ * object is changed.
+ * <p>
+ * This can be used for {@link String}s - the display string
+ * will simply be the string itself.
+ */
+public class SimpleDisplayable
+	extends AbstractModel
+	implements Displayable
+{
+	/** The object to be converted to a displayable. */
+	protected Object object;
+
+
+	/**
+	 * Construct a displayable for the specified object.
+	 */
+	public SimpleDisplayable(Object object) {
+		super();
+		this.object = object;
+	}
+
+	public SimpleDisplayable(boolean b) {
+		this(Boolean.valueOf(b));
+	}
+
+	public SimpleDisplayable(char c) {
+		this(Character.valueOf(c));
+	}
+
+	public SimpleDisplayable(byte b) {
+		this(Byte.valueOf(b));
+	}
+
+	public SimpleDisplayable(short s) {
+		this(Short.valueOf(s));
+	}
+
+	public SimpleDisplayable(int i) {
+		this(Integer.valueOf(i));
+	}
+
+	public SimpleDisplayable(long l) {
+		this(Long.valueOf(l));
+	}
+
+	public SimpleDisplayable(float f) {
+		this(Float.valueOf(f));
+	}
+
+	public SimpleDisplayable(double d) {
+		this(Double.valueOf(d));
+	}
+
+
+	// ********** Displayable implementation **********
+
+	@Override
+	public String displayString() {
+		return this.object.toString();
+	}
+
+	@Override
+	public Icon icon() {
+		return null;
+	}
+
+
+	// ********** accessors **********
+
+	public Object getObject() {
+		return this.object;
+	}
+
+	public void setObject(Object object) {
+		String oldDisplayString = this.displayString();
+		Icon oldIcon = this.icon();
+		this.object = object;
+		this.firePropertyChanged(DISPLAY_STRING_PROPERTY, oldDisplayString, this.displayString());
+		this.firePropertyChanged(ICON_PROPERTY, oldIcon, this.icon());
+	}
+
+	public boolean getBoolean() {
+		return ((Boolean) this.object).booleanValue();
+	}
+
+	public void setBoolean(boolean b) {
+		this.setObject(Boolean.valueOf(b));
+	}
+
+	public char getChar() {
+		return ((Character) this.object).charValue();
+	}
+
+	public void setChar(char c) {
+		this.setObject(Character.valueOf(c));
+	}
+
+	public byte getByte() {
+		return ((Byte) this.object).byteValue();
+	}
+
+	public void setByte(byte b) {
+		this.setObject(Byte.valueOf(b));
+	}
+
+	public short getShort() {
+		return ((Short) this.object).shortValue();
+	}
+
+	public void setShort(short s) {
+		this.setObject(Short.valueOf(s));
+	}
+
+	public int getInt() {
+		return ((Integer) this.object).intValue();
+	}
+
+	public void setInt(int i) {
+		this.setObject(Integer.valueOf(i));
+	}
+
+	public long getLong() {
+		return ((Long) this.object).longValue();
+	}
+
+	public void setLong(long l) {
+		this.setObject(Long.valueOf(l));
+	}
+
+	public float getFloat() {
+		return ((Float) this.object).floatValue();
+	}
+
+	public void setFloat(float f) {
+		this.setObject(Float.valueOf(f));
+	}
+
+	public double getDouble() {
+		return ((Double) this.object).doubleValue();
+	}
+
+	public void setDouble(double d) {
+		this.setObject(Double.valueOf(d));
+	}
+
+
+	// ********** override methods **********
+
+	@Override
+	public void toString(StringBuilder sb) {
+		sb.append(this.object);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java
new file mode 100644
index 0000000..0c5e1d9
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CollectionListValueModelAdapterTests.java
@@ -0,0 +1,253 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CollectionListValueModelAdapterTests extends TestCase {
+	private ListValueModel<String> adapter;
+	private SimpleCollectionValueModel<String> wrappedCollectionHolder;
+	private Collection<String> wrappedCollection;
+
+	public CollectionListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.wrappedCollection = new HashBag<String>();
+		this.wrappedCollectionHolder = new SimpleCollectionValueModel<String>(this.wrappedCollection);
+		this.adapter = new CollectionListValueModelAdapter<String>(this.wrappedCollectionHolder);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testIterator() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		Collection<String> adapterCollection = this.adapterCollection();
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection, adapterCollection);
+	}
+
+	private Collection<String> adapterCollection() {
+		return CollectionTools.collection(this.adapter.iterator());
+	}
+
+	public void testStaleValue() {
+		ListChangeListener listener = new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+		};
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		Collection<String> adapterCollection = this.adapterCollection();
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection, adapterCollection);
+
+		this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, listener);
+		adapterCollection = this.adapterCollection();
+		assertEquals(0, adapterCollection.size());
+		assertEquals(new HashBag<String>(), adapterCollection);
+
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		adapterCollection = this.adapterCollection();
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection, adapterCollection);
+	}
+
+	public void testAdd() {
+		List<String> synchList = new CoordinatedList<String>(this.adapter);
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+		this.wrappedCollectionHolder.add("foo");
+		assertTrue(this.wrappedCollection.contains("foo"));
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		assertEquals(6, this.wrappedCollection.size());
+
+		Collection<String> adapterCollection = this.adapterCollection();
+		assertEquals(this.wrappedCollection, adapterCollection);
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+	}
+
+	public void testRemove() {
+		List<String> synchList = new CoordinatedList<String>(this.adapter);
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		assertTrue(this.wrappedCollection.contains("jaz"));
+		this.wrappedCollectionHolder.remove("jaz");
+		assertFalse(this.wrappedCollection.contains("jaz"));
+		this.wrappedCollectionHolder.remove("foo");
+		assertFalse(this.wrappedCollection.contains("foo"));
+		assertEquals(4, this.wrappedCollection.size());
+
+		Collection<String> adapterCollection = this.adapterCollection();
+		assertEquals(this.wrappedCollection, adapterCollection);
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+	}
+
+	public void testListSynch() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		this.wrappedCollectionHolder.remove("jaz");
+		assertFalse(this.wrappedCollection.contains("jaz"));
+		this.wrappedCollectionHolder.remove("foo");
+		assertFalse(this.wrappedCollection.contains("foo"));
+		assertEquals(4, this.wrappedCollection.size());
+
+		Collection<String> adapterCollection = this.adapterCollection();
+		assertEquals(this.wrappedCollection, adapterCollection);
+	}
+
+	public void testHasListeners() {
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		ChangeListener cl = new ChangeAdapter();
+		this.adapter.addChangeListener(cl);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeChangeListener(cl);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	public void testCollectionChangedToEmpty() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void listCleared(ListClearEvent e) {/* OK */}
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+		this.wrappedCollectionHolder.setValues(new HashBag<String>());
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+	public void testCollectionChangedFromEmpty() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		HashBag<String> bag = new HashBag<String>();
+		bag.add("foo");
+		bag.add("bar");
+		this.wrappedCollectionHolder.setValues(bag);
+		assertEquals(2, jList.getModel().getSize());
+	}
+
+	public void testCollectionChangedFromEmptyToEmpty() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		HashBag<String> bag = new HashBag<String>();
+		this.wrappedCollectionHolder.setValues(bag);
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+
+	class TestListChangeListener implements ListChangeListener {
+		@Override
+		public void itemsAdded(ListAddEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsRemoved(ListRemoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsReplaced(ListReplaceEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsMoved(ListMoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listCleared(ListClearEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listChanged(ListChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java
new file mode 100644
index 0000000..05a5dab
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CompositeListValueModelTests.java
@@ -0,0 +1,1256 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CompositeListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CompositeListValueModelTests extends TestCase {
+
+	private LocalListValueModel<String> lvm0;
+	private LocalListValueModel<String> lvm1;
+	private LocalListValueModel<String> lvm2;
+	private LocalListValueModel<String> lvm3;
+	private LocalListValueModel<LocalListValueModel<String>> uberLVM;
+	private CompositeListValueModel<LocalListValueModel<String>, String> compositeLVM;
+
+	public CompositeListValueModelTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+
+		this.lvm0 = new LocalListValueModel<String>();
+		this.lvm0.add("aaa");
+		this.lvm0.add("bbb");
+		this.lvm0.add("ccc");
+
+		this.lvm1 = new LocalListValueModel<String>();
+		this.lvm1.add("ddd");
+		this.lvm1.add("eee");
+
+		this.lvm2 = new LocalListValueModel<String>();
+		this.lvm2.add("fff");
+
+		this.lvm3 = new LocalListValueModel<String>();
+		this.lvm3.add("ggg");
+		this.lvm3.add("hhh");
+		this.lvm3.add("iii");
+		this.lvm3.add("jjj");
+		this.lvm3.add("kkk");
+
+		this.uberLVM = new LocalListValueModel<LocalListValueModel<String>>();
+		this.uberLVM.add(this.lvm0);
+		this.uberLVM.add(this.lvm1);
+		this.uberLVM.add(this.lvm2);
+		this.uberLVM.add(this.lvm3);
+
+		this.compositeLVM = CompositeListValueModel.forModels((ListValueModel<LocalListValueModel<String>>) this.uberLVM);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testGetInt() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+		assertEquals("aaa", this.compositeLVM.get(0));
+		assertEquals("aaa", coordList.get(0));
+		assertEquals("bbb", this.compositeLVM.get(1));
+		assertEquals("bbb", coordList.get(1));
+		assertEquals("ccc", this.compositeLVM.get(2));
+		assertEquals("ccc", coordList.get(2));
+
+		assertEquals("ddd", this.compositeLVM.get(3));
+		assertEquals("ddd", coordList.get(3));
+		assertEquals("eee", this.compositeLVM.get(4));
+		assertEquals("eee", coordList.get(4));
+
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testIterator() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+		assertEquals("aaa", this.compositeLVM.iterator().next());
+		assertEquals("aaa", coordList.iterator().next());
+		Iterator<String> stream1 = coordList.iterator();
+		for (Iterator<String> stream2 = this.compositeLVM.iterator(); stream2.hasNext(); ) {
+			assertEquals(stream1.next(), stream2.next());
+		}
+		assertFalse(stream1.hasNext());
+	}
+
+	public void testSize() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+		assertEquals(11, this.compositeLVM.size());
+		assertEquals(11, coordList.size());
+	}
+
+	public void testToArray() {
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+	}
+
+	public void testHasListeners() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		assertTrue(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		this.compositeLVM.removeListChangeListener(ListValueModel.LIST_VALUES, coordList);
+		assertFalse(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, coordList);
+		assertTrue(this.compositeLVM.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.lvm0.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	public void testAddSource_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+		lvm.add("xxx");
+		lvm.add("yyy");
+		lvm.add("zzz");
+		this.uberLVM.add(0, lvm);
+
+		Object[] expected = new Object[] { "xxx", "yyy", "zzz", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testAddSource_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+		lvm.add("xxx");
+		lvm.add("yyy");
+		lvm.add("zzz");
+		this.uberLVM.add(2, lvm);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testAddSource_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		LocalListValueModel<String> lvm = new LocalListValueModel<String>();
+		lvm.add("xxx");
+		lvm.add("yyy");
+		lvm.add("zzz");
+		this.uberLVM.add(lvm);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx", "yyy", "zzz" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testAddSources() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		LocalListValueModel<String> lvmA = new LocalListValueModel<String>();
+		lvmA.add("xxx");
+		lvmA.add("yyy");
+		lvmA.add("zzz");
+		LocalListValueModel<String> lvmB = new LocalListValueModel<String>();
+		lvmB.add("ppp");
+		lvmB.add("qqq");
+		lvmB.add("rrr");
+		Collection<LocalListValueModel<String>> c = new ArrayList<LocalListValueModel<String>>();
+		c.add(lvmA);
+		c.add(lvmB);
+		this.uberLVM.addAll(2, c);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "ppp", "qqq", "rrr", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(12));
+		assertEquals("ggg", coordList.get(12));
+	}
+
+	public void testRemoveSource_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.remove(0);
+
+		Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(3));
+		assertEquals("ggg", coordList.get(3));
+	}
+
+	public void testRemoveSource_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.remove(2);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(5));
+		assertEquals("ggg", coordList.get(5));
+	}
+
+	public void testRemoveSource_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.remove(3);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testRemoveSources() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.remove(2, 2);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("eee", this.compositeLVM.get(4));
+		assertEquals("eee", coordList.get(4));
+	}
+
+	public void testReplaceSources() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		LocalListValueModel<String> lvmA = new LocalListValueModel<String>();
+		lvmA.add("xxx");
+		lvmA.add("yyy");
+		lvmA.add("zzz");
+		LocalListValueModel<String> lvmB = new LocalListValueModel<String>();
+		lvmB.add("ppp");
+		lvmB.add("qqq");
+		lvmB.add("rrr");
+		List<LocalListValueModel<String>> list = new ArrayList<LocalListValueModel<String>>();
+		list.add(lvmA);
+		list.add(lvmB);
+		this.uberLVM.set(2, list);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "yyy", "zzz", "ppp", "qqq", "rrr" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("qqq", this.compositeLVM.get(9));
+		assertEquals("qqq", coordList.get(9));
+	}
+
+	public void testMoveSources_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.move(0, 2, 2);
+
+		Object[] expected = new Object[] { "fff", "ggg", "hhh", "iii", "jjj", "kkk", "aaa", "bbb", "ccc", "ddd", "eee" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(1));
+		assertEquals("ggg", coordList.get(1));
+	}
+
+	public void testMoveSources_Middle() {
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		this.uberLVM.add(lvm4);
+
+		LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+		lvm5.add("nnn");
+		lvm5.add("ooo");
+		lvm5.add("ppp");
+		lvm5.add("qqq");
+		this.uberLVM.add(lvm5);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.move(1, 3, 2);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "ddd", "eee", "fff", "nnn", "ooo", "ppp", "qqq" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(3));
+		assertEquals("ggg", coordList.get(3));
+	}
+
+	public void testMoveSources_End() {
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		this.uberLVM.add(lvm4);
+
+		LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+		lvm5.add("nnn");
+		lvm5.add("ooo");
+		lvm5.add("ppp");
+		lvm5.add("qqq");
+		this.uberLVM.add(lvm5);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.move(3, 0, 3);
+
+		Object[] expected = new Object[] { "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(0));
+		assertEquals("ggg", coordList.get(0));
+	}
+
+	public void testMoveSource() {
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		this.uberLVM.add(lvm4);
+
+		LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+		lvm5.add("nnn");
+		lvm5.add("ooo");
+		lvm5.add("ppp");
+		lvm5.add("qqq");
+		this.uberLVM.add(lvm5);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.move(3, 1);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "ddd", "eee", "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ooo", this.compositeLVM.get(14));
+		assertEquals("ooo", coordList.get(14));
+	}
+
+	public void testClearSources() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.clear();
+
+		Object[] expected = new Object[0];
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+	}
+
+	public void testChangeSources1() {
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		newList.add(lvm4);
+
+		LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+		lvm5.add("nnn");
+		lvm5.add("ooo");
+		lvm5.add("ppp");
+		lvm5.add("qqq");
+		newList.add(lvm5);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.setListValues(newList);
+
+		Object[] expected = new Object[] { "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ooo", this.compositeLVM.get(3));
+		assertEquals("ooo", coordList.get(3));
+	}
+
+	public void testChangeSources2() {
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		newList.add(lvm4);
+
+		LocalListValueModel<String> lvm5 = new LocalListValueModel<String>();
+		lvm5.add("nnn");
+		lvm5.add("ooo");
+		lvm5.add("ppp");
+		lvm5.add("qqq");
+		newList.add(lvm5);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.changeListValues(newList);
+
+		Object[] expected = new Object[] { "lll", "mmm", "nnn", "ooo", "ppp", "qqq" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ooo", this.compositeLVM.get(3));
+		assertEquals("ooo", coordList.get(3));
+	}
+
+	public void testChangeSources3() {
+		ListChangeListener listener = new ErrorListener();
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		newList.add(this.lvm0);
+		newList.add(this.lvm1);
+		newList.add(this.lvm2);
+		newList.add(this.lvm3);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.changeListValues(newList);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ddd", this.compositeLVM.get(3));
+		assertEquals("ddd", coordList.get(3));
+	}
+
+	public void testChangeSources4() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		newList.add(this.lvm0);
+		newList.add(this.lvm1);
+		newList.add(this.lvm2);
+		newList.add(this.lvm3);
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		newList.add(lvm4);
+
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.changeListValues(newList);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ddd", this.compositeLVM.get(3));
+		assertEquals("ddd", coordList.get(3));
+	}
+
+	public void testChangeSources5() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		newList.add(this.lvm0);
+		newList.add(this.lvm1);
+		newList.add(this.lvm2);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.changeListValues(newList);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ddd", this.compositeLVM.get(3));
+		assertEquals("ddd", coordList.get(3));
+	}
+
+	public void testChangeSources6() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) { /* OK */ }
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+
+		List<LocalListValueModel<String>> newList = new ArrayList<LocalListValueModel<String>>();
+		newList.add(this.lvm0);
+		newList.add(this.lvm1);
+
+		LocalListValueModel<String> lvm4 = new LocalListValueModel<String>();
+		lvm4.add("lll");
+		lvm4.add("mmm");
+		newList.add(lvm4);
+
+		newList.add(this.lvm3);
+
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.uberLVM.changeListValues(newList);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "lll", "mmm", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ddd", this.compositeLVM.get(3));
+		assertEquals("ddd", coordList.get(3));
+	}
+
+	public void testAddItem_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.add(0, "xxx");
+
+		Object[] expected = new Object[] { "xxx", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(7));
+		assertEquals("ggg", coordList.get(7));
+	}
+
+	public void testAddItem_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm2.add(1, "xxx");
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(7));
+		assertEquals("ggg", coordList.get(7));
+	}
+
+	public void testAddItem_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.add(5, "xxx");
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testAddItems_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.addAll(0, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "xxx", "yyy", "zzz", "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testAddItems_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm2.addAll(1, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "yyy", "zzz", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testAddItems_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.addAll(5, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx", "yyy", "zzz" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testRemoveItem_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.remove(0);
+
+		Object[] expected = new Object[] { "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(5));
+		assertEquals("ggg", coordList.get(5));
+	}
+
+	public void testRemoveItem_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm2.remove(0);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(5));
+		assertEquals("ggg", coordList.get(5));
+	}
+
+	public void testRemoveItem_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.remove(4);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testRemoveItems_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.remove(0, 3);
+
+		Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(3));
+		assertEquals("ggg", coordList.get(3));
+	}
+
+	public void testRemoveItems_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.remove(1, 3);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("kkk", this.compositeLVM.get(7));
+		assertEquals("kkk", coordList.get(7));
+	}
+
+	public void testRemoveItems_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.remove(3, 2);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testReplaceItem_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.set(0, "xxx");
+
+		Object[] expected = new Object[] { "xxx", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testReplaceItem_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm2.set(0, "xxx");
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testReplaceItem_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.set(4, "xxx");
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "xxx" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testReplaceItems_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.set(0, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "xxx", "yyy", "zzz", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testReplaceItems_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.set(1, Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "xxx", "yyy", "zzz", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("kkk", this.compositeLVM.get(10));
+		assertEquals("kkk", coordList.get(10));
+	}
+
+	public void testReplaceItems_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.set(3, Arrays.asList(new String[] { "xxx", "yyy" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "xxx", "yyy" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testMoveItem_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.move(2, 0);
+
+		Object[] expected = new Object[] { "bbb", "ccc", "aaa", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testMoveItem_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.move(0, 1);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "eee", "ddd", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testMoveItem_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.move(0, 4);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "kkk", "ggg", "hhh", "iii", "jjj" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(7));
+		assertEquals("ggg", coordList.get(7));
+	}
+
+	public void testMoveItems_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.move(1, 0, 2);
+
+		Object[] expected = new Object[] { "ccc", "aaa", "bbb", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testMoveItems_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.add("eee.1");
+		this.lvm1.add("eee.2");
+		this.lvm1.add("eee.3");
+		this.lvm1.move(1, 2, 3);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee.1", "eee.2", "eee.3", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testMoveItems_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.move(0, 2, 3);
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "iii", "jjj", "kkk", "ggg", "hhh" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(9));
+		assertEquals("ggg", coordList.get(9));
+	}
+
+	public void testClearItems_Begin() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.clear();
+
+		Object[] expected = new Object[] { "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(3));
+		assertEquals("ggg", coordList.get(3));
+	}
+
+	public void testClearItems_Middle() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.clear();
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(4));
+		assertEquals("ggg", coordList.get(4));
+	}
+
+	public void testClearItems_End() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.clear();
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testChangeItems_Begin1() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "xxx", "yyy", "zzz", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testChangeItems_Middle1() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "xxx", "yyy", "zzz", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(7));
+		assertEquals("ggg", coordList.get(7));
+	}
+
+	public void testChangeItems_End1() {
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.setListValues(Arrays.asList(new String[] { "xxx", "yyy", "zzz" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "xxx", "yyy", "zzz" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testChangeItems_Begin2() {
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "ccc" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testChangeItems_Middle2() {
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "eee" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("hhh", this.compositeLVM.get(7));
+		assertEquals("hhh", coordList.get(7));
+	}
+
+	public void testChangeItems_End2() {
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, new ErrorListener());
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "jjj", "kkk" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testChangeItems_Begin3() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "xxx" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "xxx", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(6));
+		assertEquals("ggg", coordList.get(6));
+	}
+
+	public void testChangeItems_Middle3() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "xxx" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "xxx", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("hhh", this.compositeLVM.get(7));
+		assertEquals("hhh", coordList.get(7));
+	}
+
+	public void testChangeItems_End3() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "xxx", "kkk" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "xxx", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testChangeItems_Begin4() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa", "bbb", "ccc", "xxx" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "xxx", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(6));
+		assertEquals("fff", coordList.get(6));
+	}
+
+	public void testChangeItems_Middle4() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd", "eee", "xxx" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "xxx", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("ggg", this.compositeLVM.get(7));
+		assertEquals("ggg", coordList.get(7));
+	}
+
+	public void testChangeItems_End4() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii", "jjj", "kkk", "xxx" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "xxx" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	public void testChangeItems_Begin5() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm0.changeListValues(Arrays.asList(new String[] { "aaa" }));
+
+		Object[] expected = new Object[] { "aaa", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("iii", this.compositeLVM.get(6));
+		assertEquals("iii", coordList.get(6));
+	}
+
+	public void testChangeItems_Middle5() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm1.changeListValues(Arrays.asList(new String[] { "ddd" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "fff", "ggg", "hhh", "iii", "jjj", "kkk" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("iii", this.compositeLVM.get(7));
+		assertEquals("iii", coordList.get(7));
+	}
+
+	public void testChangeItems_End5() {
+		ListChangeListener listener = new ErrorListener() {
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) { /* OK */ }
+		};
+		this.compositeLVM.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		CoordinatedList<String> coordList = new CoordinatedList<String>(this.compositeLVM);
+
+		this.lvm3.changeListValues(Arrays.asList(new String[] { "ggg", "hhh", "iii" }));
+
+		Object[] expected = new Object[] { "aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii" };
+		assertEquals(expected.length, this.compositeLVM.size());
+		assertEquals(expected.length, coordList.size());
+		assertTrue(Arrays.equals(expected, this.compositeLVM.toArray()));
+		assertTrue(Arrays.equals(expected, coordList.toArray()));
+		assertEquals("fff", this.compositeLVM.get(5));
+		assertEquals("fff", coordList.get(5));
+	}
+
+	class ErrorListener implements ListChangeListener {
+		@Override
+		public void itemsAdded(ListAddEvent event) {
+			fail();
+		}
+		@Override
+		public void itemsRemoved(ListRemoveEvent event) {
+			fail();
+		}
+		@Override
+		public void itemsMoved(ListMoveEvent event) {
+			fail();
+		}
+		@Override
+		public void itemsReplaced(ListReplaceEvent event) {
+			fail();
+		}
+		@Override
+		public void listCleared(ListClearEvent event) {
+			fail();
+		}
+		@Override
+		public void listChanged(ListChangeEvent event) {
+			fail();
+		}
+	}
+
+	class LocalListValueModel<E> extends SimpleListValueModel<E> {
+		LocalListValueModel() {
+			super();
+		}
+		void changeListValues(Iterable<E> listValues) {
+			if (listValues == null) {
+				throw new NullPointerException();
+			}
+			this.list.clear();
+			CollectionTools.addAll(this.list, listValues);
+			this.fireListChanged(LIST_VALUES, this.list);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java
new file mode 100644
index 0000000..85b5670
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/CoordinatedList.java
@@ -0,0 +1,298 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.ListModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * Helper class that keeps an internal list in synch with the
+ * list held by a list value model.
+ */
+public class CoordinatedList<E> implements List<E>, ListChangeListener, ListDataListener {
+	private List<E> list = new ArrayList<E>();
+
+	public CoordinatedList(ListValueModel<E> listValueModel) {
+		listValueModel.addListChangeListener(ListValueModel.LIST_VALUES, this);
+		for (Iterator<E> stream = listValueModel.iterator(); stream.hasNext(); ) {
+			this.add(stream.next());
+		}
+	}
+
+	public CoordinatedList(ListModel listModel) {
+		listModel.addListDataListener(this);
+		for (int i = 0; i < listModel.getSize(); i++) {
+			this.add(i, this.getElementAt(listModel, i));
+		}
+	}
+
+
+	// ********** List implementation **********
+
+	@Override
+	public void add(int index, E element) {
+		this.list.add(index, element);
+	}
+
+	@Override
+	public boolean add(E o) {
+		return this.list.add(o);
+	}
+
+	@Override
+	public boolean addAll(Collection<? extends E> c) {
+		return this.list.addAll(c);
+	}
+
+	@Override
+	public boolean addAll(int index, Collection<? extends E> c) {
+		return this.list.addAll(index, c);
+	}
+
+	@Override
+	public void clear() {
+		this.list.clear();
+	}
+
+	@Override
+	public boolean contains(Object o) {
+		return this.list.contains(o);
+	}
+
+	@Override
+	public boolean containsAll(Collection<?> c) {
+		return this.list.containsAll(c);
+	}
+
+	@Override
+	public E get(int index) {
+		return this.list.get(index);
+	}
+
+	@Override
+	public int indexOf(Object o) {
+		return this.list.indexOf(o);
+	}
+
+	@Override
+	public boolean isEmpty() {
+		return this.list.isEmpty();
+	}
+
+	@Override
+	public Iterator<E> iterator() {
+		return this.list.iterator();
+	}
+
+	@Override
+	public int lastIndexOf(Object o) {
+		return this.list.lastIndexOf(o);
+	}
+
+	@Override
+	public ListIterator<E> listIterator() {
+		return this.list.listIterator();
+	}
+
+	@Override
+	public ListIterator<E> listIterator(int index) {
+		return this.list.listIterator(index);
+	}
+
+	@Override
+	public E remove(int index) {
+		return this.list.remove(index);
+	}
+
+	@Override
+	public boolean remove(Object o) {
+		return this.list.remove(o);
+	}
+
+	@Override
+	public boolean removeAll(Collection<?> c) {
+		return this.list.removeAll(c);
+	}
+
+	@Override
+	public boolean retainAll(Collection<?> c) {
+		return this.list.retainAll(c);
+	}
+
+	@Override
+	public E set(int index, E element) {
+		return this.list.set(index, element);
+	}
+
+	@Override
+	public int size() {
+		return this.list.size();
+	}
+
+	@Override
+	public List<E> subList(int fromIndex, int toIndex) {
+		return this.list.subList(fromIndex, toIndex);
+	}
+
+	@Override
+	public Object[] toArray() {
+		return this.list.toArray();
+	}
+
+	@Override
+	public <T> T[] toArray(T[] a) {
+		return this.list.toArray(a);
+	}
+
+
+	// ********** ListChangeListener implementation **********
+
+	@Override
+	public void itemsAdded(ListAddEvent e) {
+		int i = e.getIndex();
+		for (E item : this.getItems(e)) {
+			this.list.add(i++, item);
+		}
+	}
+
+	@Override
+	public void itemsRemoved(ListRemoveEvent e) {
+		int base = e.getIndex();
+		for (int i = e.getItemsSize(); i-- > 0; ) {
+			this.list.remove(base + i);  // remove from end
+		}
+	}
+
+	@Override
+	public void itemsReplaced(ListReplaceEvent e) {
+		int i = e.getIndex();
+		for (E item : this.getNewItems(e)) {
+			this.list.set(i++, item);
+		}
+	}
+
+	@Override
+	public void itemsMoved(ListMoveEvent e) {
+		ListTools.move(this.list, e.getTargetIndex(), e.getSourceIndex(), e.getLength());
+	}
+
+	@Override
+	public void listCleared(ListClearEvent e) {
+		this.list.clear();
+	}
+
+	@Override
+	public void listChanged(ListChangeEvent e) {
+		this.list.clear();
+		CollectionTools.addAll(this.list, this.getSource(e).iterator());
+	}
+
+
+	// ********** ListDataListener implementation **********
+
+	@Override
+	public void contentsChanged(ListDataEvent e) {
+		this.list.clear();
+		ListModel lm = (ListModel) e.getSource();
+		int size = lm.getSize();
+		for (int i = 0; i < size; i++) {
+			this.list.add(i, this.getElementAt(lm, i));
+		}
+	}
+
+	@Override
+	public void intervalAdded(ListDataEvent e) {
+		ListModel lm = (ListModel) e.getSource();
+		int start = Math.min(e.getIndex0(), e.getIndex1());
+		int end = Math.max(e.getIndex0(), e.getIndex1());
+		for (int i = start; i <= end; i++) {
+			this.list.add(i, this.getElementAt(lm, i));
+		}
+	}
+
+	@Override
+	public void intervalRemoved(ListDataEvent e) {
+		int start = Math.min(e.getIndex0(), e.getIndex1());
+		int end = Math.max(e.getIndex0(), e.getIndex1());
+		int length = end - start + 1;
+		for (int i = 1; i <= length; i++) {
+			this.list.remove(start);
+		}
+	}
+
+
+	// ********** standard methods **********
+
+    @Override
+	public boolean equals(Object o) {
+		return this.list.equals(o);
+	}
+
+    @Override
+	public int hashCode() {
+		return this.list.hashCode();
+	}
+
+    @Override
+	public String toString() {
+		return this.list.toString();
+	}
+
+
+	// ********** internal methods **********
+
+	/**
+	 * minimize the scope of the suppressed warnings.=
+	 */
+	@SuppressWarnings("unchecked")
+	private E getElementAt(ListModel listModel, int index) {
+		return (E) listModel.getElementAt(index);
+	}
+
+	// minimized scope of suppressed warnings
+	@SuppressWarnings("unchecked")
+	private Iterable<E> getItems(ListAddEvent event) {
+		return (Iterable<E>) event.getItems();
+	}
+
+	// minimized scope of suppressed warnings
+	@SuppressWarnings("unchecked")
+	private Iterable<E> getNewItems(ListReplaceEvent event) {
+		return (Iterable<E>) event.getNewItems();
+	}
+
+	/**
+	 * minimize the scope of the suppressed warnings.=
+	 */
+	@SuppressWarnings("unchecked")
+	private ListValueModel<E> getSource(ListChangeEvent event) {
+		return (ListValueModel<E>) event.getSource();
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java
new file mode 100644
index 0000000..85fa4cd
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemCollectionListValueModelAdapterTests.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemCollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemCollectionListValueModelAdapterTests extends TestCase {
+
+	private Junk foo;
+	private Junk bar;
+	private Junk baz;
+	private Junk joo;
+	private Junk jar;
+	private Junk jaz;
+
+	private Junk tom;
+	private Junk dick;
+	private Junk harry;
+
+	public ItemCollectionListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.foo = new Junk("foo");
+		this.bar = new Junk("bar");
+		this.baz = new Junk("baz");
+		this.joo = new Junk("joo");
+		this.jar = new Junk("jar");
+		this.jaz = new Junk("jaz");
+
+		this.tom = new Junk("tom");
+		this.dick = new Junk("dick");
+		this.harry = new Junk("harry");
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testCollectionSynchronization() {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(collectionHolder, Junk.STUFF_COLLECTION);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	public void testListSynchronization() {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.add(6, this.tom);
+		listHolder.add(7, this.dick);
+		listHolder.add(8, this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.remove(8);
+		listHolder.remove(0);
+		listHolder.remove(4);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+		assertEquals(listValueModel.size(), list.size());
+		for (int i = 0; i < listValueModel.size(); i++) {
+			assertEquals(listValueModel.get(i), list.get(i));
+		}
+	}
+
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_COLLECTION));
+		assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_COLLECTION));
+
+		ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		assertFalse(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		this.verifyHasNoListeners(listValueModel);
+
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		assertTrue(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		this.verifyHasListeners(listValueModel);
+
+		listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		assertFalse(this.jaz.hasAnyCollectionChangeListeners(Junk.STUFF_COLLECTION));
+		this.verifyHasNoListeners(listValueModel);
+	}
+
+	public void testGetSize() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(6, listValueModel.size());
+		assertEquals(6, synchList.size());
+	}
+
+	public void testGet() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemCollectionListValueModelAdapter<Junk>(listHolder, Junk.STUFF_COLLECTION));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(this.bar, listValueModel.get(0));
+		assertEquals(this.bar, synchList.get(0));
+		this.bar.removeStuff("bar");
+		this.bar.addStuff("zzz");
+		this.bar.addStuff("bar");
+		assertEquals(this.bar, listValueModel.get(5));
+		assertEquals(this.bar, synchList.get(5));
+		this.bar.removeStuff("zzz");
+	}
+
+	private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+		return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+	}
+
+	private Collection<Junk> buildCollection() {
+		Bag<Junk> bag = new HashBag<Junk>();
+		this.populateCollection(bag);
+		return bag;
+	}
+
+	private SimpleListValueModel<Junk> buildListHolder() {
+		return new SimpleListValueModel<Junk>(this.buildList());
+	}
+
+	private List<Junk> buildList() {
+		List<Junk> list = new ArrayList<Junk>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<Junk> c) {
+		c.add(this.foo);
+		c.add(this.bar);
+		c.add(this.baz);
+		c.add(this.joo);
+		c.add(this.jar);
+		c.add(this.jaz);
+	}
+
+
+	// ********** Junk class **********
+
+	private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+		private Collection<String> stuff;
+			public static final String STUFF_COLLECTION = "stuff";
+
+
+		public Junk(String stuffItem) {
+			this.stuff = new ArrayList<String>();
+			this.stuff.add(stuffItem);
+		}
+
+		public void addStuff(String stuffItem) {
+			this.addItemToCollection(stuffItem, this.stuff, STUFF_COLLECTION);
+		}
+
+		public void removeStuff(String stuffItem) {
+			this.removeItemFromCollection(stuffItem, this.stuff, STUFF_COLLECTION);
+		}
+
+		@Override
+		public String displayString() {
+			return toString();
+		}
+
+		@Override
+		public Icon icon() {
+			return null;
+		}
+
+		@Override
+		public int compareTo(Junk o) {
+			return this.displayString().compareTo(o.displayString());
+		}
+
+		@Override
+		public String toString() {
+			return "Junk(" + this.stuff + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java
new file mode 100644
index 0000000..8006fe0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemListListValueModelAdapterTests.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemListListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemListListValueModelAdapterTests extends TestCase {
+
+	private Junk foo;
+	private Junk bar;
+	private Junk baz;
+	private Junk joo;
+	private Junk jar;
+	private Junk jaz;
+
+	private Junk tom;
+	private Junk dick;
+	private Junk harry;
+
+	public ItemListListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.foo = new Junk("foo");
+		this.bar = new Junk("bar");
+		this.baz = new Junk("baz");
+		this.joo = new Junk("joo");
+		this.jar = new Junk("jar");
+		this.jaz = new Junk("jaz");
+
+		this.tom = new Junk("tom");
+		this.dick = new Junk("dick");
+		this.harry = new Junk("harry");
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testCollectionSynchronization() {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(collectionHolder, Junk.STUFF_LIST);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	public void testListSynchronization() {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.add(6, this.tom);
+		listHolder.add(7, this.dick);
+		listHolder.add(8, this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.remove(8);
+		listHolder.remove(0);
+		listHolder.remove(4);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+		assertEquals(listValueModel.size(), list.size());
+		for (int i = 0; i < listValueModel.size(); i++) {
+			assertEquals(listValueModel.get(i), list.get(i));
+		}
+	}
+
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+
+		ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		this.verifyHasNoListeners(listValueModel);
+
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		assertTrue(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		this.verifyHasListeners(listValueModel);
+
+		listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		assertFalse(this.jaz.hasAnyListChangeListeners(Junk.STUFF_LIST));
+		this.verifyHasNoListeners(listValueModel);
+	}
+
+	public void testGetSize() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(6, listValueModel.size());
+		assertEquals(6, synchList.size());
+	}
+
+	public void testGet() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemListListValueModelAdapter<Junk>(listHolder, Junk.STUFF_LIST));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(this.bar, listValueModel.get(0));
+		assertEquals(this.bar, synchList.get(0));
+		this.bar.removeStuff("bar");
+		this.bar.addStuff("zzz");
+		this.bar.addStuff("bar");
+		assertEquals(this.bar, listValueModel.get(5));
+		assertEquals(this.bar, synchList.get(5));
+		this.bar.removeStuff("zzz");
+	}
+
+	private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+		return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+	}
+
+	private Collection<Junk> buildCollection() {
+		Bag<Junk> bag = new HashBag<Junk>();
+		this.populateCollection(bag);
+		return bag;
+	}
+
+	private SimpleListValueModel<Junk> buildListHolder() {
+		return new SimpleListValueModel<Junk>(this.buildList());
+	}
+
+	private List<Junk> buildList() {
+		List<Junk> list = new ArrayList<Junk>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<Junk> c) {
+		c.add(this.foo);
+		c.add(this.bar);
+		c.add(this.baz);
+		c.add(this.joo);
+		c.add(this.jar);
+		c.add(this.jaz);
+	}
+
+
+	// ********** Junk class **********
+
+	private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+		private List<String> stuff;
+			public static final String STUFF_LIST = "stuff";
+
+
+		public Junk(String stuffItem) {
+			this.stuff = new ArrayList<String>();
+			this.stuff.add(stuffItem);
+		}
+		public void addStuff(String stuffItem) {
+			this.stuff.add(stuffItem);
+			fireItemAdded(STUFF_LIST, this.stuff.indexOf(stuffItem), stuffItem);
+		}
+
+		public void removeStuff(String stuffItem) {
+			int index = this.stuff.indexOf(stuffItem);
+			this.stuff.remove(stuffItem);
+			fireItemRemoved(STUFF_LIST, index, stuffItem);
+		}
+
+		@Override
+		public String displayString() {
+			return toString();
+		}
+
+		@Override
+		public Icon icon() {
+			return null;
+		}
+
+		@Override
+		public int compareTo(Junk o) {
+			return this.displayString().compareTo(o.displayString());
+		}
+
+		@Override
+		public String toString() {
+			return "Junk(" + this.stuff + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java
new file mode 100644
index 0000000..ed61223
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemPropertyListValueModelAdapterTests.java
@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+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 javax.swing.Icon;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class ItemPropertyListValueModelAdapterTests extends TestCase {
+
+	private Junk foo;
+	private Junk bar;
+	private Junk baz;
+	private Junk joo;
+	private Junk jar;
+	private Junk jaz;
+
+	private Junk tom;
+	private Junk dick;
+	private Junk harry;
+
+	public ItemPropertyListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.foo = new Junk("this.foo");
+		this.bar = new Junk("this.bar");
+		this.baz = new Junk("this.baz");
+		this.joo = new Junk("this.joo");
+		this.jar = new Junk("this.jar");
+		this.jaz = new Junk("this.jaz");
+
+		this.tom = new Junk("this.tom");
+		this.dick = new Junk("this.dick");
+		this.harry = new Junk("this.harry");
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testCollectionSynchronization() {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(collectionHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.setValues(this.buildCollection());
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	public void testListSynchronization() {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(listHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.add(6, this.tom);
+		listHolder.add(7, this.dick);
+		listHolder.add(8, this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.remove(8);
+		listHolder.remove(0);
+		listHolder.remove(4);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		// test concurrent modification exception
+		listHolder.setListValues(this.buildList());
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+		assertEquals(listValueModel.size(), list.size());
+		for (int i = 0; i < listValueModel.size(); i++) {
+			assertEquals(listValueModel.get(i), list.get(i));
+		}
+	}
+
+	public void testCollectionSort() {
+		this.verifyCollectionSort(null);
+	}
+
+	public void testListSort() {
+		this.verifyListSort(null);
+	}
+
+	public void testCustomCollectionSort() {
+		this.verifyCollectionSort(this.buildCustomComparator());
+	}
+
+	public void testCustomListSort() {
+		this.verifyListSort(this.buildCustomComparator());
+	}
+
+	private Comparator<Junk> buildCustomComparator() {
+		// sort with reverse order
+		return new Comparator<Junk>() {
+			@Override
+			public int compare(Junk o1, Junk o2) {
+				return o2.displayString().compareTo(o1.displayString());
+			}
+		};
+	}
+
+	private void verifyCollectionSort(Comparator<Junk> comparator) {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelAdapter<Junk>(collectionHolder, comparator), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		collectionHolder.setValues(this.buildCollection());
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+	}
+
+	private void verifyListSort(Comparator<Junk> comparator) {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder, comparator), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		listHolder.add(0, this.tom);
+		listHolder.add(0, this.dick);
+		listHolder.add(0, this.harry);
+		assertEquals(9, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		listHolder.remove(8);
+		listHolder.remove(4);
+		listHolder.remove(0);
+		listHolder.remove(5);
+		assertEquals(5, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		listHolder.setListValues(this.buildList());
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+	}
+
+	private void compareSort(ListValueModel<Junk> listValueModel, List<Junk> list, Comparator<Junk> comparator) {
+		SortedSet<Junk> ss = new TreeSet<Junk>(comparator);
+		for (int i = 0; i < listValueModel.size(); i++) {
+			ss.add(listValueModel.get(i));
+		}
+		assertEquals(ss.size(), list.size());
+		for (Iterator<Junk> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+			assertEquals(stream1.next(), stream2.next());
+		}
+	}
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		this.verifyHasNoListeners(listValueModel);
+
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertTrue(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		assertTrue(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertTrue(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		this.verifyHasListeners(listValueModel);
+
+		listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.foo.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.DISPLAY_STRING_PROPERTY));
+		assertFalse(this.jaz.hasAnyPropertyChangeListeners(Displayable.ICON_PROPERTY));
+		this.verifyHasNoListeners(listValueModel);
+	}
+
+	public void testGetSize() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemPropertyListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder), Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(6, listValueModel.size());
+		assertEquals(6, synchList.size());
+	}
+
+	public void testGet() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemPropertyListValueModelAdapter<Junk>(listHolder, Displayable.DISPLAY_STRING_PROPERTY, Displayable.ICON_PROPERTY));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(this.bar, listValueModel.get(0));
+		assertEquals(this.bar, synchList.get(0));
+		this.bar.setName("zzz");
+		assertEquals(this.bar, listValueModel.get(5));
+		assertEquals(this.bar, synchList.get(5));
+		this.bar.setName("this.bar");
+	}
+
+	private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+		return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+	}
+
+	private Collection<Junk> buildCollection() {
+		Bag<Junk> bag = new HashBag<Junk>();
+		this.populateCollection(bag);
+		return bag;
+	}
+
+	private SimpleListValueModel<Junk> buildListHolder() {
+		return new SimpleListValueModel<Junk>(this.buildList());
+	}
+
+	private List<Junk> buildList() {
+		List<Junk> list = new ArrayList<Junk>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<Junk> c) {
+		c.add(this.foo);
+		c.add(this.bar);
+		c.add(this.baz);
+		c.add(this.joo);
+		c.add(this.jar);
+		c.add(this.jaz);
+	}
+
+
+	// ********** Junk class **********
+
+	private class Junk extends AbstractModel implements Displayable, Comparable<Junk> {
+		private String name;
+		public Junk(String name) {
+			this.name = name;
+		}
+		@Override
+		public String displayString() {
+			return this.name;
+		}
+		@Override
+		public Icon icon() {
+			return null;
+		}
+		public void setName(String name) {
+			Object old = this.name;
+			this.name = name;
+			this.firePropertyChanged(DISPLAY_STRING_PROPERTY, old, name);
+		}
+		@Override
+		public int compareTo(Junk o) {
+			return this.displayString().compareTo(o.displayString());
+		}
+		@Override
+		public String toString() {
+			return "Junk(" + this.name + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java
new file mode 100644
index 0000000..6d65012
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ItemStateListValueModelAdapterTests.java
@@ -0,0 +1,310 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+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 junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemStateListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ItemStateListValueModelAdapterTests extends TestCase {
+
+	private Junk foo;
+	private Junk bar;
+	private Junk baz;
+	private Junk joo;
+	private Junk jar;
+	private Junk jaz;
+
+	private Junk tom;
+	private Junk dick;
+	private Junk harry;
+
+	public ItemStateListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.foo = new Junk("this.foo");
+		this.bar = new Junk("this.bar");
+		this.baz = new Junk("this.baz");
+		this.joo = new Junk("this.joo");
+		this.jar = new Junk("this.jar");
+		this.jaz = new Junk("this.jaz");
+
+		this.tom = new Junk("this.tom");
+		this.dick = new Junk("this.dick");
+		this.harry = new Junk("this.harry");
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testCollectionSynchronization() {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(collectionHolder);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	public void testListSynchronization() {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(listHolder);
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.add(6, this.tom);
+		listHolder.add(7, this.dick);
+		listHolder.add(8, this.harry);
+		assertEquals(9, synchList.size());
+		this.compare(listValueModel, synchList);
+
+		listHolder.remove(8);
+		listHolder.remove(0);
+		listHolder.remove(4);
+		assertEquals(6, synchList.size());
+		this.compare(listValueModel, synchList);
+	}
+
+	private void compare(ListValueModel<Junk> listValueModel, List<Junk> list) {
+		assertEquals(listValueModel.size(), list.size());
+		for (int i = 0; i < listValueModel.size(); i++) {
+			assertEquals(listValueModel.get(i), list.get(i));
+		}
+	}
+
+	public void testCollectionSort() {
+		this.verifyCollectionSort(null);
+	}
+
+	public void testListSort() {
+		this.verifyListSort(null);
+	}
+
+	public void testCustomCollectionSort() {
+		this.verifyCollectionSort(this.buildCustomComparator());
+	}
+
+	public void testCustomListSort() {
+		this.verifyListSort(this.buildCustomComparator());
+	}
+
+	private Comparator<Junk> buildCustomComparator() {
+		// sort with reverse order
+		return new Comparator<Junk>() {
+			@Override
+			public int compare(Junk o1, Junk o2) {
+				return o2.compareTo(o1);
+			}
+		};
+	}
+
+	private void verifyCollectionSort(Comparator<Junk> comparator) {
+		SimpleCollectionValueModel<Junk> collectionHolder = this.buildCollectionHolder();
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelAdapter<Junk>(collectionHolder, comparator));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		collectionHolder.add(this.tom);
+		collectionHolder.add(this.dick);
+		collectionHolder.add(this.harry);
+		assertEquals(9, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		collectionHolder.remove(this.foo);
+		collectionHolder.remove(this.jar);
+		collectionHolder.remove(this.harry);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+	}
+
+	private void verifyListSort(Comparator<Junk> comparator) {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder, comparator));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		listHolder.add(0, this.tom);
+		listHolder.add(0, this.dick);
+		listHolder.add(0, this.harry);
+		assertEquals(9, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+
+		listHolder.remove(8);
+		listHolder.remove(4);
+		listHolder.remove(0);
+		listHolder.remove(5);
+		assertEquals(5, synchList.size());
+		this.compareSort(listValueModel, synchList, comparator);
+	}
+
+	private void compareSort(ListValueModel<Junk> listValueModel, List<Junk> list, Comparator<Junk> comparator) {
+		SortedSet<Junk> ss = new TreeSet<Junk>(comparator);
+		for (int i = 0; i < listValueModel.size(); i++) {
+			ss.add(listValueModel.get(i));
+		}
+		assertEquals(ss.size(), list.size());
+		for (Iterator<Junk> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+			assertEquals(stream1.next(), stream2.next());
+		}
+	}
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder));
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+		this.verifyHasNoListeners(listValueModel);
+
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(this.foo.hasAnyStateChangeListeners());
+		assertTrue(this.foo.hasAnyStateChangeListeners());
+		assertTrue(this.jaz.hasAnyStateChangeListeners());
+		assertTrue(this.jaz.hasAnyStateChangeListeners());
+		this.verifyHasListeners(listValueModel);
+
+		listValueModel.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.foo.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+		assertFalse(this.jaz.hasAnyStateChangeListeners());
+		this.verifyHasNoListeners(listValueModel);
+	}
+
+	public void testGetSize() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new ItemStateListValueModelAdapter<Junk>(new SortedListValueModelWrapper<Junk>(listHolder));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(6, listValueModel.size());
+		assertEquals(6, synchList.size());
+	}
+
+	public void testGet() throws Exception {
+		SimpleListValueModel<Junk> listHolder = this.buildListHolder();
+		ListValueModel<Junk> listValueModel = new SortedListValueModelWrapper<Junk>(new ItemStateListValueModelAdapter<Junk>(listHolder));
+		CoordinatedList<Junk> synchList = new CoordinatedList<Junk>(listValueModel);
+		this.verifyHasListeners(listValueModel);
+		assertEquals(this.bar, listValueModel.get(0));
+		assertEquals(this.bar, synchList.get(0));
+		this.bar.setName("zzz");
+		assertEquals(this.bar, listValueModel.get(5));
+		assertEquals(this.bar, synchList.get(5));
+		this.bar.setName("this.bar");
+	}
+
+	private void verifyHasNoListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private void verifyHasListeners(ListValueModel<Junk> listValueModel) throws Exception {
+		assertTrue(((AbstractModel) listValueModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private SimpleCollectionValueModel<Junk> buildCollectionHolder() {
+		return new SimpleCollectionValueModel<Junk>(this.buildCollection());
+	}
+
+	private Collection<Junk> buildCollection() {
+		Bag<Junk> bag = new HashBag<Junk>();
+		this.populateCollection(bag);
+		return bag;
+	}
+
+	private SimpleListValueModel<Junk> buildListHolder() {
+		return new SimpleListValueModel<Junk>(this.buildList());
+	}
+
+	private List<Junk> buildList() {
+		List<Junk> list = new ArrayList<Junk>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<Junk> c) {
+		c.add(this.foo);
+		c.add(this.bar);
+		c.add(this.baz);
+		c.add(this.joo);
+		c.add(this.jar);
+		c.add(this.jaz);
+	}
+
+	// ********** Junk class **********
+	private class Junk extends AbstractModel implements Comparable<Junk> {
+		private String name;
+		public Junk(String name) {
+			this.name = name;
+		}
+		public void setName(String name) {
+			this.name = name;
+			this.fireStateChanged();
+		}
+		@Override
+		public int compareTo(Junk j) {
+			return this.name.compareTo(j.name);
+		}
+		@Override
+		public String toString() {
+			return "Junk(" + this.name + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java
new file mode 100644
index 0000000..0542321
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/ListCollectionValueModelAdapterTests.java
@@ -0,0 +1,288 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.CollectionChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListCollectionValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ListCollectionValueModelAdapterTests extends TestCase {
+
+	CollectionValueModel<String> adapter;
+	private SimpleListValueModel<String> wrappedListHolder;
+	private List<String> wrappedList;
+
+	public ListCollectionValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.wrappedList = new ArrayList<String>();
+		this.wrappedListHolder = new SimpleListValueModel<String>(this.wrappedList);
+		this.adapter = new ListCollectionValueModelAdapter<String>(this.wrappedListHolder);
+	}
+
+	private Collection<String> wrappedCollection() {
+		return CollectionTools.collection(this.wrappedList.iterator());
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testIterator() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {
+				// override failure
+			}
+		});
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+	}
+
+	public void testStaleValues() {
+		CollectionChangeListener listener = new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {/* OK */}
+		};
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+
+		this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, listener);
+		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(0, adapterCollection.size());
+		assertEquals(new HashBag<String>(), adapterCollection);
+
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, listener);
+		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+	}
+
+	public void testAdd() {
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+		List<String> synchList = new CoordinatedList<String>(this.wrappedListHolder);
+		this.wrappedListHolder.add(0, "foo");
+		assertTrue(this.wrappedList.contains("foo"));
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		this.wrappedListHolder.add(3, "joo");
+		this.wrappedListHolder.add(4, "jar");
+		this.wrappedListHolder.add(5, "jaz");
+		assertEquals(6, this.wrappedList.size());
+
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+		assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection(), synchCollection);
+	}
+
+	public void testRemove() {
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+		List<String> synchList = new CoordinatedList<String>(this.wrappedListHolder);
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		this.wrappedListHolder.add(3, "joo");
+		this.wrappedListHolder.add(4, "jar");
+		this.wrappedListHolder.add(5, "jaz");
+		assertEquals("jaz", this.wrappedListHolder.remove(5));
+		assertFalse(this.wrappedList.contains("jaz"));
+		assertEquals("foo", this.wrappedListHolder.remove(0));
+		assertFalse(this.wrappedList.contains("foo"));
+		assertEquals(4, this.wrappedList.size());
+
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+		assertEquals(this.wrappedCollection(), CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection(), synchCollection);
+	}
+
+	public void testListSynch() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {
+				// override failure
+			}
+			@Override
+			public void itemsRemoved(CollectionRemoveEvent e) {
+				// override failure
+			}
+		});
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		this.wrappedListHolder.add(3, "joo");
+		this.wrappedListHolder.add(4, "jar");
+		this.wrappedListHolder.add(5, "jaz");
+		this.wrappedListHolder.remove(5);
+		assertFalse(this.wrappedList.contains("jaz"));
+		this.wrappedListHolder.remove(0);
+		assertFalse(this.wrappedList.contains("foo"));
+		assertEquals(4, this.wrappedList.size());
+
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+	}
+
+	public void testReplace() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {
+				// override failure
+			}
+			@Override
+			public void itemsRemoved(CollectionRemoveEvent e) {
+				// override failure
+			}
+		});
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		Collection<String> adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(3, adapterCollection.size());
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsRemoved(CollectionRemoveEvent e) {
+				assertEquals("foo", e.getItems().iterator().next());
+				assertFalse(IteratorTools.contains(ListCollectionValueModelAdapterTests.this.adapter.iterator(), "joo"));
+				assertEquals(2, ListCollectionValueModelAdapterTests.this.adapter.size());
+			}
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {
+				assertEquals("joo", e.getItems().iterator().next());
+				assertEquals(3, ListCollectionValueModelAdapterTests.this.adapter.size());
+			}
+		});
+		this.wrappedListHolder.set(0, "joo");
+		adapterCollection = CollectionTools.collection(this.adapter.iterator());
+		assertEquals(3, adapterCollection.size());
+		assertEquals(this.wrappedCollection(), adapterCollection);
+	}
+
+	public void testHasListeners() {
+		assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+		CoordinatedBag<String> synchCollection = new CoordinatedBag<String>(this.adapter);
+		assertTrue(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+		this.adapter.removeCollectionChangeListener(CollectionValueModel.VALUES, synchCollection);
+		assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+
+		ChangeListener cl = new ChangeAdapter();
+		this.adapter.addChangeListener(cl);
+		assertTrue(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+		this.adapter.removeChangeListener(cl);
+		assertFalse(((AbstractModel) this.adapter).hasAnyCollectionChangeListeners(CollectionValueModel.VALUES));
+	}
+
+	public void testListChangedToEmpty() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {/* OK */}
+			@Override
+			public void collectionCleared(CollectionClearEvent e) {/* OK */}
+		});
+		this.wrappedListHolder.add(0, "foo");
+		this.wrappedListHolder.add(1, "bar");
+		this.wrappedListHolder.add(2, "baz");
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+		this.wrappedListHolder.setListValues(new ArrayList<String>());
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+	public void testCollectionChangedFromEmpty() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		ArrayList<String> list = new ArrayList<String>();
+		list.add("foo");
+		list.add("bar");
+		this.wrappedListHolder.setListValues(list);
+		assertEquals(2, jList.getModel().getSize());
+	}
+
+	public void testCollectionChangedFromEmptyToEmpty() {
+		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(CollectionAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		ArrayList<String> list = new ArrayList<String>();
+		this.wrappedListHolder.setListValues(list);
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+
+	// ********** inner class **********
+
+	class TestListener implements CollectionChangeListener {
+		@Override
+		public void itemsAdded(CollectionAddEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsRemoved(CollectionRemoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void collectionCleared(CollectionClearEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void collectionChanged(CollectionChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
index 0526590..ec77da5 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyCollectionValueModelAdapterTests.java
@@ -14,6 +14,7 @@
 package org.eclipse.persistence.tools.utility.tests.model.value;
 
 import java.util.Collection;
+import javax.swing.JList;
 import junit.framework.TestCase;
 import org.eclipse.persistence.tools.utility.collection.CollectionTools;
 import org.eclipse.persistence.tools.utility.collection.HashBag;
@@ -30,6 +31,7 @@
 import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
 import org.eclipse.persistence.tools.utility.model.value.PropertyCollectionValueModelAdapter;
 import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
 import org.eclipse.persistence.tools.utility.tests.TestTools;
 
 @SuppressWarnings("nls")
@@ -116,9 +118,9 @@
 			public void itemsRemoved(CollectionRemoveEvent e) {/* OK */}
 		});
 		this.wrappedValueHolder.setValue("foo");
-//		JList jList = new JList(new ListModelAdapter(this.adapter));
+		JList jList = new JList(new ListModelAdapter(this.adapter));
 		this.wrappedValueHolder.setValue(null);
-//		assertEquals(0, jList.getModel().getSize());
+		assertEquals(0, jList.getModel().getSize());
 	}
 
 	public void testCollectionChangedFromEmpty() {
@@ -126,18 +128,18 @@
 			@Override
 			public void itemsAdded(CollectionAddEvent e) {/* OK */}
 		});
-//		JList jList = new JList(new ListModelAdapter(this.adapter));
+		JList jList = new JList(new ListModelAdapter(this.adapter));
 
 		this.wrappedValueHolder.setValue("foo");
-//		assertEquals(1, jList.getModel().getSize());
+		assertEquals(1, jList.getModel().getSize());
 	}
 
 	public void testCollectionChangedFromEmptyToEmpty() {
 		this.adapter.addCollectionChangeListener(CollectionValueModel.VALUES, new TestListener());
-//		JList jList = new JList(new ListModelAdapter(this.adapter));
+		JList jList = new JList(new ListModelAdapter(this.adapter));
 
 		this.wrappedValueHolder.setValue(null);
-//		assertEquals(0, jList.getModel().getSize());
+		assertEquals(0, jList.getModel().getSize());
 	}
 
 
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java
new file mode 100644
index 0000000..a572c93
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/PropertyListValueModelAdapterTests.java
@@ -0,0 +1,218 @@
+/*******************************************************************************
+ * Copyright (c) 2008, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.JList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.iterator.SingleElementIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class PropertyListValueModelAdapterTests extends TestCase {
+
+	private ListValueModel<String> adapter;
+	private ModifiablePropertyValueModel<String> wrappedValueHolder;
+
+	public PropertyListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.wrappedValueHolder = new SimplePropertyValueModel<String>();
+		this.adapter = new PropertyListValueModelAdapter<String>(this.wrappedValueHolder);
+	}
+
+	private Collection<String> wrappedList() {
+		return ListTools.list(new SingleElementIterator<String>(this.wrappedValueHolder.getValue()));
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testIterator() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {/* OK */}
+		});
+		assertFalse(this.adapter.iterator().hasNext());
+		this.wrappedValueHolder.setValue("foo");
+		List<String> adapterList = ListTools.list(this.adapter.iterator());
+		assertEquals(1, adapterList.size());
+		assertEquals(this.wrappedList(), adapterList);
+		assertEquals("foo", adapterList.iterator().next());
+	}
+
+	public void testGetInt() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {/* OK */}
+		});
+		this.wrappedValueHolder.setValue("foo");
+		assertEquals("foo", this.adapter.get(0));
+	}
+
+	public void testToArray1() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {/* OK */}
+		});
+		this.wrappedValueHolder.setValue("foo");
+		Object[] array = this.adapter.toArray();
+		assertEquals("foo", array[0]);
+		assertEquals(1, array.length);
+	}
+
+	public void testToArray2() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener());
+		Object[] array = this.adapter.toArray();
+		assertEquals(0, array.length);
+	}
+
+	public void testStaleValue() {
+		ListChangeListener listener = new TestListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {/* OK */}
+		};
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		this.wrappedValueHolder.setValue("foo");
+		List<String> adapterList = ListTools.list(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());
+		assertEquals(0, adapterList.size());
+		assertEquals(new ArrayList<String>(), adapterList);
+
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, listener);
+		adapterList = ListTools.list(this.adapter.iterator());
+		assertEquals(1, adapterList.size());
+		assertEquals(this.wrappedList(), adapterList);
+		assertEquals("foo", adapterList.iterator().next());
+	}
+
+	public void testHasListeners() {
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		ChangeListener cl = new ChangeAdapter();
+		this.adapter.addChangeListener(cl);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeChangeListener(cl);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	public void testListChangedToEmpty() {
+		this.wrappedValueHolder.setValue("foo");
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+		this.wrappedValueHolder.setValue(null);
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+	public void testListChangedFromEmpty() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		this.wrappedValueHolder.setValue("foo");
+		assertEquals(1, jList.getModel().getSize());
+	}
+
+	public void testListItemChanged() {
+		this.wrappedValueHolder.setValue("foo");
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener() {
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) {/* OK */}
+		});
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+		assertEquals(1, jList.getModel().getSize());
+		assertEquals("foo", jList.getModel().getElementAt(0));
+
+		this.wrappedValueHolder.setValue("bar");
+		assertEquals(1, jList.getModel().getSize());
+		assertEquals("bar", jList.getModel().getElementAt(0));
+	}
+
+	public void testListChangedFromEmptyToEmpty() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListener());
+		JList jList = new JList(new ListModelAdapter(this.adapter));
+
+		this.wrappedValueHolder.setValue(null);
+		assertEquals(0, jList.getModel().getSize());
+	}
+
+
+	// ********** member class **********
+
+	static class TestListener implements ListChangeListener {
+		@Override
+		public void listChanged(ListChangeEvent event) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listCleared(ListClearEvent event) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsAdded(ListAddEvent event) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsRemoved(ListRemoveEvent event) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsMoved(ListMoveEvent event) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsReplaced(ListReplaceEvent event) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java
new file mode 100644
index 0000000..c7a042c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelAdapterTests.java
@@ -0,0 +1,230 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ReverseComparator;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SortedListValueModelAdapterTests extends TestCase {
+	private SortedListValueModelAdapter<String> adapter;
+	private SimpleCollectionValueModel<String> wrappedCollectionHolder;
+	private Collection<String> wrappedCollection;
+
+
+	public SortedListValueModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.wrappedCollection = new HashBag<String>();
+		this.wrappedCollectionHolder = new SimpleCollectionValueModel<String>(this.wrappedCollection);
+		this.adapter = new SortedListValueModelAdapter<String>(this.wrappedCollectionHolder);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	private void verifyList(Collection<String> expected, ListValueModel<String> actual) {
+		this.verifyList(expected, actual, null);
+	}
+
+	private void verifyList(Collection<String> expected, ListValueModel<String> actual, Comparator<String> comparator) {
+		Collection<String> sortedSet = new TreeSet<String>(comparator);
+		sortedSet.addAll(expected);
+		List<String> expectedList = new ArrayList<String>(sortedSet);
+		List<String> actualList = ListTools.list(actual.iterator());
+		assertEquals(expectedList, actualList);
+	}
+
+	public void testAdd() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		assertEquals(3, this.adapter.size());
+		this.verifyList(this.wrappedCollection, this.adapter);
+	}
+
+	public void testAddItem() {
+		List<String> synchList = new CoordinatedList<String>(this.adapter);
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+		this.wrappedCollectionHolder.add("foo");
+		assertTrue(this.wrappedCollection.contains("foo"));
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		assertEquals(6, this.wrappedCollection.size());
+
+		this.verifyList(this.wrappedCollection, this.adapter);
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+	}
+
+	public void testRemoveItem() {
+		List<String> synchList = new CoordinatedList<String>(this.adapter);
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		this.wrappedCollectionHolder.remove("jaz");
+		assertFalse(this.wrappedCollection.contains("jaz"));
+		this.wrappedCollectionHolder.remove("foo");
+		assertFalse(this.wrappedCollection.contains("foo"));
+		assertEquals(4, this.wrappedCollection.size());
+
+		this.verifyList(this.wrappedCollection, this.adapter);
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+	}
+
+	public void testListSynch() {
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+			@Override
+			public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.add("foo");
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		this.wrappedCollectionHolder.remove("jaz");
+		assertFalse(this.wrappedCollection.contains("jaz"));
+		this.wrappedCollectionHolder.remove("foo");
+		assertFalse(this.wrappedCollection.contains("foo"));
+		assertEquals(4, this.wrappedCollection.size());
+
+		this.verifyList(this.wrappedCollection, this.adapter);
+	}
+
+	public void testSetComparator() {
+		List<String> synchList = new CoordinatedList<String>(this.adapter);
+		Bag<String> synchCollection = new CoordinatedBag<String>(this.wrappedCollectionHolder);
+		this.wrappedCollectionHolder.add("foo");
+		assertTrue(this.wrappedCollection.contains("foo"));
+		this.wrappedCollectionHolder.add("bar");
+		this.wrappedCollectionHolder.add("baz");
+		this.wrappedCollectionHolder.add("joo");
+		this.wrappedCollectionHolder.add("jar");
+		this.wrappedCollectionHolder.add("jaz");
+		assertEquals(6, this.wrappedCollection.size());
+
+		this.verifyList(this.wrappedCollection, this.adapter);
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+
+		this.adapter.setComparator(new ReverseComparator<String>());
+		this.verifyList(this.wrappedCollection, this.adapter, new ReverseComparator<String>());
+		assertEquals(this.wrappedCollection, CollectionTools.collection(synchList.iterator()));
+		assertEquals(this.wrappedCollection, synchCollection);
+	}
+
+	public void testHasListeners() {
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(this.adapter);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeListChangeListener(ListValueModel.LIST_VALUES, synchList);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		ChangeListener cl = new ChangeAdapter();
+		this.adapter.addChangeListener(cl);
+		assertTrue(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.adapter.removeChangeListener(cl);
+		assertFalse(((AbstractModel) this.adapter).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	public void testCollectionChange() {
+		this.wrappedCollectionHolder.add("fred");
+		this.adapter.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+		});
+		this.wrappedCollectionHolder.setValues(Arrays.asList(new String[] {"foo", "bar", "baz"}));
+		assertEquals(3, this.adapter.size());
+		this.verifyList(this.wrappedCollection, this.adapter);
+	}
+
+	class TestListChangeListener implements ListChangeListener {
+		@Override
+		public void itemsAdded(ListAddEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsRemoved(ListRemoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsReplaced(ListReplaceEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsMoved(ListMoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listCleared(ListClearEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listChanged(ListChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java
new file mode 100644
index 0000000..8a8ebb4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/SortedListValueModelWrapperTests.java
@@ -0,0 +1,244 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+import java.util.TreeSet;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ReverseComparator;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeAdapter;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SortedListValueModelWrapperTests extends TestCase {
+	private List<String> list;
+	private SimpleListValueModel<String> listModel;
+	private SortedListValueModelWrapper<String> sortedListModel;
+
+
+	public SortedListValueModelWrapperTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.list = new ArrayList<String>();
+		this.listModel = new SimpleListValueModel<String>(this.list);
+		this.sortedListModel = new SortedListValueModelWrapper<String>(this.listModel);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	private void verifyList(Collection<String> expected, ListValueModel<String> actual) {
+		this.verifyList(expected, actual, null);
+	}
+
+	private void verifyList(Collection<String> expected, ListValueModel<String> actual, Comparator<String> comparator) {
+		Collection<String> sortedSet = new TreeSet<String>(comparator);
+		sortedSet.addAll(expected);
+		List<String> expectedList = new ArrayList<String>(sortedSet);
+		List<String> actualList = ListTools.list(actual);
+		assertEquals(expectedList, actualList);
+	}
+
+	public void testAdd() {
+		this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+		});
+		this.listModel.add("foo");
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		assertEquals(3, this.sortedListModel.size());
+		this.verifyList(this.list, this.sortedListModel);
+	}
+
+	public void testAddItem() {
+		List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+		List<String> synchList = new CoordinatedList<String>(this.listModel);
+		this.listModel.add("foo");
+		assertTrue(this.list.contains("foo"));
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		this.listModel.add("joo");
+		this.listModel.add("jar");
+		this.listModel.add("jaz");
+		assertEquals(6, this.list.size());
+
+		this.verifyList(this.list, this.sortedListModel);
+		assertEquals(this.list, synchList);
+		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+	}
+
+	public void testRemoveItem() {
+		List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+		List<String> synchList = new CoordinatedList<String>(this.listModel);
+		this.listModel.add("foo");
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		this.listModel.add("joo");
+		this.listModel.add("jar");
+		this.listModel.add("jaz");
+		this.listModel.remove("jaz");
+		assertFalse(this.list.contains("jaz"));
+		this.listModel.remove("foo");
+		assertFalse(this.list.contains("foo"));
+		assertEquals(4, this.list.size());
+
+		this.verifyList(this.list, this.sortedListModel);
+		assertEquals(this.list, synchList);
+		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+	}
+
+	public void testReplaceItem() {
+		List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+		List<String> synchList = new CoordinatedList<String>(this.listModel);
+		this.listModel.add("foo");
+		assertTrue(this.list.contains("foo"));
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		this.listModel.add("joo");
+		this.listModel.add("jar");
+		this.listModel.add("jaz");
+		assertEquals(6, this.list.size());
+		this.listModel.set(3, "ttt");
+		this.listModel.set(4, "xxx");
+		assertTrue(this.list.contains("xxx"));
+
+		this.verifyList(this.list, this.sortedListModel);
+		assertEquals(this.list, synchList);
+		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+	}
+
+	public void testListSynch() {
+		this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent e) {/* OK */}
+			@Override
+			public void itemsRemoved(ListRemoveEvent e) {/* OK */}
+			@Override
+			public void itemsReplaced(ListReplaceEvent e) {/* OK */}
+		});
+		this.listModel.add("foo");
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		this.listModel.add("joo");
+		this.listModel.add("jar");
+		this.listModel.add("jaz");
+		this.listModel.remove("jaz");
+		assertFalse(this.list.contains("jaz"));
+		this.listModel.remove("foo");
+		assertFalse(this.list.contains("foo"));
+		assertEquals(4, this.list.size());
+
+		this.verifyList(this.list, this.sortedListModel);
+	}
+
+	public void testSetComparator() {
+		List<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+		List<String> synchList = new CoordinatedList<String>(this.listModel);
+		this.listModel.add("foo");
+		assertTrue(this.list.contains("foo"));
+		this.listModel.add("bar");
+		this.listModel.add("baz");
+		this.listModel.add("joo");
+		this.listModel.add("jar");
+		this.listModel.add("jaz");
+		assertEquals(6, this.list.size());
+
+		this.verifyList(this.list, this.sortedListModel);
+		assertEquals(this.list, synchList);
+		assertEquals(ListTools.list(this.sortedListModel), sortedSynchList);
+
+		this.sortedListModel.setComparator(new ReverseComparator<String>());
+		this.verifyList(this.list, this.sortedListModel, new ReverseComparator<String>());
+		assertEquals(this.list, synchList);
+	}
+
+	public void testHasListeners() {
+		assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		CoordinatedList<String> sortedSynchList = new CoordinatedList<String>(this.sortedListModel);
+		assertTrue(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.sortedListModel.removeListChangeListener(ListValueModel.LIST_VALUES, sortedSynchList);
+		assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		ChangeListener cl = new ChangeAdapter();
+		this.sortedListModel.addChangeListener(cl);
+		assertTrue(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.sortedListModel.removeChangeListener(cl);
+		assertFalse(((AbstractModel) this.sortedListModel).hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	public void testListChange() {
+		this.listModel.add("fred");
+		this.sortedListModel.addListChangeListener(ListValueModel.LIST_VALUES, new TestListChangeListener() {
+			@Override
+			public void listChanged(ListChangeEvent e) {/* OK */}
+		});
+		this.listModel.setListValues(Arrays.asList(new String[] {"foo", "bar", "baz"}));
+		assertEquals(3, this.sortedListModel.size());
+		this.verifyList(this.list, this.sortedListModel);
+	}
+
+	class TestListChangeListener implements ListChangeListener {
+		@Override
+		public void itemsAdded(ListAddEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsRemoved(ListRemoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsReplaced(ListReplaceEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void itemsMoved(ListMoveEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listCleared(ListClearEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void listChanged(ListChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
index d257def..3597486 100644
--- a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/UtilityModelValueTests.java
@@ -16,7 +16,7 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.eclipse.persistence.tools.utility.tests.model.value.prefs.UtilityModelValuePrefsTests;
-//import org.eclipse.persistence.tools.utility.tests.model.value.swing.UtilityModelValueSwingTests;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.UtilityModelValueSwingTests;
 
 public class UtilityModelValueTests {
 
@@ -24,42 +24,42 @@
 		TestSuite suite = new TestSuite(UtilityModelValueTests.class.getPackage().getName());
 
 		suite.addTest(UtilityModelValuePrefsTests.suite());
-//		suite.addTest(UtilityModelValueSwingTests.suite());
+		suite.addTest(UtilityModelValueSwingTests.suite());
 
 		suite.addTestSuite(BufferedModifiablePropertyValueModelTests.class);
 		suite.addTestSuite(CachingTransformationPropertyValueModelTests.class);
 		suite.addTestSuite(CollectionAspectAdapterTests.class);
-//		suite.addTestSuite(CollectionListValueModelAdapterTests.class);
+		suite.addTestSuite(CollectionListValueModelAdapterTests.class);
 		suite.addTestSuite(CollectionPropertyValueModelAdapterTests.class);
 		suite.addTestSuite(CompositeBooleanPropertyValueModelTests.class);
 		suite.addTestSuite(CompositeCollectionValueModelTests.class);
-//		suite.addTestSuite(CompositeListValueModelTests.class);
+		suite.addTestSuite(CompositeListValueModelTests.class);
 		suite.addTestSuite(CompositePropertyValueModelTests.class);
 		suite.addTestSuite(DoubleModifiablePropertyValueModelTests.class);
 		suite.addTestSuite(DoublePropertyValueModelTests.class);
 		suite.addTestSuite(ExtendedListValueModelWrapperTests.class);
 		suite.addTestSuite(FilteringCollectionValueModelTests.class);
 		suite.addTestSuite(FilteringPropertyValueModelTests.class);
-//		suite.addTestSuite(ItemCollectionListValueModelAdapterTests.class);
-//		suite.addTestSuite(ItemListListValueModelAdapterTests.class);
-//		suite.addTestSuite(ItemPropertyListValueModelAdapterTests.class);
-//		suite.addTestSuite(ItemStateListValueModelAdapterTests.class);
+		suite.addTestSuite(ItemCollectionListValueModelAdapterTests.class);
+		suite.addTestSuite(ItemListListValueModelAdapterTests.class);
+		suite.addTestSuite(ItemPropertyListValueModelAdapterTests.class);
+		suite.addTestSuite(ItemStateListValueModelAdapterTests.class);
 		suite.addTestSuite(ListAspectAdapterTests.class);
-//		suite.addTestSuite(ListCollectionValueModelAdapterTests.class);
+		suite.addTestSuite(ListCollectionValueModelAdapterTests.class);
 		suite.addTestSuite(ListCuratorTests.class);
 		suite.addTestSuite(NullCollectionValueModelTests.class);
 		suite.addTestSuite(NullListValueModelTests.class);
 		suite.addTestSuite(NullPropertyValueModelTests.class);
 		suite.addTestSuite(PropertyAspectAdapterTests.class);
 		suite.addTestSuite(PropertyCollectionValueModelAdapterTests.class);
-//		suite.addTestSuite(PropertyListValueModelAdapterTests.class);
+		suite.addTestSuite(PropertyListValueModelAdapterTests.class);
 		suite.addTestSuite(ReadOnlyModifiablePropertyValueModelWrapperTests.class);
 		suite.addTestSuite(SetCollectionValueModelTests.class);
 		suite.addTestSuite(SimpleCollectionValueModelTests.class);
 		suite.addTestSuite(SimpleListValueModelTests.class);
 		suite.addTestSuite(SimplePropertyValueModelTests.class);
-//		suite.addTestSuite(SortedListValueModelAdapterTests.class);
-//		suite.addTestSuite(SortedListValueModelWrapperTests.class);
+		suite.addTestSuite(SortedListValueModelAdapterTests.class);
+		suite.addTestSuite(SortedListValueModelWrapperTests.class);
 		suite.addTestSuite(StaticCollectionValueModelTests.class);
 		suite.addTestSuite(StaticListValueModelTests.class);
 		suite.addTestSuite(StaticValueModelTests.class);
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java
new file mode 100644
index 0000000..fc99c76
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterTests.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ButtonModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class CheckBoxModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Boolean> booleanHolder;
+	private ButtonModel buttonModelAdapter;
+	boolean eventFired;
+
+	public CheckBoxModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.booleanHolder = new SimplePropertyValueModel<Boolean>(Boolean.TRUE);
+		this.buttonModelAdapter = new CheckBoxModelAdapter(this.booleanHolder) {
+			@Override
+			protected PropertyChangeListener buildBooleanChangeListener() {
+				return this.buildBooleanChangeListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetSelected() throws Exception {
+		this.eventFired = false;
+		this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				CheckBoxModelAdapterTests.this.eventFired = true;
+			}
+		});
+		this.buttonModelAdapter.setSelected(false);
+		assertTrue(this.eventFired);
+		assertEquals(Boolean.FALSE, this.booleanHolder.getValue());
+	}
+
+	public void testSetValue() throws Exception {
+		this.eventFired = false;
+		this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				CheckBoxModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertTrue(this.buttonModelAdapter.isSelected());
+		this.booleanHolder.setValue(Boolean.FALSE);
+		assertTrue(this.eventFired);
+		assertFalse(this.buttonModelAdapter.isSelected());
+	}
+
+	public void testDefaultValue() throws Exception {
+		this.eventFired = false;
+		this.buttonModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				CheckBoxModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertTrue(this.buttonModelAdapter.isSelected());
+		this.booleanHolder.setValue(null);
+		assertTrue(this.eventFired);
+		assertFalse(this.buttonModelAdapter.isSelected());
+
+		this.eventFired = false;
+		this.booleanHolder.setValue(Boolean.FALSE);
+		assertFalse(this.eventFired);
+		assertFalse(this.buttonModelAdapter.isSelected());
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Boolean> localBooleanHolder = (SimplePropertyValueModel<Boolean>) this.booleanHolder;
+		assertFalse(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.buttonModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.buttonModelAdapter.addChangeListener(listener);
+		assertTrue(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.buttonModelAdapter);
+
+		this.buttonModelAdapter.removeChangeListener(listener);
+		assertFalse(localBooleanHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.buttonModelAdapter);
+	}
+
+	private void verifyHasNoListeners(Object model) throws Exception {
+		EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+		assertEquals(0, listenerList.getListenerList().length);
+	}
+
+	private void verifyHasListeners(Object model) throws Exception {
+		EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+		assertFalse(listenerList.getListenerList().length == 0);
+	}
+
+
+	// ********** member class **********
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java
new file mode 100644
index 0000000..18210e8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/CheckBoxModelAdapterUITest.java
@@ -0,0 +1,322 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+
+/**
+ * Play around with a set of check boxes.
+ */
+@SuppressWarnings("nls")
+public class CheckBoxModelAdapterUITest {
+
+	private TestModel testModel;
+	private ModifiablePropertyValueModel<TestModel> testModelHolder;
+	private ModifiablePropertyValueModel<Boolean> flag1Holder;
+	private ModifiablePropertyValueModel<Boolean> flag2Holder;
+	private ModifiablePropertyValueModel<Boolean> notFlag2Holder;
+	private ButtonModel flag1ButtonModel;
+	private ButtonModel flag2ButtonModel;
+	private ButtonModel notFlag2ButtonModel;
+
+	public static void main(String[] args) throws Exception {
+		new CheckBoxModelAdapterUITest().exec();
+	}
+
+	private CheckBoxModelAdapterUITest() {
+		super();
+	}
+
+	private void exec() throws Exception {
+		this.testModel = new TestModel(true, true);
+		this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+		this.flag1Holder = this.buildFlag1Holder(this.testModelHolder);
+		this.flag1ButtonModel = this.buildCheckBoxModelAdapter(this.flag1Holder);
+		this.flag2Holder = this.buildFlag2Holder(this.testModelHolder);
+		this.flag2ButtonModel = this.buildCheckBoxModelAdapter(this.flag2Holder);
+		this.notFlag2Holder = this.buildNotFlag2Holder(this.testModelHolder);
+		this.notFlag2ButtonModel = this.buildCheckBoxModelAdapter(this.notFlag2Holder);
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<Boolean> buildFlag1Holder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.FLAG1_PROPERTY) {
+			@Override
+			protected Boolean buildValue_() {
+				return Boolean.valueOf(this.subject.isFlag1());
+			}
+			@Override
+			protected void setValue_(Boolean value) {
+				this.subject.setFlag1(value.booleanValue());
+			}
+		};
+	}
+
+	private ModifiablePropertyValueModel<Boolean> buildFlag2Holder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.FLAG2_PROPERTY) {
+			@Override
+			protected Boolean buildValue_() {
+				return Boolean.valueOf(this.subject.isFlag2());
+			}
+			@Override
+			protected void setValue_(Boolean value) {
+				this.subject.setFlag2(value.booleanValue());
+			}
+		};
+	}
+
+	private ModifiablePropertyValueModel<Boolean> buildNotFlag2Holder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Boolean>(vm, TestModel.NOT_FLAG2_PROPERTY) {
+			@Override
+			protected Boolean buildValue_() {
+				return Boolean.valueOf(this.subject.isNotFlag2());
+			}
+			@Override
+			protected void setValue_(Boolean value) {
+				this.subject.setNotFlag2(value.booleanValue());
+			}
+		};
+	}
+
+	private ButtonModel buildCheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+		return new CheckBoxModelAdapter(booleanHolder);
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setSize(400, 100);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildCheckBoxPanel(), BorderLayout.NORTH);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildCheckBoxPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildFlag1CheckBox());
+		taskListPanel.add(this.buildFlag2CheckBox());
+		taskListPanel.add(this.buildNotFlag2CheckBox());
+		taskListPanel.add(this.buildUnattachedCheckBox());
+		return taskListPanel;
+	}
+
+	private JCheckBox buildFlag1CheckBox() {
+		JCheckBox checkBox = new JCheckBox();
+		checkBox.setText("flag 1");
+		checkBox.setModel(this.flag1ButtonModel);
+		return checkBox;
+	}
+
+	private JCheckBox buildFlag2CheckBox() {
+		JCheckBox checkBox = new JCheckBox();
+		checkBox.setText("flag 2");
+		checkBox.setModel(this.flag2ButtonModel);
+		return checkBox;
+	}
+
+	private JCheckBox buildNotFlag2CheckBox() {
+		JCheckBox checkBox = new JCheckBox();
+		checkBox.setText("not flag 2");
+		checkBox.setModel(this.notFlag2ButtonModel);
+		return checkBox;
+	}
+
+	private JCheckBox buildUnattachedCheckBox() {
+		JCheckBox checkBox = new JCheckBox("unattached");
+		checkBox.getModel().addItemListener(this.buildUnattachedItemListener());
+		return checkBox;
+	}
+
+	private ItemListener buildUnattachedItemListener() {
+		return new ItemListener() {
+			@Override
+			public void itemStateChanged(ItemEvent e) {
+				System.out.println("unattached state changed: " + e);
+			}
+		};
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+		controlPanel.add(this.buildFlipFlag1Button());
+		controlPanel.add(this.buildClearModelButton());
+		controlPanel.add(this.buildRestoreModelButton());
+		controlPanel.add(this.buildPrintModelButton());
+		return controlPanel;
+	}
+
+	private JButton buildFlipFlag1Button() {
+		return new JButton(this.buildFlipFlag1Action());
+	}
+
+	private Action buildFlipFlag1Action() {
+		Action action = new AbstractAction("flip flag 1") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				CheckBoxModelAdapterUITest.this.flipFlag1();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void flipFlag1() {
+		this.testModel.setFlag1( ! this.testModel.isFlag1());
+	}
+
+	private JButton buildClearModelButton() {
+		return new JButton(this.buildClearModelAction());
+	}
+
+	private Action buildClearModelAction() {
+		Action action = new AbstractAction("clear model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				CheckBoxModelAdapterUITest.this.clearModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void clearModel() {
+		this.testModelHolder.setValue(null);
+	}
+
+	private JButton buildRestoreModelButton() {
+		return new JButton(this.buildRestoreModelAction());
+	}
+
+	private Action buildRestoreModelAction() {
+		Action action = new AbstractAction("restore model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				CheckBoxModelAdapterUITest.this.restoreModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void restoreModel() {
+		this.testModelHolder.setValue(this.testModel);
+	}
+
+	private JButton buildPrintModelButton() {
+		return new JButton(this.buildPrintModelAction());
+	}
+
+	private Action buildPrintModelAction() {
+		Action action = new AbstractAction("print model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				CheckBoxModelAdapterUITest.this.printModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printModel() {
+		System.out.println("flag 1: " + this.testModel.isFlag1());
+		System.out.println("flag 2: " + this.testModel.isFlag2());
+		System.out.println("not flag 2: " + this.testModel.isNotFlag2());
+		System.out.println("***");
+	}
+
+
+	private class TestModel extends AbstractModel {
+		private boolean flag1;
+			public static final String FLAG1_PROPERTY = "flag1";
+		private boolean flag2;
+			public static final String FLAG2_PROPERTY = "flag2";
+		private boolean notFlag2;
+			public static final String NOT_FLAG2_PROPERTY = "notFlag2";
+
+		public TestModel(boolean flag1, boolean flag2) {
+			this.flag1 = flag1;
+			this.flag2 = flag2;
+			this.notFlag2 = ! flag2;
+		}
+		public boolean isFlag1() {
+			return this.flag1;
+		}
+		public void setFlag1(boolean flag1) {
+			boolean old = this.flag1;
+			this.flag1 = flag1;
+			this.firePropertyChanged(FLAG1_PROPERTY, old, flag1);
+		}
+		public boolean isFlag2() {
+			return this.flag2;
+		}
+		public void setFlag2(boolean flag2) {
+			boolean old = this.flag2;
+			this.flag2 = flag2;
+			this.firePropertyChanged(FLAG2_PROPERTY, old, flag2);
+
+			old = this.notFlag2;
+			this.notFlag2 = ! flag2;
+			this.firePropertyChanged(NOT_FLAG2_PROPERTY, old, this.notFlag2);
+		}
+		public boolean isNotFlag2() {
+			return this.notFlag2;
+		}
+		public void setNotFlag2(boolean notFlag2) {
+			this.setFlag2( ! notFlag2);
+		}
+		@Override
+		public String toString() {
+			return "TestModel(" + this.isFlag1() + " - " + this.isFlag2() + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java
new file mode 100644
index 0000000..65e3bf1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterTests.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import javax.swing.ComboBoxModel;
+import javax.swing.ListModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+import org.eclipse.persistence.tools.utility.tests.model.SimpleDisplayable;
+import org.eclipse.persistence.tools.utility.tests.model.value.CoordinatedList;
+
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterTests extends TestCase {
+
+	public ComboBoxModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		// nothing yet...
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		// nothing yet...
+		super.tearDown();
+	}
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<Displayable> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		SimplePropertyValueModel<Object> selectionHolder = new SimplePropertyValueModel<Object>(listHolder.iterator().next());
+		assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+
+		ComboBoxModel comboBoxModel = new ComboBoxModelAdapter(listHolder, selectionHolder);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(comboBoxModel);
+
+		CoordinatedList<Displayable> synchList = new CoordinatedList<Displayable>(comboBoxModel);
+		PropertyChangeListener selectionListener = this.buildSelectionListener();
+		selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, selectionListener);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(comboBoxModel);
+
+		comboBoxModel.removeListDataListener(synchList);
+		selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, selectionListener);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertFalse(selectionHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(comboBoxModel);
+	}
+
+	private PropertyChangeListener buildSelectionListener() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent evt) {
+				// do nothing...
+			}
+		};
+	}
+
+	private void verifyHasNoListeners(ListModel listModel) throws Exception {
+		boolean hasNoListeners = ((Boolean) ObjectTools.execute(listModel, "hasNoListDataListeners")).booleanValue();
+		assertTrue(hasNoListeners);
+	}
+
+	private void verifyHasListeners(ListModel listModel) throws Exception {
+		boolean hasListeners = ((Boolean) ObjectTools.execute(listModel, "hasListDataListeners")).booleanValue();
+		assertTrue(hasListeners);
+	}
+
+	private SimpleListValueModel<Displayable> buildListHolder() {
+		return new SimpleListValueModel<Displayable>(this.buildList());
+	}
+
+	private List<Displayable> buildList() {
+		List<Displayable> list = new ArrayList<Displayable>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<Displayable> c) {
+		c.add(new SimpleDisplayable("foo"));
+		c.add(new SimpleDisplayable("bar"));
+		c.add(new SimpleDisplayable("baz"));
+		c.add(new SimpleDisplayable("joo"));
+		c.add(new SimpleDisplayable("jar"));
+		c.add(new SimpleDisplayable("jaz"));
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java
new file mode 100644
index 0000000..a601008
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest.java
@@ -0,0 +1,400 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ComboBoxModel;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.swing.FilteringListBrowser;
+import org.eclipse.persistence.tools.utility.swing.ListChooser;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+
+
+/**
+ * Play around with a set of combo-boxes.
+ *
+ * DefaultLongListBrowserDialogUITest subclasses this class; so be
+ * careful when making changes.
+ */
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterUITest {
+
+	protected JFrame window;
+	private TestModel testModel;
+	private ModifiablePropertyValueModel<TestModel> testModelHolder;
+	private ModifiablePropertyValueModel<Object> colorHolder;
+	private SimpleListValueModel<String> colorListHolder;
+	protected ComboBoxModel colorComboBoxModel;
+	private int nextColorNumber = 0;
+
+	public static void main(String[] args) throws Exception {
+		new ComboBoxModelAdapterUITest().exec();
+	}
+
+	protected ComboBoxModelAdapterUITest() {
+		super();
+	}
+
+	protected void exec() throws Exception {
+		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+//		UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());	// Metal LAF
+//		UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel.class.getName());
+//		UIManager.setLookAndFeel(com.sun.java.swing.plaf.motif.MotifLookAndFeel.class.getName());
+//		UIManager.setLookAndFeel(oracle.bali.ewt.olaf.OracleLookAndFeel.class.getName());
+		this.testModel = this.buildTestModel();
+		this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+		this.colorHolder = this.buildColorHolder(this.testModelHolder);
+		this.colorListHolder = this.buildColorListHolder();
+		this.colorComboBoxModel = this.buildComboBoxModelAdapter(this.colorListHolder, this.colorHolder);
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<Object> buildColorHolder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.COLOR_PROPERTY) {
+			@Override
+			protected String buildValue_() {
+				return this.subject.getColor();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setColor((String) value);
+			}
+		};
+	}
+
+	protected TestModel buildTestModel() {
+		return new TestModel();
+	}
+
+	private SimpleListValueModel<String> buildColorListHolder() {
+		return new SimpleListValueModel<String>(TestModel.validColors());
+//		return new AbstractReadOnlyListValueModel() {
+//			public Object value() {
+//				return new ArrayListIterator(TestModel.VALID_COLORS);
+//			}
+//			public int size() {
+//				return TestModel.VALID_COLORS.length;
+//			}
+//		};
+	}
+
+	protected ListValueModel<String> uiColorListHolder() {
+		return this.colorListHolder;
+	}
+
+	private ComboBoxModel buildComboBoxModelAdapter(ListValueModel<String> listHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+		return new ComboBoxModelAdapter(listHolder, selectionHolder);
+	}
+
+	private void openWindow() {
+		this.window = new JFrame(this.getClass().getSimpleName());
+		this.window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		this.window.addWindowListener(this.buildWindowListener());
+		this.window.getContentPane().add(this.buildMainPanel(), "Center");
+		this.window.setLocation(300, 300);
+		this.window.setSize(400, 150);
+		this.window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildComboBoxPanel(), BorderLayout.NORTH);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	protected JPanel buildComboBoxPanel() {
+		JPanel panel = new JPanel(new GridLayout(1, 0));
+		panel.add(this.buildComboBox());
+		panel.add(this.buildComboBox());
+		panel.add(this.buildListChooser1());
+		panel.add(this.buildListChooser2());
+		return panel;
+	}
+
+	private JComboBox buildComboBox() {
+		JComboBox comboBox = new JComboBox(this.colorComboBoxModel);
+		comboBox.setRenderer(this.buildComboBoxRenderer());
+		return comboBox;
+	}
+
+	protected ListCellRenderer buildComboBoxRenderer() {
+		return new SimpleListCellRenderer() {
+			@Override
+			protected String buildText(Object value) {
+				return super.buildText(value);
+			}
+		};
+	}
+
+	private ListChooser buildListChooser1() {
+		return new LocalListChooser1(this.colorComboBoxModel);
+	}
+
+	private ListChooser buildListChooser2() {
+		return new LocalListChooser2(this.colorComboBoxModel);
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(2, 0));
+		controlPanel.add(this.buildResetColorButton());
+		controlPanel.add(this.buildClearModelButton());
+		controlPanel.add(this.buildRestoreModelButton());
+		controlPanel.add(this.buildPrintModelButton());
+		controlPanel.add(this.buildAddTenButton());
+		controlPanel.add(this.buildRemoveTenButton());
+		return controlPanel;
+	}
+
+	// ********** reset color button **********
+	private JButton buildResetColorButton() {
+		return new JButton(this.buildResetColorAction());
+	}
+
+	private Action buildResetColorAction() {
+		Action action = new AbstractAction("reset color") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.resetColor();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void resetColor() {
+		this.testModel.setColor(TestModel.DEFAULT_COLOR);
+	}
+
+	// ********** clear model button **********
+	private JButton buildClearModelButton() {
+		return new JButton(this.buildClearModelAction());
+	}
+
+	private Action buildClearModelAction() {
+		Action action = new AbstractAction("clear model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.clearModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void clearModel() {
+		this.testModelHolder.setValue(null);
+	}
+
+	// ********** restore model button **********
+	private JButton buildRestoreModelButton() {
+		return new JButton(this.buildRestoreModelAction());
+	}
+
+	private Action buildRestoreModelAction() {
+		Action action = new AbstractAction("restore model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.restoreModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void restoreModel() {
+		this.testModelHolder.setValue(this.testModel);
+	}
+
+	// ********** print model button **********
+	private JButton buildPrintModelButton() {
+		return new JButton(this.buildPrintModelAction());
+	}
+
+	private Action buildPrintModelAction() {
+		Action action = new AbstractAction("print model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.printModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printModel() {
+		System.out.println(this.testModel);
+	}
+
+	// ********** add 20 button **********
+	private JButton buildAddTenButton() {
+		return new JButton(this.buildAddTenAction());
+	}
+
+	private Action buildAddTenAction() {
+		Action action = new AbstractAction("add 20") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.addTen();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void addTen() {
+		for (int i = this.nextColorNumber; i < this.nextColorNumber + 20; i++) {
+			this.colorListHolder.add(this.colorListHolder.size(), "color" + i);
+		}
+		this.nextColorNumber += 20;
+	}
+
+	// ********** remove 20 button **********
+	private JButton buildRemoveTenButton() {
+		return new JButton(this.buildRemoveTenAction());
+	}
+
+	private Action buildRemoveTenAction() {
+		Action action = new AbstractAction("remove 20") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ComboBoxModelAdapterUITest.this.removeTen();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void removeTen() {
+		for (int i = 0; i < 20; i++) {
+			if (this.colorListHolder.size() > 0) {
+				this.colorListHolder.remove(this.colorListHolder.size() - 1);
+			}
+		}
+	}
+
+
+	protected static class TestModel extends AbstractModel {
+		private String color;
+			public static final String COLOR_PROPERTY = "color";
+			public static final String RED = "red";
+			public static final String ORANGE = "orange";
+			public static final String YELLOW = "yellow";
+			public static final String GREEN = "green";
+			public static final String BLUE = "blue";
+			public static final String INDIGO = "indigo";
+			public static final String VIOLET = "violet";
+			public static final String DEFAULT_COLOR = RED;
+			public static List<String> validColors;
+			public static final String[] DEFAULT_VALID_COLORS = {
+				RED,
+				ORANGE,
+				YELLOW,
+				GREEN,
+				BLUE,
+				INDIGO,
+				VIOLET
+			};
+
+		public static List<String> validColors() {
+			if (validColors == null) {
+				validColors = buildDefaultValidColors();
+			}
+			return validColors;
+		}
+		public static List<String> buildDefaultValidColors() {
+			List<String> result = new ArrayList<String>();
+			CollectionTools.addAll(result, DEFAULT_VALID_COLORS);
+			return result;
+		}
+
+		public TestModel() {
+			this(DEFAULT_COLOR);
+		}
+		public TestModel(String color) {
+			this.color = color;
+		}
+		public String getColor() {
+			return this.color;
+		}
+		public void setColor(String color) {
+			this.checkColor(color);
+			Object old = this.color;
+			this.color = color;
+			this.firePropertyChanged(COLOR_PROPERTY, old, color);
+		}
+		public void checkColor(String c) {
+			if ( ! validColors().contains(c)) {
+				throw new IllegalArgumentException(c);
+			}
+		}
+		@Override
+		public String toString() {
+			return "TestModel(" + this.color + ")";
+		}
+	}
+
+
+	private class LocalListChooser1 extends ListChooser {
+		public LocalListChooser1(ComboBoxModel model) {
+			super(model);
+		}
+	}
+
+
+	private class LocalListChooser2 extends ListChooser {
+		public LocalListChooser2(ComboBoxModel model) {
+			super(model);
+		}
+		@Override
+		protected ListBrowser buildBrowser() {
+			return new FilteringListBrowser<String>();
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java
new file mode 100644
index 0000000..89b29fb
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ComboBoxModelAdapterUITest2.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ListCellRenderer;
+import org.eclipse.persistence.tools.utility.model.value.ExtendedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapterUITest2 extends ComboBoxModelAdapterUITest {
+
+	public static void main(String[] args) throws Exception {
+		new ComboBoxModelAdapterUITest2().exec();
+	}
+
+	public ComboBoxModelAdapterUITest2() {
+		super();
+	}
+
+	/**
+	 * use a different model that allows the color to be set to null
+	 */
+	@Override
+	protected TestModel buildTestModel() {
+		return new TestModel2();
+	}
+
+	/**
+	 * add a null to the front of the list
+	 */
+	@Override
+	protected ListValueModel<String> uiColorListHolder() {
+		// the default is to prepend the wrapped list with a null item
+		return new ExtendedListValueModelWrapper<String>(super.uiColorListHolder());
+	}
+
+	/**
+	 * convert null to some text
+	 */
+	@Override
+	protected ListCellRenderer buildComboBoxRenderer() {
+		return new SimpleListCellRenderer() {
+			@Override
+			protected String buildText(Object value) {
+				return (value == null) ? "<none selected>" : super.buildText(value);
+			}
+		};
+	}
+
+
+	protected static class TestModel2 extends TestModel {
+		/**
+		 * null is OK here
+		 */
+		@Override
+		public void checkColor(String color) {
+			if (color == null) {
+				return;
+			}
+			super.checkColor(color);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..3c5f408
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DateSpinnerModelAdapterTests.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.Date;
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class DateSpinnerModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Object> valueHolder;
+	private SpinnerModel spinnerModelAdapter;
+	boolean eventFired;
+
+	public DateSpinnerModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.valueHolder = new SimplePropertyValueModel<Object>(new Date());
+		this.spinnerModelAdapter = new DateSpinnerModelAdapter(this.valueHolder) {
+			@Override
+			protected PropertyChangeListener buildDateChangeListener() {
+				return this.buildDateChangeListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetValueSpinnerModel() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				DateSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		Date newDate = new Date();
+		newDate.setTime(777777);
+		this.spinnerModelAdapter.setValue(newDate);
+		assertTrue(this.eventFired);
+		assertEquals(777777, ((Date) this.valueHolder.getValue()).getTime());
+	}
+
+	public void testSetValueValueHolder() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				DateSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		Date newDate = new Date();
+		newDate.setTime(777777);
+		this.valueHolder.setValue(newDate);
+		assertTrue(this.eventFired);
+		assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+	}
+
+	public void testDefaultValue() throws Exception {
+		Date newDate = new Date();
+		newDate.setTime(777777);
+		this.valueHolder.setValue(newDate);
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				DateSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+		this.valueHolder.setValue(null);
+		assertTrue(this.eventFired);
+		assertFalse(((Date) this.spinnerModelAdapter.getValue()).getTime() == 777777);
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.spinnerModelAdapter.addChangeListener(listener);
+		assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.spinnerModelAdapter);
+
+		this.spinnerModelAdapter.removeChangeListener(listener);
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+	}
+
+	private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+		assertEquals(0, ((DateSpinnerModelAdapter) adapter).getChangeListeners().length);
+	}
+
+	private void verifyHasListeners(Object adapter) throws Exception {
+		assertFalse(((DateSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+	}
+
+	public void testNullInitialValue() {
+		Date today = new Date();
+		this.valueHolder = new SimplePropertyValueModel<Object>();
+		this.spinnerModelAdapter = new DateSpinnerModelAdapter(this.valueHolder, today) {
+			@Override
+			protected PropertyChangeListener buildDateChangeListener() {
+				return this.buildDateChangeListener_();
+			}
+		};
+
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				DateSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(today, this.spinnerModelAdapter.getValue());
+
+		Date newDate = new Date();
+		newDate.setTime(777777);
+		this.valueHolder.setValue(newDate);
+
+		assertTrue(this.eventFired);
+		assertEquals(777777, ((Date) this.spinnerModelAdapter.getValue()).getTime());
+	}
+
+
+	// ********** inner class **********
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java
new file mode 100644
index 0000000..8b51181
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterTests.java
@@ -0,0 +1,165 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentEvent.EventType;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.Document;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class DocumentAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<String> stringHolder;
+	Document documentAdapter;
+	boolean eventFired;
+
+	public DocumentAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.stringHolder = new SimplePropertyValueModel<String>("0123456789");
+		this.documentAdapter = new DocumentAdapter(this.stringHolder) {
+			@Override
+			protected PropertyChangeListener buildStringListener() {
+				return this.buildStringListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testRemove() throws Exception {
+		this.eventFired = false;
+		this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+			@Override
+			public void removeUpdate(DocumentEvent e) {
+				DocumentAdapterTests.this.eventFired = true;
+				assertEquals(EventType.REMOVE, e.getType());
+				assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+				// this will be the removal of "23456"
+				assertEquals(2, e.getOffset());
+				assertEquals(5, e.getLength());
+			}
+		});
+		this.documentAdapter.remove(2, 5);
+		assertTrue(this.eventFired);
+		assertEquals("01789", this.stringHolder.getValue());
+	}
+
+	public void testInsert() throws Exception {
+		this.eventFired = false;
+		this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+			@Override
+			public void insertUpdate(DocumentEvent e) {
+				DocumentAdapterTests.this.eventFired = true;
+				assertEquals(EventType.INSERT, e.getType());
+				assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+				// this will be the insert of "xxxxxx"
+				assertEquals(2, e.getOffset());
+				assertEquals(5, e.getLength());
+			}
+		});
+		this.documentAdapter.insertString(2, "xxxxx", null);
+		assertTrue(this.eventFired);
+		assertEquals("01xxxxx23456789", this.stringHolder.getValue());
+	}
+
+	public void testSetValue() throws Exception {
+		this.eventFired = false;
+		this.documentAdapter.addDocumentListener(new TestDocumentListener() {
+			@Override
+			public void insertUpdate(DocumentEvent e) {
+				DocumentAdapterTests.this.eventFired = true;
+				assertEquals(EventType.INSERT, e.getType());
+				assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+				// this will be the insert of "foo"
+				assertEquals(0, e.getOffset());
+				assertEquals(3, e.getLength());
+			}
+			@Override
+			public void removeUpdate(DocumentEvent e) {
+				assertEquals(EventType.REMOVE, e.getType());
+				assertEquals(DocumentAdapterTests.this.documentAdapter, e.getDocument());
+				// this will be the removal of "0123456789"
+				assertEquals(0, e.getOffset());
+				assertEquals(10, e.getLength());
+			}
+		});
+		assertEquals("0123456789", this.documentAdapter.getText(0, this.documentAdapter.getLength()));
+		this.stringHolder.setValue("foo");
+		assertTrue(this.eventFired);
+		assertEquals("foo", this.documentAdapter.getText(0, this.documentAdapter.getLength()));
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<String> localStringHolder = (SimplePropertyValueModel<String>) this.stringHolder;
+		assertFalse(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.documentAdapter);
+
+		DocumentListener listener = new TestDocumentListener();
+		this.documentAdapter.addDocumentListener(listener);
+		assertTrue(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.documentAdapter);
+
+		this.documentAdapter.removeDocumentListener(listener);
+		assertFalse(localStringHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.documentAdapter);
+	}
+
+	private void verifyHasNoListeners(Object document) throws Exception {
+		Object delegate = ObjectTools.get(document, "delegate");
+		Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getDocumentListeners");
+		assertEquals(0, listeners.length);
+	}
+
+	private void verifyHasListeners(Object document) throws Exception {
+		Object delegate = ObjectTools.get(document, "delegate");
+		Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getDocumentListeners");
+		assertFalse(listeners.length == 0);
+	}
+
+
+	private class TestDocumentListener implements DocumentListener {
+		TestDocumentListener() {
+			super();
+		}
+		@Override
+		public void changedUpdate(DocumentEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void insertUpdate(DocumentEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void removeUpdate(DocumentEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java
new file mode 100644
index 0000000..4c3b74e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/DocumentAdapterUITest.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.WindowConstants;
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.PlainDocument;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+
+/**
+ * Play around with a set of entry fields.
+ */
+@SuppressWarnings("nls")
+public class DocumentAdapterUITest {
+
+	private TestModel testModel;
+		private static final String DEFAULT_NAME = "Scooby Doo";
+	private ModifiablePropertyValueModel<TestModel> testModelHolder;
+	private ModifiablePropertyValueModel<String> nameHolder;
+	private Document nameDocument;
+	private Document upperCaseNameDocument;
+
+	public static void main(String[] args) throws Exception {
+		new DocumentAdapterUITest().exec();
+	}
+
+	private DocumentAdapterUITest() {
+		super();
+	}
+
+	private void exec() throws Exception {
+		this.testModel = new TestModel(DEFAULT_NAME);
+		this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+		this.nameHolder = this.buildNameHolder(this.testModelHolder);
+		this.nameDocument = this.buildNameDocument(this.nameHolder);
+		this.upperCaseNameDocument = this.buildUpperCaseNameDocument(this.nameHolder);
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<String> buildNameHolder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, String>(vm, TestModel.NAME_PROPERTY) {
+			@Override
+			protected String buildValue_() {
+				return this.subject.getName();
+			}
+			@Override
+			protected void setValue_(String value) {
+				this.subject.setName(value);
+			}
+		};
+	}
+
+	private Document buildNameDocument(ModifiablePropertyValueModel<String> stringHolder) {
+		return new DocumentAdapter(stringHolder);
+	}
+
+	private Document buildUpperCaseNameDocument(ModifiablePropertyValueModel<String> stringHolder) {
+		return new DocumentAdapter(stringHolder, this.buildUpperCaseNameDocumentDelegate());
+	}
+
+	private AbstractDocument buildUpperCaseNameDocumentDelegate() {
+		return new PlainDocument() {
+			@Override
+			public void insertString(int offset, String string, AttributeSet a) throws BadLocationException {
+				if (string == null) {
+					return;
+				}
+				char[] upper = string.toCharArray();
+				for (int i = 0; i < upper.length; i++) {
+					upper[i] = Character.toUpperCase(upper[i]);
+				}
+				super.insertString(offset, new String(upper), a);
+			}
+		};
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setSize(400, 100);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildTextFieldPanel(), BorderLayout.NORTH);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildTextFieldPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildNameTextField());
+		taskListPanel.add(this.buildReadOnlyNameTextField());
+		taskListPanel.add(this.buildUpperCaseNameTextField());
+		return taskListPanel;
+	}
+
+	private JTextField buildNameTextField() {
+		return new JTextField(this.nameDocument, null, 0);
+	}
+
+	private JTextField buildReadOnlyNameTextField() {
+		JTextField nameTextField = this.buildNameTextField();
+		nameTextField.setEditable(false);
+		return nameTextField;
+	}
+
+	private JTextField buildUpperCaseNameTextField() {
+		return new JTextField(this.upperCaseNameDocument, null, 0);
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+		controlPanel.add(this.buildResetNameButton());
+		controlPanel.add(this.buildClearModelButton());
+		controlPanel.add(this.buildRestoreModelButton());
+		controlPanel.add(this.buildPrintModelButton());
+		return controlPanel;
+	}
+
+	private JButton buildResetNameButton() {
+		return new JButton(this.buildResetNameAction());
+	}
+
+	private Action buildResetNameAction() {
+		Action action = new AbstractAction("reset name") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				DocumentAdapterUITest.this.resetName();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void resetName() {
+		this.testModel.setName(DEFAULT_NAME);
+	}
+
+	private JButton buildClearModelButton() {
+		return new JButton(this.buildClearModelAction());
+	}
+
+	private Action buildClearModelAction() {
+		Action action = new AbstractAction("clear model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				DocumentAdapterUITest.this.clearModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void clearModel() {
+		this.testModelHolder.setValue(null);
+	}
+
+	private JButton buildRestoreModelButton() {
+		return new JButton(this.buildRestoreModelAction());
+	}
+
+	private Action buildRestoreModelAction() {
+		Action action = new AbstractAction("restore model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				DocumentAdapterUITest.this.restoreModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void restoreModel() {
+		this.testModelHolder.setValue(this.testModel);
+	}
+
+	private JButton buildPrintModelButton() {
+		return new JButton(this.buildPrintModelAction());
+	}
+
+	private Action buildPrintModelAction() {
+		Action action = new AbstractAction("print model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				DocumentAdapterUITest.this.printModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printModel() {
+		System.out.println("name: " + this.testModel.getName());
+	}
+
+
+	private class TestModel extends AbstractModel {
+		private String name;
+			public static final String NAME_PROPERTY = "name";
+
+		public TestModel(String name) {
+			this.name = name;
+		}
+		public String getName() {
+			return this.name;
+		}
+		public void setName(String name) {
+			Object old = this.name;
+			this.name = name;
+			this.firePropertyChanged(NAME_PROPERTY, old, name);
+		}
+		@Override
+		public String toString() {
+			return "TestModel(" + this.getName() + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java
new file mode 100644
index 0000000..ad6728e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterTests.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+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 javax.swing.ListModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.Bag;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.CoordinatedList;
+
+@SuppressWarnings("nls")
+public class ListModelAdapterTests extends TestCase {
+
+	public ListModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		// nothing yet...
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		// nothing yet...
+		super.tearDown();
+	}
+
+	private ListModelAdapter buildListModel(ListValueModel<String> listHolder) {
+		return new ListModelAdapter(listHolder) {
+			@Override
+			protected ListChangeListener buildListChangeListener() {
+				return this.buildListChangeListener_();
+			}
+		};
+	}
+
+	private ListModel buildListModel(CollectionValueModel<String> collectionHolder) {
+		return new ListModelAdapter(collectionHolder) {
+			@Override
+			protected ListChangeListener buildListChangeListener() {
+				return this.buildListChangeListener_();
+			}
+		};
+	}
+
+	public void testCollectionSynchronization() {
+		SimpleCollectionValueModel<String> collectionHolder = this.buildCollectionHolder();
+		ListModel listModel = this.buildListModel(collectionHolder);
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertEquals(6, synchList.size());
+		this.compare(listModel, synchList);
+
+		collectionHolder.add("tom");
+		collectionHolder.add("dick");
+		collectionHolder.add("harry");
+		collectionHolder.add(null);
+		assertEquals(10, synchList.size());
+		this.compare(listModel, synchList);
+
+		collectionHolder.remove("foo");
+		collectionHolder.remove("jar");
+		collectionHolder.remove("harry");
+		collectionHolder.remove(null);
+		assertEquals(6, synchList.size());
+		this.compare(listModel, synchList);
+	}
+
+	public void testListSynchronization() {
+		SimpleListValueModel<String> listHolder = this.buildListHolder();
+		ListModel listModel = this.buildListModel(listHolder);
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertEquals(6, synchList.size());
+		this.compare(listModel, synchList);
+
+		listHolder.add(6, "tom");
+		listHolder.add(7, "dick");
+		listHolder.add(8, "harry");
+		listHolder.add(9, null);
+		assertEquals(10, synchList.size());
+		this.compare(listModel, synchList);
+
+		listHolder.remove(9);
+		listHolder.remove(8);
+		listHolder.remove(4);
+		listHolder.remove(0);
+		assertEquals(6, synchList.size());
+		this.compare(listModel, synchList);
+	}
+
+	public void testSetModel() {
+		SimpleListValueModel<String> listHolder1 = this.buildListHolder();
+		ListModelAdapter listModel = this.buildListModel(listHolder1);
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertTrue(listHolder1.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		assertEquals(6, synchList.size());
+		this.compare(listModel, synchList);
+
+		SimpleListValueModel<String> listHolder2 = this.buildListHolder2();
+		listModel.setModel(listHolder2);
+		assertEquals(3, synchList.size());
+		this.compare(listModel, synchList);
+		assertTrue(listHolder1.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(listHolder2.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		listModel.setModel(new SimpleListValueModel<String>());
+		assertEquals(0, synchList.size());
+		this.compare(listModel, synchList);
+		assertTrue(listHolder1.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+		assertTrue(listHolder2.hasNoListChangeListeners(ListValueModel.LIST_VALUES));
+	}
+
+	private void compare(ListModel listModel, List<String> list) {
+		assertEquals(listModel.getSize(), list.size());
+		for (int i = 0; i < listModel.getSize(); i++) {
+			assertEquals(listModel.getElementAt(i), list.get(i));
+		}
+	}
+
+	public void testCollectionSort() {
+		this.verifyCollectionSort(null);
+	}
+
+	public void testListSort() {
+		this.verifyListSort(null);
+	}
+
+	public void testCustomCollectionSort() {
+		this.verifyCollectionSort(this.buildCustomComparator());
+	}
+
+	public void testCustomListSort() {
+		this.verifyListSort(this.buildCustomComparator());
+	}
+
+	private Comparator<String> buildCustomComparator() {
+		// sort with reverse order
+		return new Comparator<String>() {
+			@Override
+			public int compare(String s1, String s2) {
+				return s2.compareTo(s1);
+			}
+		};
+	}
+
+	private void verifyCollectionSort(Comparator<String> comparator) {
+		SimpleCollectionValueModel<String> collectionHolder = this.buildCollectionHolder();
+		ListModel listModel = this.buildListModel(new SortedListValueModelAdapter<String>(collectionHolder, comparator));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+
+		collectionHolder.add("tom");
+		collectionHolder.add("dick");
+		collectionHolder.add("harry");
+		assertEquals(9, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+
+		collectionHolder.remove("foo");
+		collectionHolder.remove("jar");
+		collectionHolder.remove("harry");
+		assertEquals(6, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+	}
+
+	private void verifyListSort(Comparator<String> comparator) {
+		SimpleListValueModel<String> listHolder = this.buildListHolder();
+		ListModel listModel = this.buildListModel(new SortedListValueModelWrapper<String>(listHolder, comparator));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertEquals(6, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+
+		listHolder.add(0, "tom");
+		listHolder.add(0, "dick");
+		listHolder.add(0, "harry");
+		assertEquals(9, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+
+		listHolder.remove(8);
+		listHolder.remove(4);
+		listHolder.remove(0);
+		listHolder.remove(5);
+		assertEquals(5, synchList.size());
+		this.compareSort(listModel, synchList, comparator);
+	}
+
+	private void compareSort(ListModel listModel, List<String> list, Comparator<String> comparator) {
+		SortedSet<String> ss = new TreeSet<String>(comparator);
+		for (int i = 0; i < listModel.getSize(); i++) {
+			ss.add((String) listModel.getElementAt(i));
+		}
+		assertEquals(ss.size(), list.size());
+		for (Iterator<String> stream1 = ss.iterator(), stream2 = list.iterator(); stream1.hasNext(); ) {
+			assertEquals(stream1.next(), stream2.next());
+		}
+	}
+
+	public void testHasListeners() throws Exception {
+		SimpleListValueModel<String> listHolder = this.buildListHolder();
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+
+		ListModel listModel = this.buildListModel(listHolder);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.verifyHasNoListeners(listModel);
+
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		assertTrue(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.verifyHasListeners(listModel);
+
+		listModel.removeListDataListener(synchList);
+		assertFalse(listHolder.hasAnyListChangeListeners(ListValueModel.LIST_VALUES));
+		this.verifyHasNoListeners(listModel);
+	}
+
+	public void testGetSize() throws Exception {
+		SimpleListValueModel<String> listHolder = this.buildListHolder();
+		ListModel listModel = this.buildListModel(listHolder);
+		this.verifyHasNoListeners(listModel);
+		assertEquals(6, listModel.getSize());
+
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		this.verifyHasListeners(listModel);
+		assertEquals(6, listModel.getSize());
+
+		listModel.removeListDataListener(synchList);
+		this.verifyHasNoListeners(listModel);
+		assertEquals(6, listModel.getSize());
+	}
+
+	public void testGetElementAt() throws Exception {
+		SimpleListValueModel<String> listHolder = this.buildListHolder();
+		ListModel listModel = this.buildListModel(new SortedListValueModelWrapper<String>(listHolder));
+		CoordinatedList<String> synchList = new CoordinatedList<String>(listModel);
+		this.verifyHasListeners(listModel);
+		assertEquals("bar", listModel.getElementAt(0));
+		assertEquals("bar", synchList.get(0));
+	}
+
+	private void verifyHasNoListeners(ListModel listModel) throws Exception {
+		boolean hasNoListeners = ((Boolean) ObjectTools.execute(listModel, "hasNoListDataListeners")).booleanValue();
+		assertTrue(hasNoListeners);
+	}
+
+	private void verifyHasListeners(ListModel listModel) throws Exception {
+		boolean hasListeners = ((Boolean) ObjectTools.execute(listModel, "hasListDataListeners")).booleanValue();
+		assertTrue(hasListeners);
+	}
+
+	private SimpleCollectionValueModel<String> buildCollectionHolder() {
+		return new SimpleCollectionValueModel<String>(this.buildCollection());
+	}
+
+	private Collection<String> buildCollection() {
+		Bag<String> bag = new HashBag<String>();
+		this.populateCollection(bag);
+		return bag;
+	}
+
+	private SimpleListValueModel<String> buildListHolder() {
+		return new SimpleListValueModel<String>(this.buildList());
+	}
+
+	private List<String> buildList() {
+		List<String> list = new ArrayList<String>();
+		this.populateCollection(list);
+		return list;
+	}
+
+	private void populateCollection(Collection<String> c) {
+		c.add("foo");
+		c.add("bar");
+		c.add("baz");
+		c.add("joo");
+		c.add("jar");
+		c.add("jaz");
+	}
+
+	private SimpleListValueModel<String> buildListHolder2() {
+		return new SimpleListValueModel<String>(this.buildList2());
+	}
+
+	private List<String> buildList2() {
+		List<String> list = new ArrayList<String>();
+		this.populateCollection2(list);
+		return list;
+	}
+
+	private void populateCollection2(Collection<String> c) {
+		c.add("tom");
+		c.add("dick");
+		c.add("harry");
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java
new file mode 100644
index 0000000..be9d2b1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListModelAdapterUITest.java
@@ -0,0 +1,378 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.ListModel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ListAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+/**
+ * an example UI for testing various permutations of the ListModelAdapter
+ */
+@SuppressWarnings("nls")
+public class ListModelAdapterUITest {
+
+	private ModifiablePropertyValueModel<TaskList> taskListHolder;
+	private TextField taskTextField;
+
+	public static void main(String[] args) throws Exception {
+		new ListModelAdapterUITest().exec(args);
+	}
+
+	private ListModelAdapterUITest() {
+		super();
+	}
+
+	private void exec(@SuppressWarnings("unused") String[] args) throws Exception {
+		this.taskListHolder = new SimplePropertyValueModel<TaskList>(new TaskList());
+		this.openWindow();
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setSize(800, 400);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildTaskListPanel(), BorderLayout.CENTER);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildTaskListPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(0, 1));
+		taskListPanel.add(this.buildPrimitiveTaskListPanel());
+		taskListPanel.add(this.buildDisplayableTaskListPanel());
+		return taskListPanel;
+	}
+
+	private Component buildPrimitiveTaskListPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildUnsortedPrimitiveListPanel());
+		taskListPanel.add(this.buildStandardSortedPrimitiveListPanel());
+		taskListPanel.add(this.buildCustomSortedPrimitiveListPanel());
+		return taskListPanel;
+	}
+
+	private Component buildDisplayableTaskListPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildUnsortedDisplayableListPanel());
+		taskListPanel.add(this.buildStandardSortedDisplayableListPanel());
+		taskListPanel.add(this.buildCustomSortedDisplayableListPanel());
+		return taskListPanel;
+	}
+
+	private Component buildUnsortedPrimitiveListPanel() {
+		return this.buildListPanel("primitive unsorted", this.buildUnsortedPrimitiveListModel());
+	}
+
+	private Component buildStandardSortedPrimitiveListPanel() {
+		return this.buildListPanel("primitive sorted", this.buildStandardSortedPrimitiveListModel());
+	}
+
+	private Component buildCustomSortedPrimitiveListPanel() {
+		return this.buildListPanel("primitive reverse sorted", this.buildCustomSortedPrimitiveListModel());
+	}
+
+	private Component buildUnsortedDisplayableListPanel() {
+		return this.buildListPanel("displayable unsorted", this.buildUnsortedDisplayableListModel());
+	}
+
+	private Component buildStandardSortedDisplayableListPanel() {
+		return this.buildListPanel("displayable sorted", this.buildStandardSortedDisplayableListModel());
+	}
+
+	private Component buildCustomSortedDisplayableListPanel() {
+		return this.buildListPanel("displayable reverse sorted", this.buildCustomSortedDisplayableListModel());
+	}
+
+	private ListModel buildUnsortedPrimitiveListModel() {
+		return new ListModelAdapter(this.buildPrimitiveTaskListAdapter());
+	}
+
+	private ListModel buildStandardSortedPrimitiveListModel() {
+		return new ListModelAdapter(new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter()));
+	}
+
+	private ListModel buildCustomSortedPrimitiveListModel() {
+		return new ListModelAdapter(new SortedListValueModelWrapper<String>(this.buildPrimitiveTaskListAdapter(), this.buildCustomStringComparator()));
+	}
+
+	private ListModel buildUnsortedDisplayableListModel() {
+		return new ListModelAdapter(this.buildDisplayableTaskListAdapter());
+	}
+
+	private ListModel buildStandardSortedDisplayableListModel() {
+		return new ListModelAdapter(new SortedListValueModelWrapper<Task>(this.buildDisplayableTaskListAdapter()));
+	}
+
+	private ListModel buildCustomSortedDisplayableListModel() {
+		return new ListModelAdapter(new SortedListValueModelWrapper<Task>(this.buildDisplayableTaskListAdapter(), this.buildCustomTaskObjectComparator()));
+	}
+
+	private Component buildListPanel(String label, ListModel listModel) {
+		JPanel listPanel = new JPanel(new BorderLayout());
+		JLabel listLabel = new JLabel("  " + label);
+		listPanel.add(listLabel, BorderLayout.NORTH);
+
+		JList listBox = new JList();
+		listBox.setModel(listModel);
+		listBox.setDoubleBuffered(true);
+		listLabel.setLabelFor(listBox);
+		listPanel.add(new JScrollPane(listBox), BorderLayout.CENTER);
+		return listPanel;
+	}
+
+	private Comparator<String> buildCustomStringComparator() {
+		return new Comparator<String>() {
+			@Override
+			public int compare(String s1, String s2) {
+				return s2.compareTo(s1);
+			}
+		};
+	}
+
+	private Comparator<Task> buildCustomTaskObjectComparator() {
+		return new Comparator<Task>() {
+			@Override
+			public int compare(Task to1, Task to2) {
+				return to2.displayString().compareTo(to1.displayString());
+			}
+		};
+	}
+
+	private ListValueModel<String> buildPrimitiveTaskListAdapter() {
+		return new ListAspectAdapter<TaskList, String>(TaskList.TASK_NAMES_LIST, this.taskList()) {
+			@Override
+			protected ListIterator<String> listIterator_() {
+				return this.subject.taskNames();
+			}
+		};
+	}
+
+	private ListValueModel<Task> buildDisplayableTaskListAdapter() {
+		return new ListAspectAdapter<TaskList, Task>(TaskList.TASKS_LIST, this.taskList()) {
+			@Override
+			protected ListIterator<Task> listIterator_() {
+				return this.subject.tasks();
+			}
+		};
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new BorderLayout());
+		controlPanel.add(this.buildAddRemoveTaskPanel(), BorderLayout.CENTER);
+		controlPanel.add(this.buildClearButton(), BorderLayout.EAST);
+		return controlPanel;
+	}
+
+	private Component buildAddRemoveTaskPanel() {
+		JPanel addRemoveTaskPanel = new JPanel(new BorderLayout());
+		addRemoveTaskPanel.add(this.buildAddButton(), BorderLayout.WEST);
+		addRemoveTaskPanel.add(this.buildTaskTextField(), BorderLayout.CENTER);
+		addRemoveTaskPanel.add(this.buildRemoveButton(), BorderLayout.EAST);
+		return addRemoveTaskPanel;
+	}
+
+	private String getTask() {
+		return this.taskTextField.getText();
+	}
+
+	private TaskList taskList() {
+		return this.taskListHolder.getValue();
+	}
+
+	void addTask() {
+		String task = this.getTask();
+		if (task.length() != 0) {
+			this.taskList().addTask(task);
+		}
+	}
+
+	void removeTask() {
+		String task = this.getTask();
+		if (task.length() != 0) {
+			this.taskList().removeTask(task);
+		}
+	}
+
+	void clearTasks() {
+		this.taskList().clearTasks();
+	}
+
+	private TextField buildTaskTextField() {
+		this.taskTextField = new TextField();
+		return this.taskTextField;
+	}
+
+	private JButton buildAddButton() {
+		return new JButton(this.buildAddAction());
+	}
+
+	private Action buildAddAction() {
+		Action action = new AbstractAction("add") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ListModelAdapterUITest.this.addTask();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	private JButton buildRemoveButton() {
+		return new JButton(this.buildRemoveAction());
+	}
+
+	private Action buildRemoveAction() {
+		Action action = new AbstractAction("remove") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ListModelAdapterUITest.this.removeTask();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	private JButton buildClearButton() {
+		return new JButton(this.buildClearAction());
+	}
+
+	private Action buildClearAction() {
+		Action action = new AbstractAction("clear") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				ListModelAdapterUITest.this.clearTasks();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	public class TaskList extends AbstractModel {
+		private List<String> taskNames = new ArrayList<String>();
+		private List<Task> taskObjects = new ArrayList<Task>();
+		public static final String TASK_NAMES_LIST = "taskNames";
+		public static final String TASKS_LIST = "tasks";
+		TaskList() {
+			super();
+		}
+		public ListIterator<String> taskNames() {
+			return this.taskNames.listIterator();
+		}
+		public ListIterator<Task> tasks() {
+			return this.taskObjects.listIterator();
+		}
+		public void addTask(String taskName) {
+			int index = this.taskNames.size();
+			this.taskNames.add(index, taskName);
+			this.fireItemAdded(TASK_NAMES_LIST, index, taskName);
+
+			Task taskObject = new Task(taskName);
+			this.taskObjects.add(index, taskObject);
+			this.fireItemAdded(TASKS_LIST, index, taskObject);
+		}
+		public void removeTask(String taskName) {
+			int index = this.taskNames.indexOf(taskName);
+			if (index != -1) {
+				Object removedTask = this.taskNames.remove(index);
+				this.fireItemRemoved(TASK_NAMES_LIST, index, removedTask);
+				// assume the indexes match...
+				Object removedTaskObject = this.taskObjects.remove(index);
+				this.fireItemRemoved(TASKS_LIST, index, removedTaskObject);
+			}
+		}
+		public void clearTasks() {
+			this.taskNames.clear();
+			this.fireListChanged(TASK_NAMES_LIST, this.taskNames);
+			this.taskObjects.clear();
+			this.fireListChanged(TASKS_LIST, this.taskObjects);
+		}
+	}
+
+	public class Task extends AbstractModel implements Displayable {
+		private String name;
+		private Date creationTimeStamp;
+		public Task(String name) {
+			this.name = name;
+			this.creationTimeStamp = new Date();
+		}
+		@Override
+		public String displayString() {
+			return this.name + ": " + this.creationTimeStamp.getTime();
+		}
+		@Override
+		public Icon icon() {
+			return null;
+		}
+		public String getName() {
+			return this.name;
+		}
+		public void setName(String name) {
+			Object old = this.name;
+			this.name = name;
+			this.firePropertyChanged(DISPLAY_STRING_PROPERTY, old, name);
+		}
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, this.displayString());
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..1384c53
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ListSpinnerModelAdapterTests.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class ListSpinnerModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Object> valueHolder;
+	private SpinnerModel spinnerModelAdapter;
+	boolean eventFired;
+	private static final String[] VALUE_LIST = {"red", "green", "blue"};
+	private static final String DEFAULT_VALUE = VALUE_LIST[0];
+
+	public ListSpinnerModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.valueHolder = new SimplePropertyValueModel<Object>(DEFAULT_VALUE);
+		this.spinnerModelAdapter = new ListSpinnerModelAdapter(this.valueHolder, VALUE_LIST) {
+			@Override
+			protected PropertyChangeListener buildValueChangeListener() {
+				return this.buildValueChangeListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetValueSpinnerModel() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				ListSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(DEFAULT_VALUE, this.valueHolder.getValue());
+		this.spinnerModelAdapter.setValue(VALUE_LIST[2]);
+		assertTrue(this.eventFired);
+		assertEquals(VALUE_LIST[2], this.valueHolder.getValue());
+	}
+
+	public void testSetValueValueHolder() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				ListSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(DEFAULT_VALUE, this.spinnerModelAdapter.getValue());
+		this.valueHolder.setValue(VALUE_LIST[2]);
+		assertTrue(this.eventFired);
+		assertEquals(VALUE_LIST[2], this.spinnerModelAdapter.getValue());
+	}
+
+	public void testDefaultValue() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				ListSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(DEFAULT_VALUE, this.spinnerModelAdapter.getValue());
+
+		this.valueHolder.setValue(VALUE_LIST[2]);
+		assertTrue(this.eventFired);
+		assertEquals(VALUE_LIST[2], this.spinnerModelAdapter.getValue());
+
+		this.eventFired = false;
+		this.valueHolder.setValue(null);
+		assertTrue(this.eventFired);
+		assertEquals(VALUE_LIST[0], this.spinnerModelAdapter.getValue());
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.spinnerModelAdapter.addChangeListener(listener);
+		assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.spinnerModelAdapter);
+
+		this.spinnerModelAdapter.removeChangeListener(listener);
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+	}
+
+	private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+		assertEquals(0, ((ListSpinnerModelAdapter) adapter).getChangeListeners().length);
+	}
+
+	private void verifyHasListeners(Object adapter) throws Exception {
+		assertFalse(((ListSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+	}
+
+
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java
new file mode 100644
index 0000000..06121b7
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/NumberSpinnerModelAdapterTests.java
@@ -0,0 +1,152 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class NumberSpinnerModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Number> valueHolder;
+	private SpinnerModel spinnerModelAdapter;
+	boolean eventFired;
+
+	public NumberSpinnerModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.valueHolder = new SimplePropertyValueModel<Number>(new Integer(0));
+		this.spinnerModelAdapter = new NumberSpinnerModelAdapter(this.valueHolder, -33, 33, 1) {
+			@Override
+			protected PropertyChangeListener buildNumberChangeListener() {
+				return this.buildNumberChangeListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetValueSpinnerModel() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				NumberSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		this.spinnerModelAdapter.setValue(new Integer(5));
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(5), this.valueHolder.getValue());
+	}
+
+	public void testSetValueValueHolder() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				NumberSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+		this.valueHolder.setValue(new Integer(7));
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+	}
+
+	public void testDefaultValue() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				NumberSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+		this.valueHolder.setValue(null);
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(-33), this.spinnerModelAdapter.getValue());
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Number> localValueHolder = (SimplePropertyValueModel<Number>) this.valueHolder;
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.spinnerModelAdapter.addChangeListener(listener);
+		assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.spinnerModelAdapter);
+
+		this.spinnerModelAdapter.removeChangeListener(listener);
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+	}
+
+	private void verifyHasNoListeners(SpinnerModel adapter) throws Exception {
+		assertEquals(0, ((NumberSpinnerModelAdapter) adapter).getChangeListeners().length);
+	}
+
+	private void verifyHasListeners(Object adapter) throws Exception {
+		assertFalse(((NumberSpinnerModelAdapter) adapter).getChangeListeners().length == 0);
+	}
+
+	public void testNullInitialValue() {
+		this.valueHolder = new SimplePropertyValueModel<Number>();
+		this.spinnerModelAdapter = new NumberSpinnerModelAdapter(this.valueHolder, new Integer(-33), new Integer(33), new Integer(1), new Integer(0)) {
+			@Override
+			protected PropertyChangeListener buildNumberChangeListener() {
+				return this.buildNumberChangeListener_();
+			}
+		};
+
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				NumberSpinnerModelAdapterTests.this.eventFired = true;
+			}
+		});
+		assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+		this.valueHolder.setValue(new Integer(7));
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+	}
+
+
+	// ********** inner class **********
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java
new file mode 100644
index 0000000..f9996b3
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ObjectListSelectionModelTests.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.DefaultListModel;
+import javax.swing.ListModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.value.swing.ObjectListSelectionModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+
+@SuppressWarnings("nls")
+public class ObjectListSelectionModelTests extends TestCase {
+	private DefaultListModel listModel;
+	private ObjectListSelectionModel selectionModel;
+
+	public ObjectListSelectionModelTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.listModel = this.buildListModel();
+		this.selectionModel = this.buildSelectionModel(this.listModel);
+	}
+
+	private DefaultListModel buildListModel() {
+		DefaultListModel lm = new DefaultListModel();
+		lm.addElement("foo");
+		lm.addElement("bar");
+		lm.addElement("baz");
+		return lm;
+	}
+
+	private ObjectListSelectionModel buildSelectionModel(ListModel lm) {
+		return new ObjectListSelectionModel(lm);
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testListDataListener() {
+		this.selectionModel.addListSelectionListener(this.buildListSelectionListener());
+		this.selectionModel.setSelectionInterval(0, 0);
+		assertEquals("foo", this.selectionModel.selectedValue());
+		this.listModel.set(0, "jar");
+		assertEquals("jar", this.selectionModel.selectedValue());
+	}
+
+	public void testGetSelectedValue() {
+		this.selectionModel.setSelectionInterval(0, 0);
+		assertEquals("foo", this.selectionModel.selectedValue());
+	}
+
+	public void testGetSelectedValues() {
+		this.selectionModel.setSelectionInterval(0, 0);
+		this.selectionModel.addSelectionInterval(2, 2);
+		assertEquals(2, this.selectionModel.selectedValues().length);
+		assertTrue(ArrayTools.contains(this.selectionModel.selectedValues(), "foo"));
+		assertTrue(ArrayTools.contains(this.selectionModel.selectedValues(), "baz"));
+	}
+
+	public void testSetSelectedValue() {
+		this.selectionModel.setSelectedValue("foo");
+		assertEquals(0, this.selectionModel.getMinSelectionIndex());
+		assertEquals(0, this.selectionModel.getMaxSelectionIndex());
+	}
+
+	public void testSetSelectedValues() {
+		this.selectionModel.setSelectedValues(new Object[] {"foo", "baz"});
+		assertEquals(0, this.selectionModel.getMinSelectionIndex());
+		assertEquals(2, this.selectionModel.getMaxSelectionIndex());
+	}
+
+	public void testAddSelectedValue() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValue("foo");
+		this.selectionModel.addSelectedValue("jaz");
+		assertEquals(0, this.selectionModel.getMinSelectionIndex());
+		assertEquals(5, this.selectionModel.getMaxSelectionIndex());
+		assertTrue(this.selectionModel.isSelectedIndex(0));
+		assertFalse(this.selectionModel.isSelectedIndex(1));
+		assertFalse(this.selectionModel.isSelectedIndex(2));
+		assertFalse(this.selectionModel.isSelectedIndex(3));
+		assertFalse(this.selectionModel.isSelectedIndex(4));
+		assertTrue(this.selectionModel.isSelectedIndex(5));
+	}
+
+	public void testAddSelectedValues() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValue("foo");
+		this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+		assertEquals(0, this.selectionModel.getMinSelectionIndex());
+		assertEquals(4, this.selectionModel.getMaxSelectionIndex());
+		assertTrue(this.selectionModel.isSelectedIndex(0));
+		assertTrue(this.selectionModel.isSelectedIndex(1));
+		assertFalse(this.selectionModel.isSelectedIndex(2));
+		assertFalse(this.selectionModel.isSelectedIndex(3));
+		assertTrue(this.selectionModel.isSelectedIndex(4));
+		assertFalse(this.selectionModel.isSelectedIndex(5));
+	}
+
+	public void testRemoveSelectedValue() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValues(new Object[] {"foo", "baz", "jar"});
+		this.selectionModel.removeSelectedValue("jar");
+		assertEquals(0, this.selectionModel.getMinSelectionIndex());
+		assertEquals(2, this.selectionModel.getMaxSelectionIndex());
+		assertTrue(this.selectionModel.isSelectedIndex(0));
+		assertFalse(this.selectionModel.isSelectedIndex(1));
+		assertTrue(this.selectionModel.isSelectedIndex(2));
+		assertFalse(this.selectionModel.isSelectedIndex(3));
+		assertFalse(this.selectionModel.isSelectedIndex(4));
+		assertFalse(this.selectionModel.isSelectedIndex(5));
+	}
+
+	public void testRemoveSelectedValues() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValues(new Object[] {"foo", "baz", "joo", "jar"});
+		this.selectionModel.removeSelectedValues(new Object[] {"foo", "joo"});
+		assertEquals(2, this.selectionModel.getMinSelectionIndex());
+		assertEquals(4, this.selectionModel.getMaxSelectionIndex());
+		assertFalse(this.selectionModel.isSelectedIndex(0));
+		assertFalse(this.selectionModel.isSelectedIndex(1));
+		assertTrue(this.selectionModel.isSelectedIndex(2));
+		assertFalse(this.selectionModel.isSelectedIndex(3));
+		assertTrue(this.selectionModel.isSelectedIndex(4));
+		assertFalse(this.selectionModel.isSelectedIndex(5));
+	}
+
+	public void testGetAnchorSelectedValue() {
+		this.selectionModel.setAnchorSelectionIndex(1);
+		assertEquals("bar", this.selectionModel.getAnchorSelectedValue());
+	}
+
+	public void testGetLeadSelectedValue() {
+		this.selectionModel.setSelectedValue("bar");
+		assertEquals("bar", this.selectionModel.getLeadSelectedValue());
+		this.selectionModel.setSelectedValues(new Object[] {"foo", "baz"});
+		assertEquals("baz", this.selectionModel.getLeadSelectedValue());
+	}
+
+	public void testGetMinMaxSelectedValue() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValue("foo");
+		this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+		assertEquals("foo", this.selectionModel.getMinSelectedValue());
+		assertEquals("jar", this.selectionModel.getMaxSelectedValue());
+	}
+
+	public void testValueIsSelected() {
+		this.listModel.addElement("joo");
+		this.listModel.addElement("jar");
+		this.listModel.addElement("jaz");
+		this.selectionModel.setSelectedValue("foo");
+		this.selectionModel.addSelectedValues(new Object[] {"bar", "jar"});
+		assertTrue(this.selectionModel.valueIsSelected("foo"));
+		assertTrue(this.selectionModel.valueIsSelected("bar"));
+		assertTrue(this.selectionModel.valueIsSelected("jar"));
+		assertFalse(this.selectionModel.valueIsSelected("baz"));
+	}
+
+	public void testHasListeners() throws Exception {
+		ListSelectionListener listener = this.buildListSelectionListener();
+		assertEquals(0, this.listModel.getListDataListeners().length);
+		this.selectionModel.addListSelectionListener(listener);
+		assertEquals(1, this.listModel.getListDataListeners().length);
+		this.selectionModel.removeListSelectionListener(listener);
+		assertEquals(0, this.listModel.getListDataListeners().length);
+	}
+
+	private ListSelectionListener buildListSelectionListener() {
+		return new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				// do nothing for now...
+			}
+		};
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java
new file mode 100644
index 0000000..d1cc289
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/PrimitiveListTreeModelTests.java
@@ -0,0 +1,205 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.iterator.ReadOnlyListIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ListAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.PrimitiveListTreeModel;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class PrimitiveListTreeModelTests extends TestCase {
+	TestModel testModel;
+	private TreeModel treeModel;
+
+	public PrimitiveListTreeModelTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.testModel = this.buildTestModel();
+		this.treeModel = this.buildTreeModel();
+	}
+
+	private TestModel buildTestModel() {
+		return new TestModel();
+	}
+
+	private TreeModel buildTreeModel() {
+		return new PrimitiveListTreeModel(this.buildListValueModel()) {
+			@Override
+			protected void primitiveChanged(int index, Object newValue) {
+				if ( ! newValue.equals("")) {
+					PrimitiveListTreeModelTests.this.testModel.replaceName(index, (String) newValue);
+				}
+			}
+			@Override
+			protected ListChangeListener buildListChangeListener() {
+				return this.buildListChangeListener_();
+			}
+		};
+	}
+
+	private ListValueModel<?> buildListValueModel() {
+		return new ListAspectAdapter<TestModel, String>(TestModel.NAMES_LIST, this.testModel) {
+			@Override
+			protected ListIterator<String> listIterator_() {
+				return this.subject.names();
+			}
+			@Override
+			public String get(int index) {
+				return this.subject.getName(index);
+			}
+			@Override
+			public int size() {
+				return this.subject.namesSize();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testAddPrimitive() {
+		this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesInserted(TreeModelEvent e) {
+				PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {0}, new String[] {"foo"});
+			}
+		});
+		this.testModel.addName("foo");
+	}
+
+	public void testRemovePrimitive() {
+		this.testModel.addName("foo");
+		this.testModel.addName("bar");
+		this.testModel.addName("baz");
+		this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesRemoved(TreeModelEvent e) {
+				PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {1}, new String[] {"bar"});
+			}
+		});
+		String name = this.testModel.removeName(1);
+		assertEquals("bar", name);
+	}
+
+	public void testReplacePrimitive() {
+		this.testModel.addName("foo");
+		this.testModel.addName("bar");
+		this.testModel.addName("baz");
+		this.treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesChanged(TreeModelEvent e) {
+				PrimitiveListTreeModelTests.this.verifyTreeModelEvent(e, new int[] {1}, new String[] {"jar"});
+			}
+		});
+		String name = this.testModel.replaceName(1, "jar");
+		assertEquals("bar", name);
+	}
+
+	void verifyTreeModelEvent(TreeModelEvent e, int[] expectedChildIndices, String[] expectedNames) {
+		assertTrue(Arrays.equals(expectedChildIndices, e.getChildIndices()));
+		Object[] actualChildren = e.getChildren();
+		assertEquals(expectedNames.length, actualChildren.length);
+		for (int i = 0; i < expectedNames.length; i++) {
+			DefaultMutableTreeNode node = (DefaultMutableTreeNode) actualChildren[i];
+			assertEquals(expectedNames[i], node.getUserObject());
+		}
+		assertEquals(1, e.getPath().length);
+		assertEquals(this.treeModel.getRoot(), e.getPath()[0]);
+		assertEquals(this.treeModel, e.getSource());
+	}
+
+
+// ********** inner classes **********
+
+	class TestModel extends AbstractModel {
+		private final List<String> names;
+			static final String NAMES_LIST = "names";
+
+		TestModel() {
+			super();
+			this.names = new ArrayList<String>();
+		}
+
+		public ListIterator<String> names() {
+			return new ReadOnlyListIterator<String>(this.names);
+		}
+		public int namesSize() {
+			return this.names.size();
+		}
+		public String getName(int index) {
+			return this.names.get(index);
+		}
+		public void addName(int index, String name) {
+			this.addItemToList(index, name, this.names, NAMES_LIST);
+		}
+		public void addName(String name) {
+			this.addName(this.namesSize(), name);
+		}
+		public void addNames(int index, List<String> list) {
+			this.addItemsToList(index, this.names, list, NAMES_LIST);
+		}
+		public void addNames(List<String> list) {
+			this.addNames(this.namesSize(), list);
+		}
+		public String removeName(int index) {
+			return this.removeItemFromList(index, this.names, NAMES_LIST);
+		}
+		public List<String> removeNames(int index, int length) {
+			return this.removeItemsFromList(index, length, this.names, NAMES_LIST);
+		}
+		public String replaceName(int index, String newName) {
+			return this.setItemInList(index, newName, this.names, NAMES_LIST);
+		}
+	}
+
+
+	public class TestTreeModelListener implements TreeModelListener {
+		@Override
+		public void treeNodesChanged(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeNodesInserted(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeNodesRemoved(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeStructureChanged(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java
new file mode 100644
index 0000000..5f598fa
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterTests.java
@@ -0,0 +1,234 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.ButtonModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.EventListenerList;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.RadioButtonModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class RadioButtonModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Object> valueHolder;
+
+	private ButtonModel redButtonModelAdapter;
+	private ChangeListener redListener;
+	boolean redEventFired;
+
+	private ButtonModel greenButtonModelAdapter;
+	private ChangeListener greenListener;
+	boolean greenEventFired;
+
+	private ButtonModel blueButtonModelAdapter;
+	private ChangeListener blueListener;
+	boolean blueEventFired;
+
+//	private ButtonGroup buttonGroup;	// DO NOT use a ButtonGroup
+
+	private static final String RED = "red";
+	private static final String GREEN = "green";
+	private static final String BLUE = "blue";
+
+	public RadioButtonModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.valueHolder = new SimplePropertyValueModel<Object>(null);
+//		buttonGroup = new ButtonGroup();
+
+		this.redButtonModelAdapter = this.buildButtonModel(this.valueHolder, RED);
+//		this.redButtonModelAdapter.setGroup(buttonGroup);
+		this.redListener = new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				RadioButtonModelAdapterTests.this.redEventFired = true;
+			}
+		};
+
+		this.greenButtonModelAdapter = this.buildButtonModel(this.valueHolder, GREEN);
+//		this.greenButtonModelAdapter.setGroup(buttonGroup);
+		this.greenListener = new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				RadioButtonModelAdapterTests.this.greenEventFired = true;
+			}
+		};
+
+		this.blueButtonModelAdapter = this.buildButtonModel(this.valueHolder, BLUE);
+//		this.blueButtonModelAdapter.setGroup(buttonGroup);
+		this.blueListener = new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				RadioButtonModelAdapterTests.this.blueEventFired = true;
+			}
+		};
+
+		this.clearFlags();
+	}
+
+	private ButtonModel buildButtonModel(ModifiablePropertyValueModel<Object> pvm, Object buttonValue) {
+		return new RadioButtonModelAdapter(pvm, buttonValue) {
+			@Override
+			protected PropertyChangeListener buildBooleanChangeListener() {
+				return this.buildBooleanChangeListener_();
+			}
+		};
+	}
+
+	private void listenToModelAdapters() {
+		this.redButtonModelAdapter.addChangeListener(this.redListener);
+		this.greenButtonModelAdapter.addChangeListener(this.greenListener);
+		this.blueButtonModelAdapter.addChangeListener(this.blueListener);
+	}
+
+	private void clearFlags() {
+		this.redEventFired = false;
+		this.greenEventFired = false;
+		this.blueEventFired = false;
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetSelected() throws Exception {
+		this.listenToModelAdapters();
+
+		this.greenButtonModelAdapter.setSelected(true);
+		assertFalse(this.redEventFired);
+		assertTrue(this.greenEventFired);
+		assertFalse(this.blueEventFired);
+		assertEquals(GREEN, this.valueHolder.getValue());
+
+		this.clearFlags();
+		this.blueButtonModelAdapter.setSelected(true);
+		assertFalse(this.redEventFired);
+		assertTrue(this.greenEventFired);
+		assertTrue(this.blueEventFired);
+		assertEquals(BLUE, this.valueHolder.getValue());
+
+		this.clearFlags();
+		this.redButtonModelAdapter.setSelected(true);
+		assertTrue(this.redEventFired);
+		assertFalse(this.greenEventFired);
+		assertTrue(this.blueEventFired);
+		assertEquals(RED, this.valueHolder.getValue());
+	}
+
+	public void testSetValue() throws Exception {
+		this.listenToModelAdapters();
+
+		this.greenButtonModelAdapter.setSelected(true);
+
+		this.clearFlags();
+		this.valueHolder.setValue(BLUE);
+		assertFalse(this.redEventFired);
+		assertTrue(this.greenEventFired);
+		assertTrue(this.blueEventFired);
+		assertFalse(this.redButtonModelAdapter.isSelected());
+		assertFalse(this.greenButtonModelAdapter.isSelected());
+		assertTrue(this.blueButtonModelAdapter.isSelected());
+
+		this.clearFlags();
+		this.valueHolder.setValue(RED);
+		assertTrue(this.redEventFired);
+		assertFalse(this.greenEventFired);
+		assertTrue(this.blueEventFired);
+		assertTrue(this.redButtonModelAdapter.isSelected());
+		assertFalse(this.greenButtonModelAdapter.isSelected());
+		assertFalse(this.blueButtonModelAdapter.isSelected());
+	}
+
+	public void testDefaultValue() throws Exception {
+		this.listenToModelAdapters();
+
+		this.valueHolder.setValue(GREEN);
+		assertFalse(this.redButtonModelAdapter.isSelected());
+		assertTrue(this.greenButtonModelAdapter.isSelected());
+		assertFalse(this.blueButtonModelAdapter.isSelected());
+
+		this.clearFlags();
+		this.valueHolder.setValue(null);
+		assertFalse(this.redEventFired);
+		assertTrue(this.greenEventFired);
+		assertFalse(this.blueEventFired);
+		assertFalse(this.redButtonModelAdapter.isSelected());
+		assertFalse(this.greenButtonModelAdapter.isSelected());
+		assertFalse(this.blueButtonModelAdapter.isSelected());
+
+		this.clearFlags();
+		this.valueHolder.setValue(BLUE);
+		assertFalse(this.redEventFired);
+		assertFalse(this.greenEventFired);
+		assertTrue(this.blueEventFired);
+		assertFalse(this.redButtonModelAdapter.isSelected());
+		assertFalse(this.greenButtonModelAdapter.isSelected());
+		assertTrue(this.blueButtonModelAdapter.isSelected());
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.redButtonModelAdapter);
+		this.verifyHasNoListeners(this.greenButtonModelAdapter);
+		this.verifyHasNoListeners(this.blueButtonModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.redButtonModelAdapter.addChangeListener(listener);
+		assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.redButtonModelAdapter);
+		this.verifyHasNoListeners(this.greenButtonModelAdapter);
+		this.verifyHasNoListeners(this.blueButtonModelAdapter);
+
+		this.redButtonModelAdapter.removeChangeListener(listener);
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.redButtonModelAdapter);
+		this.verifyHasNoListeners(this.greenButtonModelAdapter);
+		this.verifyHasNoListeners(this.blueButtonModelAdapter);
+	}
+
+	private void verifyHasNoListeners(Object model) throws Exception {
+		EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+		assertEquals(0, listenerList.getListenerList().length);
+	}
+
+	private void verifyHasListeners(Object model) throws Exception {
+		EventListenerList listenerList = (EventListenerList) ObjectTools.get(model, "listenerList");
+		assertFalse(listenerList.getListenerList().length == 0);
+	}
+
+
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java
new file mode 100644
index 0000000..a1d7c14
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/RadioButtonModelAdapterUITest.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.RadioButtonModelAdapter;
+
+/**
+ * Play around with a set of radio buttons.
+ */
+@SuppressWarnings("nls")
+public class RadioButtonModelAdapterUITest {
+
+	private TestModel testModel;
+	private ModifiablePropertyValueModel<TestModel> testModelHolder;
+	private ModifiablePropertyValueModel<Object> colorHolder;
+	private ButtonModel redButtonModel;
+	private ButtonModel greenButtonModel;
+	private ButtonModel blueButtonModel;
+
+	public static void main(String[] args) throws Exception {
+		new RadioButtonModelAdapterUITest().exec();
+	}
+
+	private RadioButtonModelAdapterUITest() {
+		super();
+	}
+
+	private void exec() throws Exception {
+		this.testModel = new TestModel();
+		this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+		this.colorHolder = this.buildColorHolder(this.testModelHolder);
+		this.redButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.RED);
+		this.greenButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.GREEN);
+		this.blueButtonModel = this.buildRadioButtonModelAdapter(this.colorHolder, TestModel.BLUE);
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<Object> buildColorHolder(PropertyValueModel<TestModel> subjectHolder) {
+		return new PropertyAspectAdapter<TestModel, Object>(subjectHolder, TestModel.COLOR_PROPERTY) {
+			@Override
+			protected Object buildValue_() {
+				return this.subject.getColor();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setColor((String) value);
+			}
+		};
+	}
+
+	private ButtonModel buildRadioButtonModelAdapter(ModifiablePropertyValueModel<Object> colorPVM, String color) {
+		return new RadioButtonModelAdapter(colorPVM, color);
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setSize(400, 100);
+		window.setLocation(200, 200);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildRadioButtonPanel(), BorderLayout.NORTH);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildRadioButtonPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildRedRadioButton());
+		taskListPanel.add(this.buildGreenRadioButton());
+		taskListPanel.add(this.buildBlueRadioButton());
+		return taskListPanel;
+	}
+
+	private JRadioButton buildRedRadioButton() {
+		JRadioButton radioButton = new JRadioButton();
+		radioButton.setText("red");
+		radioButton.setModel(this.redButtonModel);
+		return radioButton;
+	}
+
+	private JRadioButton buildGreenRadioButton() {
+		JRadioButton radioButton = new JRadioButton();
+		radioButton.setText("green");
+		radioButton.setModel(this.greenButtonModel);
+		return radioButton;
+	}
+
+	private JRadioButton buildBlueRadioButton() {
+		JRadioButton radioButton = new JRadioButton();
+		radioButton.setText("blue");
+		radioButton.setModel(this.blueButtonModel);
+		return radioButton;
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+		controlPanel.add(this.buildResetColorButton());
+		controlPanel.add(this.buildClearModelButton());
+		controlPanel.add(this.buildRestoreModelButton());
+		controlPanel.add(this.buildPrintModelButton());
+		return controlPanel;
+	}
+
+	private JButton buildResetColorButton() {
+		return new JButton(this.buildResetColorAction());
+	}
+
+	private Action buildResetColorAction() {
+		Action action = new AbstractAction("reset color") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				RadioButtonModelAdapterUITest.this.resetColor();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void resetColor() {
+		this.testModel.setColor(TestModel.DEFAULT_COLOR);
+	}
+
+	private JButton buildClearModelButton() {
+		return new JButton(this.buildClearModelAction());
+	}
+
+	private Action buildClearModelAction() {
+		Action action = new AbstractAction("clear model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				RadioButtonModelAdapterUITest.this.clearModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void clearModel() {
+		this.testModelHolder.setValue(null);
+	}
+
+	private JButton buildRestoreModelButton() {
+		return new JButton(this.buildRestoreModelAction());
+	}
+
+	private Action buildRestoreModelAction() {
+		Action action = new AbstractAction("restore model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				RadioButtonModelAdapterUITest.this.restoreModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void restoreModel() {
+		this.testModelHolder.setValue(this.testModel);
+	}
+
+	private JButton buildPrintModelButton() {
+		return new JButton(this.buildPrintModelAction());
+	}
+
+	private Action buildPrintModelAction() {
+		Action action = new AbstractAction("print model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				RadioButtonModelAdapterUITest.this.printModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printModel() {
+		System.out.println(this.testModel);
+	}
+
+
+	private static class TestModel extends AbstractModel {
+		private String color;
+			public static final String COLOR_PROPERTY = "color";
+			public static final String RED = "red";
+			public static final String GREEN = "green";
+			public static final String BLUE = "blue";
+			public static final String DEFAULT_COLOR = RED;
+			public static final String[] VALID_COLORS = {
+				RED,
+				GREEN,
+				BLUE
+			};
+
+		public TestModel() {
+			this(DEFAULT_COLOR);
+		}
+		public TestModel(String color) {
+			this.color = color;
+		}
+		public String getColor() {
+			return this.color;
+		}
+		public void setColor(String color) {
+			if ( ! ArrayTools.contains(VALID_COLORS, color)) {
+				throw new IllegalArgumentException(color);
+			}
+			Object old = this.color;
+			this.color = color;
+			this.firePropertyChanged(COLOR_PROPERTY, old, color);
+		}
+		@Override
+		public String toString() {
+			return "TestModel(" + this.color + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java
new file mode 100644
index 0000000..dbfc8f2
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/ReadOnlyTableModelAdapterUITest.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.PersonColumnAdapter;
+
+/**
+ * Make it easy to test the table model adapter and
+ * renderers without any editing allowed.
+ */
+public class ReadOnlyTableModelAdapterUITest
+	extends TableModelAdapterUITest
+{
+	public static void main(String[] args) throws Exception {
+		new ReadOnlyTableModelAdapterUITest().exec(args);
+	}
+
+	protected ReadOnlyTableModelAdapterUITest() {
+		super();
+	}
+
+	@Override
+	protected TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+		return new PersonColumnAdapter() {
+			@Override
+			public boolean columnIsEditable(int index) {
+				return false;
+			}
+		};
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java
new file mode 100644
index 0000000..90c5462
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterTests.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import javax.swing.SpinnerModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.SpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class SpinnerModelAdapterTests extends TestCase {
+	private ModifiablePropertyValueModel<Object> valueHolder;
+	SpinnerModel spinnerModelAdapter;
+	boolean eventFired;
+
+	public SpinnerModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.valueHolder = new SimplePropertyValueModel<Object>(new Integer(0));
+		this.spinnerModelAdapter = new SpinnerModelAdapter(this.valueHolder) {
+			@Override
+			protected PropertyChangeListener buildValueListener() {
+				return this.buildValueListener_();
+			}
+		};
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testSetValueSpinnerModel() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				SpinnerModelAdapterTests.this.eventFired = true;
+				assertEquals(SpinnerModelAdapterTests.this.spinnerModelAdapter, e.getSource());
+			}
+		});
+		this.spinnerModelAdapter.setValue(new Integer(5));
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(5), this.valueHolder.getValue());
+	}
+
+	public void testSetValueValueHolder() throws Exception {
+		this.eventFired = false;
+		this.spinnerModelAdapter.addChangeListener(new TestChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				SpinnerModelAdapterTests.this.eventFired = true;
+				assertEquals(SpinnerModelAdapterTests.this.spinnerModelAdapter, e.getSource());
+			}
+		});
+		assertEquals(new Integer(0), this.spinnerModelAdapter.getValue());
+		this.valueHolder.setValue(new Integer(7));
+		assertTrue(this.eventFired);
+		assertEquals(new Integer(7), this.spinnerModelAdapter.getValue());
+	}
+
+	public void testHasListeners() throws Exception {
+		SimplePropertyValueModel<Object> localValueHolder = (SimplePropertyValueModel<Object>) this.valueHolder;
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+
+		ChangeListener listener = new TestChangeListener();
+		this.spinnerModelAdapter.addChangeListener(listener);
+		assertTrue(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasListeners(this.spinnerModelAdapter);
+
+		this.spinnerModelAdapter.removeChangeListener(listener);
+		assertFalse(localValueHolder.hasAnyPropertyChangeListeners(PropertyValueModel.VALUE));
+		this.verifyHasNoListeners(this.spinnerModelAdapter);
+	}
+
+	private void verifyHasNoListeners(Object adapter) throws Exception {
+		Object delegate = ObjectTools.get(adapter, "delegate");
+		Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getChangeListeners");
+		assertEquals(0, listeners.length);
+	}
+
+	private void verifyHasListeners(Object adapter) throws Exception {
+		Object delegate = ObjectTools.get(adapter, "delegate");
+		Object[] listeners = (Object[]) ObjectTools.execute(delegate, "getChangeListeners");
+		assertFalse(listeners.length == 0);
+	}
+
+
+	private class TestChangeListener implements ChangeListener {
+		TestChangeListener() {
+			super();
+		}
+		@Override
+		public void stateChanged(ChangeEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java
new file mode 100644
index 0000000..a117c36
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/SpinnerModelAdapterUITest.java
@@ -0,0 +1,349 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Calendar;
+import java.util.Date;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerModel;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+
+/**
+ * Play around with a set of spinners.
+ */
+@SuppressWarnings("nls")
+public class SpinnerModelAdapterUITest {
+
+	private TestModel testModel;
+	private ModifiablePropertyValueModel<TestModel> testModelHolder;
+
+	private ModifiablePropertyValueModel<Object> birthDateHolder;
+	private SpinnerModel birthDateSpinnerModel;
+
+	private ModifiablePropertyValueModel<Number> ageHolder;
+	private SpinnerModel ageSpinnerModel;
+
+	private ModifiablePropertyValueModel<Object> eyeColorHolder;
+	private SpinnerModel eyeColorSpinnerModel;
+
+
+	public static void main(String[] args) throws Exception {
+		new SpinnerModelAdapterUITest().exec();
+	}
+
+	private SpinnerModelAdapterUITest() {
+		super();
+	}
+
+	private void exec() throws Exception {
+		this.testModel = new TestModel();
+		this.testModelHolder = new SimplePropertyValueModel<TestModel>(this.testModel);
+
+		this.birthDateHolder = this.buildBirthDateHolder(this.testModelHolder);
+		this.birthDateSpinnerModel = this.buildBirthDateSpinnerModel(this.birthDateHolder);
+
+		this.ageHolder = this.buildAgeHolder(this.testModelHolder);
+		this.ageSpinnerModel = this.buildAgeSpinnerModel(this.ageHolder);
+
+		this.eyeColorHolder = this.buildEyeColorHolder(this.testModelHolder);
+		this.eyeColorSpinnerModel = this.buildEyeColorSpinnerModel(this.eyeColorHolder);
+
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<Object> buildBirthDateHolder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.BIRTH_DATE_PROPERTY) {
+			@Override
+			protected Object buildValue_() {
+				return this.subject.getBirthDate();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setBirthDate((Date) value);
+			}
+		};
+	}
+
+	private SpinnerModel buildBirthDateSpinnerModel(ModifiablePropertyValueModel<Object> valueHolder) {
+		return new DateSpinnerModelAdapter(valueHolder);
+	}
+
+	private ModifiablePropertyValueModel<Number> buildAgeHolder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Number>(vm, TestModel.AGE_PROPERTY) {
+			@Override
+			protected Number buildValue_() {
+				return new Integer(this.subject.getAge());
+			}
+			@Override
+			protected void setValue_(Number value) {
+				this.subject.setAge(value.intValue());
+			}
+		};
+	}
+
+	private SpinnerModel buildAgeSpinnerModel(ModifiablePropertyValueModel<Number> valueHolder) {
+		return new NumberSpinnerModelAdapter(valueHolder, valueHolder.getValue().intValue(), TestModel.MIN_AGE, TestModel.MAX_AGE, 1);
+	}
+
+	private ModifiablePropertyValueModel<Object> buildEyeColorHolder(PropertyValueModel<TestModel> vm) {
+		return new PropertyAspectAdapter<TestModel, Object>(vm, TestModel.EYE_COLOR_PROPERTY) {
+			@Override
+			protected Object buildValue_() {
+				return this.subject.getEyeColor();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setEyeColor((String) value);
+			}
+		};
+	}
+
+	private SpinnerModel buildEyeColorSpinnerModel(ModifiablePropertyValueModel<Object> valueHolder) {
+		return new ListSpinnerModelAdapter(valueHolder, TestModel.VALID_EYE_COLORS);
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setSize(600, 100);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildSpinnerPanel(), BorderLayout.NORTH);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildSpinnerPanel() {
+		JPanel taskListPanel = new JPanel(new GridLayout(1, 0));
+		taskListPanel.add(this.buildBirthDateSpinner());
+		taskListPanel.add(this.buildAgeSpinner());
+		taskListPanel.add(this.buildEyeColorSpinner());
+		return taskListPanel;
+	}
+
+	private JSpinner buildBirthDateSpinner() {
+		return new JSpinner(this.birthDateSpinnerModel);
+	}
+
+	private JSpinner buildAgeSpinner() {
+		return new JSpinner(this.ageSpinnerModel);
+	}
+
+	private JSpinner buildEyeColorSpinner() {
+		return new JSpinner(this.eyeColorSpinnerModel);
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+		controlPanel.add(this.buildResetModelButton());
+		controlPanel.add(this.buildClearModelButton());
+		controlPanel.add(this.buildRestoreModelButton());
+		controlPanel.add(this.buildPrintModelButton());
+		return controlPanel;
+	}
+
+	private JButton buildResetModelButton() {
+		return new JButton(this.buildResetModelAction());
+	}
+
+	private Action buildResetModelAction() {
+		Action action = new AbstractAction("reset model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				SpinnerModelAdapterUITest.this.resetModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void resetModel() {
+		this.testModel.setBirthDate(TestModel.DEFAULT_BIRTH_DATE);
+		this.testModel.setEyeColor(TestModel.DEFAULT_EYE_COLOR);
+	}
+
+	private JButton buildClearModelButton() {
+		return new JButton(this.buildClearModelAction());
+	}
+
+	private Action buildClearModelAction() {
+		Action action = new AbstractAction("clear model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				SpinnerModelAdapterUITest.this.clearModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void clearModel() {
+		this.testModelHolder.setValue(null);
+	}
+
+	private JButton buildRestoreModelButton() {
+		return new JButton(this.buildRestoreModelAction());
+	}
+
+	private Action buildRestoreModelAction() {
+		Action action = new AbstractAction("restore model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				SpinnerModelAdapterUITest.this.restoreModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void restoreModel() {
+		this.testModelHolder.setValue(this.testModel);
+	}
+
+	private JButton buildPrintModelButton() {
+		return new JButton(this.buildPrintModelAction());
+	}
+
+	private Action buildPrintModelAction() {
+		Action action = new AbstractAction("print model") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				SpinnerModelAdapterUITest.this.printModel();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printModel() {
+		System.out.println("birth date: " + this.testModel.getBirthDate());
+		System.out.println("age: " + this.testModel.getAge());
+		System.out.println("eyes: " + this.testModel.getEyeColor());
+	}
+
+
+	static class TestModel extends AbstractModel {
+		private Calendar birthCal = Calendar.getInstance();
+			// "virtual" properties
+			public static final String BIRTH_DATE_PROPERTY = "birthDate";
+			public static final String AGE_PROPERTY = "age";
+			public static final Date DEFAULT_BIRTH_DATE = new Date();
+			public static final int DEFAULT_AGE = 0;
+			public static final int MIN_AGE = 0;
+			public static final int MAX_AGE = 150;
+		private String eyeColor;
+			public static final String EYE_COLOR_PROPERTY = "eyeColor";
+			public static final String[] VALID_EYE_COLORS = {"blue", "brown", "green", "hazel", "pink"};
+			public static final String DEFAULT_EYE_COLOR = VALID_EYE_COLORS[3];
+
+		TestModel() {
+			this(DEFAULT_BIRTH_DATE, DEFAULT_EYE_COLOR);
+		}
+		public TestModel(Date birthDate, String eyeColor) {
+			this.setBirthDate(birthDate);
+			this.setEyeColor(eyeColor);
+		}
+		public Date getBirthDate() {
+			return (Date) this.birthCal.getTime().clone();
+		}
+		public void setBirthDate(Date birthDate) {
+			Date oldBirthDate = this.getBirthDate();
+			int oldAge = this.getAge();
+			this.birthCal.setTimeInMillis(birthDate.getTime());
+			int newAge = this.getAge();
+			if (newAge < MIN_AGE || newAge > MAX_AGE) {
+				throw new IllegalArgumentException(birthDate.toString());
+			}
+			this.firePropertyChanged(BIRTH_DATE_PROPERTY, oldBirthDate, this.getBirthDate());
+			this.firePropertyChanged(AGE_PROPERTY, oldAge, newAge);
+		}
+		public int getAge() {
+			Calendar currentCal = Calendar.getInstance();
+			int age = currentCal.get(Calendar.YEAR) - this.birthCal.get(Calendar.YEAR);
+			if (currentCal.get(Calendar.MONTH) < this.birthCal.get(Calendar.MONTH)) {
+				age--;
+			} else if (currentCal.get(Calendar.MONTH) == this.birthCal.get(Calendar.MONTH)) {
+				if (currentCal.get(Calendar.DAY_OF_MONTH) < this.birthCal.get(Calendar.DAY_OF_MONTH)) {
+					age--;
+				}
+			}
+			return age;
+		}
+		public void setAge(int newAge) {
+			if (newAge < MIN_AGE || newAge > MAX_AGE) {
+				throw new IllegalArgumentException(String.valueOf(newAge));
+			}
+
+			int oldAge = this.getAge();
+			int delta = newAge - oldAge;
+
+			Calendar newBirthCal = Calendar.getInstance();
+			newBirthCal.setTimeInMillis(this.birthCal.getTime().getTime());
+			// if the age increased, the birth date must be "decreased"; and vice versa
+			newBirthCal.set(Calendar.YEAR, newBirthCal.get(Calendar.YEAR) - delta);
+			this.setBirthDate(newBirthCal.getTime());
+		}
+		public String getEyeColor() {
+			return this.eyeColor;
+		}
+		public void setEyeColor(String eyeColor) {
+			if ( ! ArrayTools.contains(VALID_EYE_COLORS, eyeColor)) {
+				throw new IllegalArgumentException(eyeColor);
+			}
+			Object old = this.eyeColor;
+			this.eyeColor = eyeColor;
+			this.firePropertyChanged(EYE_COLOR_PROPERTY, old, eyeColor);
+		}
+		@Override
+		public String toString() {
+			return "TestModel(birth: " + this.getBirthDate() + " - eyes: " + this.eyeColor + ")";
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java
new file mode 100644
index 0000000..e1e783e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterTests.java
@@ -0,0 +1,653 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.CollectionTools;
+import org.eclipse.persistence.tools.utility.iterator.CloneIterator;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.iterator.TransformationIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.TestTools;
+
+@SuppressWarnings("nls")
+public class TableModelAdapterTests extends TestCase {
+	private Crowd crowd;
+	TableModelEvent event;
+
+	public TableModelAdapterTests(String name) {
+		super(name);
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		this.crowd = this.buildCrowd();
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		TestTools.clear(this);
+		super.tearDown();
+	}
+
+	public void testGetRowCount() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		assertEquals(0, tableModelAdapter.getRowCount());
+		// we need to add a listener to wake up the adapter
+		tableModelAdapter.addTableModelListener(this.buildTableModelListener());
+		assertEquals(this.crowd.peopleSize(), tableModelAdapter.getRowCount());
+	}
+
+	public void testGetColumnCount() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		assertEquals(PersonColumnAdapter.COLUMN_COUNT, tableModelAdapter.getColumnCount());
+	}
+
+	public void testGetValueAt() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		tableModelAdapter.addTableModelListener(this.buildTableModelListener());
+
+		List<String> sortedNames = this.sortedNames();
+		for (int i = 0; i < this.crowd.peopleSize(); i++) {
+			assertEquals(sortedNames.get(i), tableModelAdapter.getValueAt(i, PersonColumnAdapter.NAME_COLUMN));
+		}
+	}
+
+	public void testSetValueAt() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		this.event = null;
+		tableModelAdapter.addTableModelListener(new TestTableModelListener() {
+			@Override
+			public void tableChanged(TableModelEvent e) {
+				TableModelAdapterTests.this.event = e;
+			}
+		});
+
+		Person person = this.crowd.personNamed("Gollum");
+		assertEquals(Person.EYE_COLOR_BLUE, person.getEyeColor());
+		assertFalse(person.isEvil());
+		assertEquals(0, person.getRank());
+
+		for (int i = 0; i < tableModelAdapter.getRowCount(); i++) {
+			if (tableModelAdapter.getValueAt(i, PersonColumnAdapter.NAME_COLUMN).equals("Gollum")) {
+				tableModelAdapter.setValueAt(Person.EYE_COLOR_HAZEL, i, PersonColumnAdapter.EYE_COLOR_COLUMN);
+				tableModelAdapter.setValueAt(Boolean.TRUE, i, PersonColumnAdapter.EVIL_COLUMN);
+				tableModelAdapter.setValueAt(new Integer(-1), i, PersonColumnAdapter.RANK_COLUMN);
+				break;
+			}
+		}
+		assertNotNull(this.event);
+		assertEquals(Person.EYE_COLOR_HAZEL, person.getEyeColor());
+		assertTrue(person.isEvil());
+		assertEquals(-1, person.getRank());
+	}
+
+	public void testAddRow() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		this.event = null;
+		tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+		// add a person to the end of the list so we only trigger one event
+		this.crowd.addPerson("Zzzzz");
+		assertNotNull(this.event);
+		assertEquals(TableModelEvent.INSERT, this.event.getType());
+		assertEquals(TableModelEvent.ALL_COLUMNS, this.event.getColumn());
+	}
+
+	public void testRemoveRow() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		this.event = null;
+		tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+		// removing a person should only trigger one event, since a re-sort is not needed
+		this.crowd.removePerson(this.crowd.personNamed("Gollum"));
+		assertNotNull(this.event);
+		assertEquals(TableModelEvent.DELETE, this.event.getType());
+		assertEquals(TableModelEvent.ALL_COLUMNS, this.event.getColumn());
+	}
+
+	public void testChangeCell() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		this.event = null;
+		tableModelAdapter.addTableModelListener(this.buildSingleEventListener());
+		// add a person to the end of the list so we only trigger one event
+		Person person = this.crowd.personNamed("Gollum");
+		person.setEvil(true);
+		assertNotNull(this.event);
+		assertEquals(TableModelEvent.UPDATE, this.event.getType());
+		assertEquals(PersonColumnAdapter.EVIL_COLUMN, this.event.getColumn());
+	}
+
+	public void testLazyListListener() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		TableModelListener listener = this.buildTableModelListener();
+		assertTrue(this.crowd.hasNoCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+		tableModelAdapter.addTableModelListener(listener);
+		assertTrue(this.crowd.hasAnyCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+		tableModelAdapter.removeTableModelListener(listener);
+		assertTrue(this.crowd.hasNoCollectionChangeListeners(Crowd.PEOPLE_COLLECTION));
+	}
+
+	public void testLazyCellListener() throws Exception {
+		TableModelAdapter<Person> tableModelAdapter =  this.buildTableModelAdapter();
+		TableModelListener listener = this.buildTableModelListener();
+		Person person = this.crowd.personNamed("Gollum");
+		assertTrue(person.hasNoPropertyChangeListeners(Person.NAME_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.EVIL_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.RANK_PROPERTY));
+
+		tableModelAdapter.addTableModelListener(listener);
+		assertTrue(person.hasAnyPropertyChangeListeners(Person.NAME_PROPERTY));
+		assertTrue(person.hasAnyPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+		assertTrue(person.hasAnyPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+		assertTrue(person.hasAnyPropertyChangeListeners(Person.EVIL_PROPERTY));
+		assertTrue(person.hasAnyPropertyChangeListeners(Person.RANK_PROPERTY));
+
+		tableModelAdapter.removeTableModelListener(listener);
+		assertTrue(person.hasNoPropertyChangeListeners(Person.NAME_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.BIRTH_DATE_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.EYE_COLOR_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.EVIL_PROPERTY));
+		assertTrue(person.hasNoPropertyChangeListeners(Person.RANK_PROPERTY));
+	}
+
+	private TableModelAdapter<Person> buildTableModelAdapter() {
+		return new TableModelAdapter<Person>(this.buildSortedPeopleAdapter(), this.buildColumnAdapter()) {
+			@Override
+			protected PropertyChangeListener buildCellListener() {
+				return this.buildCellListener_();
+			}
+			@Override
+			protected ListChangeListener buildListChangeListener() {
+				return this.buildListChangeListener_();
+			}
+		};
+	}
+
+	private ListValueModel<Person> buildSortedPeopleAdapter() {
+		return new SortedListValueModelAdapter<Person>(this.buildPeopleAdapter());
+	}
+
+	private CollectionValueModel<Person> buildPeopleAdapter() {
+		return new CollectionAspectAdapter<Crowd, Person>(Crowd.PEOPLE_COLLECTION, this.crowd) {
+			@Override
+			protected Iterator<Person> iterator_() {
+				return this.subject.people();
+			}
+			@Override
+			protected int size_() {
+				return this.subject.peopleSize();
+			}
+		};
+	}
+
+	private Crowd buildCrowd() {
+		Crowd result = new Crowd();
+		result.addPerson("Bilbo");
+		result.addPerson("Gollum");
+		result.addPerson("Frodo");
+		result.addPerson("Samwise");
+		return result;
+	}
+
+	private TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+		return new PersonColumnAdapter();
+	}
+
+	private TableModelListener buildTableModelListener() {
+		return new TestTableModelListener();
+	}
+
+	private List<String> sortedNames() {
+		return new ArrayList<String>(CollectionTools.sortedSet(this.crowd.peopleNames()));
+	}
+
+	private TableModelListener buildSingleEventListener() {
+		return new TestTableModelListener() {
+			@Override
+			public void tableChanged(TableModelEvent e) {
+				// we expect only a single event
+				if (TableModelAdapterTests.this.event == null) {
+					TableModelAdapterTests.this.event = e;
+				} else {
+					fail("unexpected event");
+				}
+			}
+		};
+	}
+
+
+	// ********** classes **********
+
+	public static class PersonColumnAdapter
+		implements TableModelAdapter.ColumnAdapter
+	{
+		public static final int COLUMN_COUNT = 7;
+
+		public static final int NAME_COLUMN = 0;
+		public static final int BIRTH_DATE_COLUMN = 1;
+		public static final int GONE_WEST_DATE_COLUMN = 2;
+		public static final int EYE_COLOR_COLUMN = 3;
+		public static final int EVIL_COLUMN = 4;
+		public static final int RANK_COLUMN = 5;
+		public static final int ADVENTURE_COUNT_COLUMN = 6;
+
+		private static final String[] COLUMN_NAMES = new String[] {
+			"Name",
+			"Birth",
+			"Gone West",
+			"Eyes",
+			"Evil",
+			"Rank",
+			"Adventures"
+		};
+
+
+		@Override
+		public int columnCount() {
+			return COLUMN_COUNT;
+		}
+
+		@Override
+		public String columnName(int index) {
+			return COLUMN_NAMES[index];
+		}
+
+		@Override
+		public Class<?> columnClass(int index) {
+			switch (index) {
+				case NAME_COLUMN:					return Object.class;
+				case BIRTH_DATE_COLUMN:			return Date.class;
+				case GONE_WEST_DATE_COLUMN:	return Date.class;
+				case EYE_COLOR_COLUMN:			return Object.class;
+				case EVIL_COLUMN:					return Boolean.class;
+				case RANK_COLUMN:					return Integer.class;
+				case ADVENTURE_COUNT_COLUMN:return Integer.class;
+				default: 									return Object.class;
+			}
+		}
+
+		@Override
+		public boolean columnIsEditable(int index) {
+			return index != NAME_COLUMN;
+		}
+
+		@Override
+		public ModifiablePropertyValueModel<Object>[] cellModels(Object subject) {
+			Person person = (Person) subject;
+			@SuppressWarnings("unchecked")
+			ModifiablePropertyValueModel<Object>[] result = new ModifiablePropertyValueModel[COLUMN_COUNT];
+
+			result[NAME_COLUMN] = this.buildNameAdapter(person);
+			result[BIRTH_DATE_COLUMN] = this.buildBirthDateAdapter(person);
+			result[GONE_WEST_DATE_COLUMN] = this.buildGoneWestDateAdapter(person);
+			result[EYE_COLOR_COLUMN] = this.buildEyeColorAdapter(person);
+			result[EVIL_COLUMN] = this.buildEvilAdapter(person);
+			result[RANK_COLUMN] = this.buildRankAdapter(person);
+			result[ADVENTURE_COUNT_COLUMN] = this.buildAdventureCountAdapter(person);
+
+			return result;
+		}
+
+		private ModifiablePropertyValueModel<Object> buildNameAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.NAME_PROPERTY, person) {
+				@Override
+				protected String buildValue_() {
+					return this.subject.getName();
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setName((String) value);
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildBirthDateAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.BIRTH_DATE_PROPERTY, person) {
+				@Override
+				protected Date buildValue_() {
+					return this.subject.getBirthDate();
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setBirthDate((Date) value);
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildGoneWestDateAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.GONE_WEST_DATE_PROPERTY, person) {
+				@Override
+				protected Date buildValue_() {
+					return this.subject.getGoneWestDate();
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setGoneWestDate((Date) value);
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildEyeColorAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.EYE_COLOR_PROPERTY, person) {
+				@Override
+				protected String buildValue_() {
+					return this.subject.getEyeColor();
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setEyeColor((String) value);
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildEvilAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.EVIL_PROPERTY, person) {
+				@Override
+				protected Boolean buildValue_() {
+					return Boolean.valueOf(this.subject.isEvil());
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setEvil(((Boolean)value).booleanValue());
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildRankAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.RANK_PROPERTY, person) {
+				@Override
+				protected Integer buildValue_() {
+					return new Integer(this.subject.getRank());
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setRank(((Integer) value).intValue());
+				}
+			};
+		}
+
+		private ModifiablePropertyValueModel<Object> buildAdventureCountAdapter(Person person) {
+			return new PropertyAspectAdapter<Person, Object>(Person.ADVENTURE_COUNT_PROPERTY, person) {
+				@Override
+				protected Integer buildValue_() {
+					return new Integer(this.subject.getAdventureCount());
+				}
+				@Override
+				protected void setValue_(Object value) {
+					this.subject.setAdventureCount(((Integer) value).intValue());
+				}
+			};
+		}
+
+	}
+
+
+	public static class Crowd extends AbstractModel {
+		private final Collection<Person> people;
+			public static final String PEOPLE_COLLECTION = "people";
+
+		public Crowd() {
+			super();
+			this.people = new ArrayList<Person>();
+		}
+
+
+		public Iterator<Person> people() {
+			return new CloneIterator<Person>(this.people, new CloneIterator.Remover<Person>() {
+				@Override
+				public void remove(Person person) {
+					Crowd.this.removePerson(person);
+				}
+			});
+		}
+
+		public int peopleSize() {
+			return this.people.size();
+		}
+
+		public Person addPerson(String name) {
+			this.checkPersonName(name);
+			return this.addPerson(new Person(this, name));
+		}
+
+		private Person addPerson(Person person) {
+			this.addItemToCollection(person, this.people, PEOPLE_COLLECTION);
+			return person;
+		}
+
+		public void removePerson(Person person) {
+			this.removeItemFromCollection(person, this.people, PEOPLE_COLLECTION);
+		}
+
+		public void removePeople(Collection<Person> persons) {
+			this.removeItemsFromCollection(persons, this.people, PEOPLE_COLLECTION);
+		}
+
+		public void removePeople(Iterator<Person> persons) {
+			this.removeItemsFromCollection(persons, this.people, PEOPLE_COLLECTION);
+		}
+
+		void checkPersonName(String personName) {
+			if (personName == null) {
+				throw new NullPointerException();
+			}
+			if (IteratorTools.contains(this.peopleNames(), personName)) {
+				throw new IllegalArgumentException(personName);
+			}
+		}
+
+		public Iterator<String> peopleNames() {
+			return new TransformationIterator<Person, String>(this.people.iterator()) {
+				@Override
+				protected String transform(Person person) {
+					return person.getName();
+				}
+			};
+		}
+
+		public Person personNamed(String name) {
+			for (Iterator<Person> stream = this.people.iterator(); stream.hasNext(); ) {
+				Person person = stream.next();
+				if (person.getName().equals(name)) {
+					return person;
+				}
+			}
+			return null;
+		}
+
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, String.valueOf(this.people.size()) + " people");
+		}
+
+	}
+
+
+	public static class Person extends AbstractModel implements Comparable<Person> {
+		private Crowd crowd;
+		private String name;
+			public static final String NAME_PROPERTY= "name";
+		private Date birthDate;
+			public static final String BIRTH_DATE_PROPERTY= "birthDate";
+		private Date goneWestDate;
+			public static final String GONE_WEST_DATE_PROPERTY= "goneWestDate";
+		private String eyeColor;
+			public static final String EYE_COLOR_PROPERTY= "eyeColor";
+			public static final String EYE_COLOR_BLUE = "blue";
+			public static final String EYE_COLOR_GREEN = "green";
+			public static final String EYE_COLOR_BROWN = "brown";
+			public static final String EYE_COLOR_HAZEL = "hazel";
+			public static final String EYE_COLOR_PINK = "pink";
+			private static Collection<String> validEyeColors;
+			public static final String DEFAULT_EYE_COLOR = EYE_COLOR_BLUE;
+		private boolean evil;
+			public static final String EVIL_PROPERTY= "evil";
+		private int rank;
+			public static final String RANK_PROPERTY= "rank";
+		private int adventureCount;
+			public static final String ADVENTURE_COUNT_PROPERTY= "adventureCount";
+
+		Person(Crowd crowd, String name) {
+			super();
+			this.crowd = crowd;
+			this.name = name;
+			this.birthDate = new Date();
+			Calendar c = Calendar.getInstance();
+			c.add(Calendar.YEAR, 250);
+			this.goneWestDate = new Date(c.getTimeInMillis());
+			this.eyeColor = DEFAULT_EYE_COLOR;
+			this.evil = false;
+			this.rank = 0;
+			this.adventureCount = 0;
+		}
+
+		public static Collection<String> getValidEyeColors() {
+			if (validEyeColors == null) {
+				validEyeColors = buildValidEyeColors();
+			}
+			return validEyeColors;
+		}
+
+		private static Collection<String> buildValidEyeColors() {
+			Collection<String> result = new ArrayList<String>();
+			result.add(EYE_COLOR_BLUE);
+			result.add(EYE_COLOR_GREEN);
+			result.add(EYE_COLOR_BROWN);
+			result.add(EYE_COLOR_HAZEL);
+			result.add(EYE_COLOR_PINK);
+			return result;
+		}
+
+		public Crowd getCrowd() {
+			return this.crowd;
+		}
+
+		public String getName() {
+			return this.name;
+		}
+		public void setName(String name) {
+			this.crowd.checkPersonName(name);
+			Object old = this.name;
+			this.name = name;
+			this.firePropertyChanged(NAME_PROPERTY, old, name);
+		}
+
+		public Date getBirthDate() {
+			return this.birthDate;
+		}
+		public void setBirthDate(Date birthDate) {
+			Object old = this.birthDate;
+			this.birthDate = birthDate;
+			this.firePropertyChanged(BIRTH_DATE_PROPERTY, old, birthDate);
+		}
+
+		public Date getGoneWestDate() {
+			return this.goneWestDate;
+		}
+		public void setGoneWestDate(Date goneWestDate) {
+			Object old = this.goneWestDate;
+			this.goneWestDate = goneWestDate;
+			this.firePropertyChanged(GONE_WEST_DATE_PROPERTY, old, goneWestDate);
+		}
+
+		public String getEyeColor() {
+			return this.eyeColor;
+		}
+		public void setEyeColor(String eyeColor) {
+			if (! getValidEyeColors().contains(eyeColor)) {
+				throw new IllegalArgumentException(eyeColor);
+			}
+			Object old = this.eyeColor;
+			this.eyeColor = eyeColor;
+			this.firePropertyChanged(EYE_COLOR_PROPERTY, old, eyeColor);
+		}
+
+		public boolean isEvil() {
+			return this.evil;
+		}
+		public void setEvil(boolean evil) {
+			boolean old = this.evil;
+			this.evil = evil;
+			this.firePropertyChanged(EVIL_PROPERTY, old, evil);
+		}
+
+		public int getRank() {
+			return this.rank;
+		}
+		public void setRank(int rank) {
+			int old = this.rank;
+			this.rank = rank;
+			this.firePropertyChanged(RANK_PROPERTY, old, rank);
+		}
+
+		public int getAdventureCount() {
+			return this.adventureCount;
+		}
+		public void setAdventureCount(int adventureCount) {
+			int old = this.adventureCount;
+			this.adventureCount = adventureCount;
+			this.firePropertyChanged(ADVENTURE_COUNT_PROPERTY, old, adventureCount);
+		}
+
+		@Override
+		public int compareTo(Person p) {
+			return this.name.compareToIgnoreCase(p.name);
+		}
+
+		@Override
+		public String toString() {
+			return this.name +
+						"\tborn: " + DateFormat.getDateInstance().format(this.birthDate) +
+						"\tgone west: " + DateFormat.getDateInstance().format(this.goneWestDate) +
+						"\teyes: " + this.eyeColor +
+						"\tevil: " + this.evil +
+						"\trank: " + this.rank +
+						"\tadventures: " + this.adventureCount
+			;
+		}
+
+	}
+
+
+	private class TestTableModelListener implements TableModelListener {
+		TestTableModelListener() {
+			super();
+		}
+		@Override
+		public void tableChanged(TableModelEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java
new file mode 100644
index 0000000..41ee4a9
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TableModelAdapterUITest.java
@@ -0,0 +1,740 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ButtonModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.SpinnerModel;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+import javax.swing.text.Document;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.SimpleCollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.swing.CheckBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ComboBoxModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.DateSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.DocumentAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ListModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.NumberSpinnerModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.swing.ObjectListSelectionModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TableModelAdapter;
+import org.eclipse.persistence.tools.utility.swing.CheckBoxTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.ComboBoxTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.SpinnerTableCellRenderer;
+import org.eclipse.persistence.tools.utility.swing.TableCellEditorAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.Crowd;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.Person;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TableModelAdapterTests.PersonColumnAdapter;
+
+/**
+ * an example UI for testing the TableModelAdapter
+ * 	"name" column is read-only text field
+ * 	"birth date" column is date text field
+ * 	"gone west date" column is date spinner
+ * 	"eye color" column is combo-box
+ * 	"evil" column is check box
+ * 	"rank" column is number text field
+ * 	"adventure count" column is number spinner
+ *
+ * Note that the table model and row selection model share the same
+ * list value model (the sorted people adapter)
+ */
+@SuppressWarnings("nls")
+public class TableModelAdapterUITest {
+	private SimpleCollectionValueModel<Object> eyeColorsHolder;  // Object because it adapts to a combo-box
+	private ModifiablePropertyValueModel<Crowd> crowdHolder;
+	private ModifiablePropertyValueModel<Person> selectedPersonHolder;
+	private ListValueModel<Person> sortedPeopleAdapter;
+	private TableModel tableModel;
+	private ObjectListSelectionModel rowSelectionModel;
+	private Action removeAction;
+	private Action renameAction;
+
+	public static void main(String[] args) throws Exception {
+		new TableModelAdapterUITest().exec(args);
+	}
+
+	protected TableModelAdapterUITest() {
+		super();
+	}
+
+	protected void exec(@SuppressWarnings("unused") String[] args) throws Exception {
+		UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+		this.eyeColorsHolder = this. buildEyeColorCollectionHolder();
+		this.crowdHolder = this.buildCrowdHolder();
+		this.selectedPersonHolder = this.buildSelectedPersonHolder();
+		this.sortedPeopleAdapter = this.buildSortedPeopleAdapter();
+		this.tableModel = this.buildTableModel();
+		this.rowSelectionModel = this.buildRowSelectionModel();
+		this.openWindow();
+	}
+
+	private SimpleCollectionValueModel<Object> buildEyeColorCollectionHolder() {
+		return new SimpleCollectionValueModel<Object>(new ArrayList<Object>(Person.getValidEyeColors()));
+	}
+
+	private ModifiablePropertyValueModel<Crowd> buildCrowdHolder() {
+		return new SimplePropertyValueModel<Crowd>(this.buildCrowd());
+	}
+
+	private Crowd buildCrowd() {
+		Crowd crowd = new Crowd();
+
+		Person p = crowd.addPerson("Bilbo");
+		p.setEyeColor(Person.EYE_COLOR_BROWN);
+		p.setRank(22);
+		p.setAdventureCount(1);
+
+		p = crowd.addPerson("Gollum");
+		p.setEyeColor(Person.EYE_COLOR_PINK);
+		p.setEvil(true);
+		p.setRank(2);
+		p.setAdventureCount(50);
+
+		p = crowd.addPerson("Frodo");
+		p.setEyeColor(Person.EYE_COLOR_BLUE);
+		p.setRank(34);
+		p.setAdventureCount(1);
+
+		p = crowd.addPerson("Samwise");
+		p.setEyeColor(Person.EYE_COLOR_GREEN);
+		p.setRank(19);
+		p.setAdventureCount(1);
+
+		return crowd;
+	}
+
+	private ModifiablePropertyValueModel<Person> buildSelectedPersonHolder() {
+		return new SimplePropertyValueModel<Person>();
+	}
+
+	private ListValueModel<Person> buildSortedPeopleAdapter() {
+		return new SortedListValueModelWrapper<Person>(this.buildPeopleNameAdapter());
+	}
+
+	// the list will need to be re-sorted if a name changes
+	private ListValueModel<Person> buildPeopleNameAdapter() {
+		return new ItemPropertyListValueModelAdapter<Person>(this.buildPeopleAdapter(), Person.NAME_PROPERTY);
+	}
+
+	private CollectionValueModel<Person> buildPeopleAdapter() {
+		return new CollectionAspectAdapter<Crowd, Person>(this.crowdHolder, Crowd.PEOPLE_COLLECTION) {
+			@Override
+			protected Iterator<Person> iterator_() {
+				return this.subject.people();
+			}
+			@Override
+			protected int size_() {
+				return this.subject.peopleSize();
+			}
+		};
+	}
+
+	private TableModel buildTableModel() {
+		return new TableModelAdapter<Person>(this.sortedPeopleAdapter, this.buildColumnAdapter());
+	}
+
+	protected TableModelAdapter.ColumnAdapter buildColumnAdapter() {
+		return new PersonColumnAdapter();
+	}
+
+	private ObjectListSelectionModel buildRowSelectionModel() {
+		ObjectListSelectionModel rsm = new ObjectListSelectionModel(new ListModelAdapter(this.sortedPeopleAdapter));
+		rsm.addListSelectionListener(this.buildRowSelectionListener());
+		rsm.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		return rsm;
+	}
+
+	private ListSelectionListener buildRowSelectionListener() {
+		return new ListSelectionListener() {
+			@Override
+			public void valueChanged(ListSelectionEvent e) {
+				if (e.getValueIsAdjusting()) {
+					return;
+				}
+				TableModelAdapterUITest.this.rowSelectionChanged(e);
+			}
+		};
+	}
+
+	void rowSelectionChanged(@SuppressWarnings("unused") ListSelectionEvent event) {
+		Person selection = (Person) this.rowSelectionModel.selectedValue();
+		this.selectedPersonHolder.setValue(selection);
+		boolean personSelected = (selection != null);
+		this.removeAction.setEnabled(personSelected);
+		this.renameAction.setEnabled(personSelected);
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getSimpleName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setLocation(200, 200);
+		window.setSize(600, 400);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildTablePane(), BorderLayout.CENTER);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildTablePane() {
+		return new JScrollPane(this.buildTable());
+	}
+
+	private JTable buildTable() {
+		JTable table = new JTable(this.tableModel);
+		table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);	// see Java bug 5007652
+		table.setSelectionModel(this.rowSelectionModel);
+		table.setDoubleBuffered(true);
+		table.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN);
+		int rowHeight = 20;	// start with minimum of 20
+
+		// gone west column (spinner)
+		TableColumn column = table.getColumnModel().getColumn(PersonColumnAdapter.GONE_WEST_DATE_COLUMN);
+		SpinnerTableCellRenderer spinnerRenderer = this.buildDateSpinnerRenderer();
+		column.setCellRenderer(spinnerRenderer);
+		column.setCellEditor(new TableCellEditorAdapter(this.buildDateSpinnerRenderer()));
+		rowHeight = Math.max(rowHeight, spinnerRenderer.preferredHeight());
+
+		// eye color column (combo-box)
+		// the jdk combo-box renderer looks like a text field
+		// until the user starts an edit - use a custom one
+		column = table.getColumnModel().getColumn(PersonColumnAdapter.EYE_COLOR_COLUMN);
+		ComboBoxTableCellRenderer eyeColorRenderer = this.buildEyeColorComboBoxRenderer();
+		column.setCellRenderer(eyeColorRenderer);
+		column.setCellEditor(new TableCellEditorAdapter(this.buildEyeColorComboBoxRenderer()));
+		rowHeight = Math.max(rowHeight, eyeColorRenderer.preferredHeight());
+
+		// evil (check box)
+		// the jdk check box renderer and editor suck - use a custom ones
+		column = table.getColumnModel().getColumn(PersonColumnAdapter.EVIL_COLUMN);
+		CheckBoxTableCellRenderer evilRenderer = new CheckBoxTableCellRenderer();
+		column.setCellRenderer(evilRenderer);
+		column.setCellEditor(new TableCellEditorAdapter(new CheckBoxTableCellRenderer()));
+		rowHeight = Math.max(rowHeight, evilRenderer.preferredHeight());
+
+		// adventure count column (spinner)
+		column = table.getColumnModel().getColumn(PersonColumnAdapter.ADVENTURE_COUNT_COLUMN);
+		spinnerRenderer = this.buildNumberSpinnerRenderer();
+		column.setCellRenderer(spinnerRenderer);
+		column.setCellEditor(new TableCellEditorAdapter(this.buildNumberSpinnerRenderer()));
+		rowHeight = Math.max(rowHeight, spinnerRenderer.preferredHeight());
+
+		table.setRowHeight(rowHeight);
+		return table;
+	}
+
+	private SpinnerTableCellRenderer buildDateSpinnerRenderer() {
+		return new SpinnerTableCellRenderer(new DateSpinnerModelAdapter(new SimplePropertyValueModel<Object>()));
+	}
+
+	private SpinnerTableCellRenderer buildNumberSpinnerRenderer() {
+		return new SpinnerTableCellRenderer(new NumberSpinnerModelAdapter(new SimplePropertyValueModel<Number>()));
+	}
+
+	private ComboBoxTableCellRenderer buildEyeColorComboBoxRenderer() {
+		return new ComboBoxTableCellRenderer(this.buildReadOnlyEyeColorComboBoxModel(), this.buildEyeColorRenderer());
+	}
+
+	private ComboBoxModel buildReadOnlyEyeColorComboBoxModel() {
+		return new ComboBoxModelAdapter(this.eyeColorsHolder, new SimplePropertyValueModel<Object>());
+	}
+
+	private ListCellRenderer buildEyeColorRenderer() {
+		return new EyeColorRenderer();
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(0, 1));
+		controlPanel.add(this.buildButtonPanel());
+		controlPanel.add(this.buildPersonPanel());
+		return controlPanel;
+	}
+
+	private Component buildButtonPanel() {
+		JPanel buttonPanel = new JPanel(new GridLayout(1, 0));
+		buttonPanel.add(this.buildAddButton());
+		buttonPanel.add(this.buildRemoveButton());
+		buttonPanel.add(this.buildRenameButton());
+		buttonPanel.add(this.buildAddEyeColorButton());
+		buttonPanel.add(this.buildPrintButton());
+		buttonPanel.add(this.buildResetButton());
+		return buttonPanel;
+	}
+
+	private Component buildPersonPanel() {
+		JPanel personPanel = new JPanel(new GridLayout(1, 0));
+		personPanel.add(this.buildNameTextField());
+		personPanel.add(this.buildBirthDateSpinner());
+		personPanel.add(this.buildGoneWestDateSpinner());
+		personPanel.add(this.buildEyeColorComboBox());
+		personPanel.add(this.buildEvilCheckBox());
+		personPanel.add(this.buildRankSpinner());
+		personPanel.add(this.buildAdventureCountSpinner());
+		return personPanel;
+	}
+
+
+	// ********** add button **********
+
+	private JButton buildAddButton() {
+		return new JButton(this.buildAddAction());
+	}
+
+	private Action buildAddAction() {
+		Action action = new AbstractAction("add") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.addPerson();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void addPerson() {
+		String name = this.getNameFromUser();
+		if (name != null) {
+			this.setSelectedPerson(this.crowd().addPerson(name));
+		}
+	}
+
+
+	// ********** remove button **********
+
+	private JButton buildRemoveButton() {
+		return new JButton(this.buildRemoveAction());
+	}
+
+	private Action buildRemoveAction() {
+		this.removeAction = new AbstractAction("remove") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.removePerson();
+			}
+		};
+		this.removeAction.setEnabled(false);
+		return this.removeAction;
+	}
+
+	void removePerson() {
+		Person person = this.selectedPerson();
+		if (person != null) {
+			this.crowd().removePerson(person);
+		}
+	}
+
+
+	// ********** rename button **********
+
+	private JButton buildRenameButton() {
+		return new JButton(this.buildRenameAction());
+	}
+
+	private Action buildRenameAction() {
+		this.renameAction = new AbstractAction("rename") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.renamePerson();
+			}
+		};
+		this.renameAction.setEnabled(false);
+		return this.renameAction;
+	}
+
+	void renamePerson() {
+		Person person = this.selectedPerson();
+		if (person != null) {
+			String name = this.promptUserForName(person.getName());
+			if (name != null) {
+				person.setName(name);
+				this.setSelectedPerson(person);
+			}
+		}
+	}
+
+
+	// ********** add eye color button **********
+
+	private JButton buildAddEyeColorButton() {
+		return new JButton(this.buildAddEyeColorAction());
+	}
+
+	private Action buildAddEyeColorAction() {
+		Action action = new AbstractAction("add eye color") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.addEyeColor();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void addEyeColor() {
+		String color = this.promptUserForEyeColor();
+		if (color != null) {
+			this.eyeColorsHolder.add(color);
+		}
+	}
+
+	private String promptUserForEyeColor() {
+		while (true) {
+			String eyeColor = JOptionPane.showInputDialog("Eye Color");
+			if (eyeColor == null) {
+				return null;		// user pressed <Cancel>
+			}
+			if ((eyeColor.length() == 0)) {
+				JOptionPane.showMessageDialog(null, "The eye color is required.", "Invalid Eye Color", JOptionPane.ERROR_MESSAGE);
+			} else if (IteratorTools.contains(this.eyeColorsHolder.iterator(), eyeColor)) {
+				JOptionPane.showMessageDialog(null, "The eye color already exists.", "Invalid Eye Color", JOptionPane.ERROR_MESSAGE);
+			} else {
+				return eyeColor;
+			}
+		}
+	}
+
+
+	// ********** print button **********
+
+	private JButton buildPrintButton() {
+		return new JButton(this.buildPrintAction());
+	}
+
+	private Action buildPrintAction() {
+		Action action = new AbstractAction("print") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.printCrowd();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void printCrowd() {
+		System.out.println(this.crowd());
+		for (Iterator<Person> stream = this.crowd().people(); stream.hasNext(); ) {
+			System.out.println("\t" + stream.next());
+		}
+	}
+
+
+	// ********** reset button **********
+
+	private JButton buildResetButton() {
+		return new JButton(this.buildResetAction());
+	}
+
+	private Action buildResetAction() {
+		Action action = new AbstractAction("reset") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TableModelAdapterUITest.this.reset();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	void reset() {
+		this.crowdHolder.setValue(this.buildCrowd());
+	}
+
+
+	// ********** new name dialog **********
+
+	private String getNameFromUser() {
+		return this.promptUserForName(null);
+	}
+
+	private String promptUserForName(@SuppressWarnings("unused") String originalName) {
+		while (true) {
+			String name = JOptionPane.showInputDialog("Person Name");
+			if (name == null) {
+				return null;		// user pressed <Cancel>
+			}
+			if ((name.length() == 0)) {
+				JOptionPane.showMessageDialog(null, "The name is required.", "Invalid Name", JOptionPane.ERROR_MESSAGE);
+			} else if (IteratorTools.contains(this.crowd().peopleNames(), name)) {
+				JOptionPane.showMessageDialog(null, "The name already exists.", "Invalid Name", JOptionPane.ERROR_MESSAGE);
+			} else {
+				return name;
+			}
+		}
+	}
+
+
+	// ********** name text field **********
+
+	private Component buildNameTextField() {
+		JTextField textField = new JTextField(this.buildNameDocument(), null, 0);
+		textField.setEditable(false);
+		return textField;
+	}
+
+	private Document buildNameDocument() {
+		return new DocumentAdapter(this.buildNameAdapter());
+	}
+
+	private ModifiablePropertyValueModel<String> buildNameAdapter() {
+		return new PropertyAspectAdapter<Person, String>(this.selectedPersonHolder, Person.NAME_PROPERTY) {
+			@Override
+			protected String buildValue_() {
+				return this.subject.getName();
+			}
+			@Override
+			protected void setValue_(String value) {
+				this.subject.setName(value);
+			}
+		};
+	}
+
+
+	// ********** birth date spinner **********
+
+	private JSpinner buildBirthDateSpinner() {
+		return new JSpinner(this.buildBirthDateSpinnerModel());
+	}
+
+	private SpinnerModel buildBirthDateSpinnerModel() {
+		return new DateSpinnerModelAdapter(this.buildBirthDateAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Object> buildBirthDateAdapter() {
+		return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.BIRTH_DATE_PROPERTY) {
+			@Override
+			protected Date buildValue_() {
+				return this.subject.getBirthDate();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setBirthDate((Date) value);
+			}
+		};
+	}
+
+
+	// ********** gone west date spinner **********
+
+	private JSpinner buildGoneWestDateSpinner() {
+		return new JSpinner(this.buildGoneWestDateSpinnerModel());
+	}
+
+	private SpinnerModel buildGoneWestDateSpinnerModel() {
+		return new DateSpinnerModelAdapter(this.buildGoneWestDateAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Object> buildGoneWestDateAdapter() {
+		return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.GONE_WEST_DATE_PROPERTY) {
+			@Override
+			protected Date buildValue_() {
+				return this.subject.getGoneWestDate();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setGoneWestDate((Date) value);
+			}
+		};
+	}
+
+
+	// ********** eye color combo-box **********
+
+	private JComboBox buildEyeColorComboBox() {
+		return new JComboBox(this.buildEyeColorComboBoxModel());
+	}
+
+	private ComboBoxModel buildEyeColorComboBoxModel() {
+		return new ComboBoxModelAdapter(this.eyeColorsHolder, this.buildEyeColorAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Object> buildEyeColorAdapter() {
+		return new PropertyAspectAdapter<Person, Object>(this.selectedPersonHolder, Person.EYE_COLOR_PROPERTY) {
+			@Override
+			protected Object buildValue_() {
+				return this.subject.getEyeColor();
+			}
+			@Override
+			protected void setValue_(Object value) {
+				this.subject.setEyeColor((String) value);
+			}
+		};
+	}
+
+
+	// ********** evil check box **********
+
+	private JCheckBox buildEvilCheckBox() {
+		JCheckBox checkBox = new JCheckBox();
+		checkBox.setText("evil");
+		checkBox.setModel(this.buildEvilCheckBoxModel());
+		return checkBox;
+	}
+
+	private ButtonModel buildEvilCheckBoxModel() {
+		return new CheckBoxModelAdapter(this.buildEvilAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Boolean> buildEvilAdapter() {
+		return new PropertyAspectAdapter<Person, Boolean>(this.selectedPersonHolder, Person.EVIL_PROPERTY) {
+			@Override
+			protected Boolean buildValue_() {
+				return Boolean.valueOf(this.subject.isEvil());
+			}
+			@Override
+			protected void setValue_(Boolean value) {
+				this.subject.setEvil(value.booleanValue());
+			}
+		};
+	}
+
+
+	// ********** rank spinner **********
+
+	private JSpinner buildRankSpinner() {
+		return new JSpinner(this.buildRankSpinnerModel());
+	}
+
+	private SpinnerModel buildRankSpinnerModel() {
+		return new NumberSpinnerModelAdapter(this.buildRankAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Number> buildRankAdapter() {
+		return new PropertyAspectAdapter<Person, Number>(this.selectedPersonHolder, Person.RANK_PROPERTY) {
+			@Override
+			protected Number buildValue_() {
+				return new Integer(this.subject.getRank());
+			}
+			@Override
+			protected void setValue_(Number value) {
+				this.subject.setRank(value.intValue());
+			}
+		};
+	}
+
+
+	// ********** adventure count spinner **********
+
+	private JSpinner buildAdventureCountSpinner() {
+		return new JSpinner(this.buildAdventureCountSpinnerModel());
+	}
+
+	private SpinnerModel buildAdventureCountSpinnerModel() {
+		return new NumberSpinnerModelAdapter(this.buildAdventureCountAdapter());
+	}
+
+	private ModifiablePropertyValueModel<Number> buildAdventureCountAdapter() {
+		return new PropertyAspectAdapter<Person, Number>(this.selectedPersonHolder, Person.ADVENTURE_COUNT_PROPERTY) {
+			@Override
+			protected Number buildValue_() {
+				return new Integer(this.subject.getAdventureCount());
+			}
+			@Override
+			protected void setValue_(Number value) {
+				this.subject.setAdventureCount(value.intValue());
+			}
+		};
+	}
+
+
+	// ********** queries **********
+
+	private Crowd crowd() {
+		return this.crowdHolder.getValue();
+	}
+
+	private Person selectedPerson() {
+		if (this.rowSelectionModel.isSelectionEmpty()) {
+			return null;
+		}
+		return (Person) this.rowSelectionModel.selectedValue();
+	}
+
+	private void setSelectedPerson(Person person) {
+		this.rowSelectionModel.setSelectedValue(person);
+	}
+
+
+	// ********** custom renderer **********
+
+	/**
+	 * This is simply an example of a renderer for the embedded combo-box.
+	 * It does nothing special unless you uncomment the code below....
+	 */
+	private class EyeColorRenderer extends DefaultListCellRenderer {
+		EyeColorRenderer() {
+			super();
+		}
+		@Override
+		public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+			// just do something to show the renderer is working...
+	//		value = ">" + value;
+			return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java
new file mode 100644
index 0000000..5afbbd4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterTests.java
@@ -0,0 +1,831 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import javax.swing.Icon;
+import javax.swing.JTree;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+import junit.framework.TestCase;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.collection.HashBag;
+import org.eclipse.persistence.tools.utility.io.IndentingPrintWriter;
+import org.eclipse.persistence.tools.utility.iterator.ReadOnlyIterator;
+import org.eclipse.persistence.tools.utility.model.AbstractModel;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+import org.eclipse.persistence.tools.utility.model.value.AbstractTreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.CollectionAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ItemPropertyListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.NullListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyAspectAdapter;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimpleListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SortedListValueModelWrapper;
+import org.eclipse.persistence.tools.utility.model.value.StaticPropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TransformationListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TreeModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+
+@SuppressWarnings("nls")
+public class TreeModelAdapterTests extends TestCase {
+	boolean eventFired;
+
+	public TreeModelAdapterTests(String name) {
+		super(name);
+	}
+
+	public void testGetRoot() {
+		TreeModel treeModel = this.buildSortedTreeModel();
+		treeModel.addTreeModelListener(new TestTreeModelListener());
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		TestModel root = rootNode.getTestModel();
+		assertEquals("root", root.getName());
+//		root.dump();
+//		rootNode.dump();
+	}
+
+	public void testGetChild() {
+		TreeModel treeModel = this.buildSortedTreeModel();
+		treeModel.addTreeModelListener(new TestTreeModelListener());
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+
+		TestNode expected = rootNode.childNamed("node 1");
+		TestNode actual = (TestNode) treeModel.getChild(rootNode, 1);
+		assertEquals(expected, actual);
+
+		expected = rootNode.childNamed("node 2");
+		actual = (TestNode) treeModel.getChild(rootNode, 2);
+		assertEquals(expected, actual);
+	}
+
+	public void testGetChildCount() {
+		TreeModel treeModel = this.buildSortedTreeModel();
+		treeModel.addTreeModelListener(new TestTreeModelListener());
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+
+		assertEquals(5, treeModel.getChildCount(rootNode));
+
+		TestNode node = rootNode.childNamed("node 1");
+		assertEquals(1, treeModel.getChildCount(node));
+	}
+
+	public void testGetIndexOfChild() {
+		TreeModel treeModel = this.buildSortedTreeModel();
+		treeModel.addTreeModelListener(new TestTreeModelListener());
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+
+		TestNode child = rootNode.childNamed("node 0");
+		assertEquals(0, treeModel.getIndexOfChild(rootNode, child));
+
+		child = rootNode.childNamed("node 1");
+		assertEquals(1, treeModel.getIndexOfChild(rootNode, child));
+
+		child = rootNode.childNamed("node 2");
+		assertEquals(2, treeModel.getIndexOfChild(rootNode, child));
+		TestNode grandchild = child.childNamed("node 2.2");
+		assertEquals(2, treeModel.getIndexOfChild(child, grandchild));
+	}
+
+	public void testIsLeaf() {
+		TreeModel treeModel = this.buildSortedTreeModel();
+		treeModel.addTreeModelListener(new TestTreeModelListener());
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		assertFalse(treeModel.isLeaf(rootNode));
+		TestNode node = rootNode.childNamed("node 1");
+		assertFalse(treeModel.isLeaf(node));
+		node = rootNode.childNamed("node 3");
+		assertTrue(treeModel.isLeaf(node));
+	}
+
+
+	public void testTreeNodesChanged() {
+		// the only way to trigger a "node changed" event is to use an unsorted tree;
+		// a sorted tree will will trigger only "node removed" and "node inserted" events
+		TreeModel treeModel = this.buildUnsortedTreeModel();
+		this.eventFired = false;
+		treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesChanged(TreeModelEvent e) {
+				TreeModelAdapterTests.this.eventFired = true;
+			}
+		});
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		TestNode node = rootNode.childNamed("node 1");
+		TestModel tm = node.getTestModel();
+		tm.setName("node 1++");
+		assertTrue(this.eventFired);
+
+		this.eventFired = false;
+		node = node.childNamed("node 1.1");
+		tm = node.getTestModel();
+		tm.setName("node 1.1++");
+		assertTrue(this.eventFired);
+	}
+
+	public void testTreeNodesInserted() {
+		// use an unsorted tree so the nodes are not re-shuffled...
+		TreeModel treeModel = this.buildUnsortedTreeModel();
+		this.eventFired = false;
+		treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesInserted(TreeModelEvent e) {
+				TreeModelAdapterTests.this.eventFired = true;
+			}
+		});
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		TestNode node = rootNode.childNamed("node 1");
+		TestModel tm = node.getTestModel();
+		tm.addChild("new child...");
+		assertTrue(this.eventFired);
+
+		this.eventFired = false;
+		node = node.childNamed("node 1.1");
+		tm = node.getTestModel();
+		tm.addChild("another new child...");
+		assertTrue(this.eventFired);
+	}
+
+	public void testTreeNodesRemoved() {
+		TreeModel treeModel = this.buildUnsortedTreeModel();
+		this.eventFired = false;
+		treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesRemoved(TreeModelEvent e) {
+				TreeModelAdapterTests.this.eventFired = true;
+			}
+		});
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		TestModel root = rootNode.getTestModel();
+		root.removeChild(root.childNamed("node 3"));
+		assertTrue(this.eventFired);
+
+		this.eventFired = false;
+		TestNode node = rootNode.childNamed("node 2");
+		TestModel tm = node.getTestModel();
+		tm.removeChild(tm.childNamed("node 2.2"));
+		assertTrue(this.eventFired);
+	}
+
+	public void testTreeStructureChanged() {
+		ModifiablePropertyValueModel<TreeNodeValueModel<Object>> nodeHolder = new SimplePropertyValueModel<TreeNodeValueModel<Object>>(this.buildSortedRootNode());
+		TreeModel treeModel = this.buildTreeModel(nodeHolder);
+		this.eventFired = false;
+		treeModel.addTreeModelListener(new TestTreeModelListener() {
+			@Override
+			public void treeNodesInserted(TreeModelEvent e) {
+				// do nothing
+			}
+			@Override
+			public void treeNodesRemoved(TreeModelEvent e) {
+				// do nothing
+			}
+			@Override
+			public void treeStructureChanged(TreeModelEvent e) {
+				TreeModelAdapterTests.this.eventFired = true;
+			}
+		});
+		nodeHolder.setValue(this.buildUnsortedRootNode());
+		assertTrue(this.eventFired);
+	}
+
+	/**
+	 * test a problem we had where removing a child from a tree would cause
+	 * the JTree to call #equals(Object) on each node removed (actually, it was
+	 * TreePath, but that was because its own #equals(Object) was called by
+	 * JTree); and since we had already removed the last listener from the
+	 * aspect adapter, the aspect adapter would say its value was null; this
+	 * would cause a NPE until we tweaked TreeModelAdapter to remove its
+	 * listeners from a node only *after* the node had been completely
+	 * removed from the JTree
+	 * @see TreeModelAdapter#removeNode(Object[], int, TreeNodeValueModel)
+	 * @see TreeModelAdapter#addNode(Object[], int, TreeNodeValueModel)
+	 */
+	public void testLazyInitialization() {
+		TreeModel treeModel = this.buildSpecialTreeModel();
+		JTree jTree = new JTree(treeModel);
+		TestNode rootNode = (TestNode) treeModel.getRoot();
+		TestModel root = rootNode.getTestModel();
+		// this would cause a NPE:
+		root.removeChild(root.childNamed("node 3"));
+		assertEquals(treeModel, jTree.getModel());
+	}
+
+
+	private TreeModel buildSortedTreeModel() {
+		return this.buildTreeModel(this.buildSortedRootNode());
+	}
+
+	private TestNode buildSortedRootNode() {
+		return new SortedTestNode(this.buildRoot());
+	}
+
+	private TreeModel buildUnsortedTreeModel() {
+		return this.buildTreeModel(this.buildUnsortedRootNode());
+	}
+
+	private TestNode buildUnsortedRootNode() {
+		return new UnsortedTestNode(this.buildRoot());
+	}
+
+	private TreeModel buildSpecialTreeModel() {
+		return this.buildTreeModel(this.buildSpecialRootNode());
+	}
+
+	private TestNode buildSpecialRootNode() {
+		return new SpecialTestNode(this.buildRoot());
+	}
+
+	private TestModel buildRoot() {
+		TestModel root = new TestModel("root");
+		/*Node node_0 = */root.addChild("node 0");
+		TestModel node_1 = root.addChild("node 1");
+		TestModel node_1_1 = node_1.addChild("node 1.1");
+		/*Node node_1_1_1 = */node_1_1.addChild("node 1.1.1");
+		TestModel node_2 = root.addChild("node 2");
+		/*Node node_2_0 = */node_2.addChild("node 2.0");
+		/*Node node_2_1 = */node_2.addChild("node 2.1");
+		/*Node node_2_2 = */node_2.addChild("node 2.2");
+		/*Node node_2_3 = */node_2.addChild("node 2.3");
+		/*Node node_2_4 = */node_2.addChild("node 2.4");
+		/*Node node_2_5 = */node_2.addChild("node 2.5");
+		/*Node node_3 = */root.addChild("node 3");
+		/*Node node_4 = */root.addChild("node 4");
+		return root;
+	}
+
+
+	// ********** member classes **********
+
+	/**
+	 * This is a typical model class with the typical change notifications
+	 * for #name and #children.
+	 */
+	public static class TestModel extends AbstractModel {
+
+		// the  parent is immutable; the root's parent is null
+		private final TestModel parent;
+
+		// the name is mutable; so I guess it isn't the "primary key" :-)
+		private String name;
+			public static final String NAME_PROPERTY = "name";
+
+		private final Collection<TestModel> children;
+			public static final String CHILDREN_COLLECTION = "children";
+
+
+		public TestModel(String name) {	// root ctor
+			this(null, name);
+		}
+		private TestModel(TestModel parent, String name) {
+			super();
+			this.parent = parent;
+			this.name = name;
+			this.children = new HashBag<TestModel>();
+		}
+
+		public TestModel getParent() {
+			return this.parent;
+		}
+
+		public String getName() {
+			return this.name;
+		}
+		public void setName(String name) {
+			Object old = this.name;
+			this.name = name;
+			this.firePropertyChanged(NAME_PROPERTY, old, name);
+		}
+
+		public Iterator<TestModel> children() {
+			return new ReadOnlyIterator<TestModel>(this.children);
+		}
+		public int childrenSize() {
+			return this.children.size();
+		}
+		public TestModel addChild(String childName) {
+			TestModel child = new TestModel(this, childName);
+			this.addItemToCollection(child, this.children, CHILDREN_COLLECTION);
+			return child;
+		}
+		public TestModel[] addChildren(String[] childNames) {
+			TestModel[] newChildren = new TestModel[childNames.length];
+			for (int i = 0; i < childNames.length; i++) {
+				newChildren[i] = new TestModel(this, childNames[i]);
+			}
+			this.addItemsToCollection(newChildren, this.children, CHILDREN_COLLECTION);
+			return newChildren;
+		}
+		public void removeChild(TestModel child) {
+			this.removeItemFromCollection(child, this.children, CHILDREN_COLLECTION);
+		}
+		public void removeChildren(TestModel[] testModels) {
+			this.removeItemsFromCollection(testModels, this.children, CHILDREN_COLLECTION);
+		}
+		public void clearChildren() {
+			this.clearCollection(this.children, CHILDREN_COLLECTION);
+		}
+		public TestModel childNamed(String childName) {
+			for (TestModel child : this.children) {
+				if (child.getName().equals(childName)) {
+					return child;
+				}
+			}
+			throw new RuntimeException("child not found: " + childName);
+		}
+
+		@SuppressWarnings("resource")
+		public String dumpString() {
+			StringWriter sw = new StringWriter();
+			IndentingPrintWriter ipw = new IndentingPrintWriter(sw);
+			this.dumpOn(ipw);
+			return sw.toString();
+		}
+		public void dumpOn(IndentingPrintWriter writer) {
+			writer.println(this);
+			writer.indent();
+			for (TestModel child : this.children) {
+				child.dumpOn(writer);
+			}
+			writer.undent();
+		}
+		@SuppressWarnings("resource")
+		public void dumpOn(OutputStream stream) {
+			IndentingPrintWriter writer = new IndentingPrintWriter(new OutputStreamWriter(stream));
+			this.dumpOn(writer);
+			writer.flush();
+		}
+		public void dump() {
+			this.dumpOn(System.out);
+		}
+
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this, this.name);
+		}
+
+	}
+
+
+	/**
+	 * This Node wraps a TestModel and converts into something that can
+	 * be used by TreeModelAdapter. It converts changes to the TestModel's
+	 * name into "state changes" to the Node; and converts the
+	 * TestModel's children into a ListValueModel of Nodes whose order is
+	 * determined by subclass implementations.
+	 */
+	public static abstract class TestNode extends AbstractTreeNodeValueModel<Object> implements Displayable, Comparable<TestNode> {
+		/** the model object wrapped by this node */
+		private final TestModel testModel;
+		/** this node's parent node; null for the root node */
+		private final TestNode parent;
+		/** this node's child nodes */
+		private final ListValueModel<TreeNodeValueModel<Object>> childrenModel;
+		/** a listener that notifies us when the model object's "internal state" changes */
+		private final PropertyChangeListener testModelListener;
+
+
+		// ********** constructors/initialization **********
+
+		/**
+		 * root node constructor
+		 */
+		public TestNode(TestModel testModel) {
+			this(null, testModel);
+		}
+
+		/**
+		 * branch or leaf node constructor
+		 */
+		public TestNode(TestNode parent, TestModel testModel) {
+			super();
+			this.parent = parent;
+			this.testModel = testModel;
+			this.childrenModel = this.buildChildrenModel(testModel);
+			this.testModelListener = this.buildTestModelListener();
+		}
+
+		private PropertyChangeListener buildTestModelListener() {
+			return new PropertyChangeListener() {
+				@Override
+				public void propertyChanged(PropertyChangeEvent e) {
+					TestNode.this.testModelChanged(e);
+				}
+			};
+		}
+
+		/**
+		 * subclasses decide the order of the child nodes
+		 */
+		protected abstract ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel model);
+
+		/**
+		 * used by subclasses;
+		 * transform the test model children into nodes
+		 */
+		protected ListValueModel<TreeNodeValueModel<Object>> buildNodeAdapter(TestModel model) {
+			return new TransformationListValueModel<TestModel, TreeNodeValueModel<Object>>(this.buildChildrenAdapter(model)) {
+				@Override
+				protected TestNode transformItem(TestModel item) {
+					return TestNode.this.buildChildNode(item);
+				}
+			};
+		}
+
+		/**
+		 * subclasses must build a concrete node for the specified test model
+		 */
+		protected abstract TestNode buildChildNode(TestModel childTestModel);
+
+		/**
+		 * return a collection value model on the specified model's children
+		 */
+		protected CollectionValueModel<TestModel> buildChildrenAdapter(TestModel model) {
+			return new CollectionAspectAdapter<TestModel, TestModel>(TestModel.CHILDREN_COLLECTION, model) {
+				@Override
+				protected Iterator<TestModel> iterator_() {
+					return this.subject.children();
+				}
+				@Override
+				protected int size_() {
+					return this.subject.childrenSize();
+				}
+			};
+		}
+
+
+		// ********** TreeNodeValueModel implementation **********
+
+		@Override
+		public TestModel getValue() {
+			return this.testModel;
+		}
+
+		@Override
+		public TreeNodeValueModel<Object> parent() {
+			return this.parent;
+		}
+
+		@Override
+		public ListValueModel<TreeNodeValueModel<Object>> childrenModel() {
+			return this.childrenModel;
+		}
+
+
+		// ********** AbstractTreeNodeValueModel implementation **********
+
+		@Override
+		protected void engageValue() {
+			this.testModel.addPropertyChangeListener(TestModel.NAME_PROPERTY, this.testModelListener);
+		}
+
+		@Override
+		protected void disengageValue() {
+			this.testModel.removePropertyChangeListener(TestModel.NAME_PROPERTY, this.testModelListener);
+		}
+
+
+		// ********** Displayable implementation **********
+
+		@Override
+		public String displayString() {
+			return this.testModel.getName();
+		}
+
+		@Override
+		public Icon icon() {
+			return null;
+		}
+
+
+		// ********** debugging support **********
+
+		@SuppressWarnings("resource")
+		public String dumpString() {
+			StringWriter sw = new StringWriter();
+			IndentingPrintWriter ipw = new IndentingPrintWriter(sw);
+			this.dumpOn(ipw);
+			return sw.toString();
+		}
+
+		public void dumpOn(IndentingPrintWriter writer) {
+			writer.println(this);
+			writer.indent();
+			for (Iterator<TreeNodeValueModel<Object>> stream = this.childrenModel.iterator(); stream.hasNext(); ) {
+				// cast to a TestNode (i.e. this won't work with a NameTestNode in the tree)
+				((TestNode) stream.next()).dumpOn(writer);
+			}
+			writer.undent();
+		}
+
+		@SuppressWarnings("resource")
+		public void dumpOn(OutputStream stream) {
+			IndentingPrintWriter writer = new IndentingPrintWriter(new OutputStreamWriter(stream));
+			this.dumpOn(writer);
+			writer.flush();
+		}
+
+		public void dump() {
+			this.dumpOn(System.out);
+		}
+
+
+		// ********** behavior **********
+
+		/**
+		 * the model's name has changed, forward the event to our listeners
+		 */
+		protected void testModelChanged(PropertyChangeEvent e) {
+			// we need to notify listeners that our "internal state" has changed
+			this.fireStateChanged();
+			// our display string stays in synch with the model's name
+			this.firePropertyChanged(DISPLAY_STRING_PROPERTY, e.getOldValue(), e.getNewValue());
+		}
+
+
+		// ********** queries **********
+
+		public TestModel getTestModel() {
+			return this.testModel;
+		}
+
+		/**
+		 * testing convenience method
+		 */
+		public TestNode childNamed(String name) {
+			for (Iterator<TreeNodeValueModel<Object>> stream = this.childrenModel.iterator(); stream.hasNext(); ) {
+				TreeNodeValueModel<Object> childNode = stream.next();
+				if (childNode instanceof TestNode) {
+					if (((TestNode) childNode).getTestModel().getName().equals(name)) {
+						return (TestNode) childNode;
+					}
+				}
+			}
+			throw new IllegalArgumentException("child not found: " + name);
+		}
+
+
+		// ********** standard methods **********
+
+		@Override
+		public int compareTo(TestNode o) {
+			return this.displayString().compareTo(o.displayString());
+		}
+
+		@Override
+		public String toString() {
+			return "Node(" + this.testModel + ")";
+		}
+
+	}
+
+	/**
+	 * concrete implementation that keeps its children sorted
+	 */
+	public static class SortedTestNode extends TestNode {
+
+		// ********** constructors **********
+		public SortedTestNode(TestModel testModel) {
+			super(testModel);
+		}
+		public SortedTestNode(TestNode parent, TestModel testModel) {
+			super(parent, testModel);
+		}
+
+		// ********** initialization **********
+		/** the list should be sorted */
+		@Override
+		protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+			return new SortedListValueModelWrapper<TreeNodeValueModel<Object>>(this.buildDisplayStringAdapter(testModel));
+		}
+		/** the display string (name) of each node can change */
+		protected ListValueModel<TreeNodeValueModel<Object>> buildDisplayStringAdapter(TestModel testModel) {
+			return new ItemPropertyListValueModelAdapter<TreeNodeValueModel<Object>>(this.buildNodeAdapter(testModel), DISPLAY_STRING_PROPERTY);
+		}
+		/** children are also sorted nodes */
+		@Override
+		protected TestNode buildChildNode(TestModel childNode) {
+			return new SortedTestNode(this, childNode);
+		}
+
+	}
+
+
+	/**
+	 * concrete implementation that leaves its children unsorted
+	 */
+	public static class UnsortedTestNode extends TestNode {
+
+		// ********** constructors **********
+		public UnsortedTestNode(TestModel testModel) {
+			super(testModel);
+		}
+		public UnsortedTestNode(TestNode parent, TestModel testModel) {
+			super(parent, testModel);
+		}
+
+		// ********** initialization **********
+		/** the list should NOT be sorted */
+		@Override
+		protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+			return this.buildNodeAdapter(testModel);
+		}
+		/** children are also unsorted nodes */
+		@Override
+		protected TestNode buildChildNode(TestModel childNode) {
+			return new UnsortedTestNode(this, childNode);
+		}
+
+	}
+
+
+	/**
+	 * concrete implementation that leaves its children unsorted
+	 * and has a special set of children for "node 3"
+	 */
+	public static class SpecialTestNode extends UnsortedTestNode {
+
+		// ********** constructors **********
+		public SpecialTestNode(TestModel testModel) {
+			super(testModel);
+		}
+		public SpecialTestNode(TestNode parent, TestModel testModel) {
+			super(parent, testModel);
+		}
+
+		// ********** initialization **********
+		/** return a different list of children for "node 3" */
+		@Override
+		protected ListValueModel<TreeNodeValueModel<Object>> buildChildrenModel(TestModel testModel) {
+			if (testModel.getName().equals("node 3")) {
+				return this.buildSpecialChildrenModel();
+			}
+			return super.buildChildrenModel(testModel);
+		}
+		protected ListValueModel<TreeNodeValueModel<Object>> buildSpecialChildrenModel() {
+			TreeNodeValueModel<Object>[] children = new NameTestNode[1];
+			children[0] = new NameTestNode(this);
+			return new SimpleListValueModel<TreeNodeValueModel<Object>>(Arrays.asList(children));
+		}
+		/** children are also special nodes */
+		@Override
+		protected TestNode buildChildNode(TestModel childNode) {
+			return new SpecialTestNode(this, childNode);
+		}
+
+	}
+
+
+	public static class NameTestNode extends AbstractTreeNodeValueModel<Object> {
+		private final ModifiablePropertyValueModel<String> nameAdapter;
+		private final SpecialTestNode specialNode;		// parent node
+		private final PropertyChangeListener nameListener;
+		private final ListValueModel<TreeNodeValueModel<Object>> childrenModel;
+
+		// ********** construction/initialization **********
+
+		public NameTestNode(SpecialTestNode specialNode) {
+			super();
+			this.nameListener = this.buildNameListener();
+			this.specialNode = specialNode;
+			this.nameAdapter = this.buildNameAdapter();
+			this.childrenModel = new NullListValueModel<TreeNodeValueModel<Object>>();
+		}
+		protected PropertyChangeListener buildNameListener() {
+			return new PropertyChangeListener() {
+				@Override
+				public void propertyChanged(PropertyChangeEvent e) {
+					NameTestNode.this.nameChanged(e);
+				}
+			};
+		}
+		protected ModifiablePropertyValueModel<String> buildNameAdapter() {
+			return new PropertyAspectAdapter<TestModel, String>(TestModel.NAME_PROPERTY, this.getTestModel()) {
+				@Override
+				protected String buildValue_() {
+					return this.subject.getName();
+				}
+				@Override
+				protected void setValue_(String value) {
+					this.subject.setName(value);
+				}
+			};
+		}
+
+		public TestModel getTestModel() {
+			return this.specialNode.getTestModel();
+		}
+
+		// ********** TreeNodeValueModel implementation **********
+
+		@Override
+		public String getValue() {
+			return this.nameAdapter.getValue();
+		}
+		@Override
+		public void setValue(Object value) {
+			this.nameAdapter.setValue((String) value);
+		}
+		@Override
+		public TreeNodeValueModel<Object> parent() {
+			return this.specialNode;
+		}
+		@Override
+		public ListValueModel<TreeNodeValueModel<Object>> childrenModel() {
+			return this.childrenModel;
+		}
+
+		// ********** AbstractTreeNodeValueModel implementation **********
+
+		@Override
+		protected void engageValue() {
+			this.nameAdapter.addPropertyChangeListener(PropertyValueModel.VALUE, this.nameListener);
+		}
+		@Override
+		protected void disengageValue() {
+			this.nameAdapter.removePropertyChangeListener(PropertyValueModel.VALUE, this.nameListener);
+		}
+
+		// ********** behavior **********
+
+		protected void nameChanged(PropertyChangeEvent e) {
+			// we need to notify listeners that our "value" has changed
+			this.firePropertyChanged(VALUE, e.getOldValue(), e.getNewValue());
+		}
+	}
+
+	private TreeModel buildTreeModel(TestNode root) {
+		return this.buildTreeModel(new StaticPropertyValueModel<TreeNodeValueModel<Object>>(root));
+	}
+
+	private TreeModel buildTreeModel(PropertyValueModel<TreeNodeValueModel<Object>> rootHolder) {
+		return new TreeModelAdapter<Object>(rootHolder) {
+			@Override
+			protected ListChangeListener buildChildrenListener() {
+				return this.buildChildrenListener_();
+			}
+			@Override
+			protected StateChangeListener buildNodeStateListener() {
+				return this.buildNodeStateListener_();
+			}
+			@Override
+			protected PropertyChangeListener buildNodeValueListener() {
+				return this.buildNodeValueListener_();
+			}
+			@Override
+			protected PropertyChangeListener buildRootListener() {
+				return this.buildRootListener_();
+			}
+		};
+	}
+
+
+
+	/**
+	 * listener that will blow up with any event;
+	 * override and implement expected event methods
+	 */
+	public class TestTreeModelListener implements TreeModelListener {
+		@Override
+		public void treeNodesChanged(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeNodesInserted(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeNodesRemoved(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+		@Override
+		public void treeStructureChanged(TreeModelEvent e) {
+			fail("unexpected event");
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java
new file mode 100644
index 0000000..b30cca8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/TreeModelAdapterUITest.java
@@ -0,0 +1,434 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.GridLayout;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.WindowConstants;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import org.eclipse.persistence.tools.utility.collection.ListTools;
+import org.eclipse.persistence.tools.utility.iterator.EnumerationIterator;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.SimplePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+import org.eclipse.persistence.tools.utility.model.value.swing.TreeModelAdapter;
+import org.eclipse.persistence.tools.utility.tests.model.Displayable;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.SortedTestNode;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.TestModel;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.TestNode;
+import org.eclipse.persistence.tools.utility.tests.model.value.swing.TreeModelAdapterTests.UnsortedTestNode;
+
+/**
+ * an example UI for testing the TreeModelAdapter
+ */
+@SuppressWarnings("nls")
+public class TreeModelAdapterUITest {
+
+	// hold the tree so we can restore its expansion state
+	private JTree tree;
+	private ModifiablePropertyValueModel<TreeNodeValueModel<Object>> rootNodeHolder;
+	private boolean sorted;
+	private TreeModel treeModel;
+	private TreeSelectionModel treeSelectionModel;
+	private TextField nameTextField;
+
+	public static void main(String[] args) throws Exception {
+		new TreeModelAdapterUITest().exec();
+	}
+
+	private TreeModelAdapterUITest() {
+		super();
+	}
+
+	private void exec() throws Exception {
+		this.rootNodeHolder = this.buildRootNodeHolder();
+		this.sorted = this.rootNodeHolder.getValue() instanceof SortedTestNode;
+		this.treeModel = this.buildTreeModel();
+		this.treeSelectionModel = this.buildTreeSelectionModel();
+		this.nameTextField = new TextField();
+		this.openWindow();
+	}
+
+	private ModifiablePropertyValueModel<TreeNodeValueModel<Object>> buildRootNodeHolder() {
+		return new SimplePropertyValueModel<TreeNodeValueModel<Object>>(this.buildSortedRootNode());
+	}
+
+	private TestNode buildSortedRootNode() {
+		return new SortedTestNode(this.buildRoot());
+	}
+
+	private TestNode buildUnsortedRootNode() {
+		return new UnsortedTestNode(this.buildRoot());
+	}
+
+	private TestModel buildRoot() {
+		TestModel root = new TestModel("root");
+
+		TestModel node_1 = root.addChild("node 1");
+		/*Node node_1_1 = */node_1.addChild("node 1.1");
+
+		TestModel node_2 = root.addChild("node 2");
+		/*Node node_2_1 = */node_2.addChild("node 2.1");
+		TestModel node_2_2 = node_2.addChild("node 2.2");
+		/*Node node_2_2_1 = */node_2_2.addChild("node 2.2.1");
+		/*Node node_2_2_2 = */node_2_2.addChild("node 2.2.2");
+		/*Node node_2_3 = */node_2.addChild("node 2.3");
+		/*Node node_2_4 = */node_2.addChild("node 2.4");
+		/*Node node_2_5 = */node_2.addChild("node 2.5");
+
+		TestModel node_3 = root.addChild("node 3");
+		TestModel node_3_1 = node_3.addChild("node 3.1");
+		TestModel node_3_1_1 = node_3_1.addChild("node 3.1.1");
+		/*Node node_3_1_1_1 = */node_3_1_1.addChild("node 3.1.1.1");
+
+		/*Node node_4 = */root.addChild("node 4");
+
+		return root;
+	}
+
+	private TreeModel buildTreeModel() {
+		return new TreeModelAdapter<Object>(this.rootNodeHolder);
+	}
+
+	private TreeSelectionModel buildTreeSelectionModel() {
+		TreeSelectionModel tsm = new DefaultTreeSelectionModel();
+		tsm.addTreeSelectionListener(this.buildTreeSelectionListener());
+		tsm.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+		return tsm;
+	}
+
+	private TreeSelectionListener buildTreeSelectionListener() {
+		return new TreeSelectionListener() {
+			@Override
+			public void valueChanged(TreeSelectionEvent e) {
+				TreeModelAdapterUITest.this.treeSelectionChanged(e);
+			}
+		};
+	}
+
+	void treeSelectionChanged(@SuppressWarnings("unused") TreeSelectionEvent e) {
+		TestModel selectedTestModel = this.selectedTestModel();
+		if (selectedTestModel != null) {
+			this.nameTextField.setText(selectedTestModel.getName());
+		}
+	}
+
+	private void openWindow() {
+		JFrame window = new JFrame(this.getClass().getName());
+		window.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		window.addWindowListener(this.buildWindowListener());
+		window.getContentPane().add(this.buildMainPanel(), "Center");
+		window.setLocation(300, 300);
+		window.setSize(400, 400);
+		window.setVisible(true);
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private Component buildMainPanel() {
+		JPanel mainPanel = new JPanel(new BorderLayout());
+		mainPanel.add(this.buildTreePane(), BorderLayout.CENTER);
+		mainPanel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return mainPanel;
+	}
+
+	private Component buildTreePane() {
+		return new JScrollPane(this.buildTree());
+	}
+
+	private JTree buildTree() {
+		this.tree = new JTree(this.treeModel) {
+			@Override
+			public String convertValueToText(Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
+				return ((Displayable) value).displayString();
+			}
+		};
+		this.tree.setSelectionModel(this.treeSelectionModel);
+		this.tree.setRootVisible(true);
+		this.tree.setShowsRootHandles(true);
+		this.tree.setRowHeight(20);
+		this.tree.setDoubleBuffered(true);
+		return this.tree;
+	}
+
+	private Component buildControlPanel() {
+		JPanel controlPanel = new JPanel(new GridLayout(0, 1));
+		controlPanel.add(this.buildAddRenameNodePanel());
+		controlPanel.add(this.buildMiscPanel());
+		return controlPanel;
+	}
+
+	private Component buildAddRenameNodePanel() {
+		JPanel addRenameNodePanel = new JPanel(new BorderLayout());
+		addRenameNodePanel.add(this.buildAddButton(), BorderLayout.WEST);
+		addRenameNodePanel.add(this.nameTextField, BorderLayout.CENTER);
+		addRenameNodePanel.add(this.buildRenameButton(), BorderLayout.EAST);
+		return addRenameNodePanel;
+	}
+
+	private Component buildMiscPanel() {
+		JPanel miscPanel = new JPanel(new GridLayout(1, 0));
+		miscPanel.add(this.buildClearChildrenButton());
+		miscPanel.add(this.buildRemoveButton());
+		miscPanel.add(this.buildResetButton());
+		return miscPanel;
+	}
+
+	private String getName() {
+		return this.nameTextField.getText();
+	}
+
+	// ********** queries **********
+	private TestNode selectedNode() {
+		if (this.treeSelectionModel.isSelectionEmpty()) {
+			return null;
+		}
+		return (TestNode) this.treeSelectionModel.getSelectionPath().getLastPathComponent();
+	}
+
+	private TestModel selectedTestModel() {
+		if (this.treeSelectionModel.isSelectionEmpty()) {
+			return null;
+		}
+		return this.selectedNode().getValue();
+	}
+
+	private TestNode rootNode() {
+		return (TestNode) this.treeModel.getRoot();
+	}
+
+	private TestModel root() {
+		return this.rootNode().getValue();
+	}
+
+	private Collection<TreePath> expandedPaths() {
+		Enumeration<TreePath> stream = this.tree.getExpandedDescendants(new TreePath(this.rootNode()));
+		if (stream == null) {
+			return Collections.emptyList();
+		}
+		return ListTools.list(new EnumerationIterator<TreePath>(stream));
+	}
+
+	// ********** behavior **********
+	private void setSelectedNode(TestNode selectedNode) {
+		this.treeSelectionModel.setSelectionPath(new TreePath(selectedNode.path()));
+	}
+
+	private void expandPaths(Collection<TreePath> paths) {
+		for (TreePath path : paths) {
+			this.tree.expandPath(path);
+		}
+	}
+
+	// ********** add **********
+	private JButton buildAddButton() {
+		return new JButton(this.buildAddAction());
+	}
+
+	private Action buildAddAction() {
+		Action action = new AbstractAction("add") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TreeModelAdapterUITest.this.addNode();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	/**
+	 * adding causes the tree to be sorted and nodes to be
+	 * removed and re-added; so we have to fiddle with the expansion state
+	 */
+	void addNode() {
+		TestModel selectedTestModel = this.selectedTestModel();
+		if (selectedTestModel != null) {
+			String name = this.getName();
+			// save the expansion state and restore it after the add
+			Collection<TreePath> paths = this.expandedPaths();
+
+			selectedTestModel.addChild(name);
+
+			this.expandPaths(paths);
+			this.setSelectedNode(this.selectedNode().childNamed(name));
+		}
+	}
+
+	// ********** remove **********
+	private JButton buildRemoveButton() {
+		return new JButton(this.buildRemoveAction());
+	}
+
+	private Action buildRemoveAction() {
+		Action action = new AbstractAction("remove") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TreeModelAdapterUITest.this.removeNode();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	/**
+	 * we need to figure out which node to select after
+	 * the selected node is deleted
+	 */
+	void removeNode() {
+		TestModel selectedTestModel = this.selectedTestModel();
+		// do not allow the root to be removed
+		if ((selectedTestModel != null) && (selectedTestModel != this.root())) {
+			// save the parent and index, so we can select another, nearby, node
+			// once the selected node is removed
+			TestNode parentNode = (TestNode) this.selectedNode().parent();
+			int childIndex = parentNode.indexOfChild(this.selectedNode());
+
+			selectedTestModel.getParent().removeChild(selectedTestModel);
+
+			int childrenSize = parentNode.childrenSize();
+			if (childIndex < childrenSize) {
+				// select the child that moved up and replaced the just-deleted child
+				this.setSelectedNode((TestNode) parentNode.child(childIndex));
+			} else {
+				if (childrenSize == 0) {
+					// if there are no more children, select the parent
+					this.setSelectedNode(parentNode);
+				} else {
+					// if the child at the bottom of the list was deleted, select the next child up
+					this.setSelectedNode((TestNode) parentNode.child(childIndex - 1));
+				}
+			}
+		}
+	}
+
+	// ********** rename **********
+	private JButton buildRenameButton() {
+		return new JButton(this.buildRenameAction());
+	}
+
+	private Action buildRenameAction() {
+		Action action = new AbstractAction("rename") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TreeModelAdapterUITest.this.renameNode();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	/**
+	 * renaming causes the tree to be sorted and nodes to be
+	 * removed and re-added; so we have to fiddle with the expansion state
+	 */
+	void renameNode() {
+		TestModel selectedTestModel = this.selectedTestModel();
+		if (selectedTestModel != null) {
+			// save the node and re-select it after the rename
+			TestNode selectedNode = this.selectedNode();
+			// save the expansion state and restore it after the rename
+			Collection<TreePath> paths = this.expandedPaths();
+
+			selectedTestModel.setName(this.getName());
+
+			this.expandPaths(paths);
+			this.setSelectedNode(selectedNode);
+		}
+	}
+
+	// ********** clear children **********
+	private JButton buildClearChildrenButton() {
+		return new JButton(this.buildClearChildrenAction());
+	}
+
+	private Action buildClearChildrenAction() {
+		Action action = new AbstractAction("clear children") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TreeModelAdapterUITest.this.clearChildren();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	/**
+	 * nothing special, we just want to test #fireCollectionChanged(String)
+	 */
+	void clearChildren() {
+		TestModel selectedTestModel = this.selectedTestModel();
+		if (selectedTestModel != null) {
+			selectedTestModel.clearChildren();
+		}
+	}
+
+	// ********** reset **********
+	private JButton buildResetButton() {
+		return new JButton(this.buildResetAction());
+	}
+
+	private Action buildResetAction() {
+		Action action = new AbstractAction("reset") {
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				TreeModelAdapterUITest.this.reset();
+			}
+		};
+		action.setEnabled(true);
+		return action;
+	}
+
+	/**
+	 * test the adapter's root node holder;
+	 * toggle between sorted and unsorted lists
+	 */
+	void reset() {
+		this.sorted = ! this.sorted;
+		if (this.sorted) {
+			this.rootNodeHolder.setValue(this.buildSortedRootNode());
+		} else {
+			this.rootNodeHolder.setValue(this.buildUnsortedRootNode());
+		}
+		this.tree.expandPath(new TreePath(this.rootNode()));
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java
new file mode 100644
index 0000000..e8b623d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/model/value/swing/UtilityModelValueSwingTests.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.model.value.swing;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class UtilityModelValueSwingTests {
+
+	public static Test suite() {
+		TestSuite suite = new TestSuite(UtilityModelValueSwingTests.class.getPackage().getName());
+
+		suite.addTestSuite(CheckBoxModelAdapterTests.class);
+		suite.addTestSuite(ComboBoxModelAdapterTests.class);
+		suite.addTestSuite(DateSpinnerModelAdapterTests.class);
+		suite.addTestSuite(DocumentAdapterTests.class);
+		suite.addTestSuite(ListModelAdapterTests.class);
+		suite.addTestSuite(ListSpinnerModelAdapterTests.class);
+		suite.addTestSuite(NumberSpinnerModelAdapterTests.class);
+		suite.addTestSuite(ObjectListSelectionModelTests.class);
+		suite.addTestSuite(PrimitiveListTreeModelTests.class);
+		suite.addTestSuite(RadioButtonModelAdapterTests.class);
+		suite.addTestSuite(SpinnerModelAdapterTests.class);
+		suite.addTestSuite(TableModelAdapterTests.class);
+		suite.addTestSuite(TreeModelAdapterTests.class);
+
+		return suite;
+	}
+
+	private UtilityModelValueSwingTests() {
+		super();
+		throw new UnsupportedOperationException();
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java
new file mode 100644
index 0000000..7c4ac59
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility.tests/src/org/eclipse/persistence/tools/utility/tests/swing/FilteringListPanelUITest.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.tests.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.UIManager;
+import javax.swing.WindowConstants;
+import org.eclipse.persistence.tools.utility.ArrayTools;
+import org.eclipse.persistence.tools.utility.ClassNameTools;
+import org.eclipse.persistence.tools.utility.Classpath;
+import org.eclipse.persistence.tools.utility.StringTools;
+import org.eclipse.persistence.tools.utility.iterable.TransformationIterable;
+import org.eclipse.persistence.tools.utility.swing.FilteringListPanel;
+import org.eclipse.persistence.tools.utility.swing.SimpleListCellRenderer;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+import org.eclipse.persistence.tools.utility.transformer.TransformerAdapter;
+
+/**
+ * Simple test class for playing around with {@link FilteringListPanel}.
+ * <p>
+ * Optional command line parm:<ul>
+ * <li>the name of a jar (or class folder) to use to populate the list box
+ * </ul>
+ */
+@SuppressWarnings("nls")
+public class FilteringListPanelUITest {
+	private Type[] completeList1;
+	private Type[] completeList2;
+	private FilteringListPanel<Type> filteringListPanel;
+	private Font font;
+
+
+	public static void main(String[] args) {
+		new FilteringListPanelUITest().exec(args);
+	}
+
+	private FilteringListPanelUITest() {
+		super();
+		this.initialize();
+	}
+
+	private void initialize() {
+		this.font = this.buildFont();
+	}
+
+	private Font buildFont() {
+		return new Font("Dialog", Font.PLAIN, 12);
+	}
+
+	private void exec(String[] args) {
+		this.completeList1 = this.buildTypeList(args);
+		this.completeList2 = this.buildCompleteList2();
+		JFrame frame = new JFrame(this.getClass().getSimpleName());
+		frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+		frame.addWindowListener(this.buildWindowListener());
+		frame.getContentPane().add(this.buildMainPanel(), "Center");
+		frame.setLocation(300, 300);
+		frame.setSize(400, 400);
+		frame.setVisible(true);
+	}
+
+	private Type[] buildTypeList(String[] args) {
+		return ArrayTools.sort(ArrayTools.array(this.buildTypes(args), Type.class));
+	}
+
+	private Type[] buildCompleteList2() {
+		String classpathEntry = Classpath.locationFor(this.getClass());
+		return ArrayTools.sort(ArrayTools.array(this.buildTypes(new String[] {classpathEntry}), Type.class));
+	}
+
+	private Iterable<Type> buildTypes(String[] args) {
+		return new TransformationIterable<String, Type>(this.buildClassNames(args), TYPE_STRING_TRANSFORMER);
+	}
+
+	private static final Transformer<String, Type> TYPE_STRING_TRANSFORMER = new TypeStringTransformer();
+	/* CU private */ static class TypeStringTransformer
+		extends TransformerAdapter<String, Type>
+	{
+		@Override
+		public Type transform(String string) {
+			return new Type(string);
+		}
+	}
+
+	private Iterable<String> buildClassNames(String[] args) {
+		return ((args == null) || (args.length == 0)) ?
+				Classpath.bootClasspath().getClassNames() :
+				new Classpath(new String[] { args[0] }).getClassNames();
+	}
+
+	private WindowListener buildWindowListener() {
+		return new WindowAdapter() {
+			@Override
+			public void windowClosing(WindowEvent e) {
+				e.getWindow().setVisible(false);
+				System.exit(0);
+			}
+		};
+	}
+
+	private JPanel buildMainPanel() {
+		JPanel panel = new JPanel(new BorderLayout());
+		this.filteringListPanel = this.buildFilteringListPanel();
+		panel.add(this.filteringListPanel, BorderLayout.CENTER);
+		panel.add(this.buildControlPanel(), BorderLayout.SOUTH);
+		return panel;
+	}
+
+	private FilteringListPanel<Type> buildFilteringListPanel() {
+		Type initialSelection = this.getTypeNamed(this.completeList1, "java.lang.Object");
+		FilteringListPanel<Type> panel = new FilteringListPanel<Type>(this.completeList1, initialSelection, TYPE_NAME_TRANSFORMER);
+		panel.setTextFieldLabelText("Choose a Type (? = any char, * = any string):");
+		panel.setListBoxLabelText("Matching Types:");
+		panel.setComponentsFont(this.font);
+		panel.setListBoxCellRenderer(new TypeCellRenderer());
+		return panel;
+	}
+
+	private static final Transformer<Type, String> TYPE_NAME_TRANSFORMER = new TypeNameTransformer();
+	/* CU private */ static class TypeNameTransformer
+		extends TransformerAdapter<Type, String>
+	{
+		@Override
+		public String transform(Type type) {
+			return (type == null) ? StringTools.EMPTY_STRING : type.getName();
+		}
+	}
+
+	/* CU private */ class TypeCellRenderer
+		extends SimpleListCellRenderer
+	{
+		private static final long serialVersionUID = 1L;
+		@Override
+		protected Icon buildIcon(Object value) {
+			return UIManager.getIcon("Tree.leafIcon");
+		}
+		@Override
+		protected String buildText(Object value) {
+			return ((Type) value).getName();
+		}
+	}
+
+	private JPanel buildControlPanel() {
+		JPanel panel = new JPanel(new GridLayout(1, 0));
+		panel.add(this.buildSwapButton());
+		panel.add(this.buildStringButton());
+		panel.add(this.buildNullButton());
+		panel.add(this.buildMax10Button());
+		panel.add(this.buildPrintButton());
+		return panel;
+	}
+
+	// ********** swap button **********
+
+	private JButton buildSwapButton() {
+		JButton button = new JButton(this.buildSwapAction());
+		button.setFont(this.font);
+		return button;
+	}
+
+	private Action buildSwapAction() {
+		return new AbstractAction("swap") {
+			private static final long serialVersionUID = 1L;
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				FilteringListPanelUITest.this.swap();
+			}
+		};
+	}
+
+	/**
+	 * swap in a new list
+	 */
+	void swap() {
+		if (this.filteringListPanel.getCompleteList() == this.completeList1) {
+			this.filteringListPanel.setCompleteList(this.completeList2);
+		} else {
+			this.filteringListPanel.setCompleteList(this.completeList1);
+		}
+	}
+
+	// ********** string button **********
+
+	private JButton buildStringButton() {
+		JButton button = new JButton(this.buildStringAction());
+		button.setFont(this.font);
+		return button;
+	}
+
+	private Action buildStringAction() {
+		return new AbstractAction("String") {
+			private static final long serialVersionUID = 1L;
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				FilteringListPanelUITest.this.selectStringType();
+			}
+		};
+	}
+
+	/**
+	 * force a selection from "outside" the filtering list panel
+	 */
+	void selectStringType() {
+		this.filteringListPanel.setSelection(this.typeNamed("java.lang.String"));
+	}
+
+	private Type typeNamed(String name) {
+		return this.getTypeNamed(this.filteringListPanel.getCompleteList(), name);
+	}
+
+	private Type getTypeNamed(Type[] types, String name) {
+		for (int i = types.length; i-- > 0; ) {
+			Type type = types[i];
+			if (type.getName().equals(name)) {
+				return type;
+			}
+		}
+		return null;
+	}
+
+	// ********** null button **********
+
+	private JButton buildNullButton() {
+		JButton button = new JButton(this.buildNullAction());
+		button.setFont(this.font);
+		return button;
+	}
+
+	private Action buildNullAction() {
+		return new AbstractAction("null") {
+			private static final long serialVersionUID = 1L;
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				FilteringListPanelUITest.this.selectNull();
+			}
+		};
+	}
+
+	/**
+	 * set the current selection to null
+	 */
+	void selectNull() {
+		this.filteringListPanel.setSelection(null);
+	}
+
+	// ********** null button **********
+
+	private JButton buildMax10Button() {
+		JButton button = new JButton(this.buildMax10Action());
+		button.setFont(this.font);
+		return button;
+	}
+
+	private Action buildMax10Action() {
+		return new AbstractAction("max = 10") {
+			private static final long serialVersionUID = 1L;
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				FilteringListPanelUITest.this.setMax10();
+			}
+		};
+	}
+
+	/**
+	 * toggle between allowing only 10 entries in the list box
+	 * and no limit
+	 */
+	void setMax10() {
+		if (this.filteringListPanel.getMaxListSize() == 10) {
+			this.filteringListPanel.setMaxListSize(-1);
+		} else {
+			this.filteringListPanel.setMaxListSize(10);
+		}
+	}
+
+	// ********** print button **********
+
+	private JButton buildPrintButton() {
+		JButton button = new JButton(this.buildPrintAction());
+		button.setFont(this.font);
+		return button;
+	}
+
+	private Action buildPrintAction() {
+		return new AbstractAction("print") {
+			private static final long serialVersionUID = 1L;
+			@Override
+			public void actionPerformed(ActionEvent event) {
+				FilteringListPanelUITest.this.printType();
+			}
+		};
+	}
+
+	/**
+	 * print the currently selected type to the console
+	 */
+	void printType() {
+		System.out.println("selected item: " + this.filteringListPanel.getSelection());
+	}
+
+
+	// ********** type **********
+
+	/* CU private */ static class Type
+		implements Comparable<Type>
+	{
+		private String name;
+
+		Type(String name) {
+			super();
+			this.name = name;
+		}
+		public String shortName() {
+			return ClassNameTools.simpleName(this.name);
+		}
+		public String getName() {
+			return this.name;
+		}
+		@Override
+		public String toString() {
+			return "Type: " + this.name ;
+		}
+		@Override
+		public int compareTo(Type type) {
+			return this.name.compareTo(type.name);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF b/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
index 85b1973..982ee8a 100644
--- a/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
+++ b/tools/org.eclipse.persistence.tools.utility/META-INF/MANIFEST.MF
@@ -12,12 +12,15 @@
  org.eclipse.persistence.tools.utility.model;version="2.5.0",
  org.eclipse.persistence.tools.utility.model.event;version="2.5.0",
  org.eclipse.persistence.tools.utility.model.listener;version="2.5.0",
+ org.eclipse.persistence.tools.utility.model.listener.awt;version="2.5.0",
  org.eclipse.persistence.tools.utility.model.value;version="2.5.0",
  org.eclipse.persistence.tools.utility.model.value.prefs;version="2.5.0",
+ org.eclipse.persistence.tools.utility.model.value.swing;version="2.5.0",
  org.eclipse.persistence.tools.utility.node;version="2.5.0",
  org.eclipse.persistence.tools.utility.prefs;version="2.5.0",
  org.eclipse.persistence.tools.utility.reference;version="2.5.0",
  org.eclipse.persistence.tools.utility.status;version="2.5.0",
+ org.eclipse.persistence.tools.utility.swing;version="2.5.0",
  org.eclipse.persistence.tools.utility.transformer;version="2.5.0"
 Bundle-ClassPath: .
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/tools/org.eclipse.persistence.tools.utility/pom.xml b/tools/org.eclipse.persistence.tools.utility/pom.xml
index a63a20a..55c43f1 100644
--- a/tools/org.eclipse.persistence.tools.utility/pom.xml
+++ b/tools/org.eclipse.persistence.tools.utility/pom.xml
@@ -16,4 +16,18 @@
         <relativePath>../org.eclipse.persistence.tools.parent/pom.xml</relativePath>
     </parent>
 
+    <build>
+	   <plugins>
+	      <plugin>
+	         <groupId>org.eclipse.tycho</groupId>
+	         <artifactId>tycho-compiler-plugin</artifactId>
+	         <version>${tycho.version}</version>
+	         <configuration>
+	         	<!-- Remove the restriction to access restricted classes, such as Swing classes. -->
+	           <compilerArgument>-err:-forbidden</compilerArgument>
+	         </configuration>
+	       </plugin> 
+	    </plugins>
+    </build>
+
 </project>
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java
new file mode 100644
index 0000000..8985bfb
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTChangeListenerWrapper.java
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ChangeListener;
+
+/**
+ * Wrap another change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTChangeListenerWrapper
+	implements ChangeListener
+{
+	private final ChangeListener listener;
+
+
+	public AWTChangeListenerWrapper(ChangeListener listener) {
+		super();
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		this.listener = listener;
+	}
+
+	@Override
+	public void stateChanged(StateChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.stateChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildStateChangedRunnable(event));
+		}
+	}
+
+	@Override
+	public void propertyChanged(PropertyChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.propertyChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildPropertyChangedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsAdded(CollectionAddEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsAdded_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsRemoved(CollectionRemoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsRemoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void collectionCleared(CollectionClearEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.collectionCleared_(event);
+		} else {
+			this.executeOnEventQueue(this.buildCollectionClearedRunnable(event));
+		}
+	}
+
+	@Override
+	public void collectionChanged(CollectionChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.collectionChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildCollectionChangedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsAdded(ListAddEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsAdded_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsRemoved(ListRemoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsRemoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsMoved(ListMoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsMoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsMovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsReplaced(ListReplaceEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsReplaced_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsReplacedRunnable(event));
+		}
+	}
+
+	@Override
+	public void listCleared(ListClearEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.listCleared_(event);
+		} else {
+			this.executeOnEventQueue(this.buildListClearedRunnable(event));
+		}
+	}
+
+	@Override
+	public void listChanged(ListChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.listChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildListChangedRunnable(event));
+		}
+	}
+
+	private Runnable buildStateChangedRunnable(final StateChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.stateChanged_(event);
+			}
+		};
+	}
+
+	private Runnable buildPropertyChangedRunnable(final PropertyChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.propertyChanged_(event);
+			}
+		};
+	}
+
+	private Runnable buildItemsAddedRunnable(final CollectionAddEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsAdded_(event);
+			}
+			@Override
+			public String toString() {
+				return "items added runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsRemovedRunnable(final CollectionRemoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsRemoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items removed runnable";
+			}
+		};
+	}
+
+	private Runnable buildCollectionClearedRunnable(final CollectionClearEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.collectionCleared_(event);
+			}
+			@Override
+			public String toString() {
+				return "collection cleared runnable";
+			}
+		};
+	}
+
+	private Runnable buildCollectionChangedRunnable(final CollectionChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.collectionChanged_(event);
+			}
+			@Override
+			public String toString() {
+				return "collection changed runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsAddedRunnable(final ListAddEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsAdded_(event);
+			}
+			@Override
+			public String toString() {
+				return "items added runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsRemovedRunnable(final ListRemoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsRemoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items removed runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsMovedRunnable(final ListMoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsMoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items moved runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsReplacedRunnable(final ListReplaceEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.itemsReplaced_(event);
+			}
+			@Override
+			public String toString() {
+				return "items replaced runnable";
+			}
+		};
+	}
+
+	private Runnable buildListClearedRunnable(final ListClearEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.listCleared_(event);
+			}
+			@Override
+			public String toString() {
+				return "list cleared runnable";
+			}
+		};
+	}
+
+	private Runnable buildListChangedRunnable(final ListChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTChangeListenerWrapper.this.listChanged_(event);
+			}
+			@Override
+			public String toString() {
+				return "list changed runnable";
+			}
+		};
+	}
+
+	private boolean isExecutingOnUIThread() {
+		return EventQueue.isDispatchThread();
+	}
+
+	/**
+	 * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+	 * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+	 * things more predictable when debugging, at the risk of deadlocks.
+	 */
+	private void executeOnEventQueue(Runnable r) {
+		EventQueue.invokeLater(r);
+//		try {
+//			EventQueue.invokeAndWait(r);
+//		} catch (InterruptedException ex) {
+//			throw new RuntimeException(ex);
+//		} catch (java.lang.reflect.InvocationTargetException ex) {
+//			throw new RuntimeException(ex);
+//		}
+	}
+
+	void stateChanged_(StateChangeEvent event) {
+		this.listener.stateChanged(event);
+	}
+
+	void propertyChanged_(PropertyChangeEvent event) {
+		this.listener.propertyChanged(event);
+	}
+
+	void itemsAdded_(CollectionAddEvent event) {
+		this.listener.itemsAdded(event);
+	}
+
+	void itemsRemoved_(CollectionRemoveEvent event) {
+		this.listener.itemsRemoved(event);
+	}
+
+	void collectionCleared_(CollectionClearEvent event) {
+		this.listener.collectionCleared(event);
+	}
+
+	void collectionChanged_(CollectionChangeEvent event) {
+		this.listener.collectionChanged(event);
+	}
+
+	void itemsAdded_(ListAddEvent event) {
+		this.listener.itemsAdded(event);
+	}
+
+	void itemsRemoved_(ListRemoveEvent event) {
+		this.listener.itemsRemoved(event);
+	}
+
+	void itemsMoved_(ListMoveEvent event) {
+		this.listener.itemsMoved(event);
+	}
+
+	void itemsReplaced_(ListReplaceEvent event) {
+		this.listener.itemsReplaced(event);
+	}
+
+	void listCleared_(ListClearEvent event) {
+		this.listener.listCleared(event);
+	}
+
+	void listChanged_(ListChangeEvent event) {
+		this.listener.listChanged(event);
+	}
+
+	@Override
+	public String toString() {
+		return "AWT(" + this.listener.toString() + ')';
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java
new file mode 100644
index 0000000..bc7e6a8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTCollectionChangeListenerWrapper.java
@@ -0,0 +1,172 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.CollectionAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.CollectionRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.listener.CollectionChangeListener;
+
+/**
+ * Wrap another collection change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTCollectionChangeListenerWrapper
+	implements CollectionChangeListener
+{
+	private final CollectionChangeListener listener;
+
+	public AWTCollectionChangeListenerWrapper(CollectionChangeListener listener) {
+		super();
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		this.listener = listener;
+	}
+
+	@Override
+	public void itemsAdded(CollectionAddEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsAdded_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsRemoved(CollectionRemoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsRemoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void collectionCleared(CollectionClearEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.collectionCleared_(event);
+		} else {
+			this.executeOnEventQueue(this.buildCollectionClearedRunnable(event));
+		}
+	}
+
+	@Override
+	public void collectionChanged(CollectionChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.collectionChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildCollectionChangedRunnable(event));
+		}
+	}
+
+	private Runnable buildItemsAddedRunnable(final CollectionAddEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTCollectionChangeListenerWrapper.this.itemsAdded_(event);
+			}
+			@Override
+			public String toString() {
+				return "items added runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsRemovedRunnable(final CollectionRemoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTCollectionChangeListenerWrapper.this.itemsRemoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items removed runnable";
+			}
+		};
+	}
+
+	private Runnable buildCollectionClearedRunnable(final CollectionClearEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTCollectionChangeListenerWrapper.this.collectionCleared_(event);
+			}
+			@Override
+			public String toString() {
+				return "collection cleared runnable";
+			}
+		};
+	}
+
+	private Runnable buildCollectionChangedRunnable(final CollectionChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTCollectionChangeListenerWrapper.this.collectionChanged_(event);
+			}
+			@Override
+			public String toString() {
+				return "collection changed runnable";
+			}
+		};
+	}
+
+	private boolean isExecutingOnUIThread() {
+		return EventQueue.isDispatchThread();
+	}
+
+	/**
+	 * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+	 * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+	 * things more predictable when debugging, at the risk of deadlocks.
+	 */
+	private void executeOnEventQueue(Runnable r) {
+		EventQueue.invokeLater(r);
+//		try {
+//			EventQueue.invokeAndWait(r);
+//		} catch (InterruptedException ex) {
+//			throw new RuntimeException(ex);
+//		} catch (java.lang.reflect.InvocationTargetException ex) {
+//			throw new RuntimeException(ex);
+//		}
+	}
+
+	void itemsAdded_(CollectionAddEvent event) {
+		this.listener.itemsAdded(event);
+	}
+
+	void itemsRemoved_(CollectionRemoveEvent event) {
+		this.listener.itemsRemoved(event);
+	}
+
+	void collectionCleared_(CollectionClearEvent event) {
+		this.listener.collectionCleared(event);
+	}
+
+	void collectionChanged_(CollectionChangeEvent event) {
+		this.listener.collectionChanged(event);
+	}
+
+	@Override
+	public String toString() {
+		return "AWT(" + this.listener.toString() + ')';
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java
new file mode 100644
index 0000000..fd57b22
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTListChangeListenerWrapper.java
@@ -0,0 +1,226 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+
+/**
+ * Wrap another list change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ */
+@SuppressWarnings("nls")
+public final class AWTListChangeListenerWrapper
+	implements ListChangeListener
+{
+	private final ListChangeListener listener;
+
+	public AWTListChangeListenerWrapper(ListChangeListener listener) {
+		super();
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		this.listener = listener;
+	}
+
+	@Override
+	public void itemsAdded(ListAddEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsAdded_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsAddedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsRemoved(ListRemoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsRemoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsRemovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsMoved(ListMoveEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsMoved_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsMovedRunnable(event));
+		}
+	}
+
+	@Override
+	public void itemsReplaced(ListReplaceEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.itemsReplaced_(event);
+		} else {
+			this.executeOnEventQueue(this.buildItemsReplacedRunnable(event));
+		}
+	}
+
+	@Override
+	public void listCleared(ListClearEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.listCleared_(event);
+		} else {
+			this.executeOnEventQueue(this.buildListClearedRunnable(event));
+		}
+	}
+
+	@Override
+	public void listChanged(ListChangeEvent event) {
+		if (this.isExecutingOnUIThread()) {
+			this.listChanged_(event);
+		} else {
+			this.executeOnEventQueue(this.buildListChangedRunnable(event));
+		}
+	}
+
+	private Runnable buildItemsAddedRunnable(final ListAddEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.itemsAdded_(event);
+			}
+			@Override
+			public String toString() {
+				return "items added runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsRemovedRunnable(final ListRemoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.itemsRemoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items removed runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsMovedRunnable(final ListMoveEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.itemsMoved_(event);
+			}
+			@Override
+			public String toString() {
+				return "items moved runnable";
+			}
+		};
+	}
+
+	private Runnable buildItemsReplacedRunnable(final ListReplaceEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.itemsReplaced_(event);
+			}
+			@Override
+			public String toString() {
+				return "items replaced runnable";
+			}
+		};
+	}
+
+	private Runnable buildListClearedRunnable(final ListClearEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.listCleared_(event);
+			}
+			@Override
+			public String toString() {
+				return "list cleared runnable";
+			}
+		};
+	}
+
+	private Runnable buildListChangedRunnable(final ListChangeEvent event) {
+		return new Runnable() {
+			@Override
+			public void run() {
+				AWTListChangeListenerWrapper.this.listChanged_(event);
+			}
+			@Override
+			public String toString() {
+				return "list changed runnable";
+			}
+		};
+	}
+
+	private boolean isExecutingOnUIThread() {
+		return EventQueue.isDispatchThread();
+	}
+
+	/**
+	 * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+	 * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+	 * things more predictable when debugging, at the risk of deadlocks.
+	 */
+	private void executeOnEventQueue(Runnable r) {
+		EventQueue.invokeLater(r);
+//		try {
+//			EventQueue.invokeAndWait(r);
+//		} catch (InterruptedException ex) {
+//			throw new RuntimeException(ex);
+//		} catch (java.lang.reflect.InvocationTargetException ex) {
+//			throw new RuntimeException(ex);
+//		}
+	}
+
+	void itemsAdded_(ListAddEvent event) {
+		this.listener.itemsAdded(event);
+	}
+
+	void itemsRemoved_(ListRemoveEvent event) {
+		this.listener.itemsRemoved(event);
+	}
+
+	void itemsMoved_(ListMoveEvent event) {
+		this.listener.itemsMoved(event);
+	}
+
+	void itemsReplaced_(ListReplaceEvent event) {
+		this.listener.itemsReplaced(event);
+	}
+
+	void listCleared_(ListClearEvent event) {
+		this.listener.listCleared(event);
+	}
+
+	void listChanged_(ListChangeEvent event) {
+		this.listener.listChanged(event);
+	}
+
+	@Override
+	public String toString() {
+		return "AWT(" + this.listener.toString() + ')';
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java
new file mode 100644
index 0000000..c3db685
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTPropertyChangeListenerWrapper.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.RunnableAdapter;
+import org.eclipse.persistence.tools.utility.collection.SynchronizedQueue;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+
+/**
+ * Wrap another property change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited. (Typically, the adapter(s) between a <em>property</em> and
+ * its corresponding UI widget are read-write; as opposed to the adapter(s)
+ * between a <em>collection</em> (or <em>list</em>) and its UI widget, which
+ * is read-only.)
+ * <p>
+ * Any events received earlier (on a non-UI thread) will be
+ * forwarded, in the order received, before the current event is forwarded.
+ */
+@SuppressWarnings("nls")
+public final class AWTPropertyChangeListenerWrapper
+	implements PropertyChangeListener
+{
+	private final PropertyChangeListener listener;
+	private final SynchronizedQueue<PropertyChangeEvent> events = new SynchronizedQueue<PropertyChangeEvent>();
+
+
+	public AWTPropertyChangeListenerWrapper(PropertyChangeListener listener) {
+		super();
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		this.listener = listener;
+	}
+
+	@Override
+	public void propertyChanged(PropertyChangeEvent event) {
+		this.events.enqueue(event);
+		if (this.isExecutingOnUIThread()) {
+			this.forwardEvents();
+		} else {
+			this.executeOnEventQueue(new ForwardEventsRunnable());
+		}
+	}
+
+	private boolean isExecutingOnUIThread() {
+		return EventQueue.isDispatchThread();
+	}
+
+	/* CU private */ class ForwardEventsRunnable
+		extends RunnableAdapter
+	{
+		@Override
+		public void run() {
+			AWTPropertyChangeListenerWrapper.this.forwardEvents();
+		}
+	}
+
+	/**
+	 * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+	 * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+	 * things more predictable when debugging, at the risk of deadlocks.
+	 */
+	private void executeOnEventQueue(Runnable r) {
+		EventQueue.invokeLater(r);
+//		try {
+//			EventQueue.invokeAndWait(r);
+//		} catch (InterruptedException ex) {
+//			throw new RuntimeException(ex);
+//		} catch (java.lang.reflect.InvocationTargetException ex) {
+//			throw new RuntimeException(ex);
+//		}
+	}
+
+	void forwardEvents() {
+		for (PropertyChangeEvent event : this.events.drain()) {
+			this.listener.propertyChanged(event);
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "AWT(" + this.listener.toString() + ')';
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java
new file mode 100644
index 0000000..cc875ea
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/listener/awt/AWTStateChangeListenerWrapper.java
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.listener.awt;
+
+import java.awt.EventQueue;
+import org.eclipse.persistence.tools.utility.RunnableAdapter;
+import org.eclipse.persistence.tools.utility.collection.SynchronizedQueue;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+
+/**
+ * Wrap another state change listener and forward events to it on the AWT
+ * event queue, asynchronously if necessary. If the event arrived on the UI
+ * thread that is probably because it was initiated by a UI widget; as a
+ * result, we want to loop back synchronously so the events can be
+ * short-circuited.
+ * <p>
+ * Any events received earlier (on a non-UI thread) will be
+ * forwarded, in the order received, before the current event is forwarded.
+ * @see AWTPropertyChangeListenerWrapper
+ */
+@SuppressWarnings("nls")
+public final class AWTStateChangeListenerWrapper
+	implements StateChangeListener
+{
+	private final StateChangeListener listener;
+	private final SynchronizedQueue<StateChangeEvent> events = new SynchronizedQueue<StateChangeEvent>();
+
+
+	public AWTStateChangeListenerWrapper(StateChangeListener listener) {
+		super();
+		if (listener == null) {
+			throw new NullPointerException();
+		}
+		this.listener = listener;
+	}
+
+	@Override
+	public void stateChanged(StateChangeEvent event) {
+		this.events.enqueue(event);
+		if (this.isExecutingOnUIThread()) {
+			this.forwardEvents();
+		} else {
+			this.executeOnEventQueue(new ForwardEventsRunnable());
+		}
+	}
+
+	private boolean isExecutingOnUIThread() {
+		return EventQueue.isDispatchThread();
+	}
+
+	/* CU private */ class ForwardEventsRunnable
+		extends RunnableAdapter
+	{
+		@Override
+		public void run() {
+			AWTStateChangeListenerWrapper.this.forwardEvents();
+		}
+	}
+
+	/**
+	 * {@link EventQueue#invokeLater(Runnable)} seems to work OK;
+	 * but using {@link EventQueue#invokeAndWait(Runnable)} can sometimes make
+	 * things more predictable when debugging, at the risk of deadlocks.
+	 */
+	private void executeOnEventQueue(Runnable r) {
+		EventQueue.invokeLater(r);
+//		try {
+//			EventQueue.invokeAndWait(r);
+//		} catch (InterruptedException ex) {
+//			throw new RuntimeException(ex);
+//		} catch (java.lang.reflect.InvocationTargetException ex) {
+//			throw new RuntimeException(ex);
+//		}
+	}
+
+	void forwardEvents() {
+		for (StateChangeEvent event : this.events.drain()) {
+			this.listener.stateChanged(event);
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "AWT(" + this.listener.toString() + ')';
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java
new file mode 100644
index 0000000..c288417
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/AbstractTreeModel.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.io.Serializable;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreeModel;
+
+/**
+ * Abstract class that should have been provided by the JDK
+ * (a la {@link javax.swing.AbstractListModel}). This class provides:<ul>
+ * <li>support for a collection of listeners
+ * <li>a number of convenience methods for firing events for those listeners
+ * </ul>
+ */
+public abstract class AbstractTreeModel
+	implements TreeModel, Serializable
+{
+	/** Our listeners. */
+	protected final EventListenerList listenerList;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors/initialization **********
+
+	protected AbstractTreeModel() {
+		super();
+		this.listenerList = new EventListenerList();
+	}
+
+
+	// ********** partial TreeModel implementation **********
+
+	@Override
+	public void addTreeModelListener(TreeModelListener l) {
+		this.listenerList.add(TreeModelListener.class, l);
+	}
+
+	@Override
+	public void removeTreeModelListener(TreeModelListener l) {
+		this.listenerList.remove(TreeModelListener.class, l);
+	}
+
+
+	// ********** queries **********
+
+	/**
+	 * Return the model's current collection of listeners.
+	 * (There seems to be a pattern of making this type of method public;
+	 * although it should probably be protected....)
+	 */
+	public TreeModelListener[] treeModelListeners() {
+ 		return this.listenerList.getListeners(TreeModelListener.class);
+	}
+
+	/**
+	 * Return whether this model has no listeners.
+	 */
+	protected boolean hasNoTreeModelListeners() {
+		return this.listenerList.getListenerCount(TreeModelListener.class) == 0;
+	}
+
+	/**
+	 * Return whether this model has any listeners.
+	 */
+	protected boolean hasTreeModelListeners() {
+		return ! this.hasNoTreeModelListeners();
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Notify listeners of a model change.
+	 * A significant property of the nodes changed, but the nodes themselves
+	 * are still the same objects.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodesChanged(Object[] path, int[] childIndices, Object[] children) {
+		// guaranteed to return a non-null array
+		Object[] listeners = this.listenerList.getListenerList();
+		TreeModelEvent event = null;
+		// process the listeners last to first, notifying
+		// those that are interested in this event
+		for (int i = listeners.length-2; i>=0; i-=2) {
+			if (listeners[i]==TreeModelListener.class) {
+				// lazily create the event
+				if (event == null) {
+					event = new TreeModelEvent(this, path, childIndices, children);
+				}
+				((TreeModelListener) listeners[i+1]).treeNodesChanged(event);
+			}
+		}
+	}
+
+
+	/**
+	 * Notify listeners of a model change.
+	 * A significant property of the node changed, but the node itself is the same object.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodeChanged(Object[] path, int childIndex, Object child) {
+		this.fireTreeNodesChanged(path, new int[] {childIndex}, new Object[] {child});
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * A significant property of the root changed, but the root itself is the same object.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeRootChanged(Object root) {
+		this.fireTreeNodesChanged(new Object[] {root}, null, null);
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodesInserted(Object[] path, int[] childIndices, Object[] children) {
+		// guaranteed to return a non-null array
+		Object[] listeners = this.listenerList.getListenerList();
+		TreeModelEvent event = null;
+		// process the listeners last to first, notifying
+		// those that are interested in this event
+		for (int i = listeners.length-2; i>=0; i-=2) {
+			if (listeners[i]==TreeModelListener.class) {
+				// lazily create the event
+				if (event == null) {
+					event = new TreeModelEvent(this, path, childIndices, children);
+				}
+				((TreeModelListener) listeners[i+1]).treeNodesInserted(event);
+			}
+		}
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodeInserted(Object[] path, int childIndex, Object child) {
+		this.fireTreeNodesInserted(path, new int[] {childIndex}, new Object[] {child});
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodesRemoved(Object[] path, int[] childIndices, Object[] children) {
+		// guaranteed to return a non-null array
+		Object[] listeners = this.listenerList.getListenerList();
+		TreeModelEvent event = null;
+		// process the listeners last to first, notifying
+		// those that are interested in this event
+		for (int i = listeners.length-2; i>=0; i-=2) {
+			if (listeners[i]==TreeModelListener.class) {
+				// lazily create the event
+				if (event == null) {
+					event = new TreeModelEvent(this, path, childIndices, children);
+				}
+				((TreeModelListener) listeners[i+1]).treeNodesRemoved(event);
+			}
+		}
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeNodeRemoved(Object[] path, int childIndex, Object child) {
+		this.fireTreeNodesRemoved(path, new int[] {childIndex}, new Object[] {child});
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeStructureChanged(Object[] path) {
+		// guaranteed to return a non-null array
+		Object[] listeners = this.listenerList.getListenerList();
+		TreeModelEvent event = null;
+		// process the listeners last to first, notifying
+		// those that are interested in this event
+		for (int i = listeners.length-2; i>=0; i-=2) {
+			if (listeners[i]==TreeModelListener.class) {
+				// lazily create the event
+				if (event == null) {
+					event = new TreeModelEvent(this, path);
+				}
+				((TreeModelListener) listeners[i+1]).treeStructureChanged(event);
+			}
+		}
+	}
+
+	/**
+	 * Notify listeners of a model change.
+	 * @see javax.swing.event.TreeModelEvent
+	 * @see javax.swing.event.TreeModelListener
+	 */
+	protected void fireTreeRootReplaced(Object newRoot) {
+		this.fireTreeStructureChanged(new Object[] {newRoot});
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java
new file mode 100644
index 0000000..e39c77a
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/CheckBoxModelAdapter.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+
+/**
+ * This javax.swing.ButtonModel can be used to keep a listener
+ * (e.g. a JCheckBox) in synch with a PropertyValueModel that
+ * holds a boolean.
+ *
+ * Maybe not the richest class in our toolbox, but it was the
+ * victim of refactoring....  ~bjv
+ */
+public class CheckBoxModelAdapter
+	extends ToggleButtonModelAdapter
+{
+	private static final long serialVersionUID = 1L;
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the boolean holder is required.
+	 */
+	public CheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
+		super(booleanHolder, defaultValue);
+	}
+
+	/**
+	 * Constructor - the boolean holder is required.
+	 * The default value will be false.
+	 */
+	public CheckBoxModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+		super(booleanHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java
new file mode 100644
index 0000000..e8add59
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ComboBoxModelAdapter.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.ComboBoxModel;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.ComboBoxModel can be used to keep a ListDataListener
+ * (e.g. a JComboBox) in synch with a ListValueModel (or a CollectionValueModel).
+ * For combo boxes, the model object that holds the current selection is
+ * typically a different model object than the one that holds the collection
+ * of choices.
+ *
+ * For example, a MWReference (the selectionOwner) has an attribute
+ * "sourceTable" (the collectionOwner)
+ * which holds on to a collection of MWDatabaseFields. When the selection
+ * is changed this model will keep the listeners aware of the changes.
+ * The inherited list model will keep its listeners aware of changes to the
+ * collection model
+ *
+ * In addition to the collection holder required by the superclass,
+ * an instance of this ComboBoxModel must be supplied with a
+ * selection holder, which is a PropertyValueModel that provides access
+ * to the selection (typically a PropertyAspectAdapter).
+ */
+@SuppressWarnings("nls")
+public class ComboBoxModelAdapter
+	extends ListModelAdapter
+	implements ComboBoxModel
+{
+	protected final ModifiablePropertyValueModel<Object> selectionHolder;
+	protected final PropertyChangeListener selectionListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the list holder and selection holder are required;
+	 */
+	public ComboBoxModelAdapter(ListValueModel<?> listHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+		super(listHolder);
+		if (selectionHolder == null) {
+			throw new NullPointerException();
+		}
+		this.selectionHolder = selectionHolder;
+		this.selectionListener = this.buildSelectionListener();
+	}
+
+	/**
+	 * Constructor - the collection holder and selection holder are required;
+	 */
+	public ComboBoxModelAdapter(CollectionValueModel<?> collectionHolder, ModifiablePropertyValueModel<Object> selectionHolder) {
+		super(collectionHolder);
+		if (selectionHolder == null) {
+			throw new NullPointerException();
+		}
+		this.selectionHolder = selectionHolder;
+		this.selectionListener = this.buildSelectionListener();
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildSelectionListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildSelectionListener_());
+	}
+
+	protected PropertyChangeListener buildSelectionListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				// notify listeners that the selection has changed
+				ComboBoxModelAdapter.this.fireSelectionChanged();
+			}
+			@Override
+			public String toString() {
+				return "selection listener";
+			}
+		};
+	}
+
+
+	// ********** ComboBoxModel implementation **********
+
+	@Override
+	public Object getSelectedItem() {
+		return this.selectionHolder.getValue();
+	}
+
+	@Override
+	public void setSelectedItem(Object selectedItem) {
+		this.selectionHolder.setValue(selectedItem);
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Extend to engage the selection holder.
+	 */
+	@Override
+	protected void engageModel() {
+		super.engageModel();
+		this.selectionHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
+	}
+
+	/**
+	 * Extend to disengage the selection holder.
+	 */
+	@Override
+	protected void disengageModel() {
+		this.selectionHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.selectionListener);
+		super.disengageModel();
+	}
+
+	/**
+	 * Notify the listeners that the selection has changed.
+	 */
+	protected void fireSelectionChanged() {
+		// I guess this will work...
+		this.fireContentsChanged(this, -1, -1);
+	}
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.selectionHolder + ":" + this.listHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java
new file mode 100644
index 0000000..bb8822f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DateSpinnerModelAdapter.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.Calendar;
+import java.util.Date;
+import javax.swing.SpinnerDateModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerDateModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a date.
+ *
+ * This class must be a sub-class of SpinnerDateModel because of some
+ * crappy jdk code....  ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see ListSpinnerModelAdapter
+ * @see NumberSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class DateSpinnerModelAdapter
+	extends SpinnerDateModel
+{
+	/**
+	 * The default spinner value; used when the underlying model date value is null.
+	 * The default is the current date.
+	 */
+	private final Date defaultValue;
+
+	/** A value model on the underlying date. */
+	private final ModifiablePropertyValueModel<Object> dateHolder;
+
+	/** A listener that allows us to synchronize with changes made to the underlying date. */
+	private final PropertyChangeListener dateChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the date holder is required.
+	 * The default spinner value is the current date.
+	 */
+	public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder) {
+		this(dateHolder, new Date());
+	}
+
+	/**
+	 * Constructor - the date holder and default value are required.
+	 */
+	public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Date defaultValue) {
+		this(dateHolder, null, null, Calendar.DAY_OF_MONTH, defaultValue);
+	}
+
+	/**
+	 * Constructor - the date holder is required.
+	 * The default spinner value is the current date.
+	 */
+	public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField) {
+		this(dateHolder, start, end, calendarField, new Date());
+	}
+
+	/**
+	 * Constructor - the date holder is required.
+	 */
+	public DateSpinnerModelAdapter(ModifiablePropertyValueModel<Object> dateHolder, Comparable<?> start, Comparable<?> end, int calendarField, Date defaultValue) {
+		super(dateHolder.getValue() == null ? defaultValue : (Date) dateHolder.getValue(), start, end, calendarField);
+		this.dateHolder = dateHolder;
+		this.dateChangeListener = this.buildDateChangeListener();
+		// postpone listening to the underlying date
+		// until we have listeners ourselves...
+		this.defaultValue = defaultValue;
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildDateChangeListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildDateChangeListener_());
+	}
+
+	protected PropertyChangeListener buildDateChangeListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				DateSpinnerModelAdapter.this.synchronize(event.getNewValue());
+			}
+			@Override
+			public String toString() {
+				return "date listener";
+			}
+		};
+	}
+
+
+	// ********** SpinnerModel implementation **********
+
+	/**
+	 * Extend to check whether this method is being called before we
+	 * have any listeners.
+	 * This is necessary because some crappy jdk code gets the value
+	 * from the model *before* listening to the model.  ~bjv
+	 * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+	 */
+    @Override
+	public Object getValue() {
+		if (this.getChangeListeners().length == 0) {
+			// sorry about this "lateral" call to super  ~bjv
+			super.setValue(this.spinnerValueOf(this.dateHolder.getValue()));
+		}
+		return super.getValue();
+	}
+
+	/**
+	 * Extend to update the underlying date directly.
+	 * The resulting event will be ignored: @see #synchronize(Object).
+	 */
+	@Override
+	public void setValue(Object value) {
+		super.setValue(value);
+		this.dateHolder.setValue(value);
+	}
+
+	/**
+	 * Extend to start listening to the underlying date if necessary.
+	 */
+	@Override
+	public void addChangeListener(ChangeListener listener) {
+		if (this.getChangeListeners().length == 0) {
+			this.dateHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
+			this.synchronize(this.dateHolder.getValue());
+		}
+		super.addChangeListener(listener);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying date if appropriate.
+	 */
+    @Override
+	public void removeChangeListener(ChangeListener listener) {
+		super.removeChangeListener(listener);
+		if (this.getChangeListeners().length == 0) {
+			this.dateHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.dateChangeListener);
+		}
+	}
+
+
+	// ********** queries **********
+
+	protected Date getDefaultValue() {
+		return this.defaultValue;
+	}
+
+	/**
+	 * Convert to a non-null value.
+	 */
+	protected Object spinnerValueOf(Object value) {
+		return (value == null) ? this.getDefaultValue() : value;
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Set the spinner value if it has changed.
+	 */
+	void synchronize(Object value) {
+		Object newValue = this.spinnerValueOf(value);
+		// check to see whether the spinner date has already been synchronized
+		// (via #setValue())
+		if ( ! this.getValue().equals(newValue)) {
+			this.setValue(newValue);
+		}
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.dateHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java
new file mode 100644
index 0000000..63c60d4
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/DocumentAdapter.java
@@ -0,0 +1,405 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.Serializable;
+import java.util.EventObject;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.EventListenerList;
+import javax.swing.event.UndoableEditEvent;
+import javax.swing.event.UndoableEditListener;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.Element;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import javax.swing.text.Segment;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.text.Document can be used to keep a DocumentListener
+ * (e.g. a JTextField) in synch with a PropertyValueModel that holds a string.
+ *
+ * NB: This model should only be used for "small" documents;
+ * i.e. documents used by text fields, not text panes.
+ * @see #synchronizeDelegate(String)
+ */
+@SuppressWarnings("nls")
+public class DocumentAdapter
+	implements Document, Serializable
+{
+	/** The delegate document whose behavior we "enhance". */
+	protected final Document delegate;
+
+	/** A listener that allows us to forward any changes made to the delegate document. */
+	protected final CombinedListener delegateListener;
+
+	/** A value model on the underlying model string. */
+	protected final ModifiablePropertyValueModel<String> stringHolder;
+
+	/** A listener that allows us to synchronize with changes made to the underlying model string. */
+	protected transient PropertyChangeListener stringListener;
+
+    /** The event listener list for the document. */
+    protected final EventListenerList listenerList = new EventListenerList();
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the string holder is required.
+	 * Wrap the specified document.
+	 */
+	public DocumentAdapter(ModifiablePropertyValueModel<String> stringHolder, Document delegate) {
+		super();
+		if (stringHolder == null || delegate == null) {
+			throw new NullPointerException();
+		}
+		this.stringHolder = stringHolder;
+		// postpone listening to the underlying model string
+		// until we have listeners ourselves...
+		this.delegate = delegate;
+		this.stringListener = this.buildStringListener();
+		this.delegateListener = this.buildDelegateListener();
+	}
+
+	/**
+	 * Constructor - the string holder is required.
+	 * Wrap a plain document.
+	 */
+	public DocumentAdapter(ModifiablePropertyValueModel<String> stringHolder) {
+		this(stringHolder, new PlainDocument());
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildStringListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildStringListener_());
+	}
+
+	protected PropertyChangeListener buildStringListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				DocumentAdapter.this.stringChanged(event);
+			}
+			@Override
+			public String toString() {
+				return "string listener";
+			}
+		};
+	}
+
+	protected CombinedListener buildDelegateListener() {
+		return new InternalListener();
+	}
+
+
+	// ********** Document implementation **********
+
+	@Override
+	public int getLength() {
+		return this.delegate.getLength();
+	}
+
+	/**
+	 * Extend to start listening to the underlying models if necessary.
+	 */
+	@Override
+	public void addDocumentListener(DocumentListener listener) {
+		if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
+			this.delegate.addDocumentListener(this.delegateListener);
+			this.engageStringHolder();
+		}
+		this.listenerList.add(DocumentListener.class, listener);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying models if appropriate.
+	 */
+	@Override
+	public void removeDocumentListener(DocumentListener listener) {
+		this.listenerList.remove(DocumentListener.class, listener);
+		if (this.listenerList.getListenerCount(DocumentListener.class) == 0) {
+			this.disengageStringHolder();
+			this.delegate.removeDocumentListener(this.delegateListener);
+		}
+	}
+
+	/**
+	 * Extend to start listening to the delegate document if necessary.
+	 */
+	@Override
+	public void addUndoableEditListener(UndoableEditListener listener) {
+		if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
+			this.delegate.addUndoableEditListener(this.delegateListener);
+		}
+		this.listenerList.add(UndoableEditListener.class, listener);
+	}
+
+	/**
+	 * Extend to stop listening to the delegate document if appropriate.
+	 */
+	@Override
+	public void removeUndoableEditListener(UndoableEditListener listener) {
+		this.listenerList.remove(UndoableEditListener.class, listener);
+		if (this.listenerList.getListenerCount(UndoableEditListener.class) == 0) {
+			this.delegate.removeUndoableEditListener(this.delegateListener);
+		}
+	}
+
+	@Override
+	public Object getProperty(Object key) {
+		return this.delegate.getProperty(key);
+	}
+
+	@Override
+	public void putProperty(Object key, Object value) {
+		this.delegate.putProperty(key, value);
+	}
+
+	/**
+	 * Extend to update the underlying model string directly.
+	 * The resulting event will be ignored: @see #synchronizeDelegate(String).
+	 */
+	@Override
+	public void remove(int offset, int len) throws BadLocationException {
+		this.delegate.remove(offset, len);
+		this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
+	}
+
+	/**
+	 * Extend to update the underlying model string directly.
+	 * The resulting event will be ignored: @see #synchronizeDelegate(String).
+	 */
+	@Override
+	public void insertString(int offset, String insertedString, AttributeSet a) throws BadLocationException {
+		this.delegate.insertString(offset, insertedString, a);
+		this.stringHolder.setValue(this.delegate.getText(0, this.delegate.getLength()));
+	}
+
+	@Override
+	public String getText(int offset, int length) throws BadLocationException {
+		return this.delegate.getText(offset, length);
+	}
+
+	@Override
+	public void getText(int offset, int length, Segment txt) throws BadLocationException {
+		this.delegate.getText(offset, length, txt);
+	}
+
+	@Override
+	public Position getStartPosition() {
+		return this.delegate.getStartPosition();
+	}
+
+	@Override
+	public Position getEndPosition() {
+		return this.delegate.getEndPosition();
+	}
+
+	@Override
+	public Position createPosition(int offs) throws BadLocationException {
+		return this.delegate.createPosition(offs);
+	}
+
+	@Override
+	public Element[] getRootElements() {
+		return this.delegate.getRootElements();
+	}
+
+	@Override
+	public Element getDefaultRootElement() {
+		return this.delegate.getDefaultRootElement();
+	}
+
+	@Override
+	public void render(Runnable r) {
+		this.delegate.render(r);
+	}
+
+
+	// ********** queries **********
+
+	public DocumentListener[] documentListeners() {
+		return this.listenerList.getListeners(DocumentListener.class);
+	}
+
+	public UndoableEditListener[] undoableEditListeners() {
+		return this.listenerList.getListeners(UndoableEditListener.class);
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * A third party has modified the underlying model string.
+	 * Synchronize the delegate document accordingly.
+	 */
+	protected void stringChanged(PropertyChangeEvent event) {
+		this.synchronizeDelegate((String) event.getNewValue());
+	}
+
+	/**
+	 * Replace the document's entire text string with the new string.
+	 */
+	protected void synchronizeDelegate(String s) {
+		try {
+			int len = this.delegate.getLength();
+			// check to see whether the delegate has already been synchronized
+			// (via #insertString() or #remove())
+			if ( ! this.delegate.getText(0, len).equals(s)) {
+				this.delegate.remove(0, len);
+				this.delegate.insertString(0, s, null);
+			}
+		} catch (BadLocationException ex) {
+			throw new IllegalStateException(ex.getMessage());	// this should not happen...
+		}
+	}
+
+	protected void engageStringHolder() {
+		this.stringHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+		this.synchronizeDelegate(this.stringHolder.getValue());
+	}
+
+	protected void disengageStringHolder() {
+		this.stringHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.stringListener);
+	}
+
+	protected void delegateChangedUpdate(DocumentEvent event) {
+		// no need to lazy-initialize the event;
+		// we wouldn't get here if we did not have listeners...
+		DocumentEvent ee = new InternalDocumentEvent(this, event);
+		DocumentListener[] listeners = this.documentListeners();
+		for (int i = listeners.length; i-- > 0; ) {
+			listeners[i].changedUpdate(ee);
+		}
+	}
+
+	protected void delegateInsertUpdate(DocumentEvent event) {
+		// no need to lazy-initialize the event;
+		// we wouldn't get here if we did not have listeners...
+		DocumentEvent ee = new InternalDocumentEvent(this, event);
+		DocumentListener[] listeners = this.documentListeners();
+		for (int i = listeners.length; i-- > 0; ) {
+			listeners[i].insertUpdate(ee);
+		}
+	}
+
+	protected void delegateRemoveUpdate(DocumentEvent event) {
+		// no need to lazy-initialize the event;
+		// we wouldn't get here if we did not have listeners...
+		DocumentEvent ee = new InternalDocumentEvent(this, event);
+		DocumentListener[] listeners = this.documentListeners();
+		for (int i = listeners.length; i-- > 0; ) {
+			listeners[i].removeUpdate(ee);
+		}
+	}
+
+	protected void delegateUndoableEditHappened(UndoableEditEvent event) {
+		// no need to lazy-initialize the event;
+		// we wouldn't get here if we did not have listeners...
+		UndoableEditEvent ee = new UndoableEditEvent(this, event.getEdit());
+		UndoableEditListener[] listeners = this.undoableEditListeners();
+		for (int i = listeners.length; i-- > 0; ) {
+			listeners[i].undoableEditHappened(ee);
+		}
+	}
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.stringHolder);
+	}
+
+	private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException {
+		// read in any hidden stuff
+		s.defaultReadObject();
+		this.stringListener = this.buildStringListener();
+	}
+
+
+// ********** inner class **********
+
+	protected interface CombinedListener extends DocumentListener, UndoableEditListener, Serializable {
+		// just consolidate the two interfaces
+	}
+
+	protected class InternalListener implements CombinedListener {
+		private static final long serialVersionUID = 1L;
+		@Override
+		public void changedUpdate(DocumentEvent event) {
+			DocumentAdapter.this.delegateChangedUpdate(event);
+		}
+		@Override
+		public void insertUpdate(DocumentEvent event) {
+			DocumentAdapter.this.delegateInsertUpdate(event);
+		}
+		@Override
+		public void removeUpdate(DocumentEvent event) {
+			DocumentAdapter.this.delegateRemoveUpdate(event);
+		}
+		@Override
+		public void undoableEditHappened(UndoableEditEvent event) {
+			DocumentAdapter.this.delegateUndoableEditHappened(event);
+		}
+	}
+
+	protected static class InternalDocumentEvent
+		extends EventObject
+		implements DocumentEvent
+	{
+		protected DocumentEvent delegate;
+
+		private static final long serialVersionUID = 1L;
+
+		protected InternalDocumentEvent(Document document, DocumentEvent delegate) {
+			super(document);
+			this.delegate = delegate;
+		}
+		@Override
+		public ElementChange getChange(Element elem) {
+			return this.delegate.getChange(elem);
+		}
+		@Override
+		public Document getDocument() {
+			return (Document) this.source;
+		}
+		@Override
+		public int getLength() {
+			return this.delegate.getLength();
+		}
+		@Override
+		public int getOffset() {
+			return this.delegate.getOffset();
+		}
+		@Override
+		public EventType getType() {
+			return this.delegate.getType();
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java
new file mode 100644
index 0000000..b1089b1
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListModelAdapter.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.AbstractListModel;
+import javax.swing.event.ListDataListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * This javax.swing.ListModel can be used to keep a ListDataListener
+ * (e.g. a JList) in synch with a ListValueModel (or a CollectionValueModel).
+ *
+ * An instance of this ListModel *must* be supplied with a value model,
+ * which is a ListValueModel on the bound list or a CollectionValueModel
+ * on the bound collection. This is required - the list (or collection)
+ * itself can be null, but the value model that holds it cannot.
+ */
+@SuppressWarnings("nls")
+public class ListModelAdapter
+	extends AbstractListModel
+{
+	/** A value model on the underlying model list. */
+	protected ListValueModel<?> listHolder;
+
+	/**
+	 * Cache the size of the list for "dramatic" changes.
+	 * @see #listChanged()
+	 */
+	protected int listSize;
+
+	/** A listener that allows us to forward changes made to the underlying model list. */
+	protected final ListChangeListener listChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Default constructor - initialize stuff.
+	 */
+	private ListModelAdapter() {
+		super();
+		this.listSize = 0;
+		this.listChangeListener = this.buildListChangeListener();
+	}
+
+	/**
+	 * Constructor - the list holder is required.
+	 */
+	public ListModelAdapter(ListValueModel<?> listHolder) {
+		this();
+		this.setModel(listHolder);
+	}
+
+	/**
+	 * Constructor - the collection holder is required.
+	 */
+	public ListModelAdapter(CollectionValueModel<?> collectionHolder) {
+		this();
+		this.setModel(collectionHolder);
+	}
+
+
+	// ********** initialization **********
+
+	protected ListChangeListener buildListChangeListener() {
+		return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+	}
+
+	protected ListChangeListener buildListChangeListener_() {
+		return new ListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {
+				ListModelAdapter.this.itemsAdded(event);
+			}
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) {
+				ListModelAdapter.this.itemsRemoved(event);
+			}
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) {
+				ListModelAdapter.this.itemsReplaced(event);
+			}
+			@Override
+			public void itemsMoved(ListMoveEvent event) {
+				ListModelAdapter.this.itemsMoved(event);
+			}
+			@Override
+			public void listCleared(ListClearEvent event) {
+				ListModelAdapter.this.listCleared();
+			}
+			@Override
+			public void listChanged(ListChangeEvent event) {
+				ListModelAdapter.this.listChanged();
+			}
+			@Override
+			public String toString() {
+				return "list listener";
+			}
+		};
+	}
+
+
+	// ********** ListModel implementation **********
+
+	@Override
+	public int getSize() {
+		return this.listHolder.size();
+	}
+
+	@Override
+	public Object getElementAt(int index) {
+		return this.listHolder.get(index);
+	}
+
+	/**
+	 * Extend to start listening to the underlying model list if necessary.
+	 */
+    @Override
+	public void addListDataListener(ListDataListener l) {
+		if (this.hasNoListDataListeners()) {
+			this.engageModel();
+			this.listSize = this.listHolder.size();
+		}
+		super.addListDataListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model list if appropriate.
+	 */
+    @Override
+	public void removeListDataListener(ListDataListener l) {
+		super.removeListDataListener(l);
+		if (this.hasNoListDataListeners()) {
+			this.disengageModel();
+			this.listSize = 0;
+		}
+	}
+
+
+	// ********** public API **********
+
+	/**
+	 * Return the underlying list model.
+	 */
+	public ListValueModel<?> model() {
+		return this.listHolder;
+	}
+
+	/**
+	 * Set the underlying list model.
+	 */
+	public void setModel(ListValueModel<?> listHolder) {
+		if (listHolder == null) {
+			throw new NullPointerException();
+		}
+		boolean hasListeners = this.hasListDataListeners();
+		if (hasListeners) {
+			this.disengageModel();
+		}
+		this.listHolder = listHolder;
+		if (hasListeners) {
+			this.engageModel();
+			this.listChanged();
+		}
+	}
+
+	/**
+	 * Set the underlying collection model.
+	 */
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public void setModel(CollectionValueModel<?> collectionHolder) {
+		this.setModel(new CollectionListValueModelAdapter(collectionHolder));
+	}
+
+
+	// ********** queries **********
+
+	/**
+	 * Return whether this model has no listeners.
+	 */
+	protected boolean hasNoListDataListeners() {
+		return this.getListDataListeners().length == 0;
+	}
+
+	/**
+	 * Return whether this model has any listeners.
+	 */
+	protected boolean hasListDataListeners() {
+		return ! this.hasNoListDataListeners();
+	}
+
+
+	// ********** behavior **********
+
+	protected void engageModel() {
+		this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+	}
+
+	protected void disengageModel() {
+		this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+	}
+
+
+
+	// ********** list change support **********
+
+	/**
+	 * Items were added to the underlying model list.
+	 * Notify listeners of the changes.
+	 */
+	protected void itemsAdded(ListAddEvent event) {
+		int start = event.getIndex();
+		int end = start + event.getItemsSize() - 1;
+		this.fireIntervalAdded(this, start, end);
+		this.listSize += event.getItemsSize();
+	}
+
+	/**
+	 * Items were removed from the underlying model list.
+	 * Notify listeners of the changes.
+	 */
+	protected void itemsRemoved(ListRemoveEvent event) {
+		int start = event.getIndex();
+		int end = start + event.getItemsSize() - 1;
+		this.fireIntervalRemoved(this, start, end);
+		this.listSize -= event.getItemsSize();
+	}
+
+	/**
+	 * Items were replaced in the underlying model list.
+	 * Notify listeners of the changes.
+	 */
+	protected void itemsReplaced(ListReplaceEvent event) {
+		int start = event.getIndex();
+		int end = start + event.getItemsSize() - 1;
+		this.fireContentsChanged(this, start, end);
+	}
+
+	/**
+	 * Items were moved in the underlying model list.
+	 * Notify listeners of the changes.
+	 */
+	protected void itemsMoved(ListMoveEvent event) {
+		int start = Math.min(event.getSourceIndex(), event.getTargetIndex());
+		int end = Math.max(event.getSourceIndex(), event.getTargetIndex()) + event.getLength() - 1;
+		this.fireContentsChanged(this, start, end);
+	}
+
+	/**
+	 * The underlying model list was cleared.
+	 * Notify listeners of the changes.
+	 */
+	protected void listCleared() {
+		if (this.listSize != 0) {
+			this.fireIntervalRemoved(this, 0, this.listSize - 1);
+			this.listSize = 0;
+		}
+	}
+
+	/**
+	 * The underlying model list has changed "dramatically".
+	 * Notify listeners of the changes.
+	 */
+	protected void listChanged() {
+		if (this.listSize != 0) {
+			this.fireIntervalRemoved(this, 0, this.listSize - 1);
+		}
+		this.listSize = this.listHolder.size();
+		if (this.listSize != 0) {
+			this.fireIntervalAdded(this, 0, this.listSize - 1);
+		}
+	}
+
+
+	// ********** Object overrides **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.listHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java
new file mode 100644
index 0000000..37cc11e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ListSpinnerModelAdapter.java
@@ -0,0 +1,224 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.Arrays;
+import java.util.List;
+import javax.swing.SpinnerListModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerListModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value
+ * in the list.
+ *
+ * This class must be a sub-class of SpinnerListModel because of some
+ * crappy jdk code....  ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * NB: This model should only be used for values that have a reasonably
+ * inexpensive #equals() implementation.
+ * @see #synchronize(Object)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see DateSpinnerModelAdapter
+ * @see NumberSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class ListSpinnerModelAdapter
+	extends SpinnerListModel
+{
+	/**
+	 * The default spinner value; used when the underlying model value is null.
+	 * The default is the first item on the list.
+	 */
+	private final Object defaultValue;
+
+	/** A value model on the underlying value. */
+	private final ModifiablePropertyValueModel<Object> valueHolder;
+
+	/** A listener that allows us to synchronize with changes made to the underlying value. */
+	private final PropertyChangeListener valueChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the value holder is required.
+	 * Use the model value itself as the default spinner value.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder) {
+		this(valueHolder, valueHolder.getValue());
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object defaultValue) {
+		this(valueHolder, new Object[] {defaultValue}, defaultValue);
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 * Use the first item in the list of values as the default spinner value.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object[] values) {
+		this(valueHolder, values, values[0]);
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object[] values, Object defaultValue) {
+		this(valueHolder, Arrays.asList(values), defaultValue);
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 * Use the first item in the list of values as the default spinner value.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, List<Object> values) {
+		this(valueHolder, values, values.get(0));
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 */
+	public ListSpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, List<Object> values, Object defaultValue) {
+		super(values);
+		this.valueHolder = valueHolder;
+		this.valueChangeListener = this.buildValueChangeListener();
+		// postpone listening to the underlying value
+		// until we have listeners ourselves...
+		this.defaultValue = defaultValue;
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildValueChangeListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildValueChangeListener_());
+	}
+
+	protected PropertyChangeListener buildValueChangeListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				ListSpinnerModelAdapter.this.synchronize(event.getNewValue());
+			}
+			@Override
+			public String toString() {
+				return "value listener";
+			}
+		};
+	}
+
+
+	// ********** SpinnerModel implementation **********
+
+	/**
+	 * Extend to check whether this method is being called before we
+	 * have any listeners.
+	 * This is necessary because some crappy jdk code gets the value
+	 * from the model *before* listening to the model.  ~bjv
+	 * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+	 */
+    @Override
+	public Object getValue() {
+		if (this.getChangeListeners().length == 0) {
+			// sorry about this "lateral" call to super  ~bjv
+			super.setValue(this.spinnerValueOf(this.valueHolder.getValue()));
+		}
+		return super.getValue();
+	}
+
+	/**
+	 * Extend to update the underlying value directly.
+	 * The resulting event will be ignored: @see #synchronize(Object).
+	 */
+    @Override
+	public void setValue(Object value) {
+		super.setValue(value);
+		this.valueHolder.setValue(value);
+	}
+
+	/**
+	 * Extend to start listening to the underlying value if necessary.
+	 */
+    @Override
+	public void addChangeListener(ChangeListener listener) {
+		if (this.getChangeListeners().length == 0) {
+			this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
+			this.synchronize(this.valueHolder.getValue());
+		}
+		super.addChangeListener(listener);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying value if appropriate.
+	 */
+    @Override
+	public void removeChangeListener(ChangeListener listener) {
+		super.removeChangeListener(listener);
+		if (this.getChangeListeners().length == 0) {
+			this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueChangeListener);
+		}
+	}
+
+
+	// ********** queries **********
+
+	protected Object getDefaultValue() {
+		return this.defaultValue;
+	}
+
+	/**
+	 * Convert to a non-null value.
+	 */
+	protected Object spinnerValueOf(Object value) {
+		return (value == null) ? this.getDefaultValue() : value;
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Set the spinner value if it has changed.
+	 */
+	void synchronize(Object value) {
+		Object newValue = this.spinnerValueOf(value);
+		// check to see whether the spinner value has already been synchronized
+		// (via #setValue())
+		if ( ! this.getValue().equals(newValue)) {
+			this.setValue(newValue);
+		}
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.valueHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java
new file mode 100644
index 0000000..366c2dc
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/NumberSpinnerModelAdapter.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerNumberModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a number.
+ *
+ * This class must be a sub-class of SpinnerNumberModel because of some
+ * crappy jdk code....  ~bjv
+ * @see javax.swing.JSpinner#createEditor(javax.swing.SpinnerModel)
+ *
+ * If this class needs to be modified, it would behoove us to review the
+ * other, similar classes:
+ * @see DateSpinnerModelAdapter
+ * @see ListSpinnerModelAdapter
+ */
+@SuppressWarnings("nls")
+public class NumberSpinnerModelAdapter
+	extends SpinnerNumberModel
+{
+	/**
+	 * The default spinner value; used when the
+	 * underlying model number value is null.
+	 */
+	private final Number defaultValue;
+
+	/** A value model on the underlying number. */
+	private final ModifiablePropertyValueModel<Number> numberHolder;
+
+	/**
+	 * A listener that allows us to synchronize with
+	 * changes made to the underlying number.
+	 */
+	private final PropertyChangeListener numberChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the number holder is required.
+	 * The default spinner value is zero.
+	 * The step size is one.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder) {
+		this(numberHolder, 0);
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 * The step size is one.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int defaultValue) {
+		this(numberHolder, null, null, Integer.valueOf(1), Integer.valueOf(defaultValue));
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 * Use the minimum value as the default spinner value.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize) {
+		this(numberHolder, minimum, maximum, stepSize, minimum);
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, int minimum, int maximum, int stepSize, int defaultValue) {
+		this(numberHolder, Integer.valueOf(minimum), Integer.valueOf(maximum), Integer.valueOf(stepSize), Integer.valueOf(defaultValue));
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 * Use the minimum value as the default spinner value.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, double minimum, double maximum, double stepSize) {
+		this(numberHolder, minimum, maximum, stepSize, minimum);
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, double minimum, double maximum, double stepSize, double defaultValue) {
+		this(numberHolder, Double.valueOf(minimum), Double.valueOf(maximum), Double.valueOf(stepSize), Double.valueOf(defaultValue));
+	}
+
+	/**
+	 * Constructor - the number holder is required.
+	 */
+	public NumberSpinnerModelAdapter(ModifiablePropertyValueModel<Number> numberHolder, Comparable<?> minimum, Comparable<?> maximum, Number stepSize, Number defaultValue) {
+		super(numberHolder.getValue() == null ? defaultValue : (Number) numberHolder.getValue(), minimum, maximum, stepSize);
+		this.numberHolder = numberHolder;
+		this.numberChangeListener = this.buildNumberChangeListener();
+		// postpone listening to the underlying number
+		// until we have listeners ourselves...
+		this.defaultValue = defaultValue;
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildNumberChangeListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildNumberChangeListener_());
+	}
+
+	protected PropertyChangeListener buildNumberChangeListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				NumberSpinnerModelAdapter.this.synchronize(event.getNewValue());
+			}
+			@Override
+			public String toString() {
+				return "number listener";
+			}
+		};
+	}
+
+
+	// ********** SpinnerModel implementation **********
+
+	/**
+	 * Extend to check whether this method is being called before we
+	 * have any listeners.
+	 * This is necessary because some crappy jdk code gets the value
+	 * from the model *before* listening to the model.  ~bjv
+	 * @see javax.swing.JSpinner.DefaultEditor#DefaultEditor(javax.swing.JSpinner)
+	 */
+    @Override
+	public Object getValue() {
+		if (this.getChangeListeners().length == 0) {
+			// sorry about this "lateral" call to super  ~bjv
+			super.setValue(this.spinnerValueOf(this.numberHolder.getValue()));
+		}
+		return super.getValue();
+	}
+
+	/**
+	 * Extend to update the underlying number directly.
+	 * The resulting event will be ignored: @see #synchronizeDelegate(Object).
+	 */
+    @Override
+	public void setValue(Object value) {
+		super.setValue(value);
+		this.numberHolder.setValue((Number) value);
+	}
+
+	/**
+	 * Extend to start listening to the underlying number if necessary.
+	 */
+    @Override
+	public void addChangeListener(ChangeListener listener) {
+		if (this.getChangeListeners().length == 0) {
+			this.numberHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
+			this.synchronize(this.numberHolder.getValue());
+		}
+		super.addChangeListener(listener);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying number if appropriate.
+	 */
+    @Override
+	public void removeChangeListener(ChangeListener listener) {
+		super.removeChangeListener(listener);
+		if (this.getChangeListeners().length == 0) {
+			this.numberHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.numberChangeListener);
+		}
+	}
+
+
+	// ********** queries **********
+
+	protected Number getDefaultValue() {
+		return this.defaultValue;
+	}
+
+	/**
+	 * Convert to a non-null value.
+	 */
+	protected Object spinnerValueOf(Object value) {
+		return (value == null) ? this.getDefaultValue() : value;
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Set the spinner value if it has changed.
+	 */
+	void synchronize(Object value) {
+		Object newValue = this.spinnerValueOf(value);
+		// check to see whether the date has already been synchronized
+		// (via #setValue())
+		if ( ! this.getValue().equals(newValue)) {
+			this.setValue(newValue);
+		}
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.numberHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java
new file mode 100644
index 0000000..b41b388
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ObjectListSelectionModel.java
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.ListModel;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+import javax.swing.event.ListSelectionListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.iterator.IteratorTools;
+
+/**
+ * This ListSelectionModel is aware of the ListModel and
+ * provides convenience methods to access and set the
+ * selected *objects*, as opposed to the selected *indexes*.
+ */
+@SuppressWarnings("nls")
+public class ObjectListSelectionModel
+	extends DefaultListSelectionModel
+{
+	/** The list model referenced by the list selection model. */
+	private final ListModel listModel;
+
+	/** A listener that allows us to clear the selection when the list model has changed. */
+	private final ListDataListener listDataListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a list selection model for the specified list model.
+	 */
+	public ObjectListSelectionModel(ListModel listModel) {
+		super();
+		this.listModel = listModel;
+		this.listDataListener = this.buildListDataListener();
+	}
+
+
+	// ********** initialization **********
+
+	private ListDataListener buildListDataListener() {
+		return new ListDataListener() {
+			@Override
+			public void intervalAdded(ListDataEvent event) {
+				// this does not affect the selection
+			}
+			@Override
+			public void intervalRemoved(ListDataEvent event) {
+				// this does not affect the selection
+			}
+			@Override
+			public void contentsChanged(ListDataEvent event) {
+				ObjectListSelectionModel.this.listModelContentsChanged(event);
+			}
+			@Override
+			public String toString() {
+				return "list data listener";
+			}
+		};
+	}
+
+	/**
+	 * Typically, the selection does not need to be cleared when the
+	 * contents of the list have changed. Most of the time this just
+	 * means an item has changed in a way that affects its display string
+	 * or icon. We typically only use the class for edits involving
+	 * single selection.
+	 * A subclass can override this method if the selection
+	 * should be cleared because a change could mean the selection is invalid.
+	 */
+	protected void listModelContentsChanged(@SuppressWarnings("unused") ListDataEvent event) {
+		/**this.clearSelection();*/
+	}
+
+
+	// ********** ListSelectionModel implementation **********
+
+	@Override
+	public void addListSelectionListener(ListSelectionListener l) {
+		if (this.hasNoListSelectionListeners()) {
+			this.listModel.addListDataListener(this.listDataListener);
+		}
+		super.addListSelectionListener(l);
+	}
+
+	@Override
+	public void removeListSelectionListener(ListSelectionListener l) {
+		super.removeListSelectionListener(l);
+		if (this.hasNoListSelectionListeners()) {
+			this.listModel.removeListDataListener(this.listDataListener);
+		}
+	}
+
+
+	// ********** queries **********
+
+	/**
+	 * Return whether this model has no listeners.
+	 */
+	protected boolean hasNoListSelectionListeners() {	// private-protected
+		return this.getListSelectionListeners().length == 0;
+	}
+
+	/**
+	 * Return the list model referenced by the list selection model.
+	 */
+	public ListModel getListModel() {
+		return this.listModel;
+	}
+
+	public int selectedValuesSize() {
+		int min = this.getMinSelectionIndex();
+		int max = this.getMaxSelectionIndex();
+
+		if ((min < 0) || (max < 0)) {
+			return 0;
+		}
+
+		int n = 0;
+		int count = this.getListModel().getSize();
+		for (int i = min; i <= max; i++) {
+			if (this.isSelectedIndex(i) && (i < count)) {
+				n++;
+			}
+		}
+		return n;
+	}
+
+	/**
+	 * Return the first selected value.
+	 * Return null if the selection is empty.
+	 */
+	public Object selectedValue() {
+		int index = this.getMinSelectionIndex();
+		if (index == -1) {
+			return null;
+		}
+		if (this.getListModel().getSize() <= index) {
+			return null;
+		}
+		return this.getListModel().getElementAt(index);
+	}
+
+	/**
+	 * Return an array of the selected values.
+	 */
+	public Object[] selectedValues() {
+		int min = this.getMinSelectionIndex();
+		int max = this.getMaxSelectionIndex();
+
+		if ((min < 0) || (max < 0)) {
+			return ObjectTools.EMPTY_OBJECT_ARRAY;
+		}
+
+		int maxSize = (max - min) + 1;
+		Object[] temp = new Object[maxSize];
+		int n = 0;
+		int count = this.getListModel().getSize();
+		for (int i = min; i <= max; i++) {
+			if (this.isSelectedIndex(i) && (i < count)) {
+				temp[n++] = this.getListModel().getElementAt(i);
+			}
+		}
+		if (n == maxSize) {
+			// all the elements in the range were selected
+			return temp;
+		}
+		// only some of the elements in the range were selected
+		Object[] result = new Object[n];
+		System.arraycopy(temp, 0, result, 0, n);
+		return result;
+	}
+
+	/**
+	 * Return an array of the selected indices in order.
+	 */
+	public int[] selectedIndices() {
+		int min = this.getMinSelectionIndex();
+		int max = this.getMaxSelectionIndex();
+
+		if ((min < 0) || (max < 0)) {
+			return new int[0];
+		}
+
+		int maxSize = (max - min) + 1;
+		int[] temp = new int[maxSize];
+		int n = 0;
+		int count = this.getListModel().getSize();
+		for (int i = min; i <= max; i++) {
+			if (this.isSelectedIndex(i) && (i < count)) {
+				temp[n++] = i;
+			}
+		}
+		if (n == maxSize) {
+			// all the elements in the range were selected
+			Arrays.sort(temp);
+			return temp;
+		}
+		// only some of the elements in the range were selected
+		int[] result = new int[n];
+		System.arraycopy(temp, 0, result, 0, n);
+		Arrays.sort(result);
+		return result;
+	}
+
+	/**
+	 * Set the selected value.
+	 */
+	public void setSelectedValue(Object object) {
+		this.setSelectedValues(IteratorTools.singletonIterator(object));
+	}
+
+	/**
+	 * Set the current set of selected objects to the specified objects.
+	 * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
+	 */
+	public void setSelectedValues(Iterator<?> objects) {
+		this.setValueIsAdjusting(true);
+		this.clearSelection();
+		this.addSelectedValuesInternal(objects);
+		this.setValueIsAdjusting(false);
+	}
+
+	/**
+	 * Set the current set of selected objects to the specified objects.
+	 * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
+	 */
+	public void setSelectedValues(Collection<?> objects) {
+		this.setSelectedValues(objects.iterator());
+	}
+
+	/**
+	 * Set the current set of selected objects to the specified objects.
+	 * @see javax.swing.ListSelectionModel#setSelectionInterval(int, int)
+	 */
+	public void setSelectedValues(Object[] objects) {
+		this.setSelectedValues(IteratorTools.iterator(objects));
+	}
+
+	/**
+	 * Add the specified object to the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+	 */
+	public void addSelectedValue(Object object) {
+		this.addSelectedValues(IteratorTools.singletonIterator(object));
+	}
+
+	/**
+	 * Add the specified objects to the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+	 */
+	public void addSelectedValues(Iterator<?> objects) {
+		this.setValueIsAdjusting(true);
+		this.addSelectedValuesInternal(objects);
+		this.setValueIsAdjusting(false);
+	}
+
+	/**
+	 * Add the specified objects to the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+	 */
+	public void addSelectedValues(Collection<?> objects) {
+		this.addSelectedValues(objects.iterator());
+	}
+
+	/**
+	 * Add the specified objects to the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#addSelectionInterval(int, int)
+	 */
+	public void addSelectedValues(Object[] objects) {
+		this.addSelectedValues(IteratorTools.iterator(objects));
+	}
+
+	/**
+	 * Remove the specified object from the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+	 */
+	public void removeSelectedValue(Object object) {
+		this.removeSelectedValues(IteratorTools.singletonIterator(object));
+	}
+
+	/**
+	 * Remove the specified objects from the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+	 */
+	public void removeSelectedValues(Iterator<?> objects) {
+		this.setValueIsAdjusting(true);
+		ListModel lm = this.getListModel();
+		int lmSize = lm.getSize();
+		while (objects.hasNext()) {
+			int index = this.indexOf(objects.next(), lm, lmSize);
+			this.removeSelectionInterval(index, index);
+		}
+		this.setValueIsAdjusting(false);
+	}
+
+	/**
+	 * Remove the specified objects from the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+	 */
+	public void removeSelectedValues(Collection<?> objects) {
+		this.removeSelectedValues(objects.iterator());
+	}
+
+	/**
+	 * Remove the specified objects from the current set of selected objects.
+	 * @see javax.swing.ListSelectionModel#removeSelectionInterval(int, int)
+	 */
+	public void removeSelectedValues(Object[] objects) {
+		this.removeSelectedValues(IteratorTools.iterator(objects));
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#getAnchorSelectionIndex()
+	 * Return null if the anchor selection is empty.
+	 */
+	public Object getAnchorSelectedValue() {
+		int index = this.getAnchorSelectionIndex();
+		if (index == -1) {
+			return null;
+		}
+		return this.getListModel().getElementAt(index);
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#setAnchorSelectionIndex(int)
+	 */
+	public void setAnchorSelectedValue(Object object) {
+		this.setAnchorSelectionIndex(this.indexOf(object));
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#getLeadSelectionIndex()
+	 * Return null if the lead selection is empty.
+	 */
+	public Object getLeadSelectedValue() {
+		int index = this.getLeadSelectionIndex();
+		if (index == -1) {
+			return null;
+		}
+		return this.getListModel().getElementAt(index);
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#setLeadSelectionIndex(int)
+	 */
+	public void setLeadSelectedValue(Object object) {
+		this.setLeadSelectionIndex(this.indexOf(object));
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#getMaxSelectionIndex()
+	 * Return null if the max selection is empty.
+	 */
+	public Object getMaxSelectedValue() {
+		int index = this.getMaxSelectionIndex();
+		if (index == -1) {
+			return null;
+		}
+		return this.getListModel().getElementAt(index);
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#getMinSelectionIndex()
+	 * Return null if the min selection is empty.
+	 */
+	public Object getMinSelectedValue() {
+		int index = this.getMinSelectionIndex();
+		if (index == -1) {
+			return null;
+		}
+		return this.getListModel().getElementAt(index);
+	}
+
+	/**
+	 * @see javax.swing.ListSelectionModel#isSelectedIndex(int)
+	 */
+	public boolean valueIsSelected(Object object) {
+		return this.isSelectedIndex(this.indexOf(object));
+	}
+
+	/**
+	 * Add the specified objects to the current set of selected objects,
+	 * without wrapping the actions in "adjusting" events.
+	 */
+	private void addSelectedValuesInternal(Iterator<?> objects) {
+		ListModel lm = this.getListModel();
+		int listModelSize = lm.getSize();
+		while (objects.hasNext()) {
+			int index = this.indexOf(objects.next(), lm, listModelSize);
+			this.addSelectionInterval(index, index);
+		}
+	}
+
+	/**
+	 * Return the index in the list model of the specified object.
+	 * Return -1 if the object is not in the list model.
+	 */
+	private int indexOf(Object object) {
+		ListModel lm = this.getListModel();
+		return this.indexOf(object, lm, lm.getSize());
+	}
+
+	/**
+	 * Return the index in the list model of the specified object.
+	 * Return -1 if the object is not in the list model.
+	 */
+	// we're just jerking around with performance optimizations here
+	// (in memory of Phil...);
+	// call this method inside loops that do not modify the listModel
+	private int indexOf(Object object, ListModel lm, int listModelSize) {
+		for (int i = listModelSize; i-- > 0; ) {
+			if (lm.getElementAt(i).equals(object)) {
+				return i;
+			}
+		}
+		return -1;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java
new file mode 100644
index 0000000..6ec072d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/PrimitiveListTreeModel.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.MutableTreeNode;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+
+/**
+ * This TreeModel implementation provides a tree with a "null" root that
+ * has a set of "primitive" children. These "primitive" children do not have
+ * children themselves, making the tree a maximum of 2 levels deep.
+ * This model automatically synchronizes the root's children with a
+ * ListValueModel that holds a collection of primitive (non-model) objects
+ * (e.g. Strings).
+ *
+ * This is useful for providing an "editable" list of primitives. Since the JDK
+ * does not provide us with an editable listbox, we must use an editable tree.
+ * We wrap everything in DefaultMutableTreeNodes.
+ *
+ * Subclasses must implement #primitiveChanged(int, Object) and update
+ * the model appropriately. This method is called when the user edits the
+ * list directly and presses <Enter>.
+ *
+ * The JTree using this model must be configured as "editable":
+ * 	tree.setEditable(true);
+ */
+// TODO convert to use an adapter instead of requiring subclass
+public abstract class PrimitiveListTreeModel
+	extends DefaultTreeModel
+{
+	/** a model on the list of primitives */
+	private final ListValueModel<?> listHolder;
+
+	/** a listener that handles the adding, removing, and replacing of the primitives */
+	private final ListChangeListener listChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Public constructor - the list holder is required
+	 */
+	public PrimitiveListTreeModel(ListValueModel<?> listHolder) {
+		super(new DefaultMutableTreeNode(null, true));  // true = the root can have children
+		if (listHolder == null) {
+			throw new NullPointerException();
+		}
+		this.listHolder = listHolder;
+		this.listChangeListener = this.buildListChangeListener();
+		// postpone listening to the model until we have listeners ourselves
+	}
+
+	protected ListChangeListener buildListChangeListener() {
+		return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+	}
+
+	protected ListChangeListener buildListChangeListener_() {
+		return new PrimitiveListChangeListener();
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Subclasses should override this method to update the
+	 * model appropriately. The primitive at the specified index was
+	 * edited directly by the user and the new value is as specified.
+	 * Convert the value appropriately and place it in the model.
+	 */
+	protected abstract void primitiveChanged(int index, Object newValue);
+
+
+	// ********** TreeModel implementation **********
+
+	/**
+	 * Override to change the underlying model instead of changing the node directly.
+	 */
+    @Override
+	public void valueForPathChanged(TreePath path, Object newValue) {
+		TreeNode node = (TreeNode) path.getLastPathComponent();
+		int index = ((TreeNode) this.getRoot()).getIndex(node);
+		this.primitiveChanged(index, newValue);
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addTreeModelListener(TreeModelListener l) {
+		if (this.getTreeModelListeners().length == 0) {
+			this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+			this.synchronizeList();
+		}
+		super.addTreeModelListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if appropriate.
+	 */
+    @Override
+	public void removeTreeModelListener(TreeModelListener l) {
+		super.removeTreeModelListener(l);
+		if (this.getTreeModelListeners().length == 0) {
+			this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+		}
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Synchronize our list of nodes with the list of primitives
+	 */
+	void synchronizeList() {
+		this.clearList();
+		this.buildList();
+	}
+
+	void clearList() {
+		int childcount = this.root.getChildCount();
+		for (int i = childcount - 1; i >= 0; i--) {
+			this.removeNodeFromParent((MutableTreeNode)this.root.getChildAt(i));
+		}
+	}
+
+	private void buildList() {
+		for (Iterator<?> stream = this.listHolder.iterator(); stream.hasNext(); ) {
+			this.addPrimitive(stream.next());
+		}
+	}
+
+	/**
+	 * Add the specified primitive to the end of the list.
+	 */
+	private void addPrimitive(Object primitive) {
+		this.insertPrimitive(this.root.getChildCount(), primitive);
+	}
+
+	/**
+	 * Create a node for the specified primitive
+	 * and insert it as a child of the root.
+	 */
+	void insertPrimitive(int index, Object primitive) {
+		DefaultMutableTreeNode node = new DefaultMutableTreeNode(primitive, false); // don't allow children on the child node
+		this.insertNodeInto(node, (MutableTreeNode) this.root, index);
+	}
+
+	/**
+	 * Remove node at the specified index.
+	 */
+	MutableTreeNode removeNode(int index) {
+		MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
+		this.removeNodeFromParent(node);
+		return node;
+	}
+
+	/**
+	 * Replace the user object of the node at childIndex.
+	 */
+	void replacePrimitive(int index, Object primitive) {
+		MutableTreeNode node = (MutableTreeNode) this.root.getChildAt(index);
+		node.setUserObject(primitive);
+		this.nodeChanged(node);
+	}
+
+
+	// ********** inner class **********
+
+	private class PrimitiveListChangeListener implements ListChangeListener {
+		PrimitiveListChangeListener() {
+			super();
+		}
+
+		@Override
+		public void itemsAdded(ListAddEvent event) {
+			int i = event.getIndex();
+			for (Object item : event.getItems()) {
+				PrimitiveListTreeModel.this.insertPrimitive(i++, item);
+			}
+		}
+
+		@Override
+		public void itemsRemoved(ListRemoveEvent event) {
+			for (int i = 0; i < event.getItemsSize(); i++) {
+				PrimitiveListTreeModel.this.removeNode(event.getIndex());
+			}
+		}
+
+		@Override
+		public void itemsReplaced(ListReplaceEvent event) {
+			int i = event.getIndex();
+			for (Object item : event.getNewItems()) {
+				PrimitiveListTreeModel.this.replacePrimitive(i++, item);
+			}
+		}
+
+		@Override
+		public void itemsMoved(ListMoveEvent event) {
+			ArrayList<MutableTreeNode> temp = new ArrayList<MutableTreeNode>(event.getLength());
+			for (int i = 0; i < event.getLength(); i++) {
+				temp.add(PrimitiveListTreeModel.this.removeNode(event.getSourceIndex()));
+			}
+			int i = event.getTargetIndex();
+			for (MutableTreeNode node : temp) {
+				PrimitiveListTreeModel.this.insertPrimitive(i++, node);
+			}
+		}
+
+		@Override
+		public void listCleared(ListClearEvent event) {
+			PrimitiveListTreeModel.this.clearList();
+		}
+
+		@Override
+		public void listChanged(ListChangeEvent event) {
+			PrimitiveListTreeModel.this.synchronizeList();
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java
new file mode 100644
index 0000000..9ca700c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/RadioButtonModelAdapter.java
@@ -0,0 +1,174 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import org.eclipse.persistence.tools.utility.filter.Filter;
+import org.eclipse.persistence.tools.utility.model.value.FilteringModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TransformationModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+
+/**
+ * This {@link javax.swing.ButtonModel} can be used to keep a listener
+ * (e.g. a {@link javax.swing.JRadioButton}) in synch with a (typically shared)
+ * {@link org.eclipse.jpt.common.utility.model.value.PropertyValueModel}
+ * that holds one value out of a set of values.
+ * <p>
+ * <strong>NB:</strong> Do <em>not</em> use this model with a
+ * {@link javax.swing.ButtonGroup}, since the
+ * shared value holder and the wrappers built by this adapter will
+ * keep the appropriate radio button checked. Also, this allows
+ * us to uncheck all the radio buttons in a group when the shared
+ * value is <code>null</code>.
+ */
+public class RadioButtonModelAdapter
+	extends ToggleButtonModelAdapter
+{
+	private static final long serialVersionUID = 1L;
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the value holder is required.
+	 */
+	public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue, boolean defaultValue) {
+		super(buildBooleanHolder(valueHolder, buttonValue), defaultValue);
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 * The default value will be false.
+	 */
+	public RadioButtonModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
+		super(buildBooleanHolder(valueHolder, buttonValue));
+	}
+
+
+	// ********** static methods **********
+
+	/**
+	 * Build up a set of wrappers that will convert the
+	 * specified value holder and button value to/from a boolean.
+	 *
+	 * If the value holder's value matches the button value,
+	 * the wrapper will return true. Likewise, if the value holder's
+	 * value is set to true, the wrapper will set the value holder's
+	 * value to the button value.
+	 */
+	public static ModifiablePropertyValueModel<Boolean> buildBooleanHolder(ModifiablePropertyValueModel<Object> valueHolder, Object buttonValue) {
+		ModifiablePropertyValueModel<Object> filteringPVM = new FilteringModifiablePropertyValueModel<Object>(valueHolder, Filter.Transparent.instance(), new SetRadioButtonFilter(buttonValue));
+		return new TransformationModifiablePropertyValueModel<Object, Boolean>(filteringPVM, new RadioButtonTransformer(buttonValue), new ReverseRadioButtonTransformer(buttonValue));
+	}
+
+
+	// ********** overrides **********
+
+	/**
+	 * The user cannot de-select a radio button - the user
+	 * can only *select* a radio button. Only the model can
+	 * cause a radio button to be de-selected. We use the
+	 * ARMED flag to indicate whether we are being de-selected
+	 * by the user.
+	 */
+    @Override
+	public void setSelected(boolean b) {
+		// do not allow the user to de-select a radio button
+		// radio buttons can
+		if ((b == false) && this.isArmed()) {
+			return;
+		}
+		super.setSelected(b);
+	}
+
+
+	// ********** filters **********
+
+	/**
+	 * This filter will only pass through a new value to the wrapped
+	 * value model when it matches the configured button value.
+	 */
+	public static class SetRadioButtonFilter
+		implements Filter<Object>
+	{
+		private Object buttonValue;
+
+		public SetRadioButtonFilter(Object buttonValue) {
+			super();
+			this.buttonValue = buttonValue;
+		}
+
+		/**
+		 * pass through the value to the wrapped property value model
+		 * *only* when it matches our button value
+		 */
+		@Override
+		public boolean accept(Object value) {
+			return (value != null) && value.equals(this.buttonValue);
+		}
+	}
+
+
+	// ********** transformers **********
+
+	/**
+	 * This transformer will convert a value to {@link Boolean#TRUE}
+	 * when it matches the configured button value.
+	 */
+	public static class RadioButtonTransformer
+		implements Transformer<Object, Boolean>
+	{
+		private Object buttonValue;
+
+		public RadioButtonTransformer(Object buttonValue) {
+			super();
+			this.buttonValue = buttonValue;
+		}
+
+		/**
+		 * If the specified value matches the button value return {@link Boolean#TRUE},
+		 * if it is some other value return {@link Boolean#FALSE};
+		 * but if it is <code>null</code> simply pass it through because it will
+		 * cause the button model's default value to be used
+		 */
+		@Override
+		public Boolean transform(Object value) {
+			return (value == null) ? null : Boolean.valueOf(value.equals(this.buttonValue));
+		}
+	}
+
+	/**
+	 * This transformer will convert {@link Boolean#TRUE} to the configured
+	 * button value and {@link Boolean#FALSE} to <code>null</code>.
+	 */
+	public static class ReverseRadioButtonTransformer
+		implements Transformer<Boolean, Object>
+	{
+		private Object buttonValue;
+
+		public ReverseRadioButtonTransformer(Object buttonValue) {
+			super();
+			this.buttonValue = buttonValue;
+		}
+
+		/**
+		 * If the specified value is {@link Boolean#TRUE},
+		 * pass through the our button value;
+		 * otherwise pass through <code>null</code>.
+		 */
+		@Override
+		public Object transform (Boolean value) {
+			return (value.booleanValue()) ? this.buttonValue : null;
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java
new file mode 100644
index 0000000..180f629
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/SpinnerModelAdapter.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import javax.swing.AbstractSpinnerModel;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.SpinnerModel can be used to keep a ChangeListener
+ * (e.g. a JSpinner) in synch with a PropertyValueModel that holds a value.
+ *
+ * Note: it is likely you want to use one of the following classes instead of
+ * this one:
+ *     DateSpinnerModelAdapter
+ *     NumberSpinnerModelAdapter
+ *     ListSpinnerModelAdapter
+ *
+ * NB: This model should only be used for values that have a fairly
+ * inexpensive #equals() implementation.
+ * @see #synchronizeDelegate(Object)
+ */
+@SuppressWarnings("nls")
+public class SpinnerModelAdapter
+	extends AbstractSpinnerModel
+{
+	/** The delegate spinner model whose behavior we "enhance". */
+	protected final SpinnerModel delegate;
+
+	/** A listener that allows us to forward any changes made to the delegate spinner model. */
+	protected final ChangeListener delegateListener;
+
+	/** A value model on the underlying value. */
+	protected final ModifiablePropertyValueModel<Object> valueHolder;
+
+	/** A listener that allows us to synchronize with changes made to the underlying value. */
+	protected final PropertyChangeListener valueListener;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the value holder and delegate are required.
+	 */
+	public SpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder, SpinnerModel delegate) {
+		super();
+		if (valueHolder == null || delegate == null) {
+			throw new NullPointerException();
+		}
+		this.valueHolder = valueHolder;
+		this.delegate = delegate;
+		// postpone listening to the underlying value
+		// until we have listeners ourselves...
+		this.valueListener = this.buildValueListener();
+		this.delegateListener = this.buildDelegateListener();
+	}
+
+	/**
+	 * Constructor - the value holder is required.
+	 * This will wrap a simple number spinner model.
+	 */
+	public SpinnerModelAdapter(ModifiablePropertyValueModel<Object> valueHolder) {
+		this(valueHolder, new SpinnerNumberModel());
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildValueListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildValueListener_());
+	}
+
+	protected PropertyChangeListener buildValueListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				SpinnerModelAdapter.this.valueChanged(event);
+			}
+			@Override
+			public String toString() {
+				return "value listener";
+			}
+		};
+	}
+
+	/**
+	 * expand access a bit for inner class
+	 */
+	@Override
+	protected void fireStateChanged() {
+		super.fireStateChanged();
+	}
+
+	protected ChangeListener buildDelegateListener() {
+		return new ChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent event) {
+				// forward the event, with this as the source
+				SpinnerModelAdapter.this.fireStateChanged();
+			}
+			@Override
+			public String toString() {
+				return "delegate listener";
+			}
+		};
+	}
+
+
+	// ********** SpinnerModel implementation **********
+
+	@Override
+	public Object getValue() {
+		return this.delegate.getValue();
+	}
+
+	/**
+	 * Extend to update the underlying value directly.
+	 * The resulting event will be ignored: @see #synchronizeDelegate(Object).
+	 */
+	@Override
+	public void setValue(Object value) {
+		this.delegate.setValue(value);
+		this.valueHolder.setValue(value);
+	}
+
+	@Override
+	public Object getNextValue() {
+		return this.delegate.getNextValue();
+	}
+
+	@Override
+	public Object getPreviousValue() {
+		return this.delegate.getPreviousValue();
+	}
+
+	/**
+	 * Extend to start listening to the underlying value if necessary.
+	 */
+    @Override
+	public void addChangeListener(ChangeListener listener) {
+		if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
+			this.delegate.addChangeListener(this.delegateListener);
+			this.engageValueHolder();
+		}
+		super.addChangeListener(listener);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying value if appropriate.
+	 */
+    @Override
+	public void removeChangeListener(ChangeListener listener) {
+		super.removeChangeListener(listener);
+		if (this.listenerList.getListenerCount(ChangeListener.class) == 0) {
+			this.disengageValueHolder();
+			this.delegate.removeChangeListener(this.delegateListener);
+		}
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * A third party has modified the underlying value.
+	 * Synchronize the delegate model accordingly.
+	 */
+	protected void valueChanged(PropertyChangeEvent event) {
+		this.synchronizeDelegate(event.getNewValue());
+	}
+
+	/**
+	 * Set the delegate's value if it has changed.
+	 */
+	protected void synchronizeDelegate(Object value) {
+		// check to see whether the delegate has already been synchronized
+		// (via #setValue())
+		if ( ! this.delegate.getValue().equals(value)) {
+			this.delegate.setValue(value);
+		}
+	}
+
+	protected void engageValueHolder() {
+		this.valueHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
+		this.synchronizeDelegate(this.valueHolder.getValue());
+	}
+
+	protected void disengageValueHolder() {
+		this.valueHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.valueListener);
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.valueHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java
new file mode 100644
index 0000000..171289f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TableModelAdapter.java
@@ -0,0 +1,470 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.CollectionListValueModelAdapter;
+import org.eclipse.persistence.tools.utility.model.value.CollectionValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This TableModel can be used to keep a TableModelListener (e.g. a JTable)
+ * in synch with a ListValueModel that holds a collection of model objects,
+ * each of which corresponds to a row in the table.
+ * Typically, each column of the table will be bound to a different aspect
+ * of the contained model objects.
+ *
+ * For example, a MWTable has an attribute 'databaseFields' that holds
+ * a collection of MWDatabaseFields that would correspond to the rows of
+ * a JTable; and each MWDatabaseField has a number
+ * of attributes (e.g. name, type, size) that can be bound to the columns of
+ * a row in the JTable. As these database fields are added, removed, and
+ * changed, this model will keep the listeners aware of the changes.
+ *
+ * An instance of this TableModel must be supplied with a
+ * list holder (e.g. the 'databaseFields'), which is a value
+ * model on the bound collection This is required - the
+ * collection itself can be null, but the list value model that
+ * holds it is required. Typically this list will be sorted (@see
+ * SortedListValueModelAdapter).
+ *
+ * This TableModel must also be supplied with a ColumnAdapter that
+ * will be used to configure the headers, renderers, editors, and contents
+ * of the various columns.
+ *
+ * Design decision:
+ * Cell listener options (from low space/high time to high space/low time):
+ * 	- 1 cell listener listening to every cell (this is the current implementation)
+ * 	- 1 cell listener per row
+ * 	- 1 cell listener per cell
+ */
+@SuppressWarnings("nls")
+public class TableModelAdapter<E>
+	extends AbstractTableModel
+{
+	/**
+	 * a list of user objects that are converted to
+	 * rows via the column adapter
+	 */
+	private ListValueModel<? extends E> listHolder;
+	private final ListChangeListener listChangeListener;
+
+	/**
+	 * each row is an array of cell models
+	 */
+	// declare as ArrayList so we can use #ensureCapacity(int)
+	private final ArrayList<ModifiablePropertyValueModel<Object>[]> rows;
+
+	/**
+	 * client-supplied adapter that provides with the various column
+	 * settings and converts the objects in the LVM
+	 * into an array of cell models
+	 */
+	private final ColumnAdapter columnAdapter;
+
+	/**
+	 * the single listener that listens to every cell's model
+	 */
+	private final PropertyChangeListener cellListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a table model adapter for the specified objects
+	 * and adapter.
+	 */
+	public TableModelAdapter(ListValueModel<? extends E> listHolder, ColumnAdapter columnAdapter) {
+		super();
+		if (listHolder == null) {
+			throw new NullPointerException();
+		}
+		this.listHolder = listHolder;
+		this.columnAdapter = columnAdapter;
+		this.listChangeListener = this.buildListChangeListener();
+		this.rows = new ArrayList<ModifiablePropertyValueModel<Object>[]>();
+		this.cellListener = this.buildCellListener();
+	}
+
+	/**
+	 * Construct a table model adapter for the specified objects
+	 * and adapter.
+	 */
+	public TableModelAdapter(CollectionValueModel<? extends E> collectionHolder, ColumnAdapter columnAdapter) {
+		this(new CollectionListValueModelAdapter<E>(collectionHolder), columnAdapter);
+	}
+
+
+	// ********** initialization **********
+
+	protected ListChangeListener buildListChangeListener() {
+		return new AWTListChangeListenerWrapper(this.buildListChangeListener_());
+	}
+
+	protected ListChangeListener buildListChangeListener_() {
+		return new ListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {
+				TableModelAdapter.this.addRows(event.getIndex(), event.getItemsSize(), this.getItems(event));
+			}
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) {
+				TableModelAdapter.this.removeRows(event.getIndex(), event.getItemsSize());
+			}
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) {
+				TableModelAdapter.this.replaceRows(event.getIndex(), this.getNewItems(event));
+			}
+			@Override
+			public void itemsMoved(ListMoveEvent event) {
+				TableModelAdapter.this.moveRows(event.getTargetIndex(), event.getSourceIndex(), event.getLength());
+			}
+			@Override
+			public void listCleared(ListClearEvent event) {
+				TableModelAdapter.this.clearTable();
+			}
+			@Override
+			public void listChanged(ListChangeEvent event) {
+				TableModelAdapter.this.rebuildTable();
+			}
+			// minimized scope of suppressed warnings
+			@SuppressWarnings("unchecked")
+			protected Iterable<Object> getItems(ListAddEvent event) {
+				return (Iterable<Object>) event.getItems();
+			}
+			// minimized scope of suppressed warnings
+			@SuppressWarnings("unchecked")
+			protected Iterable<Object> getNewItems(ListReplaceEvent event) {
+				return (Iterable<Object>) event.getNewItems();
+			}
+			@Override
+			public String toString() {
+				return "list listener";
+			}
+		};
+	}
+
+
+	protected PropertyChangeListener buildCellListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildCellListener_());
+	}
+
+	protected PropertyChangeListener buildCellListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			@SuppressWarnings("unchecked")
+			public void propertyChanged(PropertyChangeEvent event) {
+				TableModelAdapter.this.cellChanged((ModifiablePropertyValueModel<Object>) event.getSource());
+			}
+			@Override
+			public String toString() {
+				return "cell listener";
+			}
+		};
+	}
+
+
+	// ********** TableModel implementation **********
+
+	@Override
+	public int getColumnCount() {
+		return this.columnAdapter.columnCount();
+	}
+
+	@Override
+	public int getRowCount() {
+		return this.rows.size();
+	}
+
+    @Override
+	public String getColumnName(int column) {
+		return this.columnAdapter.columnName(column);
+	}
+
+    @Override
+	public Class<?> getColumnClass(int columnIndex) {
+		return this.columnAdapter.columnClass(columnIndex);
+	}
+
+    @Override
+	public boolean isCellEditable(int rowIndex, int columnIndex) {
+		return this.columnAdapter.columnIsEditable(columnIndex);
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		ModifiablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
+		return row[columnIndex].getValue();
+	}
+
+	@Override
+	public void setValueAt(Object value, int rowIndex, int columnIndex) {
+		ModifiablePropertyValueModel<Object>[] row = this.rows.get(rowIndex);
+		row[columnIndex].setValue(value);
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addTableModelListener(TableModelListener l) {
+		if (this.hasNoTableModelListeners()) {
+			this.engageModel();
+		}
+		super.addTableModelListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if necessary.
+	 */
+    @Override
+	public void removeTableModelListener(TableModelListener l) {
+		super.removeTableModelListener(l);
+		if (this.hasNoTableModelListeners()) {
+			this.disengageModel();
+		}
+	}
+
+
+	// ********** public API **********
+
+	/**
+	 * Return the underlying list model.
+	 */
+	public ListValueModel<? extends E> getModel() {
+		return this.listHolder;
+	}
+
+	/**
+	 * Set the underlying list model.
+	 */
+	public void setModel(ListValueModel<E> listHolder) {
+		if (listHolder == null) {
+			throw new NullPointerException();
+		}
+		boolean hasListeners = this.hasTableModelListeners();
+		if (hasListeners) {
+			this.disengageModel();
+		}
+		this.listHolder = listHolder;
+		if (hasListeners) {
+			this.engageModel();
+			this.fireTableDataChanged();
+		}
+	}
+
+	/**
+	 * Set the underlying collection model.
+	 */
+	public void setModel(CollectionValueModel<E> collectionHolder) {
+		this.setModel(new CollectionListValueModelAdapter<E>(collectionHolder));
+	}
+
+
+	// ********** queries **********
+
+	/**
+	 * Return whether this model has no listeners.
+	 */
+	protected boolean hasNoTableModelListeners() {
+		return this.listenerList.getListenerCount(TableModelListener.class) == 0;
+	}
+
+	/**
+	 * Return whether this model has any listeners.
+	 */
+	protected boolean hasTableModelListeners() {
+		return ! this.hasNoTableModelListeners();
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Start listening to the list of objects and the various aspects
+	 * of the objects that make up the rows.
+	 */
+	private void engageModel() {
+		this.listHolder.addListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+		this.engageAllCells();
+	}
+
+	/**
+	 * Convert the objects into rows and listen to the cells.
+	 */
+	private void engageAllCells() {
+		this.rows.ensureCapacity(this.listHolder.size());
+		for (Iterator<? extends E> stream = this.listHolder.iterator(); stream.hasNext(); ) {
+			ModifiablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(stream.next());
+			this.engageRow(row);
+			this.rows.add(row);
+		}
+	}
+
+	/**
+	 * Listen to the cells in the specified row.
+	 */
+	private void engageRow(ModifiablePropertyValueModel<Object>[] row) {
+		for (int i = row.length; i-- > 0; ) {
+			row[i].addPropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
+		}
+	}
+
+	/**
+	 * Stop listening.
+	 */
+	private void disengageModel() {
+		this.disengageAllCells();
+		this.listHolder.removeListChangeListener(ListValueModel.LIST_VALUES, this.listChangeListener);
+	}
+
+	private void disengageAllCells() {
+		for (ModifiablePropertyValueModel<Object>[] row : this.rows) {
+			this.disengageRow(row);
+		}
+		this.rows.clear();
+	}
+
+	private void disengageRow(ModifiablePropertyValueModel<Object>[] row) {
+		for (int i = row.length; i-- > 0; ) {
+			row[i].removePropertyChangeListener(PropertyValueModel.VALUE, this.cellListener);
+		}
+	}
+
+	/**
+	 * brute-force search for the cell(s) that changed...
+	 */
+	void cellChanged(ModifiablePropertyValueModel<Object> cellHolder) {
+		for (int i = this.rows.size(); i-- > 0; ) {
+			ModifiablePropertyValueModel<Object>[] row = this.rows.get(i);
+			for (int j = row.length; j-- > 0; ) {
+				if (row[j] == cellHolder) {
+					this.fireTableCellUpdated(i, j);
+				}
+			}
+		}
+	}
+
+	/**
+	 * convert the items to rows
+	 */
+	void addRows(int index, int size, Iterable<Object> items) {
+		List<ModifiablePropertyValueModel<Object>[]> newRows = new ArrayList<ModifiablePropertyValueModel<Object>[]>(size);
+		for (Object item : items) {
+			ModifiablePropertyValueModel<Object>[] row = this.columnAdapter.cellModels(item);
+			this.engageRow(row);
+			newRows.add(row);
+		}
+		this.rows.addAll(index, newRows);
+		this.fireTableRowsInserted(index, index + size - 1);
+	}
+
+	void removeRows(int index, int size) {
+		for (int i = 0; i < size; i++) {
+			this.disengageRow(this.rows.remove(index));
+		}
+		this.fireTableRowsDeleted(index, index + size - 1);
+	}
+
+	void replaceRows(int index, Iterable<Object> items) {
+		int i = index;
+		for (Object item : items) {
+			ModifiablePropertyValueModel<Object>[] row = this.rows.get(i);
+			this.disengageRow(row);
+			row = this.columnAdapter.cellModels(item);
+			this.engageRow(row);
+			this.rows.set(i, row);
+			i++;
+		}
+		this.fireTableRowsUpdated(index, i - 1);
+	}
+
+	void moveRows(int targetIndex, int sourceIndex, int length) {
+		ArrayList<ModifiablePropertyValueModel<Object>[]> temp = new ArrayList<ModifiablePropertyValueModel<Object>[]>(length);
+		for (int i = 0; i < length; i++) {
+			temp.add(this.rows.remove(sourceIndex));
+		}
+		this.rows.addAll(targetIndex, temp);
+
+		int start = Math.min(targetIndex, sourceIndex);
+		int end = Math.max(targetIndex, sourceIndex) + length - 1;
+		this.fireTableRowsUpdated(start, end);
+	}
+
+	void clearTable() {
+		this.disengageAllCells();
+		this.fireTableDataChanged();
+	}
+
+	void rebuildTable() {
+		this.disengageAllCells();
+		this.engageAllCells();
+		this.fireTableDataChanged();
+	}
+
+
+	/**
+	 * This adapter is used by the table model adapter to
+	 * convert a model object into the models used for each of
+	 * the cells for the object's corresponding row in the table.
+	 */
+	public interface ColumnAdapter {
+		/**
+		 * Return the number of columns in the table.
+		 * Typically this is static.
+		 */
+		int columnCount();
+
+		/**
+		 * Return the name of the specified column.
+		 */
+		String columnName(int index);
+
+		/**
+		 * Return the class of the specified column.
+		 */
+		Class<?> columnClass(int index);
+
+		/**
+		 * Return whether the specified column is editable.
+		 * Typically this is the same for every row.
+		 */
+		boolean columnIsEditable(int index);
+
+		/**
+		 * Return the cell models for the specified subject
+		 * that corresponds to a single row in the table.
+		 */
+		ModifiablePropertyValueModel<Object>[] cellModels(Object subject);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java
new file mode 100644
index 0000000..bf22de0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/ToggleButtonModelAdapter.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.awt.event.ActionListener;
+import java.awt.event.ItemListener;
+import javax.swing.JToggleButton.ToggleButtonModel;
+import javax.swing.event.ChangeListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ModifiablePropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+
+/**
+ * This javax.swing.ButtonModel can be used to keep a listener
+ * (e.g. a JCheckBox or a JRadioButton) in synch with a PropertyValueModel
+ * on a boolean.
+ */
+@SuppressWarnings("nls")
+public class ToggleButtonModelAdapter
+	extends ToggleButtonModel
+{
+	/**
+	 * The default setting for the toggle button; for when the underlying model is null.
+	 * The default [default value] is false (i.e. the toggle button is unchecked/empty).
+	 */
+	protected final boolean defaultValue;
+
+	/** A value model on the underlying model boolean. */
+	protected final ModifiablePropertyValueModel<Boolean> booleanHolder;
+
+	/**
+	 * A listener that allows us to synchronize with
+	 * changes made to the underlying model boolean.
+	 */
+	protected final PropertyChangeListener booleanChangeListener;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Constructor - the boolean holder is required.
+	 */
+	public ToggleButtonModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder, boolean defaultValue) {
+		super();
+		if (booleanHolder == null) {
+			throw new NullPointerException();
+		}
+		this.booleanHolder = booleanHolder;
+		this.booleanChangeListener = this.buildBooleanChangeListener();
+		// postpone listening to the underlying model
+		// until we have listeners ourselves...
+		this.defaultValue = defaultValue;
+	}
+
+	/**
+	 * Constructor - the boolean holder is required.
+	 * The default value will be false.
+	 */
+	public ToggleButtonModelAdapter(ModifiablePropertyValueModel<Boolean> booleanHolder) {
+		this(booleanHolder, false);
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildBooleanChangeListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildBooleanChangeListener_());
+	}
+
+	protected PropertyChangeListener buildBooleanChangeListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				ToggleButtonModelAdapter.this.booleanChanged(event);
+			}
+		    @Override
+			public String toString() {
+				return "boolean listener";
+			}
+		};
+	}
+
+
+	// ********** ButtonModel implementation **********
+
+	/**
+	 * Extend to update the underlying model if necessary.
+	 */
+    @Override
+	public void setSelected(boolean b) {
+		if (this.isSelected() != b) {	// stop the recursion!
+			super.setSelected(b);//put the super call first, otherwise the following gets called twice
+			this.booleanHolder.setValue(Boolean.valueOf(b));
+		}
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addActionListener(ActionListener l) {
+		if (this.hasNoListeners()) {
+			this.engageModel();
+		}
+		super.addActionListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if appropriate.
+	 */
+    @Override
+	public void removeActionListener(ActionListener l) {
+		super.removeActionListener(l);
+		if (this.hasNoListeners()) {
+			this.disengageModel();
+		}
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addItemListener(ItemListener l) {
+		if (this.hasNoListeners()) {
+			this.engageModel();
+		}
+		super.addItemListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if appropriate.
+	 */
+    @Override
+	public void removeItemListener(ItemListener l) {
+		super.removeItemListener(l);
+		if (this.hasNoListeners()) {
+			this.disengageModel();
+		}
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addChangeListener(ChangeListener l) {
+		if (this.hasNoListeners()) {
+			this.engageModel();
+		}
+		super.addChangeListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if appropriate.
+	 */
+    @Override
+	public void removeChangeListener(ChangeListener l) {
+		super.removeChangeListener(l);
+		if (this.hasNoListeners()) {
+			this.disengageModel();
+		}
+	}
+
+
+	// ********** queries **********
+
+	/**
+	 * Return whether we have no listeners at all.
+	 */
+	protected boolean hasNoListeners() {
+		return this.listenerList.getListenerCount() == 0;
+	}
+
+	protected boolean getDefaultValue() {
+		return this.defaultValue;
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Synchronize with the specified value.
+	 * If it is null, use the default value (which is typically false).
+	 */
+	protected void setSelected(Boolean value) {
+		if (value == null) {
+			this.setSelected(this.getDefaultValue());
+		} else {
+			this.setSelected(value.booleanValue());
+		}
+	}
+
+	/**
+	 * The underlying model has changed - synchronize accordingly.
+	 */
+	protected void booleanChanged(PropertyChangeEvent event) {
+		this.setSelected((Boolean) event.getNewValue());
+	}
+
+	protected void engageModel() {
+		this.booleanHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
+		this.setSelected(this.booleanHolder.getValue());
+	}
+
+	protected void disengageModel() {
+		this.booleanHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.booleanChangeListener);
+	}
+
+
+	// ********** standard methods **********
+
+    @Override
+	public String toString() {
+		return ObjectTools.toString(this, this.booleanHolder);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java
new file mode 100644
index 0000000..f65bde0
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/model/value/swing/TreeModelAdapter.java
@@ -0,0 +1,934 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.model.value.swing;
+
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.model.event.ListAddEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListClearEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListMoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListRemoveEvent;
+import org.eclipse.persistence.tools.utility.model.event.ListReplaceEvent;
+import org.eclipse.persistence.tools.utility.model.event.PropertyChangeEvent;
+import org.eclipse.persistence.tools.utility.model.event.StateChangeEvent;
+import org.eclipse.persistence.tools.utility.model.listener.ListChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.PropertyChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.StateChangeListener;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTListChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTPropertyChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.listener.awt.AWTStateChangeListenerWrapper;
+import org.eclipse.persistence.tools.utility.model.value.ListValueModel;
+import org.eclipse.persistence.tools.utility.model.value.PropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.StaticPropertyValueModel;
+import org.eclipse.persistence.tools.utility.model.value.TreeNodeValueModel;
+
+/**
+ * This javax.swing.tree.TreeModel can be used to keep a TreeModelListener
+ * (e.g. a JTree) in synch with a tree of TreeNodeValueModel objects. Unlike
+ * javax.swing.tree.DefaultTreeModel, you do not add and remove nodes with
+ * methods implemented here. You can add and remove nodes by adding and
+ * removing them directly to/from the nodes (or, more typically, the domain
+ * objects the nodes are wrapping and listening to).
+ *
+ * Due to limitations in JTree, the root of the tree can never be null,
+ * which, typically, should not be a problem. (If you want to display an empty
+ * tree you can set the JTree's treeModel to null.)
+ */
+@SuppressWarnings("nls")
+public class TreeModelAdapter<T>
+	extends AbstractTreeModel
+{
+	/**
+	 * A value model on the underlying tree's root node and its
+	 * corresponding listener. This allows clients to swap out
+	 * the entire tree. Due to limitations in JTree, the root should
+	 * never be set to null while we have listeners.
+	 */
+	private final PropertyValueModel<TreeNodeValueModel<T>> rootHolder;
+	private final PropertyChangeListener rootListener;
+
+	/**
+	 * A listener that notifies us when a node's internal
+	 * "state" changes (as opposed to the node's value or list of
+	 * children), allowing us to forward notification to our listeners.
+	 */
+	private final StateChangeListener nodeStateListener;
+
+	/**
+	 * A listener that notifies us when a node's "value"
+	 * changes (as opposed to the node's state or list of
+	 * children), allowing us to forward notification to our listeners.
+	 * Typically, this will only happen with nodes that hold
+	 * primitive data.
+	 */
+	private final PropertyChangeListener nodeValueListener;
+
+	/**
+	 * A listener that notifies us when an underlying node's
+	 * "list" of children changes, allowing us to keep our
+	 * internal tree in synch with the underlying tree model.
+	 */
+	private final ListChangeListener childrenListener;
+
+	/* these attributes make up our internal tree */
+	/**
+	 * The root cannot be null while we have listeners, which is
+	 * most of the time. The root is cached so we can disengage
+	 * from it when it has been swapped out.
+	 */
+	private TreeNodeValueModel<T> root;
+
+	/**
+	 * Map the nodes to their lists of children.
+	 * We cache these so we can swap out the entire list of children
+	 * when we receive a #listChanged() event (which does not include
+	 * the items that were affected).
+	 * @see ChangeEventChangePolicy#rebuildChildren()
+	 */
+	final IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>> childrenLists;
+
+	/**
+	 * Map the children models to their parents.
+	 * We cache these so we can figure out the "real" source of the
+	 * list change events (the parent).
+	 * @see EventChangePolicy#parent()
+	 */
+	final IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>> parents;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a tree model for the specified root.
+	 */
+	public TreeModelAdapter(PropertyValueModel<TreeNodeValueModel<T>> rootHolder) {
+		super();
+		if (rootHolder == null) {
+			throw new NullPointerException();
+		}
+		this.rootHolder = rootHolder;
+		this.rootListener = this.buildRootListener();
+		this.nodeStateListener = this.buildNodeStateListener();
+		this.nodeValueListener = this.buildNodeValueListener();
+		this.childrenListener = this.buildChildrenListener();
+		this.childrenLists = new IdentityHashMap<TreeNodeValueModel<T>, List<TreeNodeValueModel<T>>>();
+		this.parents = new IdentityHashMap<ListValueModel<TreeNodeValueModel<T>>, TreeNodeValueModel<T>>();
+	}
+
+	/**
+	 * Construct a tree model for the specified root.
+	 */
+	public TreeModelAdapter(TreeNodeValueModel<T> root) {
+		this(new StaticPropertyValueModel<TreeNodeValueModel<T>>(root));
+	}
+
+
+	// ********** initialization **********
+
+	protected PropertyChangeListener buildRootListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildRootListener_());
+	}
+
+	protected PropertyChangeListener buildRootListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			public void propertyChanged(PropertyChangeEvent event) {
+				TreeModelAdapter.this.rootChanged();
+			}
+			@Override
+			public String toString() {
+				return "root listener";
+			}
+		};
+	}
+
+	protected PropertyChangeListener buildNodeValueListener() {
+		return new AWTPropertyChangeListenerWrapper(this.buildNodeValueListener_());
+	}
+
+	protected PropertyChangeListener buildNodeValueListener_() {
+		return new PropertyChangeListener() {
+			@Override
+			@SuppressWarnings("unchecked")
+			public void propertyChanged(PropertyChangeEvent event) {
+				TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
+			}
+			@Override
+			public String toString() {
+				return "node value listener";
+			}
+		};
+	}
+
+	protected StateChangeListener buildNodeStateListener() {
+		return new AWTStateChangeListenerWrapper(this.buildNodeStateListener_());
+	}
+
+	protected StateChangeListener buildNodeStateListener_() {
+		return new StateChangeListener() {
+			@Override
+			@SuppressWarnings("unchecked")
+			public void stateChanged(StateChangeEvent event) {
+				TreeModelAdapter.this.nodeChanged((TreeNodeValueModel<T>) event.getSource());
+			}
+			@Override
+			public String toString() {
+				return "node state listener";
+			}
+		};
+	}
+
+	protected ListChangeListener buildChildrenListener() {
+		return new AWTListChangeListenerWrapper(this.buildChildrenListener_());
+	}
+
+	protected ListChangeListener buildChildrenListener_() {
+		return new ListChangeListener() {
+			@Override
+			public void itemsAdded(ListAddEvent event) {
+				new AddEventChangePolicy(event).addChildren();
+			}
+			@Override
+			public void itemsRemoved(ListRemoveEvent event) {
+				new RemoveEventChangePolicy(event).removeChildren();
+			}
+			@Override
+			public void itemsReplaced(ListReplaceEvent event) {
+				new ReplaceEventChangePolicy(event).replaceChildren();
+			}
+			@Override
+			public void itemsMoved(ListMoveEvent event) {
+				new MoveEventChangePolicy(event).moveChildren();
+			}
+			@Override
+			public void listCleared(ListClearEvent event) {
+				new ClearEventChangePolicy(event).clearChildren();
+			}
+			@Override
+			public void listChanged(ListChangeEvent event) {
+				new ChangeEventChangePolicy(event).rebuildChildren();
+			}
+			@Override
+			public String toString() {
+				return "children listener";
+			}
+		};
+	}
+
+
+	// ********** TreeModel implementation **********
+
+	@Override
+	public Object getRoot() {
+		return this.root;
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public Object getChild(Object parent, int index) {
+		return ((TreeNodeValueModel<T>) parent).child(index);
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public int getChildCount(Object parent) {
+		return ((TreeNodeValueModel<T>) parent).childrenSize();
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public boolean isLeaf(Object node) {
+		return ((TreeNodeValueModel<T>) node).isLeaf();
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public void valueForPathChanged(TreePath path, Object newValue) {
+		((TreeNodeValueModel<T>) path.getLastPathComponent()).setValue((T) newValue);
+	}
+
+	@Override
+	@SuppressWarnings("unchecked")
+	public int getIndexOfChild(Object parent, Object child) {
+		return ((TreeNodeValueModel<T>) parent).indexOfChild((TreeNodeValueModel<T>) child);
+	}
+
+	/**
+	 * Extend to start listening to the underlying model if necessary.
+	 */
+    @Override
+	public void addTreeModelListener(TreeModelListener l) {
+		if (this.hasNoTreeModelListeners()) {
+			this.engageModel();
+		}
+		super.addTreeModelListener(l);
+	}
+
+	/**
+	 * Extend to stop listening to the underlying model if appropriate.
+	 */
+    @Override
+	public void removeTreeModelListener(TreeModelListener l) {
+		super.removeTreeModelListener(l);
+		if (this.hasNoTreeModelListeners()) {
+			this.disengageModel();
+		}
+	}
+
+
+	// ********** behavior **********
+
+	/**
+	 * Listen to the root and all the other nodes
+	 * in the underlying tree model.
+	 */
+	private void engageModel() {
+		this.rootHolder.addPropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
+		this.root = this.rootHolder.getValue();
+		if (this.root == null) {
+			throw new NullPointerException();	// the root cannot be null while we have listeners
+		}
+		this.engageNode(this.root);
+		this.addRoot();
+	}
+
+	/**
+	 * Add the root and all of the nodes to the underlying tree.
+	 */
+	private void addRoot() {
+		this.addNode(0, this.root);
+	}
+
+	/**
+	 * Stop listening to the root and all the other
+	 * nodes in the underlying tree model.
+	 */
+	private void disengageModel() {
+		this.removeRoot();
+		this.disengageNode(this.root);
+		this.root = null;
+		this.rootHolder.removePropertyChangeListener(PropertyValueModel.VALUE, this.rootListener);
+	}
+
+	/**
+	 * Remove the root and all of the nodes from the underlying tree.
+	 */
+	private void removeRoot() {
+		this.removeNode(0, this.root);
+	}
+
+	/**
+	 * The root has been swapped.
+	 * This method is a bit gnarly because the API for notifying listeners
+	 * that the root has changed is a bit inconsistent with that used for
+	 * non-root nodes.
+	 */
+	void rootChanged() {
+		TreeNodeValueModel<T> newRoot = this.rootHolder.getValue();
+		if (newRoot == null) {
+			throw new NullPointerException();	// the root cannot be null while we have listeners
+		}
+		// remove all the current root's children from the tree
+		// and remove the it from the internal tree
+		this.removeRoot();
+
+		// save the old root and swap in the new root
+		TreeNodeValueModel<T> oldRoot = this.root;
+		this.root = newRoot;
+
+		// we must be listening to both the old and new roots when we fire the event
+		// because their values can be affected by whether they have listeners
+		this.engageNode(this.root);
+		this.fireTreeRootReplaced(this.root);
+		// now we can stop listening to the old root
+		this.disengageNode(oldRoot);
+
+		// add the new root to the internal tree and
+		// add all its children to the tree also
+		this.addRoot();
+	}
+
+	/**
+	 * Either the "value" or the "state" of the specified node has changed,
+	 * forward notification to our listeners.
+	 */
+	void nodeChanged(TreeNodeValueModel<T> node) {
+		TreeNodeValueModel<T> parent = node.parent();
+		if (parent == null) {
+			this.fireTreeRootChanged(node);
+		} else {
+			this.fireTreeNodeChanged(parent.path(), parent.indexOfChild(node), node);
+		}
+	}
+
+	/**
+	 * Listen to the nodes, notify our listeners that the nodes were added,
+	 * and then add the nodes to our internal tree.
+	 * We must listen to the nodes before notifying anybody, because
+	 * adding a listener can change the value of a node.
+	 */
+	void addChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) {
+		int len = childIndices.length;
+		for (int i = 0; i < len; i++) {
+			this.engageNode(children[i]);
+		}
+		this.fireTreeNodesInserted(path, childIndices, children);
+		for (int i = 0; i < len; i++) {
+			this.addNode(childIndices[i], children[i]);
+		}
+	}
+
+	/**
+	 * Listen to the node and its children model.
+	 */
+	private void engageNode(TreeNodeValueModel<T> node) {
+		node.addStateChangeListener(this.nodeStateListener);
+		node.addPropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
+		node.childrenModel().addListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
+	}
+
+	/**
+	 * Add the node to our internal tree;
+	 * then recurse down through the node's children,
+	 * adding them to the internal tree also.
+	 */
+	private void addNode(int index, TreeNodeValueModel<T> node) {
+		this.addNodeToInternalTree(node.parent(), index, node, node.childrenModel());
+		new NodeChangePolicy(node).addChildren();
+	}
+
+	/**
+	 * Add the specified node to our internal tree.
+	 */
+	private void addNodeToInternalTree(TreeNodeValueModel<T> parent, int index, TreeNodeValueModel<T> node, ListValueModel<TreeNodeValueModel<T>> childrenModel) {
+		List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent);
+		if (siblings == null) {
+			siblings = new ArrayList<TreeNodeValueModel<T>>();
+			this.childrenLists.put(parent, siblings);
+		}
+		siblings.add(index, node);
+
+		this.parents.put(childrenModel, node);
+	}
+
+	/**
+	 * Remove nodes from our internal tree, notify our listeners that the
+	 * nodes were removed, then stop listening to the nodes.
+	 * We must listen to the nodes until after notifying anybody, because
+	 * removing a listener can change the value of a node.
+	 */
+	void removeChildren(TreeNodeValueModel<T>[] path, int[] childIndices, TreeNodeValueModel<T>[] children) {
+		int len = childIndices.length;
+		for (int i = 0; i < len; i++) {
+			// the indices slide down a notch each time we remove a child
+			this.removeNode(childIndices[i] - i, children[i]);
+		}
+		this.fireTreeNodesRemoved(path, childIndices, children);
+		for (int i = 0; i < len; i++) {
+			this.disengageNode(children[i]);
+		}
+	}
+
+	/**
+	 * First, recurse down through the node's children,
+	 * removing them from our internal tree;
+	 * then remove the node itself from our internal tree.
+	 */
+	private void removeNode(int index, TreeNodeValueModel<T> node) {
+		new NodeChangePolicy(node).removeChildren();
+		this.removeNodeFromInternalTree(node.parent(), index, node.childrenModel());
+	}
+
+	/**
+	 * Remove the specified node from our internal tree.
+	 */
+	private void removeNodeFromInternalTree(TreeNodeValueModel<T> parent, int index, ListValueModel<TreeNodeValueModel<T>> childrenModel) {
+		this.parents.remove(childrenModel);
+
+		List<TreeNodeValueModel<T>> siblings = this.childrenLists.get(parent);
+		siblings.remove(index);
+		if (siblings.isEmpty()) {
+			this.childrenLists.remove(parent);
+		}
+	}
+
+	/**
+	 * Stop listening to the node and its children model.
+	 */
+	private void disengageNode(TreeNodeValueModel<T> node) {
+		node.childrenModel().removeListChangeListener(ListValueModel.LIST_VALUES, this.childrenListener);
+		node.removePropertyChangeListener(PropertyValueModel.VALUE, this.nodeValueListener);
+		node.removeStateChangeListener(this.nodeStateListener);
+	}
+
+	void moveChildren(TreeNodeValueModel<T> parent, int targetIndex, int sourceIndex, int length) {
+		List<TreeNodeValueModel<T>> childrenList = this.childrenLists.get(parent);
+		ArrayList<TreeNodeValueModel<T>> temp = new ArrayList<TreeNodeValueModel<T>>(length);
+		for (int i = 0; i < length; i++) {
+			temp.add(childrenList.remove(sourceIndex));
+		}
+		childrenList.addAll(targetIndex, temp);
+
+		this.fireTreeStructureChanged(parent.path());
+	}
+
+
+	// ********** standard methods **********
+
+	@Override
+	public String toString() {
+		return ObjectTools.toString(this, this.root);
+	}
+
+
+	// ********** inner classes **********
+
+	/**
+	 * Coalesce some of the common change policy behavior.
+	 */
+	abstract class ChangePolicy {
+
+		ChangePolicy() {
+			super();
+		}
+
+		/**
+		 * Add the current set of children.
+		 */
+		void addChildren() {
+			TreeModelAdapter.this.addChildren(this.parent().path(), this.childIndices(), this.childArray());
+		}
+
+		/**
+		 * Remove the current set of children.
+		 */
+		void removeChildren() {
+			TreeModelAdapter.this.removeChildren(this.parent().path(), this.childIndices(), this.childArray());
+		}
+
+		/**
+		 * Return an array of the indices of the current set of children,
+		 * which should be contiguous.
+		 */
+		int[] childIndices() {
+			return this.buildIndices(this.childrenStartIndex(), this.childrenSize());
+		}
+
+		/**
+		 * Return an array of the current set of children.
+		 */
+		TreeNodeValueModel<T>[] childArray() {
+			return this.buildArray(this.getChildren(), this.childrenSize());
+		}
+
+		/**
+		 * Build an array to hold the elements in the specified iterator.
+		 * If they are different sizes, something is screwed up...
+		 */
+		TreeNodeValueModel<T>[] buildArray(Iterable<TreeNodeValueModel<T>> elements, int size) {
+			@SuppressWarnings("unchecked")
+			TreeNodeValueModel<T>[] array = new TreeNodeValueModel[size];
+			int i = 0;
+			for (TreeNodeValueModel<T> element : elements) {
+				array[i++] = element;
+			}
+			return array;
+		}
+
+		/**
+		 * Return a set of indices, starting at zero and
+		 * continuing for the specified size.
+		 */
+		int[] buildIndices(int size) {
+			return buildIndices(0, size);
+		}
+
+		/**
+		 * Return a set of indices, starting at the specified index and
+		 * continuing for the specified size.
+		 */
+		int[] buildIndices(int start, int size) {
+			int[] indices = new int[size];
+			int index = start;
+			for (int i = 0; i < size; i++) {
+				indices[i] = index++;
+			}
+			return indices;
+		}
+
+		/**
+		 * Return the parent of the current set of children.
+		 */
+		abstract TreeNodeValueModel<T> parent();
+
+		/**
+		 * Return the starting index for the current set of children.
+		 */
+		abstract int childrenStartIndex();
+
+		/**
+		 * Return the size of the current set of children.
+		 */
+		abstract int childrenSize();
+
+		/**
+		 * Return the current set of children.
+		 */
+		abstract Iterable<TreeNodeValueModel<T>> getChildren();
+	}
+
+
+	/**
+	 * Wraps a ListEvent for adding, removing, replacing,
+	 * and changing children.
+	 */
+	/* CU private */ abstract class EventChangePolicy
+		extends ChangePolicy
+	{
+		final ListEvent event;
+
+		EventChangePolicy(ListEvent event) {
+			super();
+			this.event = event;
+		}
+
+		/**
+		 * Map the ListChangeEvent's source to the corresponding parent.
+		 */
+		@Override
+		TreeNodeValueModel<T> parent() {
+			return TreeModelAdapter.this.parents.get(this.event.getSource());
+		}
+	}
+
+
+	/**
+	 * Wraps a ListAddEvent for adding children.
+	 */
+	/* CU private */ class AddEventChangePolicy
+		extends EventChangePolicy
+	{
+		AddEventChangePolicy(ListAddEvent event) {
+			super(event);
+		}
+
+		private ListAddEvent getEvent() {
+			return (ListAddEvent) this.event;
+		}
+
+		/**
+		 * The ListAddEvent's item index is the children start index.
+		 */
+		@Override
+		int childrenStartIndex() {
+			return this.getEvent().getIndex();
+		}
+
+		/**
+		 * The ListAddEvent's size is the children size.
+		 */
+		@Override
+		int childrenSize() {
+			return this.getEvent().getItemsSize();
+		}
+
+		/**
+		 * The ListAddEvent's items are the children.
+		 */
+		@Override
+		@SuppressWarnings("unchecked")
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getItems();
+		}
+	}
+
+
+	/**
+	 * Wraps a ListRemoveEvent for adding children.
+	 */
+	/* CU private */ class RemoveEventChangePolicy
+		extends EventChangePolicy
+	{
+		RemoveEventChangePolicy(ListRemoveEvent event) {
+			super(event);
+		}
+
+		private ListRemoveEvent getEvent() {
+			return (ListRemoveEvent) this.event;
+		}
+
+		/**
+		 * The ListRemoveEvent's item index is the children start index.
+		 */
+		@Override
+		int childrenStartIndex() {
+			return this.getEvent().getIndex();
+		}
+
+		/**
+		 * The ListRemoveEvent's size is the children size.
+		 */
+		@Override
+		int childrenSize() {
+			return this.getEvent().getItemsSize();
+		}
+
+		/**
+		 * The ListRemoveEvent's items are the children.
+		 */
+		@Override
+		@SuppressWarnings("unchecked")
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getItems();
+		}
+	}
+
+
+	/**
+	 * Wraps a ListReplaceEvent for replacing children.
+	 */
+	/* CU private */ class ReplaceEventChangePolicy
+		extends EventChangePolicy
+	{
+		ReplaceEventChangePolicy(ListReplaceEvent event) {
+			super(event);
+		}
+
+		private ListReplaceEvent getEvent() {
+			return (ListReplaceEvent) this.event;
+		}
+
+		/**
+		 * The ListReplaceEvent's item index is the children start index.
+		 */
+		@Override
+		int childrenStartIndex() {
+			return this.getEvent().getIndex();
+		}
+
+		/**
+		 * The ListReplaceEvent's size is the children size.
+		 */
+		@Override
+		int childrenSize() {
+			return this.getEvent().getItemsSize();
+		}
+
+		/**
+		 * The ListReplaceEvent's items are the children.
+		 */
+		@Override
+		@SuppressWarnings("unchecked")
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getNewItems();
+		}
+
+		/**
+		 * Remove the old nodes and add the new ones.
+		 */
+		void replaceChildren() {
+			TreeNodeValueModel<T>[] parentPath = this.parent().path();
+			int[] childIndices = this.childIndices();
+			TreeModelAdapter.this.removeChildren(parentPath, childIndices, this.getOldChildren());
+			TreeModelAdapter.this.addChildren(parentPath, childIndices, this.childArray());
+		}
+
+		TreeNodeValueModel<T>[] getOldChildren() {
+			return this.buildArray(this.getOldItems(), this.getEvent().getItemsSize());
+		}
+
+		// minimized scope of suppressed warnings
+		@SuppressWarnings("unchecked")
+		protected Iterable<TreeNodeValueModel<T>> getOldItems() {
+			return (Iterable<TreeNodeValueModel<T>>) this.getEvent().getOldItems();
+		}
+	}
+
+
+	/**
+	 * Wraps a ListMoveEvent for moving children.
+	 */
+	/* CU private */ class MoveEventChangePolicy
+		extends EventChangePolicy
+	{
+		MoveEventChangePolicy(ListMoveEvent event) {
+			super(event);
+		}
+
+		private ListMoveEvent getEvent() {
+			return (ListMoveEvent) this.event;
+		}
+
+		void moveChildren() {
+			TreeModelAdapter.this.moveChildren(this.parent(), this.getEvent().getTargetIndex(), this.getEvent().getSourceIndex(), this.getEvent().getLength());
+		}
+
+		@Override
+		int childrenStartIndex() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		int childrenSize() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+
+	/**
+	 * Wraps a ListClearEvent for clearing children.
+	 */
+	/* CU private */ class ClearEventChangePolicy
+		extends EventChangePolicy
+	{
+		ClearEventChangePolicy(ListClearEvent event) {
+			super(event);
+		}
+
+		/**
+		 * Clear all the nodes.
+		 */
+		void clearChildren() {
+			TreeNodeValueModel<T> parent = this.parent();
+			TreeNodeValueModel<T>[] parentPath = parent.path();
+			List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent);
+			int[] childIndices = this.buildIndices(childrenList.size());
+			TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList, childrenList.size());
+			TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
+		}
+
+		@Override
+		int childrenStartIndex() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		int childrenSize() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+
+	/**
+	 * Wraps a ListChangeEvent for clearing children.
+	 */
+	/* CU private */ class ChangeEventChangePolicy
+		extends EventChangePolicy
+	{
+		ChangeEventChangePolicy(ListChangeEvent event) {
+			super(event);
+		}
+
+		/**
+		 * Remove all the old nodes and add all the new nodes.
+		 */
+		void rebuildChildren() {
+			TreeNodeValueModel<T> parent = this.parent();
+			TreeNodeValueModel<T>[] parentPath = parent.path();
+			List<TreeNodeValueModel<T>> childrenList = TreeModelAdapter.this.childrenLists.get(parent);
+			int[] childIndices = this.buildIndices(childrenList.size());
+			TreeNodeValueModel<T>[] childArray = this.buildArray(childrenList, childrenList.size());
+			TreeModelAdapter.this.removeChildren(parentPath, childIndices, childArray);
+
+			childIndices = this.buildIndices(parent.childrenModel().size());
+			childArray = this.buildArray(parent.childrenModel(), parent.childrenSize());
+			TreeModelAdapter.this.addChildren(parentPath, childIndices, childArray);
+		}
+
+		@Override
+		int childrenStartIndex() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		int childrenSize() {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			throw new UnsupportedOperationException();
+		}
+	}
+
+
+	/**
+	 * Wraps a TreeNodeValueModel for adding and removing its children.
+	 */
+	/* CU private */ class NodeChangePolicy
+		extends ChangePolicy
+	{
+		private final TreeNodeValueModel<T> node;
+
+		NodeChangePolicy(TreeNodeValueModel<T> node) {
+			super();
+			this.node = node;
+		}
+
+		/**
+		 * The node itself is the parent.
+		 */
+		@Override
+		TreeNodeValueModel<T> parent() {
+			return this.node;
+		}
+
+		/**
+		 * Since we will always be dealing with all of the node's
+		 * children, the children start index is always zero.
+		 */
+		@Override
+		int childrenStartIndex() {
+			return 0;
+		}
+
+		/**
+		 * Since we will always be dealing with all of the node's
+		 * children, the children size is always equal to the size
+		 * of the children model.
+		 */
+		@Override
+		int childrenSize() {
+			return this.node.childrenModel().size();
+		}
+
+		/**
+		 * Since we will always be dealing with all of the node's
+		 * children, the children are all the objects held by
+		 * the children model.
+		 */
+		@Override
+		Iterable<TreeNodeValueModel<T>> getChildren() {
+			return this.node.childrenModel();
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java
new file mode 100644
index 0000000..03de5cd
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CachingComboBoxModel.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.ComboBoxModel;
+
+/**
+ * This interface allows a client to better control the performance of
+ * a combo box model by allowing the client to specify when it is
+ * acceptable for the model to "cache" and "uncache" its list of elements.
+ * The model may ignore these hints if appropriate.
+ */
+public interface CachingComboBoxModel
+	extends ComboBoxModel
+{
+	/**
+	 * Cache the comboBoxModel List.  If you call this, you
+	 * must make sure to call uncacheList() as well.  Otherwise
+	 * stale data will be in the ComboBox until cacheList() is
+	 * called again or uncacheList() is called.
+	 */
+	void cacheList();
+
+	/**
+	 * Clear the cached list.  Next time the list is needed it will
+	 * be built when it is not cached.
+	 */
+	void uncacheList();
+
+	/**
+	 * Check to see if the list is already cached.  This can be used for
+	 * MouseEvents, since they are not terribly predictable.
+	 */
+	boolean isCached();
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java
new file mode 100644
index 0000000..9b174aa
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/CheckBoxTableCellRenderer.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.JCheckBox;
+import javax.swing.JTable;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import org.eclipse.persistence.tools.utility.swing.TableCellEditorAdapter.ImmediateEditListener;
+
+/**
+ * Make the cell look like a check box.
+ */
+@SuppressWarnings("nls")
+public class CheckBoxTableCellRenderer
+	implements TableCellEditorAdapter.Renderer
+{
+	/** the component used to paint the cell */
+	private final JCheckBox checkBox;
+
+	/** the listener to be notified on an immediate edit */
+	protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+	/** "normal" border - assume the default table "focus" border is 1 pixel thick */
+	private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
+
+
+	// ********** constructors/initialization **********
+
+	/**
+	 * Construct a cell renderer with no label or icon.
+	 */
+	public CheckBoxTableCellRenderer() {
+		super();
+		this.checkBox = this.buildCheckBox();
+		// by default, check boxes do not paint their borders
+		this.checkBox.setBorderPainted(true);
+		// this setting is recommended for check boxes inside of trees and tables
+		this.checkBox.setBorderPaintedFlat(true);
+	}
+
+	/**
+	 * Construct a cell renderer with the specified text and icon,
+	 * either of which may be null.
+	 */
+	public CheckBoxTableCellRenderer(String text, Icon icon) {
+		this();
+		this.setText(text);
+		this.setIcon(icon);
+	}
+
+	/**
+	 * Construct a cell renderer with the specified text.
+	 */
+	public CheckBoxTableCellRenderer(String text) {
+		this(text, null);
+	}
+
+	/**
+	 * Construct a cell renderer with the specified icon.
+	 */
+	public CheckBoxTableCellRenderer(Icon icon) {
+		this(null, icon);
+	}
+
+	protected JCheckBox buildCheckBox() {
+		JCheckBox cb = new JCheckBox();
+		cb.addActionListener(this.buildActionListener());
+		return cb;
+	}
+
+	private ActionListener buildActionListener() {
+		return new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				if (CheckBoxTableCellRenderer.this.immediateEditListener != null) {
+					CheckBoxTableCellRenderer.this.immediateEditListener.immediateEdit();
+				}
+			}
+		};
+	}
+
+
+	// ********** TableCellRenderer implementation **********
+
+	@Override
+	public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
+	    this.checkBox.setHorizontalAlignment(SwingConstants.CENTER);
+		this.checkBox.setComponentOrientation(table.getComponentOrientation());
+		this.checkBox.setFont(table.getFont());
+		this.checkBox.setEnabled(table.isEnabled());
+
+		this.checkBox.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
+		this.checkBox.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
+		// once the colors are set, calculate opaque setting
+		this.checkBox.setOpaque(this.cellIsOpaqueIn(table, value, selected, hasFocus, row, column));
+		this.checkBox.setBorder(this.border(table, value, selected, hasFocus, row, column));
+
+		this.setValue(value);
+		return this.checkBox;
+	}
+
+	/**
+	 * Return the cell's foreground color.
+	 */
+	protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return UIManager.getColor("Table.focusCellForeground");
+			}
+			return table.getSelectionForeground();
+		}
+		return table.getForeground();
+	}
+
+	/**
+	 * Return the cell's background color.
+	 */
+	protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return UIManager.getColor("Table.focusCellBackground");
+			}
+			return table.getSelectionBackground();
+		}
+		return table.getBackground();
+	}
+
+	/**
+	 * Return the cell's border.
+	 */
+	protected Border border(@SuppressWarnings("unused") JTable table, @SuppressWarnings("unused") Object value, @SuppressWarnings("unused") boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+		return hasFocus ?  UIManager.getBorder("Table.focusCellHighlightBorder") : NO_FOCUS_BORDER;
+	}
+
+	/**
+	 * Return whether the cell should be opaque in the table.
+	 * If the cell's background is the same as the table's background
+	 * and table is opaque, we don't need to paint the background -
+	 * the table will do it.
+	 */
+	protected boolean cellIsOpaqueIn(JTable table, @SuppressWarnings("unused") Object value, @SuppressWarnings("unused") boolean selected, @SuppressWarnings("unused") boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+		Color cellBackground = this.checkBox.getBackground();
+		Color tableBackground = table.getBackground();
+		return ! (table.isOpaque() && cellBackground.equals(tableBackground));
+	}
+
+	/**
+	 * Set the check box's value.
+	 */
+	protected void setValue(Object value) {
+		// CR#3999318 - This null check needs to be removed once JDK bug is fixed
+		if (value == null) {
+			value = Boolean.FALSE;
+		}
+		this.checkBox.setSelected(((Boolean) value).booleanValue());
+	}
+
+
+	// ********** TableCellEditorAdapter.Renderer implementation **********
+
+	@Override
+	public Object getValue() {
+		return Boolean.valueOf(this.checkBox.isSelected());
+	}
+
+	@Override
+	public void setImmediateEditListener(ImmediateEditListener listener) {
+		this.immediateEditListener = listener;
+	}
+
+	// ********** public API **********
+
+	/**
+	 * Set the check box's text; which by default is blank.
+	 */
+	public void setText(String text) {
+		this.checkBox.setText(text);
+	}
+
+	/**
+	 * Set the check box's icon; which by default is not present.
+	 */
+	public void setIcon(Icon icon) {
+		this.checkBox.setIcon(icon);
+	}
+
+	/**
+	 * Return the renderer's preferred height. This allows you
+	 * to set the table's row height to something the check box
+	 * will look good in....
+	 */
+	public int preferredHeight() {
+		// add in space for the border top and bottom
+		return (int) this.checkBox.getPreferredSize().getHeight() + 2;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java
new file mode 100644
index 0000000..cef9904
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ComboBoxTableCellRenderer.java
@@ -0,0 +1,342 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import javax.swing.BorderFactory;
+import javax.swing.ComboBoxModel;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JTable;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * Make the cell look like a combo-box.
+ */
+@SuppressWarnings("nls")
+public class ComboBoxTableCellRenderer
+	implements TableCellEditorAdapter.Renderer
+{
+	/* caching the combo box because we are caching the comboBoxModel.
+	 * Everytime we rebuilt the comboBox we would set the model on it and not
+	 * remove the model from the old combo box.  This meant that new listeners
+	 * kept being added to the comboBoxModel for every comboBox build.
+	 * Not sure if there is a way to clear out the old combo box, or why
+	 * we were buildig a new combo box every time so I went with caching it.
+	 */
+	private JComboBox comboBox;
+
+	/** the items used to populate the combo box */
+	private CachingComboBoxModel model;
+	private ListCellRenderer renderer;
+	Object value;
+	private static int height = -1;
+	boolean fakeFocusFlag;
+
+	/** the listener to be notified on an immediate edit */
+	protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+	/** hold the original colors of the combo-box */
+	private static Color defaultForeground;
+	private static Color defaultBackground;
+
+	/** "normal" border - assume the default table "focus" border is 1 pixel thick */
+	private static final Border NO_FOCUS_BORDER = BorderFactory.createEmptyBorder(1, 1, 1, 1);
+
+
+	// ********** constructors/initialization **********
+
+	/**
+	 * Default constructor.
+	 */
+	private ComboBoxTableCellRenderer() {
+		super();
+		initialize();
+	}
+
+	/**
+	 * Construct a cell renderer that uses the specified combo-box model.
+	 */
+	public ComboBoxTableCellRenderer(ComboBoxModel model) {
+		this(new NonCachingComboBoxModel(model));
+	}
+
+	/**
+	 * Construct a cell renderer that uses the specified caching combo-box model.
+	 */
+	public ComboBoxTableCellRenderer(CachingComboBoxModel model) {
+		this();
+		this.model = model;
+	}
+
+	/**
+	 * Construct a cell renderer that uses the specified
+	 * combo-box model and renderer.
+	 */
+	public ComboBoxTableCellRenderer(ComboBoxModel model, ListCellRenderer renderer) {
+		this(new NonCachingComboBoxModel(model), renderer);
+	}
+
+	/**
+	 * Construct a cell renderer that uses the specified
+	 * caching combo-box model and renderer.
+	 */
+	public ComboBoxTableCellRenderer(CachingComboBoxModel model, ListCellRenderer renderer) {
+		this(model);
+		this.renderer = renderer;
+	}
+
+	protected void initialize() {
+		// save the original colors of the combo-box, so we
+		// can use them to paint non-selected cells
+		if (height == -1) {
+			JComboBox cb = new JComboBox();
+			cb.addItem("m");
+
+			// add in space for the border top and bottom
+			height = cb.getPreferredSize().height + 2;
+
+			defaultForeground = cb.getForeground();
+			defaultBackground = cb.getBackground();
+		}
+	}
+
+    static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(16), SwingConstants.LEADING);
+
+    protected JComboBox buildComboBox() {
+
+		final JComboBox result = new JComboBox() {
+			private boolean fakeFocus;
+			private static final long serialVersionUID = 1L;
+			@Override
+			public boolean hasFocus() {
+				return this.fakeFocus || super.hasFocus();
+			}
+			@Override
+			public void paint(Graphics g) {
+				this.fakeFocus = ComboBoxTableCellRenderer.this.fakeFocusFlag;
+				super.paint(g);
+				this.fakeFocus = false;
+			}
+			//wrap the renderer to deal with the prototypeDisplayValue
+		    @Override
+			public void setRenderer(final ListCellRenderer aRenderer) {
+		        super.setRenderer(new ListCellRenderer(){
+		            @Override
+						public Component getListCellRendererComponent(JList list, Object v, int index, boolean isSelected, boolean cellHasFocus) {
+		                if (v == prototypeLabel) {
+		                    return prototypeLabel;
+		                }
+		                return aRenderer.getListCellRendererComponent(list, v, index, isSelected, cellHasFocus);
+		            }
+		        });
+		    }
+			@Override
+			public int getSelectedIndex() {
+		        boolean listNotCached = !listIsCached();
+		        if (listNotCached) {
+		            cacheList();
+		        }
+
+				int index = super.getSelectedIndex();
+
+		        if (listNotCached) {
+		            uncacheList();
+		        }
+				return index;
+		   }
+
+		};
+		// stole this code from javax.swing.DefaultCellEditor
+		result.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
+		result.addActionListener(this.buildActionListener());
+		result.addPopupMenuListener(this.buildPopupMenuListener());
+
+        //These are used to workaround problems with Swing trying to
+        //determine the size of a comboBox with a large model
+        result.setPrototypeDisplayValue(prototypeLabel);
+        getListBox(result).setPrototypeCellValue(prototypeLabel);
+
+		return result;
+	}
+
+
+    private JList getListBox(JComboBox result) {
+        return (JList) ObjectTools.get(result.getUI(), "listBox");
+    }
+
+
+	private ActionListener buildActionListener() {
+		return new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				JComboBox cb = (JComboBox) e.getSource();
+				Object selectedItem = cb.getSelectedItem();
+
+				// Only update the selected item and invoke immediateEdit() if the
+				// selected item actually changed, during the initialization of the
+				// editing, the model changes and causes this method to be invoked,
+				// it causes CR#3963675 to occur because immediateEdit() stop the
+				// editing, which is done at the wrong time
+				if (ComboBoxTableCellRenderer.this.value != selectedItem) {
+					ComboBoxTableCellRenderer.this.value = cb.getSelectedItem();
+					ComboBoxTableCellRenderer.this.immediateEdit();
+				}
+			}
+		};
+	}
+
+	void immediateEdit() {
+		if (this.immediateEditListener != null) {
+			this.immediateEditListener.immediateEdit();
+		}
+	}
+
+	private PopupMenuListener buildPopupMenuListener() {
+		return new PopupMenuListener() {
+
+			@Override
+			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+				if (listIsCached()) {
+					uncacheList();
+				}
+				cacheList();
+			}
+
+			@Override
+			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+	            if (listIsCached()) {
+	                uncacheList();
+	            }
+
+			}
+
+			@Override
+			public void popupMenuCanceled(PopupMenuEvent e) {
+	            if (listIsCached()) {
+	                uncacheList();
+	            }
+			}
+		};
+	}
+
+
+	void cacheList() {
+		this.model.cacheList();
+	}
+
+	void uncacheList() {
+		this.model.uncacheList();
+	}
+
+	boolean listIsCached() {
+		return this.model.isCached();
+	}
+	// ********** TableCellRenderer implementation **********
+
+	@Override
+	public Component getTableCellRendererComponent(JTable table, Object val, boolean selected, boolean hasFocus, int row, int column) {
+		this.fakeFocusFlag = selected || hasFocus;
+		if (this.comboBox == null) {
+			this.comboBox = this.buildComboBox();
+
+			this.comboBox.setComponentOrientation(table.getComponentOrientation());
+			this.comboBox.setModel(this.model);
+			if (this.renderer != null) {
+				this.comboBox.setRenderer(this.renderer);
+			}
+			this.comboBox.setFont(table.getFont());
+			this.comboBox.setEnabled(table.isEnabled());
+			this.comboBox.setBorder(this.border(table, val, selected, hasFocus, row, column));
+		}
+
+		// We need to go through the model since JComboBox might prevent us from
+		// selecting the value. This can happen when the value is not contained
+		// in the model, see CR#3950044 for an example
+		this.model.setSelectedItem(val);
+
+		return this.comboBox;
+	}
+
+	/**
+	 * Return the cell's foreground color.
+	 */
+	protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object val, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return defaultForeground;
+			}
+			return table.getSelectionForeground();
+		}
+		return defaultForeground;
+	}
+
+	/**
+	 * Return the cell's background color.
+	 */
+	protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object val, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return defaultBackground;
+			}
+			return table.getSelectionBackground();
+		}
+		return defaultBackground;
+	}
+
+	/**
+	 * Return the cell's border.
+	 */
+	protected Border border(@SuppressWarnings("unused") JTable table, @SuppressWarnings("unused") Object val, @SuppressWarnings("unused") boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+		return hasFocus ?
+			UIManager.getBorder("Table.focusCellHighlightBorder") //$NON-NLS-1$
+		:
+			NO_FOCUS_BORDER;
+	}
+
+
+	// ********** TableCellEditorAdapter.Renderer implementation **********
+
+	@Override
+	public Object getValue() {
+		return this.value;
+	}
+
+	@Override
+	public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
+		this.immediateEditListener = listener;
+	}
+
+
+	// ********** public API **********
+
+	/**
+	 * Return the renderer's preferred height. This allows you
+	 * to set the row height to something the combo-box will look good in....
+	 */
+	public int preferredHeight() {
+		return height;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java
new file mode 100644
index 0000000..9d3f076
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/EmptyIcon.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import java.awt.Graphics;
+import javax.swing.Icon;
+
+/**
+ * Implement the {@link Icon} interface with an icon that has a size but
+ * does not paint anything on the graphics context.
+ */
+public class EmptyIcon
+	implements Icon
+{
+	private final int width;
+	private final int height;
+
+	public static final EmptyIcon NULL_INSTANCE = new EmptyIcon(0);
+
+
+	public EmptyIcon(int size) {
+		this(size, size);
+	}
+
+	public EmptyIcon(int width, int height) {
+		super();
+		this.width = width;
+		this.height = height;
+	}
+
+	@Override
+	public void paintIcon(Component c, Graphics g, int x, int y) {
+		// don't paint anything for an empty icon
+	}
+
+	@Override
+	public int getIconWidth() {
+		return this.width;
+	}
+
+	@Override
+	public int getIconHeight() {
+		return this.height;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java
new file mode 100644
index 0000000..2721830
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListBrowser.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JOptionPane;
+import javax.swing.ListModel;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * This implementation of ListChooser.ListBrowser uses a
+ * {@link JOptionPane} to prompt the user for the selection. The {@link JOptionPane}
+ * is passed a {@link FilteringListPanel} to assist the user in making
+ * a selection.
+ */
+@SuppressWarnings("nls")
+public class FilteringListBrowser<T>
+	implements ListChooser.ListBrowser
+{
+	private FilteringListPanel<T> panel;
+
+	/**
+	 * Default constructor.
+	 */
+	public FilteringListBrowser() {
+		super();
+		this.panel = this.buildPanel();
+	}
+
+	protected FilteringListPanel<T> buildPanel() {
+		return new LocalFilteringListPanel<T>();
+	}
+
+	/**
+	 * Prompt the user using a JOptionPane with a filtering
+	 * list panel.
+	 */
+	@Override
+	public void browse(ListChooser chooser) {
+		this.initializeCellRenderer(chooser);
+
+		int option =
+			JOptionPane.showOptionDialog(
+				chooser,
+				this.buildMessage(chooser),
+				this.buildTitle(chooser),
+				this.buildOptionType(chooser),
+				this.buildMessageType(chooser),
+				this.buildIcon(chooser),
+				this.buildSelectionValues(chooser),
+				this.buildInitialSelectionValue(chooser)
+		);
+
+		if (option == JOptionPane.OK_OPTION) {
+			chooser.getModel().setSelectedItem(this.panel.getSelection());
+		}
+
+		// clear the text field so the list box is re-filtered
+		this.panel.getTextField().setText("");
+	}
+
+	protected void initializeCellRenderer(JComboBox comboBox) {
+		// default behavior should be to use the cell renderer from the combobox.
+		this.panel.getListBox().setCellRenderer(comboBox.getRenderer());
+	}
+
+	/**
+	 * the message can be anything - here we build a component
+	 */
+	protected Object buildMessage(JComboBox comboBox) {
+		this.panel.setCompleteList(this.convertListModelToArray(comboBox.getModel()));
+		this.panel.setSelection(comboBox.getModel().getSelectedItem());
+		return this.panel;
+	}
+
+	/**
+	 * Convert the list of objects in the specified list model
+	 * into an array.
+	 */
+	@SuppressWarnings("unchecked")
+	protected T[] convertListModelToArray(ListModel model) {
+		int size = model.getSize();
+		T[] result = (T[]) new Object[size];
+		for (int i = 0; i < size; i++) {
+			result[i] = (T) model.getElementAt(i);
+		}
+		return result;
+	}
+
+	protected String buildTitle(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected int buildOptionType(@SuppressWarnings("unused") JComboBox comboBox) {
+		return JOptionPane.OK_CANCEL_OPTION;
+	}
+
+	protected int buildMessageType(@SuppressWarnings("unused") JComboBox comboBox) {
+		return JOptionPane.QUESTION_MESSAGE;
+	}
+
+	protected Icon buildIcon(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected Object[] buildSelectionValues(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected Object buildInitialSelectionValue(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+
+	// ********** custom panel **********
+
+	protected static class LocalFilteringListPanel<S>
+		extends FilteringListPanel<S>
+	{
+		private static final long serialVersionUID = 1L;
+
+		@SuppressWarnings("unchecked")
+		protected LocalFilteringListPanel() {
+			super((S[]) ObjectTools.EMPTY_OBJECT_ARRAY, null);
+		}
+
+		/**
+		 * Disable the performance tweak because JOptionPane
+		 * will try open wide enough to disable the horizontal scroll bar;
+		 * and it looks a bit clumsy.
+		 */
+		@Override
+		protected String getPrototypeCellValue() {
+			return null;
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java
new file mode 100644
index 0000000..b01566d
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/FilteringListPanel.java
@@ -0,0 +1,459 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+import javax.swing.AbstractListModel;
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListModel;
+import javax.swing.ListSelectionModel;
+import javax.swing.border.Border;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+import org.eclipse.persistence.tools.utility.StringMatcher;
+import org.eclipse.persistence.tools.utility.transformer.StringObjectTransformer;
+import org.eclipse.persistence.tools.utility.transformer.Transformer;
+
+/**
+ * This panel presents an entry field and a list box of choices that
+ * allows the user to filter the entries in the list box by entering
+ * a pattern in the entry field.
+ * <p>
+ * Two wildcards are allowed in the pattern:<ul>
+ * <li>'*' will match any set of zero or more characters
+ * <li>'?' will match any single character
+ * <.ul>
+ * The panel consists of 4 components that can be customized:<ul>
+ * <li>1 text field
+ * <li>1 list box
+ * <li>2 labels, one for each of the above
+ * </ul>
+ * Other aspects of the panel's behavior can be changed:<ul>
+ * <li>the string converter determines how the objects in the
+ *     list are converted to strings and compared to the pattern
+ *     entered in the text field; by default the converter simply
+ *     uses the result of the object's #toString() method
+ *     (if you replace the string converter, you will probably
+ *     want to replace the list box's cell renderer also)
+ * <li>the string matcher can also be changed if you would
+ *     like different pattern matching behavior than that
+ *     described above
+ * <li>you can specify the maximum size of the list - this may
+ *     force the user to enter a pattern restrictive enough
+ *     to result in a list smaller than the maximum size; the
+ *     default is -1, which disables the restriction
+ * </ul>
+ * This panel is not a typical panel, in the sense that it does not share
+ * its model with clients via value models. Instead, this panel's model
+ * is set and queried directly because it is designed to be used in a
+ * dialog that directs the user's behavior (as opposed to a "normal"
+ * window).
+ */
+@SuppressWarnings("nls")
+public class FilteringListPanel<T>
+	extends JPanel
+{
+	/**
+	 * The complete list of available choices
+	 * (as opposed to the partial list held by the list box).
+	 */
+	private T[] completeList;
+
+	/**
+	 * An adapter used to convert the objects in the list
+	 * to strings so they can be run through the matcher
+	 * and displayed in the text field.
+	 */
+	Transformer<T, String> transformer;
+
+	/** The text field. */
+	private JTextField textField;
+	private JLabel textFieldLabel;
+	private DocumentListener textFieldListener;
+
+	/** The list box. */
+	private JList listBox;
+	private JLabel listBoxLabel;
+
+	/** The maximum number of entries displayed in the list box. */
+	private int maxListSize;
+
+	/**
+	 * Performance tweak: We use this buffer instead of
+	 * a temporary variable during filtering so we don't have
+	 * to keep re-allocating it.
+	 */
+	private Object[] buffer;
+
+	private static final Border TEXT_FIELD_LABEL_BORDER = BorderFactory.createEmptyBorder(0, 0, 5, 0);
+	private static final Border LIST_BOX_LABEL_BORDER = BorderFactory.createEmptyBorder(5, 0, 5, 0);
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors **********
+
+	/**
+	 * Construct a FilteringListPanel with the specified list of choices
+	 * and initial selection. Use the default string converter to convert the
+	 * choices and selection to strings (which simply calls #toString() on
+	 * the objects).
+	 */
+	public FilteringListPanel(T[] completeList, T initialSelection) {
+		this(completeList, initialSelection, StringObjectTransformer.<T>instance());
+	}
+
+	/**
+	 * Construct a FilteringListPanel with the specified list of choices
+	 * and initial selection. Use the specified string converter to convert the
+	 * choices and selection to strings.
+	 */
+	public FilteringListPanel(T[] completeList, T initialSelection, Transformer<T, String> stringConverter) {
+		super(new BorderLayout());
+		this.completeList = completeList;
+		this.transformer = stringConverter;
+		this.initialize(initialSelection);
+	}
+
+
+	// ********** initialization **********
+
+	private void initialize(T initialSelection) {
+		this.maxListSize = this.getDefaultMaxListSize();
+		this.buffer = this.buildBuffer();
+
+		this.textFieldListener = this.buildTextFieldListener();
+
+		this.initializeLayout(initialSelection);
+	}
+
+	private Object[] buildBuffer() {
+		return new Object[this.getMax()];
+	}
+
+	/**
+	 * Return the current max number of entries allowed in the list box.
+	 */
+	private int getMax() {
+		return (this.maxListSize == -1) ?
+				this.completeList.length :
+				Math.min(this.maxListSize, this.completeList.length);
+	}
+
+	/**
+	 * Build a listener that will listen to changes in the text field
+	 * and filter the list appropriately.
+	 */
+	private DocumentListener buildTextFieldListener() {
+		return new TextFieldListener();
+	}
+
+	/* CU private */ class TextFieldListener
+		implements DocumentListener
+	{
+		@Override
+		public void insertUpdate(DocumentEvent e) {
+			FilteringListPanel.this.filterList();
+		}
+		@Override
+		public void changedUpdate(DocumentEvent e) {
+			FilteringListPanel.this.filterList();
+		}
+		@Override
+		public void removeUpdate(DocumentEvent e) {
+			FilteringListPanel.this.filterList();
+		}
+		@Override
+		public String toString() {
+			return ObjectTools.toString(this);
+		}
+	}
+
+	private int getDefaultMaxListSize() {
+		return -1;
+	}
+
+	private void initializeLayout(Object initialSelection) {
+		// text field
+		JPanel textFieldPanel = new JPanel(new BorderLayout());
+		this.textFieldLabel = new JLabel();
+		this.textFieldLabel.setBorder(TEXT_FIELD_LABEL_BORDER);
+		textFieldPanel.add(this.textFieldLabel, BorderLayout.NORTH);
+
+		this.textField = new JTextField();
+		this.textField.getDocument().addDocumentListener(this.textFieldListener);
+		this.textFieldLabel.setLabelFor(this.textField);
+		textFieldPanel.add(this.textField, BorderLayout.CENTER);
+
+		this.add(textFieldPanel, BorderLayout.NORTH);
+
+		// list box
+		JPanel listBoxPanel = new JPanel(new BorderLayout());
+		this.listBoxLabel = new JLabel();
+		this.listBoxLabel.setBorder(LIST_BOX_LABEL_BORDER);
+		listBoxPanel.add(this.listBoxLabel, BorderLayout.NORTH);
+
+		this.listBox = new JList();
+		this.listBox.setDoubleBuffered(true);
+		this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.getMax()));
+		this.listBox.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		// performance tweak(?)
+		this.listBox.setPrototypeCellValue(this.getPrototypeCellValue());
+		this.listBox.setPrototypeCellValue(null);
+		this.listBox.setCellRenderer(this.buildDefaultCellRenderer());
+		this.listBoxLabel.setLabelFor(this.listBox);
+		// bug 2777802 - scroll bars shouldn't be on the tab sequence
+		JScrollPane listBoxScrollPane = new JScrollPane(this.listBox);
+		listBoxScrollPane.getHorizontalScrollBar().setFocusable(false);
+		listBoxScrollPane.getVerticalScrollBar().setFocusable(false);
+		listBoxPanel.add(listBoxScrollPane, BorderLayout.CENTER);
+
+		// initialize the widgets
+		this.listBox.setSelectedValue(initialSelection, true);
+		this.textField.select(0, this.textField.getText().length());
+
+		this.add(listBoxPanel, BorderLayout.CENTER);
+	}
+
+
+	// ********** public API **********
+
+	public Object getSelection() {
+		return this.listBox.getSelectedValue();
+	}
+
+	public void setSelection(Object selection) {
+		this.listBox.setSelectedValue(selection, true);
+	}
+
+	public T[] getCompleteList() {
+		return this.completeList;
+	}
+
+	/**
+	 * rebuild the filtering buffer and re-apply the filter
+	 * to the new list
+	 */
+	public void setCompleteList(T[] completeList) {
+		this.completeList = completeList;
+		if (this.buffer.length < this.getMax()) {
+			// the buffer will never shrink - might want to re-consider...  ~bjv
+			this.buffer = this.buildBuffer();
+		}
+		this.filterList();
+	}
+
+	public int getMaxListSize() {
+		return this.maxListSize;
+	}
+
+	public void setMaxListSize(int maxListSize) {
+		this.maxListSize = maxListSize;
+		if (this.buffer.length < this.getMax()) {
+			// the buffer will never shrink - might want to re-consider...  ~bjv
+			this.buffer = this.buildBuffer();
+		}
+		this.filterList();
+	}
+
+	public Transformer<T, String> getTransformer() {
+		return this.transformer;
+	}
+
+	/**
+	 * apply the new filter to the list
+	 */
+	public void setTransformer(Transformer<T, String> transformer) {
+		this.transformer = transformer;
+		this.filterList();
+	}
+
+	/**
+	 * allow client code to access the text field
+	 * (so we can set the focus)
+	 */
+	public JTextField getTextField() {
+		return this.textField;
+	}
+
+	/**
+	 * allow client code to access the text field label
+	 */
+	public JLabel getTextFieldLabel() {
+		return this.textFieldLabel;
+	}
+
+	/**
+	 * convenience method
+	 */
+	public void setTextFieldLabelText(String text) {
+		this.textFieldLabel.setText(text);
+	}
+
+	/**
+	 * allow client code to access the list box
+	 * (so we can add mouse listeners for double-clicking)
+	 */
+	public JList getListBox() {
+		return this.listBox;
+	}
+
+	/**
+	 * convenience method
+	 */
+	public void setListBoxCellRenderer(ListCellRenderer renderer) {
+		this.listBox.setCellRenderer(renderer);
+	}
+
+	/**
+	 * allow client code to access the list box label
+	 */
+	public JLabel getListBoxLabel() {
+		return this.listBoxLabel;
+	}
+
+	/**
+	 * convenience method
+	 */
+	public void setListBoxLabelText(String text) {
+		this.listBoxLabel.setText(text);
+	}
+
+	/**
+	 * convenience method
+	 */
+	public void setComponentsFont(Font font) {
+		this.textFieldLabel.setFont(font);
+		this.textField.setFont(font);
+		this.listBoxLabel.setFont(font);
+		this.listBox.setFont(font);
+	}
+
+
+	// ********** internal methods **********
+
+	/**
+	 * Allow subclasses to disable performance tweak
+	 * by returning null here.
+	 */
+	protected String getPrototypeCellValue() {
+		return "==========> A_STRING_THAT_IS_DEFINITELY_LONGER_THAN_EVERY_STRING_IN_THE_LIST <==========";
+	}
+
+	/**
+	 * By default, use the string converter to build the text
+	 * used by the list box's cell renderer.
+	 */
+	protected ListCellRenderer buildDefaultCellRenderer() {
+		return new DefaultCellRenderer();
+	}
+
+	protected class DefaultCellRenderer
+		extends SimpleListCellRenderer
+	{
+		private static final long serialVersionUID = 1L;
+
+		@Override
+		@SuppressWarnings("unchecked")
+		protected String buildText(Object value) {
+			return FilteringListPanel.this.transformer.transform((T) value);
+		}
+	}
+
+	/**
+	 * Something has changed that requires us to filter the list.
+	 * <p>
+	 * This method is synchronized because a fast typist can
+	 * generate events quicker than we can filter the list. (?  ~bjv)
+	 */
+	synchronized void filterList() {
+		// temporarily stop listening to the list box selection, since we will
+		// be changing the selection during the filtering and don't want
+		// that to affect the text field
+		this.filterList(this.textField.getText());
+	}
+
+	/**
+	 * Filter the contents of the list box to match the
+	 * specified pattern.
+	 */
+	private void filterList(String pattern) {
+		if (pattern.length() == 0) {
+			this.listBox.setModel(this.buildPartialArrayListModel(this.completeList, this.getMax()));
+		} else {
+			StringMatcher stringMatcher = new StringMatcher(pattern + ALL, true, false);
+			int j = 0;
+			int len = this.completeList.length;
+			int max = this.getMax();
+			for (int i = 0; i < len; i++) {
+				if (stringMatcher.match(this.transformer.transform(this.completeList[i]))) {
+					this.buffer[j++] = this.completeList[i];
+				}
+				if (j == max) {
+					break;
+				}
+			}
+			this.listBox.setModel(this.buildPartialArrayListModel(this.buffer, j));
+		}
+
+		// after filtering the list, determine the appropriate selection
+		if (this.listBox.getModel().getSize() == 0) {
+			this.listBox.getSelectionModel().clearSelection();
+		} else {
+			this.listBox.getSelectionModel().setAnchorSelectionIndex(0);
+			this.listBox.getSelectionModel().setLeadSelectionIndex(0);
+			this.listBox.ensureIndexIsVisible(0);
+		}
+	}
+	private static final String ALL = "*";
+
+	/**
+	 * Build a list model that wraps only a portion of the specified array.
+	 * The model will include the array entries from 0 to (size - 1).
+	 */
+	private ListModel buildPartialArrayListModel(Object[] array, int size) {
+		return new PartialArrayListModel<T>(array, size);
+	}
+
+	/* CU private */ static class PartialArrayListModel<T>
+		extends AbstractListModel
+	{
+		private final Object[] array;
+		private final int size;
+		private static final long serialVersionUID = 1L;
+
+		PartialArrayListModel(Object[] array, int size) {
+			super();
+			this.array = array;
+			this.size = size;
+		}
+		@Override
+		public int getSize() {
+			return this.size;
+		}
+		@Override
+		@SuppressWarnings("unchecked")
+		public T getElementAt(int index) {
+			return (T) this.array[index];
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java
new file mode 100644
index 0000000..5335e3c
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/ListChooser.java
@@ -0,0 +1,482 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.AWTEvent;
+import java.awt.AWTException;
+import java.awt.Component;
+import java.awt.EventQueue;
+import java.awt.Point;
+import java.awt.Robot;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.io.Serializable;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.SwingConstants;
+import javax.swing.event.PopupMenuEvent;
+import javax.swing.event.PopupMenuListener;
+import javax.swing.plaf.basic.BasicComboBoxUI;
+import org.eclipse.persistence.tools.utility.ObjectTools;
+
+/**
+ * This component provides a way to handle selecting an item from a
+ * list that may grow too large to be handled conveniently by a combo-box.
+ * If the list's size is less than the designated "long" list size,
+ * the choice list will be displayed in a normal combo-box popup;
+ * otherwise, a dialog will be used to prompt the user to choose a selection.
+ *
+ * To change the browse mechanism, subclasses may
+ * 	- override the method #buildBrowser()
+ *  - override the method #browse(), in which case the method
+ * 		#buildBrowser() may be ignored.
+ */
+@SuppressWarnings("nls")
+public class ListChooser
+	extends JComboBox
+{
+	/** the size of a "long" list - anything smaller is a "short" list */
+	int longListSize = DEFAULT_LONG_LIST_SIZE;
+
+	/** the default size of a "long" list, which is 20 (to match JOptionPane's behavior) */
+	public static final int DEFAULT_LONG_LIST_SIZE = 20;
+
+	/** property change associated with long list size */
+	public static final String LONG_LIST_SIZE_PROPERTY = "longListSize";
+
+	static JLabel prototypeLabel = new JLabel("Prototype", new EmptyIcon(17), SwingConstants.LEADING);
+
+	/**
+	 * whether the chooser is choosable.  if a chooser is not choosable,
+	 * it only serves as a display widget.  a user may not change its
+	 * selected value.
+	 */
+	boolean choosable = true;
+
+	/** property change associated with choosable */
+	public static final String CHOOSABLE_PROPERTY = "choosable";
+
+	/** the browser used to make a selection from the long list - typically via a dialog */
+	private ListBrowser browser;
+
+	private NodeSelector nodeSelector;
+
+	/** INTERNAL - The popup is being shown.  Used to prevent infinite loop. */
+	boolean popupAlreadyInProgress;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// **************** Constructors ******************************************
+
+	/**
+	 * Construct a list chooser for the specified model.
+	 */
+	public ListChooser(ComboBoxModel model) {
+		this(model, NodeSelector.Default.instance());
+	}
+
+	public ListChooser(CachingComboBoxModel model) {
+		this(model, NodeSelector.Default.instance());
+	}
+
+	public ListChooser(ComboBoxModel model, NodeSelector nodeSelector) {
+		this(new NonCachingComboBoxModel(model), nodeSelector);
+	}
+
+	public ListChooser(CachingComboBoxModel model, NodeSelector nodeSelector) {
+		super(model);
+		this.initialize();
+		this.nodeSelector = nodeSelector;
+	}
+	// **************** Initialization ****************************************
+
+	protected void initialize() {
+		this.addPopupMenuListener(this.buildPopupMenuListener());
+		this.setRenderer(new DefaultListCellRenderer());
+		this.addKeyListener(this.buildF3KeyListener());
+
+		//These are used to workaround problems with Swing trying to
+		//determine the size of a comboBox with a large model
+		this.setPrototypeDisplayValue(prototypeLabel);
+		this.listBox().setPrototypeCellValue(prototypeLabel);
+	}
+
+
+	private JList listBox() {
+		return (JList) ObjectTools.get(this.ui, "listBox");
+	}
+
+	/**
+	 * When the popup is about to be shown, the event is consumed, and
+	 * PopupHandler determines whether to reshow the popup or to show
+	 * the long list browser.
+	 */
+	private PopupMenuListener buildPopupMenuListener() {
+		return new PopupMenuListener() {
+			@Override
+			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+				ListChooser.this.aboutToShowPopup();
+			}
+			@Override
+			public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+				// do nothing
+			}
+			@Override
+			public void popupMenuCanceled(PopupMenuEvent e) {
+				// do nothing
+			}
+			@Override
+			public String toString() {
+				return "pop-up menu listener";
+			}
+		};
+	}
+
+	/**
+	 * If this code is being reached due to the PopupHandler already being in progress,
+	 * then do nothing.  Otherwise, set the flag to true and launch the PopupHandler.
+	 */
+	void aboutToShowPopup() {
+		if (this.popupAlreadyInProgress) {
+			return;
+		}
+
+		this.popupAlreadyInProgress = true;
+		EventQueue.invokeLater(new PopupHandler());
+	}
+
+
+	private KeyListener buildF3KeyListener() {
+		return new KeyAdapter() {
+			@Override
+			public void keyPressed(KeyEvent e) {
+				if (e.getKeyCode() == KeyEvent.VK_F3) {
+					ListChooser.this.goToSelectedItem();
+				}
+			}
+			@Override
+			public String toString() {
+				return "F3 key listener";
+			}
+		};
+	}
+
+	public void goToSelectedItem() {
+		if (this.getSelectedItem() != null) {
+			ListChooser.this.nodeSelector.selectNodeFor(this.getSelectedItem());
+		}
+	}
+
+	// **************** Browsing **********************************************
+
+	/**
+	 * Lazily initialize because subclasses may have further initialization to do
+	 * before browser can be built.
+	 */
+	protected void browse() {
+		if (this.browser == null) {
+			this.browser = this.buildBrowser();
+		}
+
+		this.browser.browse(this);
+	}
+
+	/**
+	 * Return the "browser" used to make a selection from the long list,
+	 * typically via a dialog.
+	 */
+	protected ListChooser.ListBrowser buildBrowser() {
+		return new SimpleListBrowser();
+	}
+
+
+	// **************** Choosable functionality *******************************
+
+	/** override behavior - consume selection if chooser is not choosable */
+	@Override
+	public void setSelectedIndex(int anIndex) {
+		if (this.choosable) {
+			super.setSelectedIndex(anIndex);
+		}
+	}
+
+	private void updateArrowButton() {
+		try {
+			BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
+			JButton arrowButton = (JButton) ObjectTools.get(comboBoxUi, "arrowButton");
+			arrowButton.setEnabled(this.isEnabled() && this.choosable);
+		}
+		catch (Exception e) {
+			// this is a huge hack to try and make the combo box look right,
+			// so if it doesn't work, just swallow the exception
+		}
+	}
+
+
+	// **************** List Caching *******************************
+
+	void cacheList() {
+		((CachingComboBoxModel) this.getModel()).cacheList();
+	}
+
+	void uncacheList() {
+		((CachingComboBoxModel) this.getModel()).uncacheList();
+	}
+
+	boolean listIsCached() {
+		return ((CachingComboBoxModel) this.getModel()).isCached();
+	}
+
+	// **************** Public ************************************************
+
+	public int longListSize() {
+		return this.longListSize;
+	}
+
+	public void setLongListSize(int newLongListSize) {
+		int oldLongListSize = this.longListSize;
+		this.longListSize = newLongListSize;
+		this.firePropertyChange(LONG_LIST_SIZE_PROPERTY, oldLongListSize, newLongListSize);
+	}
+
+	public boolean isChoosable() {
+		return this.choosable;
+	}
+
+	public void setChoosable(boolean newValue) {
+		boolean oldValue = this.choosable;
+		this.choosable = newValue;
+		this.firePropertyChange(CHOOSABLE_PROPERTY, oldValue, newValue);
+		this.updateArrowButton();
+	}
+
+	// **************** Handle selecting null as a value **********************
+
+	private boolean selectedIndexIsNoneSelectedItem(int index) {
+		return (index == -1) &&
+				 (this.getModel().getSize() > 0) &&
+				 (this.getModel().getElementAt(0) == null);
+	}
+
+	@Override
+	public int getSelectedIndex() {
+		boolean listNotCached = !this.listIsCached();
+		if (listNotCached) {
+			this.cacheList();
+		}
+
+		int index = super.getSelectedIndex();
+
+		// Use index 0 to show the <none selected> item since the actual value is
+		// null and JComboBox does not handle null values
+		if (this.selectedIndexIsNoneSelectedItem(index)) {
+			index = 0;
+		}
+
+		if (listNotCached) {
+			this.uncacheList();
+		}
+		return index;
+   }
+
+	//wrap the renderer to deal with the prototypeDisplayValue
+	@Override
+	public void setRenderer(final ListCellRenderer aRenderer) {
+		super.setRenderer(new ListCellRenderer(){
+			@Override
+			public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+				if (value == prototypeLabel) {
+					return prototypeLabel;
+				}
+				return aRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+			}
+		});
+	}
+
+
+	// **************** Member classes ****************************************
+
+	/**
+	 * Define the API required by this ListChooser when it must
+	 * prompt the user to select an item from the "long" list.
+	 */
+	public interface ListBrowser
+	{
+		/**
+		 * Prompt the user to make a selection from the specified
+		 * combo-box's model.
+		 */
+		void browse(ListChooser parentChooser);
+	}
+
+
+	/**
+	 * Runnable class that consumes popup window and determines whether
+	 * to reshow popup or to launch browser, based on the size of the list.
+	 */
+	private class PopupHandler
+		implements Runnable
+	{
+		/** The mouse event */
+		private MouseEvent lastMouseEvent;
+
+		/** The component from which the last mouse event was thrown */
+		private JComponent eventComponent;
+
+		/** The location of the component at the time the last mouse event was thrown */
+		private Point componentLocation;
+
+		/** The location of the mouse at the time the last mouse event was thrown */
+		private Point mouseLocation;
+
+
+		PopupHandler() {
+			this.initialize();
+		}
+
+		private void initialize() {
+			AWTEvent event = EventQueue.getCurrentEvent();
+
+			if (event instanceof MouseEvent) {
+				this.lastMouseEvent = (MouseEvent) event;
+				this.eventComponent = (JComponent) this.lastMouseEvent.getSource();
+				this.componentLocation = this.eventComponent.getLocationOnScreen();
+				this.mouseLocation = this.lastMouseEvent.getPoint();
+			}
+			else {
+				this.eventComponent = null;
+				this.componentLocation = null;
+				this.mouseLocation = null;
+			}
+		}
+
+		@Override
+		public void run() {
+			ListChooser.this.hidePopup();
+
+			ListChooser.this.cacheList();
+			if (ListChooser.this.choosable == true) {
+				// If the combo box model is of sufficient length, the browser will be shown.
+				// Asking the combo box model for its size should be enough to ensure that
+				//  its size is recalculated.
+				if (ListChooser.this.getModel().getSize() > ListChooser.this.longListSize) {
+					this.checkComboBoxButton();
+					ListChooser.this.browse();
+				}
+				else {
+					ListChooser.this.showPopup();
+					this.checkMousePosition();
+				}
+			}
+			if (ListChooser.this.listIsCached()) {
+				ListChooser.this.uncacheList();
+			}
+
+			ListChooser.this.popupAlreadyInProgress = false;
+		}
+
+		/** If this is not done, the button never becomes un-pressed */
+		private void checkComboBoxButton() {
+			try {
+				BasicComboBoxUI comboBoxUi = (BasicComboBoxUI) ListChooser.this.getUI();
+				JButton arrowButton = (JButton) ObjectTools.get(comboBoxUi, "arrowButton");
+				arrowButton.getModel().setPressed(false);
+			}
+			catch (Exception ex) {
+				// this is a huge hack to try and make the combo box look right,
+				// so if it doesn't work, just swallow the exception
+				this.handleException(ex);
+			}
+		}
+
+		private void handleException(@SuppressWarnings("unused") Exception ex) {
+			// do nothing for now
+		}
+
+		/**
+		 * Moves the mouse back to its original position before any jiggery pokery that we've done.
+		 */
+		private void checkMousePosition() {
+			if (this.eventComponent == null) {
+				return;
+			}
+
+			final Point newComponentLocation = this.eventComponent.getLocationOnScreen();
+			boolean componentMoved =
+				((newComponentLocation.x - this.componentLocation.x) != 0)
+				|| ((newComponentLocation.y - this.componentLocation.y) != 0);
+
+			if (componentMoved) {
+				try {
+					new Robot().mouseMove(
+						newComponentLocation.x + this.mouseLocation.x,
+						newComponentLocation.y + this.mouseLocation.y
+					);
+				}
+				catch (AWTException ex) {
+					// move failed - do nothing
+				}
+			}
+		}
+	}
+
+	/**
+	 * This will be called when the user presses F3 or chooses
+	 * 'Go To' in the context menu
+	 */
+	public interface NodeSelector {
+		/**
+		 * Select the appropriate Node in the tree or the editor panel.
+		 */
+		void selectNodeFor(Object item);
+
+		/**
+		 * This NodeSelector will do nothing when selectNodeFor(Object) is called
+		 */
+		final class Default
+			implements NodeSelector, Serializable
+		{
+			public static final NodeSelector INSTANCE = new Default();
+			public static NodeSelector instance() {
+				return INSTANCE;
+			}
+			// ensure single instance
+			private Default() {
+				super();
+			}
+			@Override
+			public void selectNodeFor(Object item) {
+				//default is to do nothing
+			}
+			@Override
+			public String toString() {
+				return ObjectTools.singletonToString(this);
+			}
+			private static final long serialVersionUID = 1L;
+			private Object readResolve() {
+				// replace this object with the singleton
+				return INSTANCE;
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java
new file mode 100644
index 0000000..4b4469e
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/NonCachingComboBoxModel.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.ComboBoxModel;
+import javax.swing.event.ListDataListener;
+
+/**
+ * This implementation of the CachingComboBoxModel interface can be used
+ * whenever there is no need for caching (i.e. the contents of the selection
+ * list can be generated with little latency). All the normal ComboBoxModel
+ * behavior is delegated to a client-supplied ComboBoxModel.
+ */
+public class NonCachingComboBoxModel
+	implements CachingComboBoxModel
+{
+	private ComboBoxModel wrappedComboBoxModel;
+
+
+	public NonCachingComboBoxModel(ComboBoxModel wrappedComboBoxModel) {
+		this.wrappedComboBoxModel = wrappedComboBoxModel;
+	}
+
+
+	// ********** CachingComboBoxModel implementation **********
+
+	@Override
+	public void cacheList() {
+		//do nothing
+	}
+
+	@Override
+	public void uncacheList() {
+		//do nothing
+	}
+
+	@Override
+	public boolean isCached() {
+		return false;
+	}
+
+
+	// ********** ComboBoxModel implementation **********
+
+	@Override
+	public void setSelectedItem(Object anItem) {
+		this.wrappedComboBoxModel.setSelectedItem(anItem);
+	}
+
+	@Override
+	public Object getSelectedItem() {
+		return this.wrappedComboBoxModel.getSelectedItem();
+	}
+
+
+	// ********** ListModel implementation **********
+
+	@Override
+	public int getSize() {
+		return this.wrappedComboBoxModel.getSize();
+	}
+
+	@Override
+	public Object getElementAt(int index) {
+		return this.wrappedComboBoxModel.getElementAt(index);
+	}
+
+	@Override
+	public void addListDataListener(ListDataListener l) {
+		this.wrappedComboBoxModel.addListDataListener(l);
+	}
+
+	@Override
+	public void removeListDataListener(ListDataListener l) {
+		this.wrappedComboBoxModel.removeListDataListener(l);
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java
new file mode 100644
index 0000000..f16045f
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListBrowser.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JOptionPane;
+import javax.swing.ListModel;
+
+/**
+ * This implementation of ListChooser.Browser uses a
+ * JOptionPane to prompt the user for the selection. Subclasses
+ * can change the dialog's title, message, and/or icon.
+ */
+public class SimpleListBrowser
+	implements ListChooser.ListBrowser
+{
+	/** Default constructor */
+	protected SimpleListBrowser() {
+		super();
+	}
+
+	/**
+	 * Prompt the user using a JOptionPane.
+	 */
+	@Override
+	public void browse(ListChooser chooser) {
+		Object selection =
+			JOptionPane.showInputDialog(
+				chooser,
+				this.message(chooser),
+				this.title(chooser),
+				this.messageType(chooser),
+				this.icon(chooser),
+				this.selectionValues(chooser),
+				this.initialSelectionValue(chooser)
+			);
+
+		if (selection != null) {
+			chooser.getModel().setSelectedItem(selection);
+		}
+	}
+
+	protected Object message(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected String title(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected int messageType(@SuppressWarnings("unused") JComboBox comboBox) {
+		return JOptionPane.QUESTION_MESSAGE;
+	}
+
+	protected Icon icon(@SuppressWarnings("unused") JComboBox comboBox) {
+		return null;
+	}
+
+	protected Object[] selectionValues(JComboBox comboBox) {
+		return this.convertToArray(comboBox.getModel());
+	}
+
+	protected Object initialSelectionValue(JComboBox comboBox) {
+		return comboBox.getModel().getSelectedItem();
+	}
+
+	/**
+	 * Convert the list of objects in the specified list model
+	 * into an array.
+	 */
+	protected Object[] convertToArray(ListModel model) {
+		int size = model.getSize();
+		Object[] result = new Object[size];
+		for (int i = 0; i < size; i++) {
+			result[i] = model.getElementAt(i);
+		}
+		return result;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java
new file mode 100644
index 0000000..dfb4ca2
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SimpleListCellRenderer.java
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.Icon;
+import javax.swing.JList;
+import org.eclipse.persistence.tools.utility.StringTools;
+
+/**
+ * This renderer should behave the same as the DefaultListCellRenderer;
+ * but it slightly refactors the calculation of the icon and text of the list
+ * cell so that subclasses can easily override the methods that build
+ * the icon and text.
+ *
+ * In most cases, you need only override:
+ *     #buildIcon(Object value)
+ *     #buildText(Object value)
+ */
+public class SimpleListCellRenderer
+	extends DefaultListCellRenderer
+{
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * Construct a simple renderer.
+	 */
+	public SimpleListCellRenderer() {
+		super();
+	}
+
+	@Override
+	public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		// substitute null for the cell value so nothing is drawn initially...
+		super.getListCellRendererComponent(list, null, index, isSelected, cellHasFocus);
+		this.setOpaque(true);
+
+		// ...then set the icon and text manually
+		this.setIcon(this.buildIcon(list, value, index, isSelected, cellHasFocus));
+		this.setText(this.buildText(list, value, index, isSelected, cellHasFocus));
+
+		this.setToolTipText(this.buildToolTipText(list, value, index, isSelected, cellHasFocus));
+
+		// the context will be initialized only if a reader is running
+		if (this.accessibleContext != null) {
+			this.accessibleContext.setAccessibleName(this.buildAccessibleName(list, value, index, isSelected, cellHasFocus));
+		}
+
+		return this;
+	}
+
+	/**
+	 * Return the icon representation of the specified cell
+	 * value and other settings. (Even more settings are
+	 * accessible via inherited getters: hasFocus, isEnabled, etc.)
+	 */
+	protected Icon buildIcon(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+		return this.buildIcon(value);
+	}
+
+	/**
+	 * Return the icon representation of the specified cell
+	 * value. The default is to display no icon at all unless the
+	 * value itself is an icon.
+	 */
+	protected Icon buildIcon(Object value) {
+		// replicate the default behavior
+		return (value instanceof Icon) ? (Icon) value : null;
+	}
+
+	/**
+	 * Return the textual representation of the specified cell
+	 * value and other settings. (Even more settings are
+	 * accessible via inherited getters: hasFocus, isEnabled, etc.)
+	 */
+	protected String buildText(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+		return this.buildText(value);
+	}
+
+	/**
+	 * Return the textual representation of the specified cell
+	 * value. The default is to display the object's default string
+	 * representation (as returned by #toString()); unless the
+	 * value itself is an icon, in which case no text is displayed.
+	 */
+	protected String buildText(Object value) {
+		return (value instanceof Icon) ? StringTools.EMPTY_STRING : ((value == null) ? StringTools.EMPTY_STRING : value.toString());
+	}
+
+	/**
+	 * Return the text displayed when the cursor lingers over the specified cell.
+	 * (Even more settings are accessible via inherited getters: hasFocus, isEnabled, etc.)
+	 */
+	protected String buildToolTipText(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+		return this.buildToolTipText(value);
+	}
+
+	/**
+	 * Return the text displayed when the cursor lingers over the specified cell.
+	 */
+	protected String buildToolTipText(@SuppressWarnings("unused") Object value) {
+		return null;
+	}
+
+	/**
+	 * Return the accessible name to be given to the component used to render
+	 * the given value and other settings. (Even more settings are accessible via
+	 * inherited getters: hasFocus, isEnabled, etc.)
+	 */
+	protected String buildAccessibleName(@SuppressWarnings("unused") JList list, Object value, @SuppressWarnings("unused") int index, @SuppressWarnings("unused") boolean isSelected, @SuppressWarnings("unused") boolean cellHasFocus) {
+		return this.buildAccessibleName(value);
+	}
+
+	/**
+	 * Return the accessible name to be given to the component used to render
+	 * the given value.
+	 */
+	protected String buildAccessibleName(@SuppressWarnings("unused") Object value) {
+		return null;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java
new file mode 100644
index 0000000..a59b883
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/SpinnerTableCellRenderer.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JSpinner;
+import javax.swing.JTable;
+import javax.swing.SpinnerModel;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Make the cell look like a spinner.
+ */
+@SuppressWarnings("nls")
+public class SpinnerTableCellRenderer
+	implements TableCellEditorAdapter.Renderer
+{
+	/** the component used to paint the cell */
+	protected JSpinner spinner;
+
+	/** the listener to be notified on an immediate edit */
+	protected TableCellEditorAdapter.ImmediateEditListener immediateEditListener;
+
+
+	// ********** constructors/initialization **********
+
+	/**
+	 * Construct a cell renderer that uses the default
+	 * spinner model, which is a "number" model.
+	 */
+	public SpinnerTableCellRenderer() {
+		super();
+		this.initialize();
+	}
+
+	/**
+	 * Construct a cell renderer that uses the specified
+	 * spinner model, which will determine how the values are displayed.
+	 */
+	public SpinnerTableCellRenderer(SpinnerModel model) {
+		this();
+		this.setModel(model);
+	}
+
+	protected void initialize() {
+		this.spinner = this.buildSpinner();
+	}
+
+	protected JSpinner buildSpinner() {
+		JSpinner s = new JSpinner();
+		s.addChangeListener(this.buildChangeListener());
+		return s;
+	}
+
+	private ChangeListener buildChangeListener() {
+		return new ChangeListener() {
+			@Override
+			public void stateChanged(ChangeEvent e) {
+				if (SpinnerTableCellRenderer.this.immediateEditListener != null) {
+					SpinnerTableCellRenderer.this.immediateEditListener.immediateEdit();
+				}
+			}
+		};
+	}
+
+
+	// ********** TableCellRenderer implementation **********
+
+	@Override
+	public Component getTableCellRendererComponent(JTable table, Object value, boolean selected, boolean hasFocus, int row, int column) {
+		this.spinner.setComponentOrientation(table.getComponentOrientation());
+		this.spinner.setFont(table.getFont());
+		this.spinner.setEnabled(table.isEnabled());
+
+		JComponent editor = this.editor();
+		editor.setForeground(this.foregroundColor(table, value, selected, hasFocus, row, column));
+		editor.setBackground(this.backgroundColor(table, value, selected, hasFocus, row, column));
+		this.spinner.setBorder(this.border(table, value, selected, hasFocus, row, column));
+
+		this.setValue(value);
+		return this.spinner;
+	}
+
+	/**
+	 * Return the cell's foreground color.
+	 */
+	protected Color foregroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return UIManager.getColor("Table.focusCellForeground");
+			}
+			return table.getSelectionForeground();
+		}
+		return table.getForeground();
+	}
+
+	/**
+	 * Return the cell's background color.
+	 */
+	protected Color backgroundColor(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, int row, int column) {
+		if (selected) {
+			if (hasFocus && table.isCellEditable(row, column)) {
+				return UIManager.getColor("Table.focusCellBackground");
+			}
+			return table.getSelectionBackground();
+		}
+		return table.getBackground();
+	}
+
+	/**
+	 * Return the cell's border.
+	 */
+	protected Border border(JTable table, @SuppressWarnings("unused") Object value, boolean selected, boolean hasFocus, @SuppressWarnings("unused") int row, @SuppressWarnings("unused") int column) {
+		if (hasFocus) {
+			return UIManager.getBorder("Table.focusCellHighlightBorder");
+		}
+		if (selected) {
+			return BorderFactory.createLineBorder(table.getSelectionBackground(), 1);
+		}
+		return BorderFactory.createLineBorder(table.getBackground(), 1);
+	}
+
+	/**
+	 * Return the editor component whose colors should be set
+	 * by the renderer.
+	 */
+	protected JComponent editor() {
+		JComponent editor = this.spinner.getEditor();
+		if (editor instanceof JSpinner.DefaultEditor) {
+			// typically, the editor will be the default or one of its subclasses...
+			editor = ((JSpinner.DefaultEditor) editor).getTextField();
+		}
+		return editor;
+	}
+
+	/**
+	 * Set the spinner's value
+	 */
+	protected void setValue(Object value) {
+		// CR#3999318 - This null check needs to be removed once JDK bug is fixed
+		if (value == null) {
+			value = Integer.valueOf(0);
+		}
+		this.spinner.setValue(value);
+	}
+
+
+	// ********** TableCellEditorAdapter.Renderer implementation **********
+
+	@Override
+	public Object getValue() {
+		return this.spinner.getValue();
+	}
+
+	@Override
+	public void setImmediateEditListener(TableCellEditorAdapter.ImmediateEditListener listener) {
+		this.immediateEditListener = listener;
+	}
+
+
+	// ********** public API **********
+
+	/**
+	 * Set the spinner's model.
+	 */
+	public void setModel(SpinnerModel model) {
+		this.spinner.setModel(model);
+	}
+
+	/**
+	 * Return the renderer's preferred height. This allows you
+	 * to set the row height to something the spinner will look good in....
+	 */
+	public int preferredHeight() {
+		// add in space for the border top and bottom
+		return (int) this.spinner.getPreferredSize().getHeight() + 2;
+	}
+}
\ No newline at end of file
diff --git a/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java
new file mode 100644
index 0000000..d691ee8
--- /dev/null
+++ b/tools/org.eclipse.persistence.tools.utility/src/org/eclipse/persistence/tools/utility/swing/TableCellEditorAdapter.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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 v. 1.0
+ * which accompanies this distribution.
+ * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ *     Oracle - initial API and implementation
+ *
+ ******************************************************************************/
+package org.eclipse.persistence.tools.utility.swing;
+
+import java.awt.Component;
+import javax.swing.AbstractCellEditor;
+import javax.swing.JTable;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+
+/**
+ * A table cell editor that wraps a table cell renderer.
+ */
+public class TableCellEditorAdapter
+	extends AbstractCellEditor
+	implements TableCellEditor
+{
+	/** delegate to a renderer */
+	private Renderer renderer;
+
+	private static final long serialVersionUID = 1L;
+
+
+	// ********** constructors/initialization **********
+
+	private TableCellEditorAdapter() {
+		super();
+	}
+
+	/**
+	 * Construct a cell editor that behaves like the specified renderer.
+	 */
+	public TableCellEditorAdapter(Renderer renderer) {
+		this();
+		this.initialize(renderer);
+	}
+
+	protected void initialize(Renderer r) {
+		this.renderer = r;
+		r.setImmediateEditListener(this.buildImmediateEditListener());
+	}
+
+	private ImmediateEditListener buildImmediateEditListener() {
+		return new ImmediateEditListener() {
+			@Override
+			public void immediateEdit() {
+				TableCellEditorAdapter.this.stopCellEditing();
+			}
+		};
+	}
+
+
+	// ********** CellEditor implementation **********
+
+	@Override
+	public Object getCellEditorValue() {
+		return this.renderer.getValue();
+	}
+
+
+	// ********** TableCellEditor implementation **********
+
+	@Override
+	public Component getTableCellEditorComponent(JTable table, Object value, boolean selected, int row, int column) {
+		return this.renderer.getTableCellRendererComponent(table, value, selected, true, row, column);
+	}
+
+
+	// ********** Member classes **********************************************
+
+	/**
+	 * This interface defines the methods that must be implemented by a renderer
+	 * that can be wrapped by a TableCellEditorAdapter.
+	 */
+	public interface Renderer
+		extends TableCellRenderer
+	{
+		/**
+		 * Return the current value of the renderer.
+		 */
+		Object getValue();
+
+		/**
+		 * Set the immediate edit listener
+		 */
+		void setImmediateEditListener(ImmediateEditListener listener);
+	}
+
+
+	public interface ImmediateEditListener {
+		/**
+		 * Called when the renderer does an "immediate edit"
+		 */
+		void immediateEdit();
+	}
+}
\ No newline at end of file