FIXED - bug 303847: [Databinding] MapSimpleValueObservableMap#get(Object) is not scaling very well
https://bugs.eclipse.org/bugs/show_bug.cgi?id=303847
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityMap.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityMap.java
index 4fdf296..48f055a 100644
--- a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityMap.java
+++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityMap.java
@@ -9,7 +9,7 @@
  *     Matthew Hall - initial API and implementation (bug 215531)
  *     Matthew Hall - bug 228125
  *         (through ViewerElementMap.java)
- *     Matthew Hall - bug 262269
+ *     Matthew Hall - bugs 262269, 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding.identity;
@@ -63,7 +63,7 @@
 	}
 
 	public boolean containsKey(Object key) {
-		return wrappedMap.containsKey(new IdentityWrapper(key));
+		return wrappedMap.containsKey(IdentityWrapper.wrap(key));
 	}
 
 	public boolean containsValue(Object value) {
@@ -152,8 +152,8 @@
 
 			public boolean remove(Object o) {
 				final Map.Entry unwrappedEntry = (Map.Entry) o;
-				final IdentityWrapper wrappedKey = new IdentityWrapper(
-						unwrappedEntry.getKey());
+				final IdentityWrapper wrappedKey = IdentityWrapper
+						.wrap(unwrappedEntry.getKey());
 				Map.Entry wrappedEntry = new Map.Entry() {
 					public Object getKey() {
 						return wrappedKey;
@@ -247,7 +247,7 @@
 	}
 
 	public Object get(Object key) {
-		return wrappedMap.get(new IdentityWrapper(key));
+		return wrappedMap.get(IdentityWrapper.wrap(key));
 	}
 
 	public boolean isEmpty() {
@@ -270,12 +270,12 @@
 			}
 
 			public boolean contains(Object o) {
-				return wrappedKeySet.contains(new IdentityWrapper(o));
+				return wrappedKeySet.contains(IdentityWrapper.wrap(o));
 			}
 
 			public boolean containsAll(Collection c) {
 				for (Iterator iterator = c.iterator(); iterator.hasNext();)
-					if (!wrappedKeySet.contains(new IdentityWrapper(iterator
+					if (!wrappedKeySet.contains(IdentityWrapper.wrap(iterator
 							.next())))
 						return false;
 				return true;
@@ -304,14 +304,14 @@
 			}
 
 			public boolean remove(Object o) {
-				return wrappedKeySet.remove(new IdentityWrapper(o));
+				return wrappedKeySet.remove(IdentityWrapper.wrap(o));
 			}
 
 			public boolean removeAll(Collection c) {
 				boolean changed = false;
 				for (Iterator iterator = c.iterator(); iterator.hasNext();)
-					changed |= wrappedKeySet.remove(new IdentityWrapper(
-							iterator.next()));
+					changed |= wrappedKeySet.remove(IdentityWrapper
+							.wrap(iterator.next()));
 				return changed;
 			}
 
@@ -368,20 +368,20 @@
 	}
 
 	public Object put(Object key, Object value) {
-		return wrappedMap.put(new IdentityWrapper(key), value);
+		return wrappedMap.put(IdentityWrapper.wrap(key), value);
 	}
 
 	public void putAll(Map other) {
 		for (Iterator iterator = other.entrySet().iterator(); iterator
 				.hasNext();) {
 			Map.Entry entry = (Map.Entry) iterator.next();
-			wrappedMap.put(new IdentityWrapper(entry.getKey()), entry
+			wrappedMap.put(IdentityWrapper.wrap(entry.getKey()), entry
 					.getValue());
 		}
 	}
 
 	public Object remove(Object key) {
-		return wrappedMap.remove(new IdentityWrapper(key));
+		return wrappedMap.remove(IdentityWrapper.wrap(key));
 	}
 
 	public int size() {
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentitySet.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentitySet.java
index f914438..04e61a1 100644
--- a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentitySet.java
+++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentitySet.java
@@ -9,7 +9,7 @@
  *     Matthew Hall - initial API and implementation (bug 215531)
  *     Matthew Hall - bug 124684
  *         (through ViewerElementSet.java)
- *     Matthew Hall - bug 262269
+ *     Matthew Hall - bugs 262269, 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding.identity;
@@ -54,13 +54,13 @@
 	}
 
 	public boolean add(Object o) {
-		return wrappedSet.add(new IdentityWrapper(o));
+		return wrappedSet.add(IdentityWrapper.wrap(o));
 	}
 
 	public boolean addAll(Collection c) {
 		boolean changed = false;
 		for (Iterator iterator = c.iterator(); iterator.hasNext();)
-			changed |= wrappedSet.add(new IdentityWrapper(iterator.next()));
+			changed |= wrappedSet.add(IdentityWrapper.wrap(iterator.next()));
 		return changed;
 	}
 
@@ -69,12 +69,12 @@
 	}
 
 	public boolean contains(Object o) {
-		return wrappedSet.contains(new IdentityWrapper(o));
+		return wrappedSet.contains(IdentityWrapper.wrap(o));
 	}
 
 	public boolean containsAll(Collection c) {
 		for (Iterator iterator = c.iterator(); iterator.hasNext();)
-			if (!wrappedSet.contains(new IdentityWrapper(iterator.next())))
+			if (!wrappedSet.contains(IdentityWrapper.wrap(iterator.next())))
 				return false;
 		return true;
 	}
@@ -101,7 +101,7 @@
 	}
 
 	public boolean remove(Object o) {
-		return wrappedSet.remove(new IdentityWrapper(o));
+		return wrappedSet.remove(IdentityWrapper.wrap(o));
 	}
 
 	public boolean removeAll(Collection c) {
diff --git a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityWrapper.java b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityWrapper.java
index c3cb5f9..508ccec 100644
--- a/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityWrapper.java
+++ b/bundles/org.eclipse.core.databinding.observable/src/org/eclipse/core/internal/databinding/identity/IdentityWrapper.java
@@ -8,6 +8,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Daniel Kruegler - bug 137435
+ *     Matthew Hall - bug 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding.identity;
@@ -21,15 +22,27 @@
  * 
  */
 public class IdentityWrapper {
+	private static final IdentityWrapper NULL_WRAPPER = new IdentityWrapper(
+			null);
+
+	/**
+	 * @param o
+	 *            the object to wrap
+	 * @return an IdentityWrapper wrapping the specified object
+	 */
+	public static IdentityWrapper wrap(Object o) {
+		return o == null ? NULL_WRAPPER : new IdentityWrapper(o);
+	}
+
 	final Object o;
 
 	/**
 	 * @param o
 	 */
-	public IdentityWrapper(Object o) {
+	private IdentityWrapper(Object o) {
 		this.o = o;
 	}
-	
+
 	/**
 	 * @return the unwrapped object
 	 */
diff --git a/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/map/SimplePropertyObservableMap.java b/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/map/SimplePropertyObservableMap.java
index 290702d..43fb647 100644
--- a/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/map/SimplePropertyObservableMap.java
+++ b/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/map/SimplePropertyObservableMap.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  *     Matthew Hall - initial API and implementation (bug 194734)
- *     Matthew Hall - bugs 265561, 262287, 268203, 268688, 301774
+ *     Matthew Hall - bugs 265561, 262287, 268203, 268688, 301774, 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding.property.map;
@@ -209,6 +209,18 @@
 		return super.keySet();
 	}
 
+	public boolean containsKey(Object key) {
+		getterCalled();
+
+		return getMap().containsKey(key);
+	}
+
+	public Object get(Object key) {
+		getterCalled();
+
+		return getMap().get(key);
+	}
+
 	public Object put(Object key, Object value) {
 		checkRealm();
 
diff --git a/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java b/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java
index 4708e01..a9a9394 100644
--- a/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java
+++ b/bundles/org.eclipse.core.databinding.property/src/org/eclipse/core/internal/databinding/property/value/MapSimpleValueObservableMap.java
@@ -7,7 +7,7 @@
  *
  * Contributors:
  *     Matthew Hall - initial API and implementation (bug 194734)
- *     Matthew Hall - bugs 262269, 265561, 262287, 268688, 278550
+ *     Matthew Hall - bugs 262269, 265561, 262287, 268688, 278550, 303847
  *     Ovidio Mallo - bugs 299619, 301370
  ******************************************************************************/
 
@@ -310,6 +310,18 @@
 		}
 	}
 
+	public boolean containsKey(Object key) {
+		getterCalled();
+
+		return masterMap.containsKey(key);
+	}
+
+	public Object get(Object key) {
+		getterCalled();
+
+		return detailProperty.getValue(masterMap.get(key));
+	}
+
 	public Object put(Object key, Object value) {
 		if (!masterMap.containsKey(key))
 			return null;
@@ -320,6 +332,17 @@
 		return oldValue;
 	}
 
+	public Object remove(Object key) {
+		checkRealm();
+
+		Object masterValue = masterMap.get(key);
+		Object oldValue = detailProperty.getValue(masterValue);
+
+		masterMap.remove(key);
+
+		return oldValue;
+	}
+
 	private void notifyIfChanged(Object masterValue) {
 		if (cachedValues != null) {
 			final Set keys = keysFor(masterValue);
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java
index 8f464bf..b8a1510 100644
--- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityMap.java
@@ -9,7 +9,7 @@
  *     Matthew Hall - initial API and implementation (bug 215531)
  *     Matthew Hall - bug 228125
  *         (through ViewerElementMap.java)
- *     Matthew Hall - bug 262269
+ *     Matthew Hall - bugs 262269, 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding;
@@ -62,7 +62,7 @@
 	}
 
 	public boolean containsKey(Object key) {
-		return wrappedMap.containsKey(new IdentityWrapper(key));
+		return wrappedMap.containsKey(IdentityWrapper.wrap(key));
 	}
 
 	public boolean containsValue(Object value) {
@@ -151,8 +151,8 @@
 
 			public boolean remove(Object o) {
 				final Map.Entry unwrappedEntry = (Map.Entry) o;
-				final IdentityWrapper wrappedKey = new IdentityWrapper(
-						unwrappedEntry.getKey());
+				final IdentityWrapper wrappedKey = IdentityWrapper
+						.wrap(unwrappedEntry.getKey());
 				Map.Entry wrappedEntry = new Map.Entry() {
 					public Object getKey() {
 						return wrappedKey;
@@ -246,7 +246,7 @@
 	}
 
 	public Object get(Object key) {
-		return wrappedMap.get(new IdentityWrapper(key));
+		return wrappedMap.get(IdentityWrapper.wrap(key));
 	}
 
 	public boolean isEmpty() {
@@ -269,12 +269,12 @@
 			}
 
 			public boolean contains(Object o) {
-				return wrappedKeySet.contains(new IdentityWrapper(o));
+				return wrappedKeySet.contains(IdentityWrapper.wrap(o));
 			}
 
 			public boolean containsAll(Collection c) {
 				for (Iterator iterator = c.iterator(); iterator.hasNext();)
-					if (!wrappedKeySet.contains(new IdentityWrapper(iterator
+					if (!wrappedKeySet.contains(IdentityWrapper.wrap(iterator
 							.next())))
 						return false;
 				return true;
@@ -303,14 +303,14 @@
 			}
 
 			public boolean remove(Object o) {
-				return wrappedKeySet.remove(new IdentityWrapper(o));
+				return wrappedKeySet.remove(IdentityWrapper.wrap(o));
 			}
 
 			public boolean removeAll(Collection c) {
 				boolean changed = false;
 				for (Iterator iterator = c.iterator(); iterator.hasNext();)
-					changed |= wrappedKeySet.remove(new IdentityWrapper(
-							iterator.next()));
+					changed |= wrappedKeySet.remove(IdentityWrapper
+							.wrap(iterator.next()));
 				return changed;
 			}
 
@@ -367,20 +367,20 @@
 	}
 
 	public Object put(Object key, Object value) {
-		return wrappedMap.put(new IdentityWrapper(key), value);
+		return wrappedMap.put(IdentityWrapper.wrap(key), value);
 	}
 
 	public void putAll(Map other) {
 		for (Iterator iterator = other.entrySet().iterator(); iterator
 				.hasNext();) {
 			Map.Entry entry = (Map.Entry) iterator.next();
-			wrappedMap.put(new IdentityWrapper(entry.getKey()), entry
+			wrappedMap.put(IdentityWrapper.wrap(entry.getKey()), entry
 					.getValue());
 		}
 	}
 
 	public Object remove(Object key) {
-		return wrappedMap.remove(new IdentityWrapper(key));
+		return wrappedMap.remove(IdentityWrapper.wrap(key));
 	}
 
 	public int size() {
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java
index 4aa7713..4fc3704 100644
--- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentitySet.java
@@ -9,7 +9,7 @@
  *     Matthew Hall - initial API and implementation (bug 215531)
  *     Matthew Hall - bug 124684
  *         (through ViewerElementSet.java)
- *     Matthew Hall - bug 262269
+ *     Matthew Hall - bugs 262269, 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding;
@@ -54,13 +54,13 @@
 	}
 
 	public boolean add(Object o) {
-		return wrappedSet.add(new IdentityWrapper(o));
+		return wrappedSet.add(IdentityWrapper.wrap(o));
 	}
 
 	public boolean addAll(Collection c) {
 		boolean changed = false;
 		for (Iterator iterator = c.iterator(); iterator.hasNext();)
-			changed |= wrappedSet.add(new IdentityWrapper(iterator.next()));
+			changed |= wrappedSet.add(IdentityWrapper.wrap(iterator.next()));
 		return changed;
 	}
 
@@ -69,12 +69,12 @@
 	}
 
 	public boolean contains(Object o) {
-		return wrappedSet.contains(new IdentityWrapper(o));
+		return wrappedSet.contains(IdentityWrapper.wrap(o));
 	}
 
 	public boolean containsAll(Collection c) {
 		for (Iterator iterator = c.iterator(); iterator.hasNext();)
-			if (!wrappedSet.contains(new IdentityWrapper(iterator.next())))
+			if (!wrappedSet.contains(IdentityWrapper.wrap(iterator.next())))
 				return false;
 		return true;
 	}
@@ -101,7 +101,7 @@
 	}
 
 	public boolean remove(Object o) {
-		return wrappedSet.remove(new IdentityWrapper(o));
+		return wrappedSet.remove(IdentityWrapper.wrap(o));
 	}
 
 	public boolean removeAll(Collection c) {
diff --git a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityWrapper.java b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityWrapper.java
index 978c996..7122a91 100644
--- a/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityWrapper.java
+++ b/bundles/org.eclipse.core.databinding/src/org/eclipse/core/internal/databinding/IdentityWrapper.java
@@ -8,6 +8,7 @@
  * Contributors:
  *     IBM Corporation - initial API and implementation
  *     Daniel Kruegler - bug 137435
+ *     Matthew Hall - bug 303847
  ******************************************************************************/
 
 package org.eclipse.core.internal.databinding;
@@ -21,15 +22,28 @@
  * 
  */
 public class IdentityWrapper {
+
+	private static final IdentityWrapper NULL_WRAPPER = new IdentityWrapper(
+			null);
+
+	/**
+	 * @param obj
+	 *            the object to wrap
+	 * @return an IdentityWrapper wrapping the specified object
+	 */
+	public static IdentityWrapper wrap(Object obj) {
+		return obj == null ? NULL_WRAPPER : new IdentityWrapper(obj);
+	}
+
 	final Object o;
 
 	/**
 	 * @param o
 	 */
-	public IdentityWrapper(Object o) {
+	private IdentityWrapper(Object o) {
 		this.o = o;
 	}
-	
+
 	/**
 	 * @return the unwrapped object
 	 */