Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2012-05-01 08:44:31 +0000
committerEike Stepper2012-05-01 08:44:31 +0000
commit08ee9b77f614a70a477d1fc239937293aff17419 (patch)
tree8155e1a04f95169d3aa969d0a2e3f0cc3deac876
parent6f78819bb60c19b8ecd34d7607c9c3c79db7aa2b (diff)
downloadcdo-08ee9b77f614a70a477d1fc239937293aff17419.tar.gz
cdo-08ee9b77f614a70a477d1fc239937293aff17419.tar.xz
cdo-08ee9b77f614a70a477d1fc239937293aff17419.zip
[343084] Add security infos to BaseCDORevision and adjust the framework accordingly
https://bugs.eclipse.org/bugs/show_bug.cgi?id=343084
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevision.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java17
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoReadPermissionException.java41
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoWritePermissionException.java41
-rw-r--r--plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/BaseCDORevision.java62
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java6
-rw-r--r--plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java4
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java236
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java15
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStateMachine.java2087
12 files changed, 1360 insertions, 1163 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevision.java
index 084af345df..d3884bc678 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/revision/CDORevision.java
@@ -62,11 +62,11 @@ public interface CDORevision extends CDORevisionKey, CDORevisable
*/
public static final CDOPermissionProvider PERMISSION_PROVIDER = new CDOPermissionProvider()
{
- public CDOPermission getPermission(Object object)
+ public CDOPermission getPermission(Object protectableObject)
{
- if (object instanceof CDORevision)
+ if (protectableObject instanceof CDORevision)
{
- CDORevision revision = (CDORevision)object;
+ CDORevision revision = (CDORevision)protectableObject;
return revision.getPermission();
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java
index 44133db22a..e101a9f2cc 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java
@@ -11,7 +11,7 @@
package org.eclipse.emf.cdo.common.security;
/**
- * Describes the possible protection levels a protectable entity may have.
+ * Describes the possible protection levels a protectable object may have.
* @author Eike Stepper
* @since 4.1
*/
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java
index dc5781ba8a..7bdfef532b 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java
@@ -11,7 +11,7 @@
package org.eclipse.emf.cdo.common.security;
/**
- * Provides the protection level of protectable entities.
+ * Provides the protection level of protectable objects.
*
* @author Eike Stepper
* @since 4.1
@@ -24,7 +24,7 @@ public interface CDOPermissionProvider
public static final CDOPermissionProvider WRITE = new Constant(CDOPermission.WRITE);
- public CDOPermission getPermission(Object object);
+ public CDOPermission getPermission(Object protectableObject);
/**
* Provides a constant protection level for all protectable entities.
@@ -40,7 +40,7 @@ public interface CDOPermissionProvider
this.permission = permission;
}
- public CDOPermission getPermission(Object object)
+ public CDOPermission getPermission(Object protectableObject)
{
return permission;
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java
index 3674854bfb..8639adf069 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java
@@ -20,22 +20,21 @@ public class NoPermissionException extends SecurityException
{
private static final long serialVersionUID = 1L;
- public NoPermissionException()
- {
- }
+ private Object protectableObject;
- public NoPermissionException(String message)
+ public NoPermissionException(Object protectableObject)
{
- super(message);
+ this(protectableObject, "No permission to access " + protectableObject);
}
- public NoPermissionException(Throwable cause)
+ public NoPermissionException(Object protectableObject, String message)
{
- super(cause);
+ super(message);
+ this.protectableObject = protectableObject;
}
- public NoPermissionException(String message, Throwable cause)
+ public Object getProtectableObject()
{
- super(message, cause);
+ return protectableObject;
}
}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoReadPermissionException.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoReadPermissionException.java
deleted file mode 100644
index 784ece3ec2..0000000000
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoReadPermissionException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2004 - 2012 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:
- * Eike Stepper - initial API and implementation
- */
-package org.eclipse.emf.cdo.common.security;
-
-/**
- * An unchecked exception indicating the lack of permission required to read something.
- *
- * @author Eike Stepper
- * @since 4.1
- */
-public class NoReadPermissionException extends NoPermissionException
-{
- private static final long serialVersionUID = 1L;
-
- public NoReadPermissionException()
- {
- }
-
- public NoReadPermissionException(String message)
- {
- super(message);
- }
-
- public NoReadPermissionException(Throwable cause)
- {
- super(cause);
- }
-
- public NoReadPermissionException(String message, Throwable cause)
- {
- super(message, cause);
- }
-}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoWritePermissionException.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoWritePermissionException.java
deleted file mode 100644
index 5774433932..0000000000
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoWritePermissionException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2004 - 2012 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:
- * Eike Stepper - initial API and implementation
- */
-package org.eclipse.emf.cdo.common.security;
-
-/**
- * An unchecked exception indicating the lack of permission required to write something.
- *
- * @author Eike Stepper
- * @since 4.1
- */
-public class NoWritePermissionException extends NoPermissionException
-{
- private static final long serialVersionUID = 1L;
-
- public NoWritePermissionException()
- {
- }
-
- public NoWritePermissionException(String message)
- {
- super(message);
- }
-
- public NoWritePermissionException(Throwable cause)
- {
- super(cause);
- }
-
- public NoWritePermissionException(String message, Throwable cause)
- {
- super(message, cause);
- }
-}
diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/BaseCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/BaseCDORevision.java
index 17d2451a7e..7bf07f72fc 100644
--- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/BaseCDORevision.java
+++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/BaseCDORevision.java
@@ -34,8 +34,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.common.security.CDOPermission;
import org.eclipse.emf.cdo.common.security.CDOPermissionProvider;
-import org.eclipse.emf.cdo.common.security.NoReadPermissionException;
-import org.eclipse.emf.cdo.common.security.NoWritePermissionException;
+import org.eclipse.emf.cdo.common.security.NoPermissionException;
import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
import org.eclipse.emf.cdo.internal.common.bundle.OM;
import org.eclipse.emf.cdo.internal.common.messages.Messages;
@@ -146,13 +145,14 @@ public abstract class BaseCDORevision extends AbstractCDORevision
readSystemValues(in);
- flags = (byte)(in.readByte() & PERMISSION_MASK);
-
- if (isReadable())
+ byte permissionBits = (byte)(in.readByte() & PERMISSION_MASK);
+ if (permissionBits != CDOPermission.NONE.ordinal())
{
readValues(in);
}
+ flags = permissionBits;
+
if (READING.isEnabled())
{
READING.stop(this);
@@ -686,16 +686,19 @@ public abstract class BaseCDORevision extends AbstractCDORevision
{
flags |= FROZEN_FLAG;
- EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(getEClass());
- for (int i = 0; i < features.length; i++)
+ if (isReadable())
{
- EStructuralFeature feature = features[i];
- if (feature.isMany())
+ EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(getEClass());
+ for (int i = 0; i < features.length; i++)
{
- InternalCDOList list = (InternalCDOList)getValue(i);
- if (list != null)
+ EStructuralFeature feature = features[i];
+ if (feature.isMany())
{
- list.freeze();
+ InternalCDOList list = (InternalCDOList)doGetValue(i);
+ if (list != null)
+ {
+ list.freeze();
+ }
}
}
}
@@ -703,26 +706,15 @@ public abstract class BaseCDORevision extends AbstractCDORevision
protected Object getValue(int featureIndex)
{
- if (isReadable())
- {
- return doGetValue(featureIndex);
- }
-
- throw new NoReadPermissionException("No permission to read from " + this);
+ checkReadable();
+ return doGetValue(featureIndex);
}
protected void setValue(int featureIndex, Object value)
{
checkFrozen(featureIndex, value);
-
- if (isWritable())
- {
- doSetValue(featureIndex, value);
- }
- else
- {
- throw new NoWritePermissionException("No permission to write to " + this);
- }
+ checkWritable();
+ doSetValue(featureIndex, value);
}
protected abstract void initValues(EStructuralFeature[] allPersistentFeatures);
@@ -769,6 +761,22 @@ public abstract class BaseCDORevision extends AbstractCDORevision
}
}
+ private void checkReadable()
+ {
+ if (!isReadable())
+ {
+ throw new NoPermissionException(this);
+ }
+ }
+
+ private void checkWritable()
+ {
+ if (!isWritable())
+ {
+ throw new NoPermissionException(this);
+ }
+ }
+
private void writeValues(CDODataOutput out, int referenceChunk) throws IOException
{
EClass owner = getEClass();
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
index 0ccb241c6c..707cc9639e 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/Session.java
@@ -354,15 +354,15 @@ public class Session extends Container<IView> implements InternalSession
return (CDOID)idObject;
}
- public CDOPermission getPermission(Object object)
+ public CDOPermission getPermission(Object protectableObject)
{
IPermissionManager permissionManager = manager.getPermissionManager();
if (permissionManager != null)
{
- return permissionManager.getPermission(object, userID);
+ return permissionManager.getPermission(protectableObject, userID);
}
- return CDORevision.PERMISSION_PROVIDER.getPermission(object);
+ return CDORevision.PERMISSION_PROVIDER.getPermission(protectableObject);
}
public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java
index 68bdfd3f6e..69f9d01f8d 100644
--- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java
+++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java
@@ -13,12 +13,12 @@ package org.eclipse.emf.cdo.server;
import org.eclipse.emf.cdo.common.security.CDOPermission;
/**
- * Provides the protection level of protectable entities in the context of a specific user.
+ * Provides the protection level of protectable objects in the context of a specific user.
*
* @author Eike Stepper
* @since 4.1
*/
public interface IPermissionManager
{
- public CDOPermission getPermission(Object object, String userID);
+ public CDOPermission getPermission(Object protectableObject, String userID);
}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java
new file mode 100644
index 0000000000..f939173a05
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2004 - 2012 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:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.tests.bugzilla;
+
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.security.CDOPermission;
+import org.eclipse.emf.cdo.common.security.NoPermissionException;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.server.IPermissionManager;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.tests.config.impl.RepositoryConfig;
+import org.eclipse.emf.cdo.tests.config.impl.SessionConfig;
+import org.eclipse.emf.cdo.tests.model1.Category;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+
+import org.eclipse.net4j.util.security.PasswordCredentials;
+import org.eclipse.net4j.util.security.PasswordCredentialsProvider;
+import org.eclipse.net4j.util.security.UserManager;
+
+import org.eclipse.emf.ecore.EClass;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Eike Stepper
+ */
+public class Bugzilla_343084_Test extends AbstractCDOTest
+{
+ private static final String REPO_NAME = "protectedrepo";
+
+ private static final String USER_ID = "stepper";
+
+ private static final char[] PASSWORD = "eike2010".toCharArray();
+
+ private Map<EClass, CDOPermission> permissions = new HashMap<EClass, CDOPermission>();
+
+ @Override
+ protected void doSetUp() throws Exception
+ {
+ super.doSetUp();
+
+ UserManager userManager = new UserManager();
+ userManager.activate();
+ userManager.addUser(USER_ID, PASSWORD);
+
+ IPermissionManager permissionManager = new IPermissionManager()
+ {
+ public CDOPermission getPermission(Object protectableObject, String userID)
+ {
+ if (protectableObject instanceof CDORevision)
+ {
+ EClass eClass = ((CDORevision)protectableObject).getEClass();
+ CDOPermission permission = permissions.get(eClass);
+ if (permission != null)
+ {
+ return permission;
+ }
+ }
+
+ return CDOPermission.WRITE;
+ }
+ };
+
+ getTestProperties().put(RepositoryConfig.PROP_TEST_USER_MANAGER, userManager);
+ getTestProperties().put(RepositoryConfig.PROP_TEST_PERMISSION_MANAGER, permissionManager);
+ getTestProperties().put(SessionConfig.PROP_TEST_CREDENTIALS_PROVIDER,
+ new PasswordCredentialsProvider(new PasswordCredentials(USER_ID, PASSWORD)));
+
+ getRepository(REPO_NAME);
+ }
+
+ public void testPermissionManagerWRITE() throws Exception
+ {
+ {
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("res"));
+
+ Category category = getModel1Factory().createCategory();
+ category.getCategories().add(getModel1Factory().createCategory());
+
+ resource.getContents().add(category);
+ transaction.commit();
+ session.close();
+ }
+
+ permissions.put(getModel1Package().getCategory(), CDOPermission.WRITE);
+
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("res"));
+
+ Category category = (Category)resource.getContents().get(0);
+ CDORevision revision = CDOUtil.getCDOObject(category).cdoRevision();
+ assertEquals(CDOPermission.WRITE, revision.getPermission());
+ assertEquals(true, revision.isReadable());
+ assertEquals(true, revision.isWritable());
+
+ category.getName();
+ category.setName("HW");
+
+ category.getCategories().get(0);
+ category.getCategories().add(getModel1Factory().createCategory());
+ }
+
+ public void testPermissionManagerREAD() throws Exception
+ {
+ {
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("res"));
+
+ Category category = getModel1Factory().createCategory();
+ category.getCategories().add(getModel1Factory().createCategory());
+
+ resource.getContents().add(category);
+ transaction.commit();
+ session.close();
+ }
+
+ permissions.put(getModel1Package().getCategory(), CDOPermission.READ);
+
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("res"));
+
+ Category category = (Category)resource.getContents().get(0);
+ CDORevision revision = CDOUtil.getCDOObject(category).cdoRevision();
+ assertEquals(CDOPermission.READ, revision.getPermission());
+ assertEquals(true, revision.isReadable());
+ assertEquals(false, revision.isWritable());
+
+ category.getName();
+
+ try
+ {
+ category.setName("HW");
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+
+ category.getCategories().get(0);
+
+ try
+ {
+ category.getCategories().add(getModel1Factory().createCategory());
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+ }
+
+ public void testPermissionManagerNONE() throws Exception
+ {
+ {
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.createResource(getResourcePath("res"));
+
+ Category category = getModel1Factory().createCategory();
+ category.getCategories().add(getModel1Factory().createCategory());
+
+ resource.getContents().add(category);
+ transaction.commit();
+ session.close();
+ }
+
+ permissions.put(getModel1Package().getCategory(), CDOPermission.NONE);
+
+ CDOSession session = openSession(REPO_NAME);
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getResource(getResourcePath("res"));
+
+ Category category = (Category)resource.getContents().get(0);
+ CDORevision revision = CDOUtil.getCDOObject(category).cdoRevision();
+ assertEquals(CDOPermission.NONE, revision.getPermission());
+ assertEquals(false, revision.isReadable());
+ assertEquals(false, revision.isWritable());
+
+ try
+ {
+ category.getName();
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+
+ try
+ {
+ category.setName("HW");
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+
+ try
+ {
+ category.getCategories().get(0);
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+
+ try
+ {
+ category.getCategories().add(getModel1Factory().createCategory());
+ fail("NoPermissionException expected");
+ }
+ catch (NoPermissionException expected)
+ {
+ // SUCCESS
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
index e64f1c7573..69c45035b5 100644
--- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java
@@ -24,6 +24,7 @@ import org.eclipse.emf.cdo.internal.server.syncing.RepositorySynchronizer;
import org.eclipse.emf.cdo.net4j.CDONet4jSessionConfiguration;
import org.eclipse.emf.cdo.server.CDOServerBrowser;
import org.eclipse.emf.cdo.server.CDOServerUtil;
+import org.eclipse.emf.cdo.server.IPermissionManager;
import org.eclipse.emf.cdo.server.IQueryHandlerProvider;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IRepository.Handler;
@@ -91,6 +92,8 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
public static final String PROP_TEST_USER_MANAGER = "test.repository.UserManager";
+ public static final String PROP_TEST_PERMISSION_MANAGER = "test.repository.PermissionManager";
+
public static final String PROP_TEST_QUERY_HANDLER_PROVIDER = "test.repository.QueryHandlerProvider";
private static final boolean LOG_MULTI_VIEW_COMMIT = false;
@@ -492,7 +495,12 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
if (userManager != null)
{
sessionManager.setUserManager(userManager);
- repository.setSessionManager(sessionManager);
+ }
+
+ IPermissionManager permissionManager = getTestPermissionManager();
+ if (permissionManager != null)
+ {
+ sessionManager.setPermissionManager(permissionManager);
}
IQueryHandlerProvider queryHandlerProvider = getTestQueryHandlerProvider();
@@ -524,6 +532,11 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf
return (IUserManager)getTestProperty(PROP_TEST_USER_MANAGER);
}
+ protected IPermissionManager getTestPermissionManager()
+ {
+ return (IPermissionManager)getTestProperty(PROP_TEST_PERMISSION_MANAGER);
+ }
+
protected IQueryHandlerProvider getTestQueryHandlerProvider()
{
return (IQueryHandlerProvider)getTestProperty(PROP_TEST_QUERY_HANDLER_PROVIDER);
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 ffb614135b..1599b2ae86 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
@@ -1,1032 +1,1055 @@
-/*
- * Copyright (c) 2004 - 2012 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:
- * Eike Stepper - initial API and implementation
- * Simon McDuff - maintenance
- */
-package org.eclipse.emf.internal.cdo.view;
-
-import org.eclipse.emf.cdo.CDOObject;
-import org.eclipse.emf.cdo.CDOState;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDTemp;
-import org.eclipse.emf.cdo.common.model.EMFUtil;
-import org.eclipse.emf.cdo.common.revision.CDORevisable;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-import org.eclipse.emf.cdo.common.util.PartialCollectionLoadingNotSupportedException;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
-import org.eclipse.emf.cdo.transaction.CDOTransaction;
-import org.eclipse.emf.cdo.view.CDOInvalidationPolicy;
-import org.eclipse.emf.cdo.view.CDOView;
-
-import org.eclipse.emf.internal.cdo.CDOObjectImpl;
-import org.eclipse.emf.internal.cdo.bundle.OM;
-import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder;
-
-import org.eclipse.net4j.util.collection.Pair;
-import org.eclipse.net4j.util.fsm.FiniteStateMachine;
-import org.eclipse.net4j.util.fsm.ITransition;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.common.notify.NotificationChain;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
-import org.eclipse.emf.spi.cdo.FSMUtil;
-import org.eclipse.emf.spi.cdo.InternalCDOObject;
-import org.eclipse.emf.spi.cdo.InternalCDOSavepoint;
-import org.eclipse.emf.spi.cdo.InternalCDOSession;
-import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
-import org.eclipse.emf.spi.cdo.InternalCDOView;
-
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Eike Stepper
- */
-public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent, InternalCDOObject>
-{
- // @Singleton
- public static final CDOStateMachine INSTANCE = new CDOStateMachine();
-
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_STATEMACHINE, CDOStateMachine.class);
-
- private InternalCDOObject lastTracedObject;
-
- private CDOState lastTracedState;
-
- private CDOEvent lastTracedEvent;
-
- @SuppressWarnings("unchecked")
- private CDOStateMachine()
- {
- super(CDOState.class, CDOEvent.class);
-
- init(CDOState.TRANSIENT, CDOEvent.PREPARE, new PrepareTransition());
- init(CDOState.TRANSIENT, CDOEvent.ATTACH, FAIL);
- init(CDOState.TRANSIENT, CDOEvent.DETACH, IGNORE);
- init(CDOState.TRANSIENT, CDOEvent.REATTACH, new ReattachTransition());
- init(CDOState.TRANSIENT, CDOEvent.READ, IGNORE);
- init(CDOState.TRANSIENT, CDOEvent.WRITE, IGNORE);
- init(CDOState.TRANSIENT, CDOEvent.INVALIDATE, IGNORE);
- init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, IGNORE);
- init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
- init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
-
- init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL);
- init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition());
- init(CDOState.PREPARED, CDOEvent.DETACH, FAIL);
- init(CDOState.PREPARED, CDOEvent.REATTACH, FAIL);
- init(CDOState.PREPARED, CDOEvent.READ, IGNORE);
- init(CDOState.PREPARED, CDOEvent.WRITE, FAIL);
- init(CDOState.PREPARED, CDOEvent.INVALIDATE, FAIL);
- init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL);
- init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL);
- init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL);
-
- init(CDOState.NEW, CDOEvent.PREPARE, FAIL);
- init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
- init(CDOState.NEW, CDOEvent.DETACH, new DetachTransition());
- init(CDOState.NEW, CDOEvent.REATTACH, FAIL);
- init(CDOState.NEW, CDOEvent.READ, IGNORE);
- init(CDOState.NEW, CDOEvent.WRITE, new WriteNewTransition());
- init(CDOState.NEW, CDOEvent.INVALIDATE, FAIL);
- init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL);
- init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false));
- init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
-
- init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL);
- init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
- init(CDOState.CLEAN, CDOEvent.DETACH, new DetachTransition());
- init(CDOState.CLEAN, CDOEvent.REATTACH, FAIL);
- init(CDOState.CLEAN, CDOEvent.READ, IGNORE);
- init(CDOState.CLEAN, CDOEvent.WRITE, new WriteTransition());
- init(CDOState.CLEAN, CDOEvent.INVALIDATE, new InvalidateTransition());
- init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
- init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
- init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
-
- init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL);
- init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
- init(CDOState.DIRTY, CDOEvent.DETACH, new DetachTransition());
- init(CDOState.DIRTY, CDOEvent.REATTACH, FAIL);
- init(CDOState.DIRTY, CDOEvent.READ, IGNORE);
- init(CDOState.DIRTY, CDOEvent.WRITE, new RewriteTransition());
- init(CDOState.DIRTY, CDOEvent.INVALIDATE, new ConflictTransition());
- init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition());
- init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true));
- init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition());
-
- init(CDOState.PROXY, CDOEvent.PREPARE, FAIL);
- init(CDOState.PROXY, CDOEvent.ATTACH, FAIL);
- init(CDOState.PROXY, CDOEvent.DETACH, new DetachTransition());
- init(CDOState.PROXY, CDOEvent.REATTACH, FAIL);
- init(CDOState.PROXY, CDOEvent.READ, new LoadTransition(false));
- init(CDOState.PROXY, CDOEvent.WRITE, new LoadTransition(true));
- init(CDOState.PROXY, CDOEvent.INVALIDATE, IGNORE);
- init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
- init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
- init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
-
- init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL);
- init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE);
- init(CDOState.CONFLICT, CDOEvent.DETACH, new DetachTransition());
- init(CDOState.CONFLICT, CDOEvent.REATTACH, FAIL);
- init(CDOState.CONFLICT, CDOEvent.READ, IGNORE);
- init(CDOState.CONFLICT, CDOEvent.WRITE, new RewriteTransition());
- init(CDOState.CONFLICT, CDOEvent.INVALIDATE, IGNORE);
- init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
- init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE);
- init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition());
-
- init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.DETACH, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.REATTACH, FAIL);
- init(CDOState.INVALID, CDOEvent.READ, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.WRITE, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.INVALIDATE, IGNORE); // TODO Handle changeViewTarget!!!
- init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE);
- init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
- init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE);
-
- init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH, InvalidTransition.INSTANCE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.REATTACH, FAIL);
- init(CDOState.INVALID_CONFLICT, CDOEvent.READ, IGNORE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.WRITE, IGNORE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.INVALIDATE, IGNORE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
- init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE);
- }
-
- /**
- * The object is already attached in EMF world. It contains all the information needed to know where it will be
- * connected.
- *
- * @since 2.0
- */
- public void attach(InternalCDOObject object, InternalCDOTransaction transaction)
- {
- synchronized (transaction)
- {
- List<InternalCDOObject> contents = new ArrayList<InternalCDOObject>();
- prepare(object, new Pair<InternalCDOTransaction, List<InternalCDOObject>>(transaction, contents));
-
- attachOrReattach(object, transaction);
- for (InternalCDOObject content : contents)
- {
- attachOrReattach(content, transaction);
- }
- }
- }
-
- private void attachOrReattach(InternalCDOObject object, InternalCDOTransaction transaction)
- {
- // Bug 283985 (Re-attachment):
- // If the object going through a prepareTransition is present in cleanRevisions,
- // then it was detached earlier, and so we can infer that it is being re-attached
- if (transaction.getCleanRevisions().containsKey(object))
- {
- reattachObject(object, transaction);
- }
- else
- {
- attachObject(object);
- }
- }
-
- /**
- * Phase 1: TRANSIENT --> PREPARED
- */
- private void prepare(InternalCDOObject object,
- Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndContents)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1()); //$NON-NLS-1$
- }
-
- process(object, CDOEvent.PREPARE, transactionAndContents);
- }
-
- /**
- * Phase 2: PREPARED --> NEW
- */
- private void attachObject(InternalCDOObject object)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("ATTACH: {0}", object); //$NON-NLS-1$
- }
-
- process(object, CDOEvent.ATTACH, null);
- }
-
- private void reattachObject(InternalCDOObject object, InternalCDOTransaction transaction)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("REATTACH: {0}", object);
- }
-
- process(object, CDOEvent.REATTACH, transaction);
- }
-
- /**
- * @since 2.0
- */
- public void detach(InternalCDOObject object)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.DETACH);
- }
-
- List<InternalCDOObject> objectsToDetach = new ArrayList<InternalCDOObject>();
- InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
-
- // Accumulate objects that needs to be detached
- // If we have an error, we will keep the graph exactly like it was before.
- process(object, CDOEvent.DETACH, objectsToDetach);
-
- // postDetach requires the object to be TRANSIENT
- for (InternalCDOObject content : objectsToDetach)
- {
- CDOState oldState = content.cdoInternalSetState(CDOState.TRANSIENT);
- content.cdoInternalPostDetach(false);
- content.cdoInternalSetState(oldState);
- }
-
- // detachObject needs to know the state before we change the object to TRANSIENT
- for (InternalCDOObject content : objectsToDetach)
- {
- transaction.detachObject(content);
- content.cdoInternalSetState(CDOState.TRANSIENT);
-
- content.cdoInternalSetView(null);
- content.cdoInternalSetID(null);
- content.cdoInternalSetRevision(null);
- }
- }
- }
-
- /**
- * @since 2.0
- */
- public InternalCDORevision read(InternalCDOObject object)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.READ);
- }
-
- process(object, CDOEvent.READ, null);
-
- return object.cdoRevision();
- }
- }
-
- /**
- * @since 2.0
- */
- public InternalCDORevision readNoLoad(InternalCDOObject object)
- {
- synchronized (getMonitor(object))
- {
- switch (object.cdoState())
- {
- case TRANSIENT:
- case PREPARED:
- case NEW:
- case CONFLICT:
- case INVALID_CONFLICT:
- case INVALID:
- case PROXY:
- return null;
- }
-
- return object.cdoRevision();
- }
- }
-
- /**
- * @since 2.0
- */
- public void write(InternalCDOObject object)
- {
- write(object, null);
- }
-
- /**
- * @since 2.0
- */
- public void write(InternalCDOObject object, CDOFeatureDelta featureDelta)
- {
- synchronized (getMonitor(object))
- {
- writeWithoutViewLock(object, featureDelta);
- }
- }
-
- private void writeWithoutViewLock(InternalCDOObject object, CDOFeatureDelta featureDelta)
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.WRITE);
- }
-
- process(object, CDOEvent.WRITE, featureDelta);
- }
-
- /**
- * @since 2.0
- */
- public void reload(InternalCDOObject... objects)
- {
- if (objects == null || objects.length == 0)
- {
- return;
- }
-
- synchronized (getMonitor(objects[0]))
- {
- for (InternalCDOObject object : objects)
- {
- CDOState state = object.cdoState();
- if (state == CDOState.CLEAN || state == CDOState.PROXY)
- {
- changeState(object, CDOState.PROXY);
- object.cdoInternalSetRevision(null);
- read(object);
- }
- }
- }
- }
-
- /**
- * @since 3.0
- */
- public void invalidate(InternalCDOObject object, CDORevisionKey key, long lastUpdateTime)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.INVALIDATE);
- }
-
- process(object, CDOEvent.INVALIDATE, new Pair<CDORevisionKey, Long>(key, lastUpdateTime));
- }
- }
-
- /**
- * @since 2.0
- */
- public void detachRemote(InternalCDOObject object)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.DETACH_REMOTE);
- }
-
- process(object, CDOEvent.DETACH_REMOTE, null);
- }
- }
-
- /**
- * @since 2.0
- */
- public void commit(InternalCDOObject object, CommitTransactionResult result)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.COMMIT);
- }
-
- process(object, CDOEvent.COMMIT, result);
- }
- }
-
- /**
- * @since 2.0
- */
- public void rollback(InternalCDOObject object)
- {
- synchronized (getMonitor(object))
- {
- if (TRACER.isEnabled())
- {
- trace(object, CDOEvent.ROLLBACK);
- }
-
- process(object, CDOEvent.ROLLBACK, null);
- object.cdoInternalPostRollback();
- }
- }
-
- @Override
- protected CDOState getState(InternalCDOObject object)
- {
- return object.cdoState();
- }
-
- @Override
- protected void setState(InternalCDOObject object, CDOState state)
- {
- object.cdoInternalSetState(state);
- }
-
- private Object getMonitor(InternalCDOObject object)
- {
- InternalCDOView view = object.cdoView();
- if (view != null)
- {
- return view;
- }
-
- // In TRANSIENT and PREPARED the object is not yet attached to a view
- return object;
- }
-
- /**
- * Removes clutter from the trace log
- */
- private void trace(InternalCDOObject object, CDOEvent event)
- {
- CDOState state = object.cdoState();
- if (lastTracedObject != object || lastTracedState != state || lastTracedEvent != event)
- {
- TRACER.format("{0}: {1}", event, object.getClass().getName()); //$NON-NLS-1$
- lastTracedObject = object;
- lastTracedState = state;
- lastTracedEvent = event;
- }
- }
-
- @SuppressWarnings("unused")
- private void testAttach(InternalCDOObject object)
- {
- process(object, CDOEvent.ATTACH, null);
- }
-
- /**
- * Prepares a tree of transient objects to be subsequently {@link AttachTransition attached} to a CDOView.
- * <p>
- * Execution is recursive and includes:
- * <ol>
- * <li>Assignment of a new {@link CDOIDTemp}
- * <li>Assignment of a new {@link CDORevision}
- * <li>Bidirectional association with the {@link CDOView}
- * <li>Registration with the {@link CDOTransaction}
- * <li>Changing state to {@link CDOState#PREPARED PREPARED}
- * </ol>
- *
- * @see AttachTransition
- * @author Eike Stepper
- */
- private final class PrepareTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<InternalCDOTransaction, List<InternalCDOObject>>>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
- Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndContents)
- {
- InternalCDOTransaction transaction = transactionAndContents.getElement1();
- List<InternalCDOObject> contents = transactionAndContents.getElement2();
-
- // If the object going through a prepareTransition is present in cleanRevisions,
- // then it was detached earlier, and so we can infer that it is being re-attached
- boolean reattaching = transaction.getCleanRevisions().containsKey(object);
-
- if (!reattaching)
- {
- // Prepare object
- CDOID id = transaction.createIDForNewObject(object.cdoInternalInstance());
- object.cdoInternalSetID(id);
- object.cdoInternalSetView(transaction);
- changeState(object, CDOState.PREPARED);
-
- // Create new revision
- EClass eClass = object.eClass();
- InternalCDOSession session = transaction.getSession();
- checkPackageRegistrationProblems(session, eClass);
-
- CDORevisionFactory factory = session.getRevisionManager().getFactory();
- InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
- revision.setID(id);
- revision.setBranchPoint(transaction.getBranch().getHead());
-
- object.cdoInternalSetRevision(revision);
-
- // Register object
- transaction.registerObject(object);
- }
-
- transaction.registerAttached(object, !reattaching);
-
- // Prepare content tree
- for (Iterator<InternalCDOObject> it = getProperContents(object, transaction); it.hasNext();)
- {
- InternalCDOObject content = it.next();
- contents.add(content);
- INSTANCE.process(content, CDOEvent.PREPARE, transactionAndContents);
- }
- }
-
- private void checkPackageRegistrationProblems(InternalCDOSession session, EClass eClass)
- {
- if (session.options().isGeneratedPackageEmulationEnabled())
- {
- // Check that there are no multiple EPackages with the same URI in system. Bug 335004
- String packageURI = eClass.getEPackage().getNsURI();
- Object packageObject = session.getPackageRegistry().get(packageURI);
- if (packageObject instanceof InternalCDOPackageInfo)
- {
- packageObject = ((InternalCDOPackageInfo)packageObject).getEPackage(false);
- }
-
- if (packageObject instanceof EPackage && packageObject != eClass.getEPackage())
- {
- throw new IllegalStateException(MessageFormat.format(
- "Global EPackage {0} for EClass {1} is different from EPackage found in CDOPackageRegistry", packageURI,
- eClass));
- }
- }
- }
-
- private Iterator<InternalCDOObject> getProperContents(final InternalCDOObject object,
- final CDOTransaction transaction)
- {
- final boolean isResource = object instanceof Resource;
- final Iterator<EObject> delegate = object.eContents().iterator();
-
- return new Iterator<InternalCDOObject>()
- {
- private Object next;
-
- public boolean hasNext()
- {
- while (delegate.hasNext())
- {
- InternalEObject eObject = (InternalEObject)delegate.next();
- EStructuralFeature eContainingFeature = eObject.eContainingFeature();
- if (isResource || eObject.eDirectResource() == null
- && (eContainingFeature == null || EMFUtil.isPersistent(eContainingFeature)))
- {
- next = FSMUtil.adapt(eObject, transaction);
- return true;
- }
- }
-
- return false;
- }
-
- public InternalCDOObject next()
- {
- return (InternalCDOObject)next;
- }
-
- public void remove()
- {
- throw new UnsupportedOperationException();
- }
- };
- }
- }
-
- /**
- * Attaches a tree of {@link PrepareTransition prepared} objects to a CDOView.
- * <p>
- * Execution is recursive and includes:
- * <ol>
- * <li>Calling {@link InternalCDOObject#cdoInternalPostAttach()},<br>
- * which includes for {@link CDOObjectImpl}:
- * <ol>
- * <li>Population of the CDORevision with the current values in
- * {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
- * <li>Unsetting {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
- * </ol>
- * <li>Changing state to {@link CDOState#NEW NEW}
- * </ol>
- *
- * @see PrepareTransition
- * @author Eike Stepper
- */
- private final class AttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
- {
- object.cdoInternalPostAttach();
- changeState(object, CDOState.NEW);
- }
- }
-
- /**
- * Bug 283985 (Re-attachment)
- *
- * @author Caspar De Groot
- */
- private final class ReattachTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, InternalCDOTransaction>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, InternalCDOTransaction transaction)
- {
- InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
- InternalCDORevision cleanRevision = transaction.getCleanRevisions().get(object).copy();
- CDOID id = cleanRevision.getID();
-
- // Bug 373096: Determine clean revision of the CURRENT/LAST savepoint
- InternalCDOSavepoint savepoint = transaction.getFirstSavepoint();
- while (savepoint.getNextSavepoint() != null)
- {
- CDORevisionDelta delta = savepoint.getRevisionDeltas().get(id);
- if (delta != null)
- {
- delta.apply(cleanRevision);
- }
-
- savepoint = savepoint.getNextSavepoint();
- }
-
- object.cdoInternalSetID(id);
- object.cdoInternalSetView(transaction);
-
- // Construct a new revision
- CDORevisionFactory factory = revisionManager.getFactory();
- InternalCDORevision revision = (InternalCDORevision)factory.createRevision(object.eClass());
- revision.setID(id);
- revision.setBranchPoint(cleanRevision.getBranch().getHead());
- revision.setVersion(cleanRevision.getVersion());
-
- // Populate the revision based on the values in the CDOObject
- object.cdoInternalSetRevision(revision);
- object.cdoInternalPostAttach();
-
- // Compute a revision delta and register it with the tx
- CDORevisionDelta revisionDelta = revision.compare(cleanRevision);
- if (revisionDelta.isEmpty())
- {
- changeState(object, CDOState.CLEAN);
- }
- else
- {
- transaction.registerRevisionDelta(revisionDelta);
- transaction.registerDirty(object, (CDOFeatureDelta)null);
- changeState(object, CDOState.DIRTY);
- }
-
- // Add the object to the set of reattached objects
- Map<CDOID, CDOObject> reattachedObjects = transaction.getLastSavepoint().getReattachedObjects();
- reattachedObjects.put(id, object);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private static final class DetachTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, List<InternalCDOObject>>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
- List<InternalCDOObject> objectsToDetach)
- {
- InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
- objectsToDetach.add(object);
- boolean isResource = object instanceof Resource;
-
- // Prepare content tree
- for (Iterator<EObject> it = object.eContents().iterator(); it.hasNext();)
- {
- InternalEObject eObject = (InternalEObject)it.next();
- boolean isDirectlyConnected = isResource && eObject.eDirectResource() == object;
- if (isDirectlyConnected || eObject.eDirectResource() == null)
- {
- InternalCDOObject content = FSMUtil.adapt(eObject, transaction);
- if (content != null)
- {
- INSTANCE.process(content, CDOEvent.DETACH, objectsToDetach);
- }
- }
- }
- }
- }
-
- /**
- * @author Eike Stepper
- */
- final private class CommitTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, CommitTransactionResult>
- {
- public CommitTransition(boolean useDeltas)
- {
- }
-
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, CommitTransactionResult data)
- {
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- InternalCDORevision revision = object.cdoRevision();
- Map<CDOID, CDOID> idMappings = data.getIDMappings();
-
- // Adjust object
- CDOID oldID = object.cdoID();
- CDOID newID = idMappings.get(oldID);
- if (newID != null)
- {
- object.cdoInternalSetID(newID);
- transaction.remapObject(oldID);
- revision.setID(newID);
- }
-
- // Adjust revision
- revision.adjustForCommit(transaction.getBranch(), data.getTimeStamp());
- revision.adjustReferences(data.getReferenceAdjuster());
- revision.freeze();
-
- InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
- revisionManager.addRevision(revision);
-
- changeState(object, CDOState.CLEAN);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class RollbackTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
- {
- object.cdoInternalSetRevision(null);
- changeState(object, CDOState.PROXY);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
- {
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- InternalCDORevision cleanRevision = object.cdoRevision();
- transaction.getCleanRevisions().put(object, cleanRevision);
-
- // Copy revision
- InternalCDORevision revision = object.cdoRevision().copy();
- object.cdoInternalSetRevision(revision);
-
- transaction.registerDirty(object, (CDOFeatureDelta)featureDelta);
- changeState(object, CDOState.DIRTY);
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private static final class WriteNewTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
- {
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private static final class RewriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
- {
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private static class DetachRemoteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- static final DetachRemoteTransition INSTANCE = new DetachRemoteTransition();
-
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
- {
- CDOStateMachine.INSTANCE.changeState(object, CDOState.INVALID);
-
- InternalCDOView view = object.cdoView();
- view.deregisterObject(object);
- object.cdoInternalPostDetach(true);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private class InvalidateTransition implements
- ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<CDORevisionKey, Long>>
- {
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> keyAndTime)
- {
- CDORevisionKey key = keyAndTime.getElement1();
- InternalCDORevision oldRevision = object.cdoRevision();
- if (key == null || key.getVersion() >= oldRevision.getVersion())
- {
- InternalCDOView view = object.cdoView();
-
- CDORevisionKey newKey = null;
- if (key != null)
- {
- int newVersion = getNewVersion(key);
- newKey = CDORevisionUtil.createRevisionKey(key.getID(), key.getBranch(), newVersion);
- }
-
- InternalCDORevision newRevision = null;
- if (newKey != null)
- {
- InternalCDORevisionCache cache = view.getSession().getRevisionManager().getCache();
- newRevision = (InternalCDORevision)cache.getRevisionByVersion(newKey.getID(), newKey);
- }
-
- if (newRevision != null)
- {
- object.cdoInternalSetRevision(newRevision);
- changeState(object, CDOState.CLEAN);
- object.cdoInternalPostLoad();
- }
- else
- {
- changeState(object, CDOState.PROXY);
-
- CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
- policy.handleInvalidation(object, key);
- object.cdoInternalPostInvalidate();
- }
- }
- }
-
- private int getNewVersion(CDORevisionKey key)
- {
- if (key instanceof CDORevisionDelta)
- {
- CDORevisionDelta delta = (CDORevisionDelta)key;
- CDORevisable target = delta.getTarget();
- if (target != null && key.getBranch() == target.getBranch())
- {
- return target.getVersion();
- }
- }
-
- return key.getVersion() + 1;
- }
- }
-
- /**
- * @author Eike Stepper
- * @since 2.0
- */
- private class ConflictTransition extends InvalidateTransition
- {
- @Override
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> keyAndTime)
- {
- CDORevisionKey key = keyAndTime.getElement1();
- InternalCDORevision oldRevision = object.cdoRevision();
- if (key == null || key.getVersion() >= oldRevision.getVersion() - 1)
- {
- changeState(object, CDOState.CONFLICT);
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- transaction.setConflict(object);
- }
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private final class InvalidConflictTransition extends ConflictTransition
- {
- @Override
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> UNUSED)
- {
- changeState(object, CDOState.INVALID_CONFLICT);
-
- InternalCDOTransaction transaction = object.cdoView().toTransaction();
- transaction.setConflict(object);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- private boolean forWrite;
-
- public LoadTransition(boolean forWrite)
- {
- this.forWrite = forWrite;
- }
-
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object delta)
- {
- object.cdoInternalPreLoad();
-
- InternalCDOView view = object.cdoView();
- InternalCDORevision revision = view.getRevision(object.cdoID(), true);
- if (revision == null)
- {
- INSTANCE.detachRemote(object);
- CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
- policy.handleInvalidObject(object);
- }
-
- object.cdoInternalSetRevision(revision);
- changeState(object, CDOState.CLEAN);
- object.cdoInternalPostLoad();
-
- if (view.options().isLoadNotificationEnabled())
- {
- try
- {
- CDONotificationBuilder builder = new CDONotificationBuilder(view);
-
- NotificationChain notification = builder.buildNotification(object, revision);
- if (notification != null)
- {
- notification.dispatch();
- }
- }
- catch (PartialCollectionLoadingNotSupportedException ex)
- {
- if (TRACER.isEnabled())
- {
- TRACER.trace(ex);
- }
- }
- }
-
- if (forWrite)
- {
- INSTANCE.writeWithoutViewLock(object, (CDOFeatureDelta)delta);
- }
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private static final class InvalidTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
- {
- public static final InvalidTransition INSTANCE = new InvalidTransition();
-
- public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
- {
- InternalCDOView view = object.cdoView();
- CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
- policy.handleInvalidObject(object);
- }
- }
-}
-
-/**
- * @author Eike Stepper
- */
-enum CDOEvent
-{
- PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK
-}
+/*
+ * Copyright (c) 2004 - 2012 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:
+ * Eike Stepper - initial API and implementation
+ * Simon McDuff - maintenance
+ */
+package org.eclipse.emf.internal.cdo.view;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDTemp;
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.common.revision.CDORevisable;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
+import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.common.security.NoPermissionException;
+import org.eclipse.emf.cdo.common.util.PartialCollectionLoadingNotSupportedException;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionCache;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.view.CDOInvalidationPolicy;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.emf.internal.cdo.CDOObjectImpl;
+import org.eclipse.emf.internal.cdo.bundle.OM;
+import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder;
+
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.fsm.FiniteStateMachine;
+import org.eclipse.net4j.util.fsm.ITransition;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
+import org.eclipse.emf.spi.cdo.FSMUtil;
+import org.eclipse.emf.spi.cdo.InternalCDOObject;
+import org.eclipse.emf.spi.cdo.InternalCDOSavepoint;
+import org.eclipse.emf.spi.cdo.InternalCDOSession;
+import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
+import org.eclipse.emf.spi.cdo.InternalCDOView;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Eike Stepper
+ */
+public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent, InternalCDOObject>
+{
+ // @Singleton
+ public static final CDOStateMachine INSTANCE = new CDOStateMachine();
+
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_STATEMACHINE, CDOStateMachine.class);
+
+ private InternalCDOObject lastTracedObject;
+
+ private CDOState lastTracedState;
+
+ private CDOEvent lastTracedEvent;
+
+ @SuppressWarnings("unchecked")
+ private CDOStateMachine()
+ {
+ super(CDOState.class, CDOEvent.class);
+
+ init(CDOState.TRANSIENT, CDOEvent.PREPARE, new PrepareTransition());
+ init(CDOState.TRANSIENT, CDOEvent.ATTACH, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.DETACH, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.REATTACH, new ReattachTransition());
+ init(CDOState.TRANSIENT, CDOEvent.READ, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.WRITE, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.INVALIDATE, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, IGNORE);
+ init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
+ init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
+
+ init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL);
+ init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition());
+ init(CDOState.PREPARED, CDOEvent.DETACH, FAIL);
+ init(CDOState.PREPARED, CDOEvent.REATTACH, FAIL);
+ init(CDOState.PREPARED, CDOEvent.READ, IGNORE);
+ init(CDOState.PREPARED, CDOEvent.WRITE, FAIL);
+ init(CDOState.PREPARED, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL);
+ init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL);
+ init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL);
+
+ init(CDOState.NEW, CDOEvent.PREPARE, FAIL);
+ init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
+ init(CDOState.NEW, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.NEW, CDOEvent.REATTACH, FAIL);
+ init(CDOState.NEW, CDOEvent.READ, IGNORE);
+ init(CDOState.NEW, CDOEvent.WRITE, new WriteNewTransition());
+ init(CDOState.NEW, CDOEvent.INVALIDATE, FAIL);
+ init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL);
+ init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false));
+ init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
+
+ init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL);
+ init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
+ init(CDOState.CLEAN, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.CLEAN, CDOEvent.REATTACH, FAIL);
+ init(CDOState.CLEAN, CDOEvent.READ, IGNORE);
+ init(CDOState.CLEAN, CDOEvent.WRITE, new WriteTransition());
+ init(CDOState.CLEAN, CDOEvent.INVALIDATE, new InvalidateTransition());
+ init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
+ init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
+ init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
+
+ init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL);
+ init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
+ init(CDOState.DIRTY, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.DIRTY, CDOEvent.REATTACH, FAIL);
+ init(CDOState.DIRTY, CDOEvent.READ, IGNORE);
+ init(CDOState.DIRTY, CDOEvent.WRITE, new RewriteTransition());
+ init(CDOState.DIRTY, CDOEvent.INVALIDATE, new ConflictTransition());
+ init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition());
+ init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true));
+ init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition());
+
+ init(CDOState.PROXY, CDOEvent.PREPARE, FAIL);
+ init(CDOState.PROXY, CDOEvent.ATTACH, FAIL);
+ init(CDOState.PROXY, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.PROXY, CDOEvent.REATTACH, FAIL);
+ init(CDOState.PROXY, CDOEvent.READ, new LoadTransition(false));
+ init(CDOState.PROXY, CDOEvent.WRITE, new LoadTransition(true));
+ init(CDOState.PROXY, CDOEvent.INVALIDATE, IGNORE);
+ init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
+ init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
+ init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
+
+ init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE);
+ init(CDOState.CONFLICT, CDOEvent.DETACH, new DetachTransition());
+ init(CDOState.CONFLICT, CDOEvent.REATTACH, FAIL);
+ init(CDOState.CONFLICT, CDOEvent.READ, IGNORE);
+ init(CDOState.CONFLICT, CDOEvent.WRITE, new RewriteTransition());
+ init(CDOState.CONFLICT, CDOEvent.INVALIDATE, IGNORE);
+ init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
+ init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE);
+ init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition());
+
+ init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.DETACH, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.REATTACH, FAIL);
+ init(CDOState.INVALID, CDOEvent.READ, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.WRITE, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.INVALIDATE, IGNORE); // TODO Handle changeViewTarget!!!
+ init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE);
+ init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE);
+
+ init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.REATTACH, FAIL);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.READ, IGNORE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.WRITE, IGNORE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.INVALIDATE, IGNORE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
+ init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE);
+ }
+
+ /**
+ * The object is already attached in EMF world. It contains all the information needed to know where it will be
+ * connected.
+ *
+ * @since 2.0
+ */
+ public void attach(InternalCDOObject object, InternalCDOTransaction transaction)
+ {
+ synchronized (transaction)
+ {
+ List<InternalCDOObject> contents = new ArrayList<InternalCDOObject>();
+ prepare(object, new Pair<InternalCDOTransaction, List<InternalCDOObject>>(transaction, contents));
+
+ attachOrReattach(object, transaction);
+ for (InternalCDOObject content : contents)
+ {
+ attachOrReattach(content, transaction);
+ }
+ }
+ }
+
+ private void attachOrReattach(InternalCDOObject object, InternalCDOTransaction transaction)
+ {
+ // Bug 283985 (Re-attachment):
+ // If the object going through a prepareTransition is present in cleanRevisions,
+ // then it was detached earlier, and so we can infer that it is being re-attached
+ if (transaction.getCleanRevisions().containsKey(object))
+ {
+ reattachObject(object, transaction);
+ }
+ else
+ {
+ attachObject(object);
+ }
+ }
+
+ /**
+ * Phase 1: TRANSIENT --> PREPARED
+ */
+ private void prepare(InternalCDOObject object,
+ Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndContents)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("PREPARE: {0} --> {1}", object, transactionAndContents.getElement1()); //$NON-NLS-1$
+ }
+
+ process(object, CDOEvent.PREPARE, transactionAndContents);
+ }
+
+ /**
+ * Phase 2: PREPARED --> NEW
+ */
+ private void attachObject(InternalCDOObject object)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("ATTACH: {0}", object); //$NON-NLS-1$
+ }
+
+ process(object, CDOEvent.ATTACH, null);
+ }
+
+ private void reattachObject(InternalCDOObject object, InternalCDOTransaction transaction)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("REATTACH: {0}", object);
+ }
+
+ process(object, CDOEvent.REATTACH, transaction);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void detach(InternalCDOObject object)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.DETACH);
+ }
+
+ List<InternalCDOObject> objectsToDetach = new ArrayList<InternalCDOObject>();
+ InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
+
+ // Accumulate objects that needs to be detached
+ // If we have an error, we will keep the graph exactly like it was before.
+ process(object, CDOEvent.DETACH, objectsToDetach);
+
+ // postDetach requires the object to be TRANSIENT
+ for (InternalCDOObject content : objectsToDetach)
+ {
+ CDOState oldState = content.cdoInternalSetState(CDOState.TRANSIENT);
+ content.cdoInternalPostDetach(false);
+ content.cdoInternalSetState(oldState);
+ }
+
+ // detachObject needs to know the state before we change the object to TRANSIENT
+ for (InternalCDOObject content : objectsToDetach)
+ {
+ transaction.detachObject(content);
+ content.cdoInternalSetState(CDOState.TRANSIENT);
+
+ content.cdoInternalSetView(null);
+ content.cdoInternalSetID(null);
+ content.cdoInternalSetRevision(null);
+ }
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InternalCDORevision read(InternalCDOObject object)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.READ);
+ }
+
+ process(object, CDOEvent.READ, null);
+
+ return object.cdoRevision();
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InternalCDORevision readNoLoad(InternalCDOObject object)
+ {
+ synchronized (getMonitor(object))
+ {
+ switch (object.cdoState())
+ {
+ case TRANSIENT:
+ case PREPARED:
+ case NEW:
+ case CONFLICT:
+ case INVALID_CONFLICT:
+ case INVALID:
+ case PROXY:
+ return null;
+ }
+
+ return object.cdoRevision();
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void write(InternalCDOObject object)
+ {
+ write(object, null);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void write(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ synchronized (getMonitor(object))
+ {
+ writeWithoutViewLock(object, featureDelta);
+ }
+ }
+
+ private void writeWithoutViewLock(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.WRITE);
+ }
+
+ process(object, CDOEvent.WRITE, featureDelta);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void reload(InternalCDOObject... objects)
+ {
+ if (objects == null || objects.length == 0)
+ {
+ return;
+ }
+
+ synchronized (getMonitor(objects[0]))
+ {
+ for (InternalCDOObject object : objects)
+ {
+ CDOState state = object.cdoState();
+ if (state == CDOState.CLEAN || state == CDOState.PROXY)
+ {
+ changeState(object, CDOState.PROXY);
+ object.cdoInternalSetRevision(null);
+ read(object);
+ }
+ }
+ }
+ }
+
+ /**
+ * @since 3.0
+ */
+ public void invalidate(InternalCDOObject object, CDORevisionKey key, long lastUpdateTime)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.INVALIDATE);
+ }
+
+ process(object, CDOEvent.INVALIDATE, new Pair<CDORevisionKey, Long>(key, lastUpdateTime));
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void detachRemote(InternalCDOObject object)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.DETACH_REMOTE);
+ }
+
+ process(object, CDOEvent.DETACH_REMOTE, null);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void commit(InternalCDOObject object, CommitTransactionResult result)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.COMMIT);
+ }
+
+ process(object, CDOEvent.COMMIT, result);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void rollback(InternalCDOObject object)
+ {
+ synchronized (getMonitor(object))
+ {
+ if (TRACER.isEnabled())
+ {
+ trace(object, CDOEvent.ROLLBACK);
+ }
+
+ process(object, CDOEvent.ROLLBACK, null);
+ object.cdoInternalPostRollback();
+ }
+ }
+
+ @Override
+ protected CDOState getState(InternalCDOObject object)
+ {
+ return object.cdoState();
+ }
+
+ @Override
+ protected void setState(InternalCDOObject object, CDOState state)
+ {
+ object.cdoInternalSetState(state);
+ }
+
+ private Object getMonitor(InternalCDOObject object)
+ {
+ InternalCDOView view = object.cdoView();
+ if (view != null)
+ {
+ return view;
+ }
+
+ // In TRANSIENT and PREPARED the object is not yet attached to a view
+ return object;
+ }
+
+ /**
+ * Removes clutter from the trace log
+ */
+ private void trace(InternalCDOObject object, CDOEvent event)
+ {
+ CDOState state = object.cdoState();
+ if (lastTracedObject != object || lastTracedState != state || lastTracedEvent != event)
+ {
+ TRACER.format("{0}: {1}", event, object.getClass().getName()); //$NON-NLS-1$
+ lastTracedObject = object;
+ lastTracedState = state;
+ lastTracedEvent = event;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void testAttach(InternalCDOObject object)
+ {
+ process(object, CDOEvent.ATTACH, null);
+ }
+
+ /**
+ * Prepares a tree of transient objects to be subsequently {@link AttachTransition attached} to a CDOView.
+ * <p>
+ * Execution is recursive and includes:
+ * <ol>
+ * <li>Assignment of a new {@link CDOIDTemp}
+ * <li>Assignment of a new {@link CDORevision}
+ * <li>Bidirectional association with the {@link CDOView}
+ * <li>Registration with the {@link CDOTransaction}
+ * <li>Changing state to {@link CDOState#PREPARED PREPARED}
+ * </ol>
+ *
+ * @see AttachTransition
+ * @author Eike Stepper
+ */
+ private final class PrepareTransition implements
+ ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<InternalCDOTransaction, List<InternalCDOObject>>>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
+ Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndContents)
+ {
+ InternalCDOTransaction transaction = transactionAndContents.getElement1();
+ List<InternalCDOObject> contents = transactionAndContents.getElement2();
+
+ // If the object going through a prepareTransition is present in cleanRevisions,
+ // then it was detached earlier, and so we can infer that it is being re-attached
+ boolean reattaching = transaction.getCleanRevisions().containsKey(object);
+
+ if (!reattaching)
+ {
+ // Prepare object
+ CDOID id = transaction.createIDForNewObject(object.cdoInternalInstance());
+ object.cdoInternalSetID(id);
+ object.cdoInternalSetView(transaction);
+ changeState(object, CDOState.PREPARED);
+
+ // Create new revision
+ EClass eClass = object.eClass();
+ InternalCDOSession session = transaction.getSession();
+ checkPackageRegistrationProblems(session, eClass);
+
+ CDORevisionFactory factory = session.getRevisionManager().getFactory();
+ InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
+ revision.setID(id);
+ revision.setBranchPoint(transaction.getBranch().getHead());
+
+ object.cdoInternalSetRevision(revision);
+
+ // Register object
+ transaction.registerObject(object);
+ }
+
+ transaction.registerAttached(object, !reattaching);
+
+ // Prepare content tree
+ for (Iterator<InternalCDOObject> it = getProperContents(object, transaction); it.hasNext();)
+ {
+ InternalCDOObject content = it.next();
+ contents.add(content);
+ INSTANCE.process(content, CDOEvent.PREPARE, transactionAndContents);
+ }
+ }
+
+ private void checkPackageRegistrationProblems(InternalCDOSession session, EClass eClass)
+ {
+ if (session.options().isGeneratedPackageEmulationEnabled())
+ {
+ // Check that there are no multiple EPackages with the same URI in system. Bug 335004
+ String packageURI = eClass.getEPackage().getNsURI();
+ Object packageObject = session.getPackageRegistry().get(packageURI);
+ if (packageObject instanceof InternalCDOPackageInfo)
+ {
+ packageObject = ((InternalCDOPackageInfo)packageObject).getEPackage(false);
+ }
+
+ if (packageObject instanceof EPackage && packageObject != eClass.getEPackage())
+ {
+ throw new IllegalStateException(MessageFormat.format(
+ "Global EPackage {0} for EClass {1} is different from EPackage found in CDOPackageRegistry", packageURI,
+ eClass));
+ }
+ }
+ }
+
+ private Iterator<InternalCDOObject> getProperContents(final InternalCDOObject object,
+ final CDOTransaction transaction)
+ {
+ final boolean isResource = object instanceof Resource;
+ final Iterator<EObject> delegate = object.eContents().iterator();
+
+ return new Iterator<InternalCDOObject>()
+ {
+ private Object next;
+
+ public boolean hasNext()
+ {
+ while (delegate.hasNext())
+ {
+ InternalEObject eObject = (InternalEObject)delegate.next();
+ EStructuralFeature eContainingFeature = eObject.eContainingFeature();
+ if (isResource || eObject.eDirectResource() == null
+ && (eContainingFeature == null || EMFUtil.isPersistent(eContainingFeature)))
+ {
+ next = FSMUtil.adapt(eObject, transaction);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public InternalCDOObject next()
+ {
+ return (InternalCDOObject)next;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ /**
+ * Attaches a tree of {@link PrepareTransition prepared} objects to a CDOView.
+ * <p>
+ * Execution is recursive and includes:
+ * <ol>
+ * <li>Calling {@link InternalCDOObject#cdoInternalPostAttach()},<br>
+ * which includes for {@link CDOObjectImpl}:
+ * <ol>
+ * <li>Population of the CDORevision with the current values in
+ * {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
+ * <li>Unsetting {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
+ * </ol>
+ * <li>Changing state to {@link CDOState#NEW NEW}
+ * </ol>
+ *
+ * @see PrepareTransition
+ * @author Eike Stepper
+ */
+ private final class AttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
+ {
+ object.cdoInternalPostAttach();
+ changeState(object, CDOState.NEW);
+ }
+ }
+
+ /**
+ * Bug 283985 (Re-attachment)
+ *
+ * @author Caspar De Groot
+ */
+ private final class ReattachTransition implements
+ ITransition<CDOState, CDOEvent, InternalCDOObject, InternalCDOTransaction>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, InternalCDOTransaction transaction)
+ {
+ InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
+ InternalCDORevision cleanRevision = transaction.getCleanRevisions().get(object).copy();
+ CDOID id = cleanRevision.getID();
+
+ // Bug 373096: Determine clean revision of the CURRENT/LAST savepoint
+ InternalCDOSavepoint savepoint = transaction.getFirstSavepoint();
+ while (savepoint.getNextSavepoint() != null)
+ {
+ CDORevisionDelta delta = savepoint.getRevisionDeltas().get(id);
+ if (delta != null)
+ {
+ delta.apply(cleanRevision);
+ }
+
+ savepoint = savepoint.getNextSavepoint();
+ }
+
+ object.cdoInternalSetID(id);
+ object.cdoInternalSetView(transaction);
+
+ // Construct a new revision
+ CDORevisionFactory factory = revisionManager.getFactory();
+ InternalCDORevision revision = (InternalCDORevision)factory.createRevision(object.eClass());
+ revision.setID(id);
+ revision.setBranchPoint(cleanRevision.getBranch().getHead());
+ revision.setVersion(cleanRevision.getVersion());
+
+ // Populate the revision based on the values in the CDOObject
+ object.cdoInternalSetRevision(revision);
+ object.cdoInternalPostAttach();
+
+ // Compute a revision delta and register it with the tx
+ CDORevisionDelta revisionDelta = revision.compare(cleanRevision);
+ if (revisionDelta.isEmpty())
+ {
+ changeState(object, CDOState.CLEAN);
+ }
+ else
+ {
+ transaction.registerRevisionDelta(revisionDelta);
+ transaction.registerDirty(object, (CDOFeatureDelta)null);
+ changeState(object, CDOState.DIRTY);
+ }
+
+ // Add the object to the set of reattached objects
+ Map<CDOID, CDOObject> reattachedObjects = transaction.getLastSavepoint().getReattachedObjects();
+ reattachedObjects.put(id, object);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class DetachTransition implements
+ ITransition<CDOState, CDOEvent, InternalCDOObject, List<InternalCDOObject>>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
+ List<InternalCDOObject> objectsToDetach)
+ {
+ InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
+ objectsToDetach.add(object);
+ boolean isResource = object instanceof Resource;
+
+ // Prepare content tree
+ for (Iterator<EObject> it = object.eContents().iterator(); it.hasNext();)
+ {
+ InternalEObject eObject = (InternalEObject)it.next();
+ boolean isDirectlyConnected = isResource && eObject.eDirectResource() == object;
+ if (isDirectlyConnected || eObject.eDirectResource() == null)
+ {
+ InternalCDOObject content = FSMUtil.adapt(eObject, transaction);
+ if (content != null)
+ {
+ INSTANCE.process(content, CDOEvent.DETACH, objectsToDetach);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ final private class CommitTransition implements
+ ITransition<CDOState, CDOEvent, InternalCDOObject, CommitTransactionResult>
+ {
+ public CommitTransition(boolean useDeltas)
+ {
+ }
+
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, CommitTransactionResult data)
+ {
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ InternalCDORevision revision = object.cdoRevision();
+ Map<CDOID, CDOID> idMappings = data.getIDMappings();
+
+ // Adjust object
+ CDOID oldID = object.cdoID();
+ CDOID newID = idMappings.get(oldID);
+ if (newID != null)
+ {
+ object.cdoInternalSetID(newID);
+ transaction.remapObject(oldID);
+ revision.setID(newID);
+ }
+
+ // Adjust revision
+ revision.adjustForCommit(transaction.getBranch(), data.getTimeStamp());
+ revision.adjustReferences(data.getReferenceAdjuster());
+ revision.freeze();
+
+ InternalCDORevisionManager revisionManager = transaction.getSession().getRevisionManager();
+ revisionManager.addRevision(revision);
+
+ changeState(object, CDOState.CLEAN);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class RollbackTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
+ {
+ object.cdoInternalSetRevision(null);
+ changeState(object, CDOState.PROXY);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
+ {
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ InternalCDORevision cleanRevision = object.cdoRevision();
+ if (!cleanRevision.isWritable())
+ {
+ throw new NoPermissionException(cleanRevision);
+ }
+
+ transaction.getCleanRevisions().put(object, cleanRevision);
+
+ // Copy revision
+ InternalCDORevision revision = object.cdoRevision().copy();
+ object.cdoInternalSetRevision(revision);
+
+ transaction.registerDirty(object, (CDOFeatureDelta)featureDelta);
+ changeState(object, CDOState.DIRTY);
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class WriteNewTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
+ {
+ InternalCDORevision revision = object.cdoRevision();
+ if (!revision.isWritable())
+ {
+ throw new NoPermissionException(revision);
+ }
+
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class RewriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
+ {
+ InternalCDORevision revision = object.cdoRevision();
+ if (!revision.isWritable())
+ {
+ throw new NoPermissionException(revision);
+ }
+
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static class DetachRemoteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ static final DetachRemoteTransition INSTANCE = new DetachRemoteTransition();
+
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
+ {
+ CDOStateMachine.INSTANCE.changeState(object, CDOState.INVALID);
+
+ InternalCDOView view = object.cdoView();
+ view.deregisterObject(object);
+ object.cdoInternalPostDetach(true);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private class InvalidateTransition implements
+ ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<CDORevisionKey, Long>>
+ {
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> keyAndTime)
+ {
+ CDORevisionKey key = keyAndTime.getElement1();
+ InternalCDORevision oldRevision = object.cdoRevision();
+ if (key == null || key.getVersion() >= oldRevision.getVersion())
+ {
+ InternalCDOView view = object.cdoView();
+
+ CDORevisionKey newKey = null;
+ if (key != null)
+ {
+ int newVersion = getNewVersion(key);
+ newKey = CDORevisionUtil.createRevisionKey(key.getID(), key.getBranch(), newVersion);
+ }
+
+ InternalCDORevision newRevision = null;
+ if (newKey != null)
+ {
+ InternalCDORevisionCache cache = view.getSession().getRevisionManager().getCache();
+ newRevision = (InternalCDORevision)cache.getRevisionByVersion(newKey.getID(), newKey);
+ }
+
+ if (newRevision != null)
+ {
+ object.cdoInternalSetRevision(newRevision);
+ changeState(object, CDOState.CLEAN);
+ object.cdoInternalPostLoad();
+ }
+ else
+ {
+ changeState(object, CDOState.PROXY);
+
+ CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
+ policy.handleInvalidation(object, key);
+ object.cdoInternalPostInvalidate();
+ }
+ }
+ }
+
+ private int getNewVersion(CDORevisionKey key)
+ {
+ if (key instanceof CDORevisionDelta)
+ {
+ CDORevisionDelta delta = (CDORevisionDelta)key;
+ CDORevisable target = delta.getTarget();
+ if (target != null && key.getBranch() == target.getBranch())
+ {
+ return target.getVersion();
+ }
+ }
+
+ return key.getVersion() + 1;
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ private class ConflictTransition extends InvalidateTransition
+ {
+ @Override
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> keyAndTime)
+ {
+ CDORevisionKey key = keyAndTime.getElement1();
+ InternalCDORevision oldRevision = object.cdoRevision();
+ if (key == null || key.getVersion() >= oldRevision.getVersion() - 1)
+ {
+ changeState(object, CDOState.CONFLICT);
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ transaction.setConflict(object);
+ }
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private final class InvalidConflictTransition extends ConflictTransition
+ {
+ @Override
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Pair<CDORevisionKey, Long> UNUSED)
+ {
+ changeState(object, CDOState.INVALID_CONFLICT);
+
+ InternalCDOTransaction transaction = object.cdoView().toTransaction();
+ transaction.setConflict(object);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ private boolean forWrite;
+
+ public LoadTransition(boolean forWrite)
+ {
+ this.forWrite = forWrite;
+ }
+
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object delta)
+ {
+ object.cdoInternalPreLoad();
+
+ InternalCDOView view = object.cdoView();
+ InternalCDORevision revision = view.getRevision(object.cdoID(), true);
+ if (revision == null)
+ {
+ INSTANCE.detachRemote(object);
+ CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
+ policy.handleInvalidObject(object);
+ }
+
+ if (forWrite && !revision.isWritable())
+ {
+ throw new NoPermissionException(revision);
+ }
+
+ object.cdoInternalSetRevision(revision);
+ changeState(object, CDOState.CLEAN);
+ object.cdoInternalPostLoad();
+
+ if (view.options().isLoadNotificationEnabled())
+ {
+ try
+ {
+ CDONotificationBuilder builder = new CDONotificationBuilder(view);
+
+ NotificationChain notification = builder.buildNotification(object, revision);
+ if (notification != null)
+ {
+ notification.dispatch();
+ }
+ }
+ catch (PartialCollectionLoadingNotSupportedException ex)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace(ex);
+ }
+ }
+ }
+
+ if (forWrite)
+ {
+ INSTANCE.writeWithoutViewLock(object, (CDOFeatureDelta)delta);
+ }
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private static final class InvalidTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
+ {
+ public static final InvalidTransition INSTANCE = new InvalidTransition();
+
+ public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
+ {
+ InternalCDOView view = object.cdoView();
+ CDOInvalidationPolicy policy = view.options().getInvalidationPolicy();
+ policy.handleInvalidObject(object);
+ }
+ }
+}
+
+/**
+ * @author Eike Stepper
+ */
+enum CDOEvent
+{
+ PREPARE, ATTACH, DETACH, REATTACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, COMMIT, ROLLBACK
+}

Back to the top