Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2013-04-17 12:50:15 -0400
committerEike Stepper2013-04-17 12:50:15 -0400
commit77ee757ef114df65f24f663f96fed6e323576e09 (patch)
tree40a72b3f6ae577423ed8330af8d0e54562a3dbe8
parent07543e3353f867e30cb3855549c386c32beec1e5 (diff)
downloadcdo-77ee757ef114df65f24f663f96fed6e323576e09.tar.gz
cdo-77ee757ef114df65f24f663f96fed6e323576e09.tar.xz
cdo-77ee757ef114df65f24f663f96fed6e323576e09.zip
[376620] IllegalStateException on
CDODeltaNotification.getNewBooleanValue() https://bugs.eclipse.org/bugs/show_bug.cgi?id=376620
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_376620b_Test.java274
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java51
-rw-r--r--plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java50
3 files changed, 375 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_376620b_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_376620b_Test.java
new file mode 100644
index 0000000000..a88daac1a4
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_376620b_Test.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 2004 - 2013 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Christian W. Damus (CEA) - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.CDOAdapter;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.model2.NotUnsettable;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.view.CDOAdapterPolicy;
+
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Bug 376620: Tests that we get the appropriate notifications for primitive-valued attributes in view invalidations.
+ *
+ * @author Christian W. Damus (CEA)
+ */
+public class Bugzilla_376620b_Test extends AbstractCDOTest
+{
+ public void testBoolean() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableBoolean(), true);
+ adapter.awaitAssertion();
+ }
+
+ public void testByte() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableByte(), (byte)42);
+ adapter.awaitAssertion();
+ }
+
+ public void testChar() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableChar(), 'a');
+ adapter.awaitAssertion();
+ }
+
+ public void testShort() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableShort(), (short)42);
+ adapter.awaitAssertion();
+ }
+
+ public void testInt() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableInt(), 42);
+ adapter.awaitAssertion();
+ }
+
+ public void testLong() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableLong(), 42L);
+ adapter.awaitAssertion();
+ }
+
+ public void testFloat() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableFloat(), 42.0f);
+ adapter.awaitAssertion();
+ }
+
+ public void testDouble() throws Exception
+ {
+ NotUnsettable object = createAndCommitTestObject();
+ TestAdapter adapter = poke(object, getModel2Package().getNotUnsettable_NotUnsettableDouble(), 42.0);
+ adapter.awaitAssertion();
+ }
+
+ //
+ // Test framework
+ //
+
+ protected NotUnsettable createAndCommitTestObject() throws CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.CDO);
+
+ Resource res = transaction.createResource(getResourcePath("test"));
+ NotUnsettable result = getModel2Factory().createNotUnsettable();
+ res.getContents().add(result);
+
+ transaction.commit();
+ return result;
+ }
+
+ protected TestAdapter poke(EObject object, EAttribute attribute, Object value) throws CommitException
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ transaction.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.CDO);
+
+ final Object oldValue = object.eGet(attribute);
+ final TestAdapter result = TestAdapter.assertFuture(object, attribute, oldValue, value);
+
+ EObject other = transaction.getObject(object);
+
+ other.eSet(attribute, value);
+ transaction.commit();
+ return result;
+ }
+
+ /**
+ * @author Christian W. Damus (CEA)
+ */
+ private static class TestAdapter extends AdapterImpl implements CDOAdapter
+ {
+ private final Semaphore semaphore = new Semaphore(0);
+
+ private final EAttribute attribute;
+
+ private final Object expectedOldValue;
+
+ private final Object expectedNewValue;
+
+ private volatile boolean received;
+
+ public TestAdapter(EAttribute attribute, Object expectedOldValue, Object expectedNewValue)
+ {
+ this.attribute = attribute;
+ this.expectedOldValue = expectedOldValue;
+ this.expectedNewValue = expectedNewValue;
+ }
+
+ public static TestAdapter assertFuture(EObject notifier, EAttribute attribute, Object oldValue, Object newValue)
+ {
+ TestAdapter result = new TestAdapter(attribute, oldValue, newValue);
+ notifier.eAdapters().add(result);
+ return result;
+ }
+
+ public void awaitAssertion()
+ {
+ try
+ {
+ semaphore.tryAcquire(DEFAULT_TIMEOUT, TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ fail("Interrupted while awaiting assertion.");
+ }
+
+ assertEquals(true, received);
+ }
+
+ @Override
+ public void notifyChanged(Notification msg)
+ {
+ if (msg.getFeature() == attribute)
+ {
+ try
+ {
+ Class<?> type = attribute.getEType().getInstanceClass();
+ if (type == boolean.class)
+ {
+ update(asBoolean(expectedOldValue) == msg.getOldBooleanValue() //
+ && asBoolean(expectedNewValue) == msg.getNewBooleanValue());
+ }
+ else if (type == byte.class)
+ {
+ update(asByte(expectedOldValue) == msg.getOldByteValue() //
+ && asByte(expectedNewValue) == msg.getNewByteValue());
+ }
+ else if (type == char.class)
+ {
+ update(asChar(expectedOldValue) == msg.getOldCharValue() //
+ && asChar(expectedNewValue) == msg.getNewCharValue());
+ }
+ else if (type == short.class)
+ {
+ update(asShort(expectedOldValue) == msg.getOldShortValue() //
+ && asShort(expectedNewValue) == msg.getNewShortValue());
+ }
+ else if (type == int.class)
+ {
+ update(asInt(expectedOldValue) == msg.getOldIntValue() //
+ && asInt(expectedNewValue) == msg.getNewIntValue());
+ }
+ else if (type == long.class)
+ {
+ update(asLong(expectedOldValue) == msg.getOldLongValue() //
+ && asLong(expectedNewValue) == msg.getNewLongValue());
+ }
+ else if (type == float.class)
+ {
+ update(asFloat(expectedOldValue) == msg.getOldFloatValue() //
+ && asFloat(expectedNewValue) == msg.getNewFloatValue());
+ }
+ else if (type == double.class)
+ {
+ update(asDouble(expectedOldValue) == msg.getOldDoubleValue() //
+ && asDouble(expectedNewValue) == msg.getNewDoubleValue());
+ }
+ }
+ finally
+ {
+ semaphore.release();
+ }
+ }
+ }
+
+ private void update(boolean received)
+ {
+ if (received)
+ {
+ this.received = received;
+ }
+ }
+
+ private boolean asBoolean(Object value)
+ {
+ return ((Boolean)value).booleanValue();
+ }
+
+ private byte asByte(Object value)
+ {
+ return ((Number)value).byteValue();
+ }
+
+ private char asChar(Object value)
+ {
+ return ((Character)value).charValue();
+ }
+
+ private short asShort(Object value)
+ {
+ return ((Number)value).shortValue();
+ }
+
+ private int asInt(Object value)
+ {
+ return ((Number)value).intValue();
+ }
+
+ private long asLong(Object value)
+ {
+ return ((Number)value).longValue();
+ }
+
+ private float asFloat(Object value)
+ {
+ return ((Number)value).floatValue();
+ }
+
+ private double asDouble(Object value)
+ {
+ return ((Number)value).doubleValue();
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java
index 5c1cbcdf10..66317533e1 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java
@@ -8,6 +8,7 @@
* Contributors:
* Simon McDuff - initial API and implementation
* Eike Stepper - maintenance
+ * Christian W. Damus (CEA) - bug 376620: notifications for primitive-valued attributes
*/
package org.eclipse.emf.internal.cdo.object;
@@ -26,6 +27,8 @@ import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.view.CDOView;
+import org.eclipse.net4j.util.ReflectUtil;
+
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.notify.impl.NotificationChainImpl;
@@ -304,11 +307,59 @@ public class CDONotificationBuilder extends CDOFeatureDeltaVisitorImpl
newValue = defaultValue;
}
+
+ // There cannot be a position if it's a primitive value because primitives cannot be in lists
+ return createPrimitiveNotification(eventType, feature, instanceClass, oldValue, newValue);
}
return new CDODeltaNotificationImpl(object, eventType, feature, oldValue, newValue, position);
}
+ private CDODeltaNotificationImpl createPrimitiveNotification(int eventType, EStructuralFeature feature,
+ Class<?> instanceClass, Object oldValue, Object newValue)
+ {
+ switch (ReflectUtil.PrimitiveType.forClass(instanceClass))
+ {
+ case BOOLEAN:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Boolean)oldValue).booleanValue(),
+ ((Boolean)newValue).booleanValue());
+
+ case BYTE:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).byteValue(),
+ ((Number)newValue).byteValue());
+
+ case CHAR:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Character)oldValue).charValue(),
+ ((Character)newValue).charValue());
+
+ case SHORT:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).shortValue(),
+ ((Number)newValue).shortValue());
+
+ case INT:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).intValue(),
+ ((Number)newValue).intValue());
+
+ case LONG:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).longValue(),
+ ((Number)newValue).longValue());
+
+ case FLOAT:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).floatValue(),
+ ((Number)newValue).floatValue());
+
+ case DOUBLE:
+ return new CDODeltaNotificationImpl(object, eventType, feature, ((Number)oldValue).doubleValue(),
+ ((Number)newValue).doubleValue());
+
+ case VOID:
+ throw new IllegalArgumentException("Feature of void type not supported: " + feature); //$NON-NLS-1$
+
+ default:
+ throw new IllegalArgumentException("Not a primitive type: " + instanceClass); //$NON-NLS-1$
+ }
+ }
+
private void add(CDODeltaNotificationImpl newNotificaton)
{
newNotificaton.setRevisionDelta(revisionDelta);
diff --git a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
index c9aef9ef81..c113d81ad2 100644
--- a/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
+++ b/plugins/org.eclipse.net4j.util/src/org/eclipse/net4j/util/ReflectUtil.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
+ * Christian W. Damus (CEA) - bug 376620: switch on primitive types
*/
package org.eclipse.net4j.util;
@@ -625,4 +626,53 @@ public final class ReflectUtil
public @interface ExcludeFromDump
{
}
+
+ /**
+ * @author Christian W. Damus (CEA)
+ * @since 3.3
+ */
+ public static enum PrimitiveType
+ {
+ BOOLEAN(boolean.class), //
+ BYTE(byte.class), //
+ CHAR(char.class), //
+ SHORT(short.class), //
+ INT(int.class), //
+ LONG(long.class), //
+ FLOAT(float.class), //
+ DOUBLE(double.class), //
+ VOID(void.class), //
+ NONE(null);
+
+ private static final Map<Class<?>, PrimitiveType> INSTANCES = new HashMap<Class<?>, PrimitiveType>();
+
+ private final Class<?> type;
+
+ static
+ {
+ for (PrimitiveType primitiveType : values())
+ {
+ if (primitiveType.type != null)
+ {
+ INSTANCES.put(primitiveType.type, primitiveType);
+ }
+ }
+ }
+
+ private PrimitiveType(Class<?> type)
+ {
+ this.type = type;
+ }
+
+ public Class<?> type()
+ {
+ return type;
+ }
+
+ public static PrimitiveType forClass(Class<?> clazz)
+ {
+ PrimitiveType result = INSTANCES.get(clazz);
+ return result == null ? NONE : result;
+ }
+ }
}

Back to the top