summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCaspar De Groot2011-05-12 05:55:33 (EDT)
committerCaspar De Groot2011-05-12 05:55:33 (EDT)
commit0675165fb5d4641d39f6334f527b500ad48e8905 (patch)
treea35f96a68442d6b5c1b6db0e20c15a65e76029d1
parent1d51ff38dbbc07736b0486ec6471a15e8bde6f4d (diff)
downloadcdo-0675165fb5d4641d39f6334f527b500ad48e8905.zip
cdo-0675165fb5d4641d39f6334f527b500ad48e8905.tar.gz
cdo-0675165fb5d4641d39f6334f527b500ad48e8905.tar.bz2
[Bug 341081] Make loaded revisions immutable
https://bugs.eclipse.org/bugs/show_bug.cgi?id=341081
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java1
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java92
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java53
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/commit/CDOChangeSetDataRevisionProvider.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DelegatingCDORevision.java9
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDOList.java10
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java5
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/StubCDORevision.java8
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/SyntheticCDORevision.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadChunkRequest.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateStoreAccessor.java9
-rw-r--r--plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/tuplizer/WrappedHibernateList.java20
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java2
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDONotificationBuilder.java10
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java1
15 files changed, 229 insertions, 5 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
index bc01b41..6da3c33 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataInputImpl.java
@@ -370,6 +370,7 @@ public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating impl
{
InternalCDORevision revision = (InternalCDORevision)getRevisionFactory().createRevision(null);
revision.read(this);
+ revision.freeze();
return revision;
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java
index 4d0b6ae..f90865a 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDOListImpl.java
@@ -23,6 +23,8 @@ import org.eclipse.net4j.util.collection.MoveableArrayList;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EStructuralFeature;
+import java.util.Collection;
+
/**
* @author Simon McDuff
*/
@@ -38,6 +40,8 @@ public class CDOListImpl extends MoveableArrayList<Object> implements InternalCD
private static final long serialVersionUID = 1L;
+ private boolean frozen;
+
public CDOListImpl(int initialCapacity, int size)
{
super(initialCapacity);
@@ -92,4 +96,92 @@ public class CDOListImpl extends MoveableArrayList<Object> implements InternalCD
protected void handleAdjustReference(int index, Object element)
{
}
+
+ public void freeze()
+ {
+ frozen = true;
+ }
+
+ private void checkFrozen()
+ {
+ if (frozen)
+ {
+ throw new IllegalStateException("Cannot modify a frozen list");
+ }
+ }
+
+ @Override
+ public boolean add(Object o)
+ {
+ checkFrozen();
+ return super.add(o);
+ }
+
+ @Override
+ public boolean remove(Object o)
+ {
+ checkFrozen();
+ return super.remove(o);
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Object> c)
+ {
+ checkFrozen();
+ return super.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends Object> c)
+ {
+ checkFrozen();
+ return super.addAll(index, c);
+ }
+
+ @Override
+ public boolean removeAll(Collection<?> c)
+ {
+ checkFrozen();
+ return super.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(Collection<?> c)
+ {
+ checkFrozen();
+ return super.retainAll(c);
+ }
+
+ @Override
+ public void clear()
+ {
+ checkFrozen();
+ super.clear();
+ }
+
+ @Override
+ public Object set(int index, Object element)
+ {
+ checkFrozen();
+ return super.set(index, element);
+ }
+
+ @Override
+ public void add(int index, Object element)
+ {
+ checkFrozen();
+ super.add(index, element);
+ }
+
+ @Override
+ public Object remove(int index)
+ {
+ checkFrozen();
+ return super.remove(index);
+ }
+
+ public void setWithoutFrozenCheck(int index, Object element)
+ {
+ super.set(index, element);
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java
index f65c28f..433d4c5 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/revision/CDORevisionImpl.java
@@ -10,15 +10,19 @@
* Simon McDuff - bug 201266
* Simon McDuff - bug 212958
* Simon McDuff - bug 213402
+ * Caspar De Groot - bug 341081
*/
package org.eclipse.emf.cdo.internal.common.revision;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDTemp;
import org.eclipse.emf.cdo.common.model.CDOModelUtil;
import org.eclipse.emf.cdo.common.model.CDOType;
import org.eclipse.emf.cdo.spi.common.revision.BaseCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -30,6 +34,8 @@ public class CDORevisionImpl extends BaseCDORevision
{
private Object[] values;
+ private boolean frozen;
+
public CDORevisionImpl(EClass eClass)
{
super(eClass);
@@ -80,6 +86,53 @@ public class CDORevisionImpl extends BaseCDORevision
@Override
protected void setValue(int featureIndex, Object value)
{
+ checkFrozen(featureIndex, value);
values[featureIndex] = value;
}
+
+ public void freeze()
+ {
+ frozen = true;
+
+ EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(getEClass());
+ for (int i = 0; i < features.length; i++)
+ {
+ EStructuralFeature feature = features[i];
+ if (feature.isMany())
+ {
+ InternalCDOList list = (InternalCDOList)values[i];
+ if (list != null)
+ {
+ list.freeze();
+ }
+ }
+ }
+ }
+
+ private void checkFrozen(int featureIndex, Object value)
+ {
+ if (frozen)
+ {
+ Object oldValue = values[featureIndex];
+
+ // Exception 1: Setting an empty list as the value for an isMany feature, is
+ // allowed if the old value is null. This is a case of lazy initialization.
+ boolean newIsEmptyList = value instanceof EList<?> && ((EList<?>)value).size() == 0;
+ if (newIsEmptyList && oldValue == null)
+ {
+ return;
+ }
+
+ // Exception 2a: Replacing a temp ID with a regular ID is allowed (happens during
+ // postCommit of new objects)
+ // Exception 2b: Replacing a temp ID with another temp ID is also allowed (happens
+ // when changes are imported in a PushTx).
+ if (oldValue instanceof CDOIDTemp && value instanceof CDOID)
+ {
+ return;
+ }
+
+ throw new IllegalStateException("Cannot modify a frozen revision");
+ }
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/commit/CDOChangeSetDataRevisionProvider.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/commit/CDOChangeSetDataRevisionProvider.java
index 7d29342..88a46d4 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/commit/CDOChangeSetDataRevisionProvider.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/commit/CDOChangeSetDataRevisionProvider.java
@@ -152,7 +152,7 @@ public class CDOChangeSetDataRevisionProvider implements CDORevisionProvider, CD
private CDORevision applyDelta(CDORevisionDelta revisionDelta)
{
CDOID id = revisionDelta.getID();
- CDORevision changedObject = delegate.getRevision(id);
+ CDORevision changedObject = delegate.getRevision(id).copy();
revisionDelta.apply(changedObject);
cachedRevisions.put(id, changedObject);
return changedObject;
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DelegatingCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DelegatingCDORevision.java
index 4dea9f0..c601b5a 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DelegatingCDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/DelegatingCDORevision.java
@@ -7,6 +7,7 @@
*
* Contributors:
* Eike Stepper - initial API and implementation
+ * Caspar De Groot - bug 341081
*/
package org.eclipse.emf.cdo.spi.common.revision;
@@ -313,4 +314,12 @@ public abstract class DelegatingCDORevision implements InternalCDORevision
{
getDelegate().convertEObjects(oidProvider);
}
+
+ /**
+ * @since 4.0
+ */
+ public void freeze()
+ {
+ getDelegate().freeze();
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDOList.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDOList.java
index 544b2b4..5ce10e4 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDOList.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDOList.java
@@ -37,4 +37,14 @@ public interface InternalCDOList extends CDOList
* Clones the list.
*/
public InternalCDOList clone(EClassifier classifier);
+
+ /**
+ * @since 4.0
+ */
+ public void freeze();
+
+ /**
+ * @since 4.0
+ */
+ public void setWithoutFrozenCheck(int i, Object value);
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java
index 8fce5fd..fe04e95 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java
@@ -114,4 +114,9 @@ public interface InternalCDORevision extends CDORevision, CDORevisionData, CDORe
* @since 3.0
*/
public InternalCDORevision copy();
+
+ /**
+ * @since 4.0
+ */
+ public void freeze();
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/StubCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/StubCDORevision.java
index 0b68400..7c3ef76 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/StubCDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/StubCDORevision.java
@@ -255,6 +255,14 @@ public class StubCDORevision extends AbstractCDORevision
throw new UnsupportedOperationException(getExceptionMessage());
}
+ /**
+ * @since 4.0
+ */
+ public void freeze()
+ {
+ throw new UnsupportedOperationException(getExceptionMessage());
+ }
+
private String getExceptionMessage()
{
return "Unsupported operation in " + this;
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/SyntheticCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/SyntheticCDORevision.java
index a4d9d10..0ea42b8 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/SyntheticCDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/SyntheticCDORevision.java
@@ -61,4 +61,10 @@ public abstract class SyntheticCDORevision extends StubCDORevision
{
return branch;
}
+
+ @Override
+ public void freeze()
+ {
+ // Do nothing
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadChunkRequest.java b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadChunkRequest.java
index 4468e34..89a99d2 100644
--- a/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadChunkRequest.java
+++ b/plugins/org.eclipse.emf.cdo.net4j/src/org/eclipse/emf/cdo/internal/net4j/protocol/LoadChunkRequest.java
@@ -18,9 +18,9 @@ import org.eclipse.emf.cdo.common.protocol.CDODataInput;
import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
import org.eclipse.emf.cdo.internal.net4j.bundle.OM;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.net4j.util.collection.MoveableList;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EStructuralFeature;
@@ -109,11 +109,11 @@ public class LoadChunkRequest extends CDOClientRequest<Object>
{
CDOType type = CDOModelUtil.getType(feature);
Object accessID = null;
- MoveableList<Object> list = revision.getList(feature);
+ InternalCDOList list = (InternalCDOList)revision.getList(feature);
for (int i = fromIndex; i <= toIndex; i++)
{
Object value = type.readValue(in);
- list.set(i, value);
+ list.setWithoutFrozenCheck(i, value);
if (i == accessIndex)
{
accessID = value;
diff --git a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateStoreAccessor.java
index 6a8d50f..d4dee96 100644
--- a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateStoreAccessor.java
+++ b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/HibernateStoreAccessor.java
@@ -467,7 +467,14 @@ public class HibernateStoreAccessor extends StoreAccessor implements IHibernateS
public InternalCDORevision readRevisionByVersion(CDOID id, CDOBranchVersion branchVersion, int listChunk,
CDORevisionCacheAdder cache)
{
- return readRevision(id, branchVersion.getBranch().getPoint(System.currentTimeMillis()), listChunk, cache);
+ InternalCDORevision revision = readRevision(id, branchVersion.getBranch().getPoint(System.currentTimeMillis()),
+ listChunk, cache);
+ if (revision != null)
+ {
+ revision.freeze();
+ }
+
+ return revision;
}
/**
diff --git a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/tuplizer/WrappedHibernateList.java b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/tuplizer/WrappedHibernateList.java
index 389ddec..a4f0625 100644
--- a/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/tuplizer/WrappedHibernateList.java
+++ b/plugins/org.eclipse.emf.cdo.server.hibernate/src/org/eclipse/emf/cdo/server/internal/hibernate/tuplizer/WrappedHibernateList.java
@@ -43,6 +43,8 @@ public class WrappedHibernateList implements InternalCDOList
{
private List<Object> delegate;
+ private boolean frozen;
+
public WrappedHibernateList()
{
}
@@ -463,4 +465,22 @@ public class WrappedHibernateList implements InternalCDOList
delegate.set(HibernateUtil.getInstance().getCDOID(o));
}
}
+
+ public void freeze()
+ {
+ frozen = true;
+ }
+
+ private void checkFrozen()
+ {
+ if (frozen)
+ {
+ throw new IllegalStateException("Cannot modify a frozen list");
+ }
+ }
+
+ public void setWithoutFrozenCheck(int i, Object value)
+ {
+ getDelegate().set(i, value);
+ }
}
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
index ce0b8b9..e15b918 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Repository.java
@@ -465,6 +465,7 @@ public class Repository extends Container<Object> implements InternalRepository
}
else
{
+ revision.freeze();
info.setResult(revision);
}
}
@@ -484,6 +485,7 @@ public class Repository extends Container<Object> implements InternalRepository
InternalCDORevision revision = accessor.readRevision(id, branchPoint, referenceChunk, revisionManager);
if (revision != null)
{
+ revision.freeze();
return revision;
}
}
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 01d4668..aee63c9 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
@@ -32,6 +32,7 @@ import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.InternalEObject;
+import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@@ -182,6 +183,9 @@ public class CDONotificationBuilder extends CDOFeatureDeltaVisitorImpl
List<Object> list = (List<Object>)oldValue;
if (!list.isEmpty())
{
+ list = new ArrayList<Object>(list); // Copy the list so that it.set() does not change the frozen oldRevision
+ boolean changed = false;
+
for (ListIterator<Object> it = list.listIterator(); it.hasNext();)
{
Object element = it.next();
@@ -192,9 +196,15 @@ public class CDONotificationBuilder extends CDOFeatureDeltaVisitorImpl
if (oldObject != null)
{
it.set(oldObject);
+ changed = true;
}
}
}
+
+ if (changed)
+ {
+ oldValue = list;
+ }
}
}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java
index e710c1b..30719c7 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java
@@ -752,6 +752,7 @@ public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent
// Adjust revision
revision.adjustForCommit(transaction.getBranch(), data.getTimeStamp());
revision.adjustReferences(data.getReferenceAdjuster());
+ revision.freeze();
InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
revisionManager.addRevision(revision);