diff options
author | Eike Stepper | 2012-05-01 10:06:14 +0000 |
---|---|---|
committer | Eike Stepper | 2012-05-01 10:06:14 +0000 |
commit | b4d78150e6b5b2277fa70ee3df3ccc1c2e6d2b48 (patch) | |
tree | db9fc0686e45436cb3ba6592fa236ee50ef611f8 /plugins | |
parent | 7698f3a56562e5e538ce5584e427ada9390b9e87 (diff) | |
parent | cbf2aed7453b7ac4e9282aba2910bce1bd1a75ff (diff) | |
download | cdo-b4d78150e6b5b2277fa70ee3df3ccc1c2e6d2b48.tar.gz cdo-b4d78150e6b5b2277fa70ee3df3ccc1c2e6d2b48.tar.xz cdo-b4d78150e6b5b2277fa70ee3df3ccc1c2e6d2b48.zip |
Merge branch 'master' into bugs/369646
Diffstat (limited to 'plugins')
33 files changed, 9558 insertions, 8785 deletions
diff --git a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF index 0b80784f1d..419b2d960b 100644 --- a/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.common/META-INF/MANIFEST.MF @@ -26,6 +26,7 @@ Export-Package: org.eclipse.emf.cdo.common;version="4.1.0", org.eclipse.emf.cdo.common.protocol;version="4.1.0", org.eclipse.emf.cdo.common.revision;version="4.1.0", org.eclipse.emf.cdo.common.revision.delta;version="4.1.0", + org.eclipse.emf.cdo.common.security;version="4.1.0", org.eclipse.emf.cdo.common.util;version="4.1.0", org.eclipse.emf.cdo.internal.common;version="4.1.0"; x-friends:="org.eclipse.emf.cdo.common, diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java index 0cb9d5915d..85be7ab966 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataInput.java @@ -1,167 +1,167 @@ -/*
- * 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.cdo.common.protocol;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
-import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDReference;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
-import org.eclipse.emf.cdo.common.lock.CDOLockState;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
-import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
-import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevisable;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.io.ExtendedDataInput;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-
-import java.io.IOException;
-
-/**
- * Provides I/O methods for reading various CDO data types and concepts from streams.
- *
- * @author Eike Stepper
- * @since 3.0
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface CDODataInput extends ExtendedDataInput
-{
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public CDOPackageUnit readCDOPackageUnit(ResourceSet resourceSet) throws IOException;
-
- public CDOPackageUnit[] readCDOPackageUnits(ResourceSet resourceSet) throws IOException;
-
- public CDOPackageUnit.Type readCDOPackageUnitType() throws IOException;
-
- public CDOPackageInfo readCDOPackageInfo() throws IOException;
-
- public CDOClassifierRef readCDOClassifierRef() throws IOException;
-
- public EClassifier readCDOClassifierRefAndResolve() throws IOException;
-
- public String readCDOPackageURI() throws IOException;
-
- public CDOType readCDOType() throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public CDOBranch readCDOBranch() throws IOException;
-
- public CDOBranchPoint readCDOBranchPoint() throws IOException;
-
- public CDOBranchVersion readCDOBranchVersion() throws IOException;
-
- public CDOChangeSetData readCDOChangeSetData() throws IOException;
-
- public CDOCommitData readCDOCommitData() throws IOException;
-
- public CDOCommitInfo readCDOCommitInfo() throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public CDOID readCDOID() throws IOException;
-
- /**
- * @since 4.0
- */
- public CDOIDReference readCDOIDReference() throws IOException;
-
- /**
- * @since 4.0
- */
- public CDOIDAndVersion readCDOIDAndVersion() throws IOException;
-
- /**
- * @since 4.0
- */
- public CDOIDAndBranch readCDOIDAndBranch() throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public CDORevisionKey readCDORevisionKey() throws IOException;
-
- public CDORevision readCDORevision() throws IOException;
-
- /**
- * @since 4.1
- */
- public CDORevision readCDORevision(boolean freeze) throws IOException;
-
- /**
- * @since 4.0
- */
- public CDORevisable readCDORevisable() throws IOException;
-
- public CDOList readCDOList(EClass owner, EStructuralFeature feature) throws IOException;
-
- public Object readCDOFeatureValue(EStructuralFeature feature) throws IOException;
-
- public CDORevisionDelta readCDORevisionDelta() throws IOException;
-
- public CDOFeatureDelta readCDOFeatureDelta(EClass owner) throws IOException;
-
- /**
- * Read either a CDORevision or a primitive value.
- */
- public Object readCDORevisionOrPrimitive() throws IOException;
-
- /**
- * Read either a CDORevision, a primitive value or a EClass.
- */
- public Object readCDORevisionOrPrimitiveOrClassifier() throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public LockType readCDOLockType() throws IOException;
-
- /**
- * @since 4.1
- */
- public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException;
-
- /**
- * @since 4.1
- */
- public CDOLockOwner readCDOLockOwner() throws IOException;
-
- /**
- * @since 4.1
- */
- public CDOLockState readCDOLockState() throws IOException;
-
- /**
- * @since 4.1
- */
- public LockArea readCDOLockArea() throws IOException;
-}
+/* + * 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.cdo.common.protocol; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.commit.CDOCommitData; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDReference; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOPackageInfo; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevisable; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionKey; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.io.ExtendedDataInput; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; + +import java.io.IOException; + +/** + * Provides I/O methods for reading various CDO data types and concepts from streams. + * + * @author Eike Stepper + * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface CDODataInput extends ExtendedDataInput +{ + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public CDOPackageUnit readCDOPackageUnit(ResourceSet resourceSet) throws IOException; + + public CDOPackageUnit[] readCDOPackageUnits(ResourceSet resourceSet) throws IOException; + + public CDOPackageUnit.Type readCDOPackageUnitType() throws IOException; + + public CDOPackageInfo readCDOPackageInfo() throws IOException; + + public CDOClassifierRef readCDOClassifierRef() throws IOException; + + public EClassifier readCDOClassifierRefAndResolve() throws IOException; + + public String readCDOPackageURI() throws IOException; + + public CDOType readCDOType() throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public CDOBranch readCDOBranch() throws IOException; + + public CDOBranchPoint readCDOBranchPoint() throws IOException; + + public CDOBranchVersion readCDOBranchVersion() throws IOException; + + public CDOChangeSetData readCDOChangeSetData() throws IOException; + + public CDOCommitData readCDOCommitData() throws IOException; + + public CDOCommitInfo readCDOCommitInfo() throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public CDOID readCDOID() throws IOException; + + /** + * @since 4.0 + */ + public CDOIDReference readCDOIDReference() throws IOException; + + /** + * @since 4.0 + */ + public CDOIDAndVersion readCDOIDAndVersion() throws IOException; + + /** + * @since 4.0 + */ + public CDOIDAndBranch readCDOIDAndBranch() throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public CDORevisionKey readCDORevisionKey() throws IOException; + + public CDORevision readCDORevision() throws IOException; + + /** + * @since 4.1 + */ + public CDORevision readCDORevision(boolean freeze) throws IOException; + + /** + * @since 4.0 + */ + public CDORevisable readCDORevisable() throws IOException; + + public CDOList readCDOList(EClass owner, EStructuralFeature feature) throws IOException; + + public Object readCDOFeatureValue(EStructuralFeature feature) throws IOException; + + public CDORevisionDelta readCDORevisionDelta() throws IOException; + + public CDOFeatureDelta readCDOFeatureDelta(EClass owner) throws IOException; + + /** + * Read either a CDORevision or a primitive value. + */ + public Object readCDORevisionOrPrimitive() throws IOException; + + /** + * Read either a CDORevision, a primitive value or a EClass. + */ + public Object readCDORevisionOrPrimitiveOrClassifier() throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public LockType readCDOLockType() throws IOException; + + /** + * @since 4.1 + */ + public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException; + + /** + * @since 4.1 + */ + public CDOLockOwner readCDOLockOwner() throws IOException; + + /** + * @since 4.1 + */ + public CDOLockState readCDOLockState() throws IOException; + + /** + * @since 4.1 + */ + public LockArea readCDOLockArea() throws IOException; +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java index 07f9aa4390..8f779ac388 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/protocol/CDODataOutput.java @@ -1,168 +1,174 @@ -/*
- * 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.cdo.common.protocol;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
-import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.id.CDOIDReference;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
-import org.eclipse.emf.cdo.common.lock.CDOLockState;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
-import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
-import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
-import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevisable;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.io.ExtendedDataOutput;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.io.IOException;
-
-/**
- * Provides I/O methods for writing various CDO data types and concepts to streams.
- *
- * @author Eike Stepper
- * @since 3.0
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface CDODataOutput extends ExtendedDataOutput
-{
- public CDOPackageRegistry getPackageRegistry();
-
- public CDOIDProvider getIDProvider();
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void writeCDOPackageUnit(CDOPackageUnit packageUnit, boolean withPackages) throws IOException;
-
- public void writeCDOPackageUnits(CDOPackageUnit... packageUnit) throws IOException;
-
- public void writeCDOPackageUnitType(CDOPackageUnit.Type type) throws IOException;
-
- public void writeCDOPackageInfo(CDOPackageInfo packageInfo) throws IOException;
-
- public void writeCDOClassifierRef(CDOClassifierRef eClassifierRef) throws IOException;
-
- public void writeCDOClassifierRef(EClassifier eClassifier) throws IOException;
-
- public void writeCDOPackageURI(String uri) throws IOException;
-
- public void writeCDOType(CDOType cdoType) throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void writeCDOBranch(CDOBranch branch) throws IOException;
-
- public void writeCDOBranchPoint(CDOBranchPoint branchPoint) throws IOException;
-
- public void writeCDOBranchVersion(CDOBranchVersion branchVersion) throws IOException;
-
- public void writeCDOChangeSetData(CDOChangeSetData changeSetData) throws IOException;
-
- public void writeCDOCommitData(CDOCommitData commitData) throws IOException;
-
- public void writeCDOCommitInfo(CDOCommitInfo commitInfo) throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void writeCDOID(CDOID id) throws IOException;
-
- /**
- * @since 4.0
- */
- public void writeCDOIDReference(CDOIDReference idReference) throws IOException;
-
- /**
- * @since 4.0
- */
- public void writeCDOIDAndVersion(CDOIDAndVersion idAndVersion) throws IOException;
-
- /**
- * @since 4.0
- */
- public void writeCDOIDAndBranch(CDOIDAndBranch idAndBranch) throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void writeCDORevisionKey(CDORevisionKey revisionKey) throws IOException;
-
- public void writeCDORevision(CDORevision revision, int referenceChunk) throws IOException;
-
- /**
- * @since 4.0
- */
- public void writeCDORevisable(CDORevisable revisable) throws IOException;
-
- public void writeCDOList(EClass owner, EStructuralFeature feature, CDOList list, int referenceChunk)
- throws IOException;
-
- public void writeCDOFeatureValue(EStructuralFeature feature, Object value) throws IOException;
-
- public void writeCDORevisionDelta(CDORevisionDelta revisionDelta) throws IOException;
-
- public void writeCDOFeatureDelta(EClass owner, CDOFeatureDelta featureDelta) throws IOException;
-
- /**
- * Write either a CDORevision or a primitive value.
- */
- public void writeCDORevisionOrPrimitive(Object value) throws IOException;
-
- /**
- * Write either a CDORevision, a primitive value or a EClass.
- */
- public void writeCDORevisionOrPrimitiveOrClassifier(Object value) throws IOException;
-
- // /////////////////////////////////////////////////////////////////////////////////////////////////
-
- public void writeCDOLockType(LockType lockType) throws IOException;
-
- /**
- * @since 4.1
- */
- public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException;
-
- /**
- * @since 4.1
- */
- public void writeCDOLockState(CDOLockState lockState) throws IOException;
-
- /**
- * @since 4.1
- */
- public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException;
-
- /**
- * @since 4.1
- */
- public void writeCDOLockArea(LockArea lockArea) throws IOException;
-}
+/* + * 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.cdo.common.protocol; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.commit.CDOCommitData; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.id.CDOIDReference; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOPackageInfo; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevisable; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionKey; +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.CDOPermissionProvider; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.io.ExtendedDataOutput; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.io.IOException; + +/** + * Provides I/O methods for writing various CDO data types and concepts to streams. + * + * @author Eike Stepper + * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface CDODataOutput extends ExtendedDataOutput +{ + public CDOPackageRegistry getPackageRegistry(); + + public CDOIDProvider getIDProvider(); + + /** + * @since 4.1 + */ + public CDOPermissionProvider getPermissionProvider(); + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public void writeCDOPackageUnit(CDOPackageUnit packageUnit, boolean withPackages) throws IOException; + + public void writeCDOPackageUnits(CDOPackageUnit... packageUnit) throws IOException; + + public void writeCDOPackageUnitType(CDOPackageUnit.Type type) throws IOException; + + public void writeCDOPackageInfo(CDOPackageInfo packageInfo) throws IOException; + + public void writeCDOClassifierRef(CDOClassifierRef eClassifierRef) throws IOException; + + public void writeCDOClassifierRef(EClassifier eClassifier) throws IOException; + + public void writeCDOPackageURI(String uri) throws IOException; + + public void writeCDOType(CDOType cdoType) throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public void writeCDOBranch(CDOBranch branch) throws IOException; + + public void writeCDOBranchPoint(CDOBranchPoint branchPoint) throws IOException; + + public void writeCDOBranchVersion(CDOBranchVersion branchVersion) throws IOException; + + public void writeCDOChangeSetData(CDOChangeSetData changeSetData) throws IOException; + + public void writeCDOCommitData(CDOCommitData commitData) throws IOException; + + public void writeCDOCommitInfo(CDOCommitInfo commitInfo) throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public void writeCDOID(CDOID id) throws IOException; + + /** + * @since 4.0 + */ + public void writeCDOIDReference(CDOIDReference idReference) throws IOException; + + /** + * @since 4.0 + */ + public void writeCDOIDAndVersion(CDOIDAndVersion idAndVersion) throws IOException; + + /** + * @since 4.0 + */ + public void writeCDOIDAndBranch(CDOIDAndBranch idAndBranch) throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public void writeCDORevisionKey(CDORevisionKey revisionKey) throws IOException; + + public void writeCDORevision(CDORevision revision, int referenceChunk) throws IOException; + + /** + * @since 4.0 + */ + public void writeCDORevisable(CDORevisable revisable) throws IOException; + + public void writeCDOList(EClass owner, EStructuralFeature feature, CDOList list, int referenceChunk) + throws IOException; + + public void writeCDOFeatureValue(EStructuralFeature feature, Object value) throws IOException; + + public void writeCDORevisionDelta(CDORevisionDelta revisionDelta) throws IOException; + + public void writeCDOFeatureDelta(EClass owner, CDOFeatureDelta featureDelta) throws IOException; + + /** + * Write either a CDORevision or a primitive value. + */ + public void writeCDORevisionOrPrimitive(Object value) throws IOException; + + /** + * Write either a CDORevision, a primitive value or a EClass. + */ + public void writeCDORevisionOrPrimitiveOrClassifier(Object value) throws IOException; + + // ///////////////////////////////////////////////////////////////////////////////////////////////// + + public void writeCDOLockType(LockType lockType) throws IOException; + + /** + * @since 4.1 + */ + public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException; + + /** + * @since 4.1 + */ + public void writeCDOLockState(CDOLockState lockState) throws IOException; + + /** + * @since 4.1 + */ + public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException; + + /** + * @since 4.1 + */ + public void writeCDOLockArea(LockArea lockArea) throws IOException; +} 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 cfb54d3a1d..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 @@ -1,103 +1,137 @@ -/*
- * 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 - delta support
- */
-package org.eclipse.emf.cdo.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-
-/**
- * Encapsulates the immutable system information of a <b>single</b> CDO {@link EObject object} between two
- * {@link CDOCommitInfo commits} in a {@link CDOBranch branch} and provides access to its modeled
- * {@link CDORevisionData data}.
- *
- * @author Eike Stepper
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- * @apiviz.landmark
- * @apiviz.has {@link CDORevisionData}
- */
-public interface CDORevision extends CDORevisionKey, CDORevisable
-{
- /**
- * @since 3.0
- */
- public static final int MAIN_BRANCH_ID = CDOBranch.MAIN_BRANCH_ID;
-
- /**
- * @since 3.0
- */
- public static final int FIRST_VERSION = CDOBranchVersion.FIRST_VERSION;
-
- public static final int UNCHUNKED = -1;
-
- /**
- * @since 3.0
- */
- public static final int DEPTH_NONE = 0;
-
- /**
- * @since 3.0
- */
- public static final int DEPTH_INFINITE = -1;
-
- /**
- * @since 2.0
- */
- public EClass getEClass();
-
- /**
- * Returns <code>true</code> exactly if {@link #getTimeStamp()} does not return {@link #UNSPECIFIED_DATE},
- * <code>false</code> otherwise.
- *
- * @since 3.0
- */
- public boolean isHistorical();
-
- public boolean isValid(long timeStamp);
-
- /**
- * @since 4.0
- */
- public boolean isValid(CDOBranchPoint branchPoint);
-
- /**
- * @since 2.0
- */
- public boolean isResourceNode();
-
- /**
- * @since 2.0
- */
- public boolean isResourceFolder();
-
- public boolean isResource();
-
- /**
- * @since 2.0
- */
- public CDORevisionData data();
-
- public CDORevisionDelta compare(CDORevision origin);
-
- public void merge(CDORevisionDelta delta);
-
- /**
- * @since 2.0
- */
- public CDORevision copy();
-}
+/* + * 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 - delta support + */ +package org.eclipse.emf.cdo.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +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.ecore.EClass; +import org.eclipse.emf.ecore.EObject; + +/** + * Encapsulates the immutable system information of a <b>single</b> CDO {@link EObject object} between two + * {@link CDOCommitInfo commits} in a {@link CDOBranch branch} and provides access to its modeled + * {@link CDORevisionData data}. + * + * @author Eike Stepper + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @apiviz.landmark + * @apiviz.has {@link CDORevisionData} + */ +public interface CDORevision extends CDORevisionKey, CDORevisable +{ + /** + * @since 3.0 + */ + public static final int MAIN_BRANCH_ID = CDOBranch.MAIN_BRANCH_ID; + + /** + * @since 3.0 + */ + public static final int FIRST_VERSION = CDOBranchVersion.FIRST_VERSION; + + public static final int UNCHUNKED = -1; + + /** + * @since 3.0 + */ + public static final int DEPTH_NONE = 0; + + /** + * @since 3.0 + */ + public static final int DEPTH_INFINITE = -1; + + /** + * @since 4.1 + */ + public static final CDOPermissionProvider PERMISSION_PROVIDER = new CDOPermissionProvider() + { + public CDOPermission getPermission(Object protectableObject) + { + if (protectableObject instanceof CDORevision) + { + CDORevision revision = (CDORevision)protectableObject; + return revision.getPermission(); + } + + return CDOPermission.NONE; + } + }; + + /** + * @since 2.0 + */ + public EClass getEClass(); + + /** + * Returns <code>true</code> exactly if {@link #getTimeStamp()} does not return {@link #UNSPECIFIED_DATE}, + * <code>false</code> otherwise. + * + * @since 3.0 + */ + public boolean isHistorical(); + + public boolean isValid(long timeStamp); + + /** + * @since 4.0 + */ + public boolean isValid(CDOBranchPoint branchPoint); + + /** + * @since 2.0 + */ + public boolean isResourceNode(); + + /** + * @since 2.0 + */ + public boolean isResourceFolder(); + + public boolean isResource(); + + /** + * @since 2.0 + */ + public CDORevisionData data(); + + public CDORevisionDelta compare(CDORevision origin); + + public void merge(CDORevisionDelta delta); + + /** + * @since 2.0 + */ + public CDORevision copy(); + + /** + * @since 4.1 + */ + public CDOPermission getPermission(); + + /** + * @since 4.1 + */ + public boolean isReadable(); + + /** + * @since 4.1 + */ + public boolean isWritable(); +} 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 new file mode 100644 index 0000000000..e101a9f2cc --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermission.java @@ -0,0 +1,64 @@ +/* + * 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; + +/** + * Describes the possible protection levels a protectable object may have. + * @author Eike Stepper + * @since 4.1 + */ +public enum CDOPermission +{ + NONE(0x00), READ(0x01), WRITE(0x03); + + private byte bits; + + private CDOPermission(int bits) + { + this.bits = (byte)bits; + } + + public byte getBits() + { + return bits; + } + + /** + * @since 4.1 + */ + public boolean isReadable() + { + return this != CDOPermission.NONE; + } + + /** + * @since 4.1 + */ + public boolean isWritable() + { + return this == CDOPermission.WRITE; + } + + public static CDOPermission get(int bits) + { + switch (bits) + { + case 0x00: + return NONE; + case 0x01: + return READ; + case 0x03: + return WRITE; + default: + throw new IllegalArgumentException("Invalid bits: " + bits); + } + } +} 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 new file mode 100644 index 0000000000..7bdfef532b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/CDOPermissionProvider.java @@ -0,0 +1,54 @@ +/* + * 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; + +/** + * Provides the protection level of protectable objects. + * + * @author Eike Stepper + * @since 4.1 + */ +public interface CDOPermissionProvider +{ + public static final CDOPermissionProvider NONE = new Constant(CDOPermission.NONE); + + public static final CDOPermissionProvider READ = new Constant(CDOPermission.READ); + + public static final CDOPermissionProvider WRITE = new Constant(CDOPermission.WRITE); + + public CDOPermission getPermission(Object protectableObject); + + /** + * Provides a constant protection level for all protectable entities. + * + * @author Eike Stepper + */ + public static final class Constant implements CDOPermissionProvider + { + private CDOPermission permission; + + private Constant(CDOPermission permission) + { + this.permission = permission; + } + + public CDOPermission getPermission(Object protectableObject) + { + return permission; + } + + @Override + public String toString() + { + return permission.toString(); + } + } +} 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 new file mode 100644 index 0000000000..8639adf069 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/NoPermissionException.java @@ -0,0 +1,40 @@ +/* + * 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; + +/** + * A {@link SecurityException security exception} indicating the lack of permission required to do something. + * + * @author Eike Stepper + * @since 4.1 + */ +public class NoPermissionException extends SecurityException +{ + private static final long serialVersionUID = 1L; + + private Object protectableObject; + + public NoPermissionException(Object protectableObject) + { + this(protectableObject, "No permission to access " + protectableObject); + } + + public NoPermissionException(Object protectableObject, String message) + { + super(message); + this.protectableObject = protectableObject; + } + + public Object getProtectableObject() + { + return protectableObject; + } +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/package-info.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/package-info.java new file mode 100644 index 0000000000..69f41cc39e --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/common/security/package-info.java @@ -0,0 +1,16 @@ +/* + * 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 + */ + +/** + * Common concepts for dealing with permissions and protectable entities. + */ +package org.eclipse.emf.cdo.common.security; + 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 9013a9485b..424704583f 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 @@ -1,651 +1,651 @@ -/*
- * 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 - bug 213402
- */
-package org.eclipse.emf.cdo.internal.common.protocol;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
-import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOID.Type;
-import org.eclipse.emf.cdo.common.id.CDOIDReference;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
-import org.eclipse.emf.cdo.common.lob.CDOLob;
-import org.eclipse.emf.cdo.common.lob.CDOLobStore;
-import org.eclipse.emf.cdo.common.lob.CDOLobUtil;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation;
-import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
-import org.eclipse.emf.cdo.common.lock.CDOLockState;
-import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
-import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
-import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDOListFactory;
-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.internal.common.bundle.OM;
-import org.eclipse.emf.cdo.internal.common.commit.CDOChangeSetDataImpl;
-import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl;
-import org.eclipse.emf.cdo.internal.common.commit.FailureCommitInfo;
-import org.eclipse.emf.cdo.internal.common.id.CDOIDExternalImpl;
-import org.eclipse.emf.cdo.internal.common.id.CDOIDObjectLongImpl;
-import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectExternalImpl;
-import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectImpl;
-import org.eclipse.emf.cdo.internal.common.lock.CDOLockAreaImpl;
-import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl;
-import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl;
-import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl;
-import org.eclipse.emf.cdo.internal.common.messages.Messages;
-import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndBranchImpl;
-import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndVersionImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOListFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl;
-import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
-import org.eclipse.emf.cdo.spi.common.id.AbstractCDOID;
-import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.io.ExtendedDataInput;
-import org.eclipse.net4j.util.io.StringIO;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.resource.ResourceSet;
-import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
-import org.eclipse.emf.ecore.util.FeatureMapUtil;
-
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author Eike Stepper
- */
-public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating implements CDODataInput
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, CDODataInputImpl.class);
-
- public CDODataInputImpl(ExtendedDataInput delegate)
- {
- super(delegate);
- }
-
- public CDOPackageUnit readCDOPackageUnit(ResourceSet resourceSet) throws IOException
- {
- InternalCDOPackageUnit packageUnit = (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit();
- packageUnit.read(this, resourceSet);
- return packageUnit;
- }
-
- public CDOPackageUnit[] readCDOPackageUnits(ResourceSet resourceSet) throws IOException
- {
- int size = readInt();
- if (TRACER.isEnabled())
- {
- TRACER.format("Reading {0} package units", size); //$NON-NLS-1$
- }
-
- CDOPackageUnit[] packageUnits = new CDOPackageUnit[size];
- for (int i = 0; i < size; i++)
- {
- packageUnits[i] = readCDOPackageUnit(resourceSet);
- }
-
- return packageUnits;
- }
-
- public CDOPackageUnit.Type readCDOPackageUnitType() throws IOException
- {
- return CDOPackageUnit.Type.values()[readByte()];
- }
-
- public CDOPackageInfo readCDOPackageInfo() throws IOException
- {
- InternalCDOPackageInfo packageInfo = (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo();
- packageInfo.read(this);
- return packageInfo;
- }
-
- public String readCDOPackageURI() throws IOException
- {
- return getPackageURICompressor().read(this);
- }
-
- public CDOClassifierRef readCDOClassifierRef() throws IOException
- {
- return new CDOClassifierRef(this);
- }
-
- public EClassifier readCDOClassifierRefAndResolve() throws IOException
- {
- CDOClassifierRef classifierRef = readCDOClassifierRef();
- EClassifier classifier = classifierRef.resolve(getPackageRegistry());
- if (classifier == null)
- {
- throw new IOException("Unable to resolve " + classifierRef);
- }
-
- return classifier;
- }
-
- public CDOType readCDOType() throws IOException
- {
- byte typeID = readByte();
- return CDOModelUtil.getType(typeID);
- }
-
- public CDOBranch readCDOBranch() throws IOException
- {
- int branchID = readInt();
- return getBranchManager().getBranch(branchID);
- }
-
- public CDOBranchPoint readCDOBranchPoint() throws IOException
- {
- CDOBranch branch = readCDOBranch();
- long timeStamp = readLong();
- return branch.getPoint(timeStamp);
- }
-
- public CDOBranchVersion readCDOBranchVersion() throws IOException
- {
- CDOBranch branch = readCDOBranch();
- int version = readInt();
- return branch.getVersion(version);
- }
-
- public CDOChangeSetData readCDOChangeSetData() throws IOException
- {
- int size1 = readInt();
- List<CDOIDAndVersion> newObjects = new ArrayList<CDOIDAndVersion>(size1);
- for (int i = 0; i < size1; i++)
- {
- boolean revision = readBoolean();
- CDOIDAndVersion data = revision ? readCDORevision() : readCDOIDAndVersion();
- newObjects.add(data);
- }
-
- int size2 = readInt();
- List<CDORevisionKey> changedObjects = new ArrayList<CDORevisionKey>(size2);
- for (int i = 0; i < size2; i++)
- {
- boolean delta = readBoolean();
- CDORevisionKey data = delta ? readCDORevisionDelta() : readCDORevisionKey();
- changedObjects.add(data);
- }
-
- int size3 = readInt();
- List<CDOIDAndVersion> detachedObjects = new ArrayList<CDOIDAndVersion>(size3);
- for (int i = 0; i < size3; i++)
- {
- CDOIDAndVersion data = readCDOIDAndVersion();
- detachedObjects.add(data);
- }
-
- return new CDOChangeSetDataImpl(newObjects, changedObjects, detachedObjects);
- }
-
- public CDOCommitData readCDOCommitData() throws IOException
- {
- InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getPackageRegistry();
- ResourceSet resourceSet = new ResourceSetImpl();
- resourceSet.setPackageRegistry(packageRegistry);
-
- int size = readInt();
- List<CDOPackageUnit> newPackageUnits = new ArrayList<CDOPackageUnit>(size);
- for (int i = 0; i < size; i++)
- {
- CDOPackageUnit data = readCDOPackageUnit(resourceSet);
- newPackageUnits.add(data);
- packageRegistry.putPackageUnit((InternalCDOPackageUnit)data);
- }
-
- CDOChangeSetData data = readCDOChangeSetData();
- return new CDOCommitDataImpl(newPackageUnits, data.getNewObjects(), data.getChangedObjects(),
- data.getDetachedObjects());
- }
-
- public CDOCommitInfo readCDOCommitInfo() throws IOException
- {
- long timeStamp = readLong();
- long previousTimeStamp = readLong();
-
- if (readBoolean())
- {
- CDOBranch branch = readCDOBranch();
- String userID = readString();
- String comment = readString();
- CDOCommitData commitData = readCDOCommitData();
-
- InternalCDOCommitInfoManager commitInfoManager = (InternalCDOCommitInfoManager)getCommitInfoManager();
- return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData);
- }
-
- return new FailureCommitInfo(timeStamp, previousTimeStamp);
- }
-
- public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException
- {
- boolean isInvalidateAll = readBoolean();
- if (isInvalidateAll)
- {
- return CDOLockUtil.createLockChangeInfo();
- }
-
- CDOBranchPoint branchPoint = readCDOBranchPoint();
- CDOLockOwner lockOwner = readCDOLockOwner();
- Operation operation = readEnum(Operation.class);
- LockType lockType = readCDOLockType();
-
- int n = readInt();
- CDOLockState[] lockStates = new CDOLockState[n];
- for (int i = 0; i < n; i++)
- {
- lockStates[i] = readCDOLockState();
- }
-
- return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation, lockType);
- }
-
- public LockArea readCDOLockArea() throws IOException
- {
- String durableLockingID = readString();
- CDOBranch branch = readCDOBranch();
- long timestamp = readLong();
- String userID = readString();
- boolean readOnly = readBoolean();
-
- int nLockStates = readInt();
- Map<CDOID, LockGrade> locks = new HashMap<CDOID, LockGrade>();
- for (int i = 0; i < nLockStates; i++)
- {
- CDOID key = readCDOID();
- LockGrade value = readEnum(LockGrade.class);
- locks.put(key, value);
- }
-
- return new CDOLockAreaImpl(durableLockingID, userID, branch.getPoint(timestamp), readOnly, locks);
- }
-
- public CDOLockOwner readCDOLockOwner() throws IOException
- {
- int session = readInt();
- int view = readInt();
- String lockAreaID = readString();
- boolean isDurableView = readBoolean();
- return new CDOLockOwnerImpl(session, view, lockAreaID, isDurableView);
- }
-
- public CDOLockState readCDOLockState() throws IOException
- {
- Object target;
- boolean sendingBranchWithID = readBoolean();
- if (!sendingBranchWithID)
- {
- target = readCDOID();
- }
- else
- {
- target = readCDOIDAndBranch();
- }
-
- InternalCDOLockState lockState = new CDOLockStateImpl(target);
-
- int nReadLockOwners = readInt();
- for (int i = 0; i < nReadLockOwners; i++)
- {
- CDOLockOwner lockOwner = readCDOLockOwner();
- lockState.addReadLockOwner(lockOwner);
- }
-
- boolean hasWriteLock = readBoolean();
- if (hasWriteLock)
- {
- CDOLockOwner lockOwner = readCDOLockOwner();
- lockState.setWriteLockOwner(lockOwner);
- }
-
- boolean hasWriteOption = readBoolean();
- if (hasWriteOption)
- {
- CDOLockOwner lockOwner = readCDOLockOwner();
- lockState.setWriteOptionOwner(lockOwner);
- }
-
- return lockState;
- }
-
- public LockType readCDOLockType() throws IOException
- {
- return readEnum(LockType.class);
- }
-
- public CDOID readCDOID() throws IOException
- {
- byte ordinal = readByte();
-
- // A subtype of OBJECT
- if (ordinal < 0)
- {
- // The ordinal value is negated in the stream to distinguish from the main type.
- // Note: Added 1 because ordinal start at 0, so correct by minus 1.
- return readCDOIDObject(-ordinal - 1);
- }
-
- if (TRACER.isEnabled())
- {
- String type;
- try
- {
- type = Type.values()[ordinal].toString();
- }
- catch (RuntimeException ex)
- {
- type = ex.getMessage();
- }
-
- TRACER.format("Reading CDOID of type {0} ({1})", ordinal, type); //$NON-NLS-1$
- }
-
- Type type = Type.values()[ordinal];
- switch (type)
- {
- case NULL:
- return CDOID.NULL;
-
- case TEMP_OBJECT:
- return new CDOIDTempObjectImpl(readInt());
-
- case EXTERNAL_OBJECT:
- return new CDOIDExternalImpl(readString());
-
- case EXTERNAL_TEMP_OBJECT:
- return new CDOIDTempObjectExternalImpl(readString());
-
- case OBJECT:
- {
- // should normally not occur is handled by
- // readCDOIDObject, code remains here
- // for backward compatibility
- AbstractCDOID id = new CDOIDObjectLongImpl();
- id.read(this);
- return id;
- }
-
- default:
- throw new IOException("Illegal type: " + type);
- }
- }
-
- private CDOID readCDOIDObject(int subTypeOrdinal) throws IOException
- {
- if (TRACER.isEnabled())
- {
- String subType;
-
- try
- {
- subType = CDOID.ObjectType.values()[subTypeOrdinal].toString();
- }
- catch (RuntimeException ex)
- {
- subType = ex.getMessage();
- }
-
- TRACER.format("Reading CDOIDObject of sub type {0} ({1})", subTypeOrdinal, subType); //$NON-NLS-1$
- }
-
- CDOID.ObjectType subType = CDOID.ObjectType.values()[subTypeOrdinal];
- AbstractCDOID id = CDOIDUtil.createCDOIDObject(subType);
- id.read(this);
- return id;
- }
-
- public CDOIDReference readCDOIDReference() throws IOException
- {
- return new CDOIDReference(this);
- }
-
- public CDOIDAndVersion readCDOIDAndVersion() throws IOException
- {
- CDOID id = readCDOID();
- int version = readInt();
- return new CDOIDAndVersionImpl(id, version);
- }
-
- public CDOIDAndBranch readCDOIDAndBranch() throws IOException
- {
- CDOID id = readCDOID();
- CDOBranch branch = readCDOBranch();
- return new CDOIDAndBranchImpl(id, branch);
- }
-
- public CDORevisionKey readCDORevisionKey() throws IOException
- {
- CDOID id = readCDOID();
- CDOBranch branch = readCDOBranch();
- int version = readInt();
- return CDORevisionUtil.createRevisionKey(id, branch, version);
- }
-
- public CDORevision readCDORevision() throws IOException
- {
- return readCDORevision(true);
- }
-
- public CDORevision readCDORevision(boolean freeze) throws IOException
- {
- boolean notNull = readBoolean();
- if (notNull)
- {
- InternalCDORevision revision = (InternalCDORevision)getRevisionFactory().createRevision(null);
- revision.read(this);
-
- if (freeze)
- {
- revision.freeze();
- }
-
- return revision;
- }
-
- return null;
- }
-
- public CDORevisable readCDORevisable() throws IOException
- {
- CDOBranch branch = readCDOBranch();
- int version = readInt();
- long timeStamp = readLong();
- long revised = readLong();
- return CDORevisionUtil.createRevisable(branch, version, timeStamp, revised);
- }
-
- public CDOList readCDOList(EClass owner, EStructuralFeature feature) throws IOException
- {
- int referenceChunk;
- int size = readInt();
- if (size < 0)
- {
- size = -size;
- referenceChunk = readInt();
- if (TRACER.isEnabled())
- {
- TRACER.format("Read feature {0}: size={1}, referenceChunk={2}", feature.getName(), size, referenceChunk); //$NON-NLS-1$
- }
- }
- else
- {
- referenceChunk = size;
- if (TRACER.isEnabled())
- {
- TRACER.format("Read feature {0}: size={1}", feature.getName(), size); //$NON-NLS-1$
- }
- }
-
- Object value = null;
- CDOType type = null;
- boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature);
- if (!isFeatureMap)
- {
- type = CDOModelUtil.getType(feature.getEType());
- }
-
- InternalCDOList list = (InternalCDOList)getListFactory().createList(size, size, referenceChunk);
- for (int j = 0; j < referenceChunk; j++)
- {
- if (isFeatureMap)
- {
- int featureID = readInt();
- EStructuralFeature innerFeature = owner.getEStructuralFeature(featureID);
- type = CDOModelUtil.getType(innerFeature.getEType());
- value = type.readValue(this);
- value = CDORevisionUtil.createFeatureMapEntry(innerFeature, value);
- }
- else
- {
- value = type.readValue(this);
- }
-
- list.set(j, value);
- if (TRACER.isEnabled())
- {
- TRACER.trace(" " + value); //$NON-NLS-1$
- }
- }
-
- return list;
- }
-
- public Object readCDOFeatureValue(EStructuralFeature feature) throws IOException
- {
- CDOType type = CDOModelUtil.getType(feature);
- Object value = type.readValue(this);
- if (value instanceof CDOLob<?>)
- {
- CDOLob<?> lob = (CDOLob<?>)value;
- CDOLobUtil.setStore(getLobStore(), lob);
- }
-
- return value;
- }
-
- public CDORevisionDelta readCDORevisionDelta() throws IOException
- {
- return new CDORevisionDeltaImpl(this);
- }
-
- public CDOFeatureDelta readCDOFeatureDelta(EClass owner) throws IOException
- {
- int typeOrdinal = readInt();
- CDOFeatureDelta.Type type = CDOFeatureDelta.Type.values()[typeOrdinal];
- switch (type)
- {
- case ADD:
- return new CDOAddFeatureDeltaImpl(this, owner);
-
- case SET:
- return new CDOSetFeatureDeltaImpl(this, owner);
-
- case LIST:
- return new CDOListFeatureDeltaImpl(this, owner);
-
- case MOVE:
- return new CDOMoveFeatureDeltaImpl(this, owner);
-
- case CLEAR:
- return new CDOClearFeatureDeltaImpl(this, owner);
-
- case REMOVE:
- return new CDORemoveFeatureDeltaImpl(this, owner);
-
- case CONTAINER:
- return new CDOContainerFeatureDeltaImpl(this, owner);
-
- case UNSET:
- return new CDOUnsetFeatureDeltaImpl(this, owner);
-
- default:
- throw new IOException(MessageFormat.format(Messages.getString("CDODataInputImpl.5"), typeOrdinal)); //$NON-NLS-1$
- }
- }
-
- public Object readCDORevisionOrPrimitive() throws IOException
- {
- CDOType type = readCDOType();
- return type.readValue(this);
- }
-
- public Object readCDORevisionOrPrimitiveOrClassifier() throws IOException
- {
- boolean isClassifier = readBoolean();
- if (isClassifier)
- {
- return readCDOClassifierRefAndResolve();
- }
-
- return readCDORevisionOrPrimitive();
- }
-
- protected StringIO getPackageURICompressor()
- {
- return StringIO.DIRECT;
- }
-
- protected abstract CDOPackageRegistry getPackageRegistry();
-
- protected abstract CDOBranchManager getBranchManager();
-
- protected abstract CDOCommitInfoManager getCommitInfoManager();
-
- protected abstract CDORevisionFactory getRevisionFactory();
-
- protected abstract CDOListFactory getListFactory();
-
- protected abstract CDOLobStore getLobStore();
-}
+/* + * 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 - bug 213402 + */ +package org.eclipse.emf.cdo.internal.common.protocol; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchManager; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.commit.CDOCommitData; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOID.Type; +import org.eclipse.emf.cdo.common.id.CDOIDReference; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lob.CDOLob; +import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.lob.CDOLobUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageInfo; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDOListFactory; +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.internal.common.bundle.OM; +import org.eclipse.emf.cdo.internal.common.commit.CDOChangeSetDataImpl; +import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl; +import org.eclipse.emf.cdo.internal.common.commit.FailureCommitInfo; +import org.eclipse.emf.cdo.internal.common.id.CDOIDExternalImpl; +import org.eclipse.emf.cdo.internal.common.id.CDOIDObjectLongImpl; +import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectExternalImpl; +import org.eclipse.emf.cdo.internal.common.id.CDOIDTempObjectImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockAreaImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockChangeInfoImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockOwnerImpl; +import org.eclipse.emf.cdo.internal.common.lock.CDOLockStateImpl; +import org.eclipse.emf.cdo.internal.common.messages.Messages; +import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndBranchImpl; +import org.eclipse.emf.cdo.internal.common.revision.CDOIDAndVersionImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOListFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl; +import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager; +import org.eclipse.emf.cdo.spi.common.id.AbstractCDOID; +import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.io.ExtendedDataInput; +import org.eclipse.net4j.util.io.StringIO; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.util.FeatureMapUtil; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public abstract class CDODataInputImpl extends ExtendedDataInput.Delegating implements CDODataInput +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, CDODataInputImpl.class); + + public CDODataInputImpl(ExtendedDataInput delegate) + { + super(delegate); + } + + public CDOPackageUnit readCDOPackageUnit(ResourceSet resourceSet) throws IOException + { + InternalCDOPackageUnit packageUnit = (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); + packageUnit.read(this, resourceSet); + return packageUnit; + } + + public CDOPackageUnit[] readCDOPackageUnits(ResourceSet resourceSet) throws IOException + { + int size = readInt(); + if (TRACER.isEnabled()) + { + TRACER.format("Reading {0} package units", size); //$NON-NLS-1$ + } + + CDOPackageUnit[] packageUnits = new CDOPackageUnit[size]; + for (int i = 0; i < size; i++) + { + packageUnits[i] = readCDOPackageUnit(resourceSet); + } + + return packageUnits; + } + + public CDOPackageUnit.Type readCDOPackageUnitType() throws IOException + { + return CDOPackageUnit.Type.values()[readByte()]; + } + + public CDOPackageInfo readCDOPackageInfo() throws IOException + { + InternalCDOPackageInfo packageInfo = (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); + packageInfo.read(this); + return packageInfo; + } + + public String readCDOPackageURI() throws IOException + { + return getPackageURICompressor().read(this); + } + + public CDOClassifierRef readCDOClassifierRef() throws IOException + { + return new CDOClassifierRef(this); + } + + public EClassifier readCDOClassifierRefAndResolve() throws IOException + { + CDOClassifierRef classifierRef = readCDOClassifierRef(); + EClassifier classifier = classifierRef.resolve(getPackageRegistry()); + if (classifier == null) + { + throw new IOException("Unable to resolve " + classifierRef); + } + + return classifier; + } + + public CDOType readCDOType() throws IOException + { + byte typeID = readByte(); + return CDOModelUtil.getType(typeID); + } + + public CDOBranch readCDOBranch() throws IOException + { + int branchID = readInt(); + return getBranchManager().getBranch(branchID); + } + + public CDOBranchPoint readCDOBranchPoint() throws IOException + { + CDOBranch branch = readCDOBranch(); + long timeStamp = readLong(); + return branch.getPoint(timeStamp); + } + + public CDOBranchVersion readCDOBranchVersion() throws IOException + { + CDOBranch branch = readCDOBranch(); + int version = readInt(); + return branch.getVersion(version); + } + + public CDOChangeSetData readCDOChangeSetData() throws IOException + { + int size1 = readInt(); + List<CDOIDAndVersion> newObjects = new ArrayList<CDOIDAndVersion>(size1); + for (int i = 0; i < size1; i++) + { + boolean revision = readBoolean(); + CDOIDAndVersion data = revision ? readCDORevision() : readCDOIDAndVersion(); + newObjects.add(data); + } + + int size2 = readInt(); + List<CDORevisionKey> changedObjects = new ArrayList<CDORevisionKey>(size2); + for (int i = 0; i < size2; i++) + { + boolean delta = readBoolean(); + CDORevisionKey data = delta ? readCDORevisionDelta() : readCDORevisionKey(); + changedObjects.add(data); + } + + int size3 = readInt(); + List<CDOIDAndVersion> detachedObjects = new ArrayList<CDOIDAndVersion>(size3); + for (int i = 0; i < size3; i++) + { + CDOIDAndVersion data = readCDOIDAndVersion(); + detachedObjects.add(data); + } + + return new CDOChangeSetDataImpl(newObjects, changedObjects, detachedObjects); + } + + public CDOCommitData readCDOCommitData() throws IOException + { + InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getPackageRegistry(); + ResourceSet resourceSet = new ResourceSetImpl(); + resourceSet.setPackageRegistry(packageRegistry); + + int size = readInt(); + List<CDOPackageUnit> newPackageUnits = new ArrayList<CDOPackageUnit>(size); + for (int i = 0; i < size; i++) + { + CDOPackageUnit data = readCDOPackageUnit(resourceSet); + newPackageUnits.add(data); + packageRegistry.putPackageUnit((InternalCDOPackageUnit)data); + } + + CDOChangeSetData data = readCDOChangeSetData(); + return new CDOCommitDataImpl(newPackageUnits, data.getNewObjects(), data.getChangedObjects(), + data.getDetachedObjects()); + } + + public CDOCommitInfo readCDOCommitInfo() throws IOException + { + long timeStamp = readLong(); + long previousTimeStamp = readLong(); + + if (readBoolean()) + { + CDOBranch branch = readCDOBranch(); + String userID = readString(); + String comment = readString(); + CDOCommitData commitData = readCDOCommitData(); + + InternalCDOCommitInfoManager commitInfoManager = (InternalCDOCommitInfoManager)getCommitInfoManager(); + return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData); + } + + return new FailureCommitInfo(timeStamp, previousTimeStamp); + } + + public CDOLockChangeInfo readCDOLockChangeInfo() throws IOException + { + boolean isInvalidateAll = readBoolean(); + if (isInvalidateAll) + { + return CDOLockUtil.createLockChangeInfo(); + } + + CDOBranchPoint branchPoint = readCDOBranchPoint(); + CDOLockOwner lockOwner = readCDOLockOwner(); + Operation operation = readEnum(Operation.class); + LockType lockType = readCDOLockType(); + + int n = readInt(); + CDOLockState[] lockStates = new CDOLockState[n]; + for (int i = 0; i < n; i++) + { + lockStates[i] = readCDOLockState(); + } + + return new CDOLockChangeInfoImpl(branchPoint, lockOwner, lockStates, operation, lockType); + } + + public LockArea readCDOLockArea() throws IOException + { + String durableLockingID = readString(); + CDOBranch branch = readCDOBranch(); + long timestamp = readLong(); + String userID = readString(); + boolean readOnly = readBoolean(); + + int nLockStates = readInt(); + Map<CDOID, LockGrade> locks = new HashMap<CDOID, LockGrade>(); + for (int i = 0; i < nLockStates; i++) + { + CDOID key = readCDOID(); + LockGrade value = readEnum(LockGrade.class); + locks.put(key, value); + } + + return new CDOLockAreaImpl(durableLockingID, userID, branch.getPoint(timestamp), readOnly, locks); + } + + public CDOLockOwner readCDOLockOwner() throws IOException + { + int session = readInt(); + int view = readInt(); + String lockAreaID = readString(); + boolean isDurableView = readBoolean(); + return new CDOLockOwnerImpl(session, view, lockAreaID, isDurableView); + } + + public CDOLockState readCDOLockState() throws IOException + { + Object target; + boolean sendingBranchWithID = readBoolean(); + if (!sendingBranchWithID) + { + target = readCDOID(); + } + else + { + target = readCDOIDAndBranch(); + } + + InternalCDOLockState lockState = new CDOLockStateImpl(target); + + int nReadLockOwners = readInt(); + for (int i = 0; i < nReadLockOwners; i++) + { + CDOLockOwner lockOwner = readCDOLockOwner(); + lockState.addReadLockOwner(lockOwner); + } + + boolean hasWriteLock = readBoolean(); + if (hasWriteLock) + { + CDOLockOwner lockOwner = readCDOLockOwner(); + lockState.setWriteLockOwner(lockOwner); + } + + boolean hasWriteOption = readBoolean(); + if (hasWriteOption) + { + CDOLockOwner lockOwner = readCDOLockOwner(); + lockState.setWriteOptionOwner(lockOwner); + } + + return lockState; + } + + public LockType readCDOLockType() throws IOException + { + return readEnum(LockType.class); + } + + public CDOID readCDOID() throws IOException + { + byte ordinal = readByte(); + + // A subtype of OBJECT + if (ordinal < 0) + { + // The ordinal value is negated in the stream to distinguish from the main type. + // Note: Added 1 because ordinal start at 0, so correct by minus 1. + return readCDOIDObject(-ordinal - 1); + } + + if (TRACER.isEnabled()) + { + String type; + try + { + type = Type.values()[ordinal].toString(); + } + catch (RuntimeException ex) + { + type = ex.getMessage(); + } + + TRACER.format("Reading CDOID of type {0} ({1})", ordinal, type); //$NON-NLS-1$ + } + + Type type = Type.values()[ordinal]; + switch (type) + { + case NULL: + return CDOID.NULL; + + case TEMP_OBJECT: + return new CDOIDTempObjectImpl(readInt()); + + case EXTERNAL_OBJECT: + return new CDOIDExternalImpl(readString()); + + case EXTERNAL_TEMP_OBJECT: + return new CDOIDTempObjectExternalImpl(readString()); + + case OBJECT: + { + // should normally not occur is handled by + // readCDOIDObject, code remains here + // for backward compatibility + AbstractCDOID id = new CDOIDObjectLongImpl(); + id.read(this); + return id; + } + + default: + throw new IOException("Illegal type: " + type); + } + } + + private CDOID readCDOIDObject(int subTypeOrdinal) throws IOException + { + if (TRACER.isEnabled()) + { + String subType; + + try + { + subType = CDOID.ObjectType.values()[subTypeOrdinal].toString(); + } + catch (RuntimeException ex) + { + subType = ex.getMessage(); + } + + TRACER.format("Reading CDOIDObject of sub type {0} ({1})", subTypeOrdinal, subType); //$NON-NLS-1$ + } + + CDOID.ObjectType subType = CDOID.ObjectType.values()[subTypeOrdinal]; + AbstractCDOID id = CDOIDUtil.createCDOIDObject(subType); + id.read(this); + return id; + } + + public CDOIDReference readCDOIDReference() throws IOException + { + return new CDOIDReference(this); + } + + public CDOIDAndVersion readCDOIDAndVersion() throws IOException + { + CDOID id = readCDOID(); + int version = readInt(); + return new CDOIDAndVersionImpl(id, version); + } + + public CDOIDAndBranch readCDOIDAndBranch() throws IOException + { + CDOID id = readCDOID(); + CDOBranch branch = readCDOBranch(); + return new CDOIDAndBranchImpl(id, branch); + } + + public CDORevisionKey readCDORevisionKey() throws IOException + { + CDOID id = readCDOID(); + CDOBranch branch = readCDOBranch(); + int version = readInt(); + return CDORevisionUtil.createRevisionKey(id, branch, version); + } + + public CDORevision readCDORevision() throws IOException + { + return readCDORevision(true); + } + + public CDORevision readCDORevision(boolean freeze) throws IOException + { + boolean notNull = readBoolean(); + if (notNull) + { + InternalCDORevision revision = (InternalCDORevision)getRevisionFactory().createRevision(null); + revision.read(this); + + if (freeze) + { + revision.freeze(); + } + + return revision; + } + + return null; + } + + public CDORevisable readCDORevisable() throws IOException + { + CDOBranch branch = readCDOBranch(); + int version = readInt(); + long timeStamp = readLong(); + long revised = readLong(); + return CDORevisionUtil.createRevisable(branch, version, timeStamp, revised); + } + + public CDOList readCDOList(EClass owner, EStructuralFeature feature) throws IOException + { + int referenceChunk; + int size = readInt(); + if (size < 0) + { + size = -size; + referenceChunk = readInt(); + if (TRACER.isEnabled()) + { + TRACER.format("Read feature {0}: size={1}, referenceChunk={2}", feature.getName(), size, referenceChunk); //$NON-NLS-1$ + } + } + else + { + referenceChunk = size; + if (TRACER.isEnabled()) + { + TRACER.format("Read feature {0}: size={1}", feature.getName(), size); //$NON-NLS-1$ + } + } + + Object value = null; + CDOType type = null; + boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); + if (!isFeatureMap) + { + type = CDOModelUtil.getType(feature.getEType()); + } + + InternalCDOList list = (InternalCDOList)getListFactory().createList(size, size, referenceChunk); + for (int j = 0; j < referenceChunk; j++) + { + if (isFeatureMap) + { + int featureID = readInt(); + EStructuralFeature innerFeature = owner.getEStructuralFeature(featureID); + type = CDOModelUtil.getType(innerFeature.getEType()); + value = type.readValue(this); + value = CDORevisionUtil.createFeatureMapEntry(innerFeature, value); + } + else + { + value = type.readValue(this); + } + + list.set(j, value); + if (TRACER.isEnabled()) + { + TRACER.trace(" " + value); //$NON-NLS-1$ + } + } + + return list; + } + + public Object readCDOFeatureValue(EStructuralFeature feature) throws IOException + { + CDOType type = CDOModelUtil.getType(feature); + Object value = type.readValue(this); + if (value instanceof CDOLob<?>) + { + CDOLob<?> lob = (CDOLob<?>)value; + CDOLobUtil.setStore(getLobStore(), lob); + } + + return value; + } + + public CDORevisionDelta readCDORevisionDelta() throws IOException + { + return new CDORevisionDeltaImpl(this); + } + + public CDOFeatureDelta readCDOFeatureDelta(EClass owner) throws IOException + { + int typeOrdinal = readInt(); + CDOFeatureDelta.Type type = CDOFeatureDelta.Type.values()[typeOrdinal]; + switch (type) + { + case ADD: + return new CDOAddFeatureDeltaImpl(this, owner); + + case SET: + return new CDOSetFeatureDeltaImpl(this, owner); + + case LIST: + return new CDOListFeatureDeltaImpl(this, owner); + + case MOVE: + return new CDOMoveFeatureDeltaImpl(this, owner); + + case CLEAR: + return new CDOClearFeatureDeltaImpl(this, owner); + + case REMOVE: + return new CDORemoveFeatureDeltaImpl(this, owner); + + case CONTAINER: + return new CDOContainerFeatureDeltaImpl(this, owner); + + case UNSET: + return new CDOUnsetFeatureDeltaImpl(this, owner); + + default: + throw new IOException(MessageFormat.format(Messages.getString("CDODataInputImpl.5"), typeOrdinal)); //$NON-NLS-1$ + } + } + + public Object readCDORevisionOrPrimitive() throws IOException + { + CDOType type = readCDOType(); + return type.readValue(this); + } + + public Object readCDORevisionOrPrimitiveOrClassifier() throws IOException + { + boolean isClassifier = readBoolean(); + if (isClassifier) + { + return readCDOClassifierRefAndResolve(); + } + + return readCDORevisionOrPrimitive(); + } + + protected StringIO getPackageURICompressor() + { + return StringIO.DIRECT; + } + + protected abstract CDOPackageRegistry getPackageRegistry(); + + protected abstract CDOBranchManager getBranchManager(); + + protected abstract CDOCommitInfoManager getCommitInfoManager(); + + protected abstract CDORevisionFactory getRevisionFactory(); + + protected abstract CDOListFactory getListFactory(); + + protected abstract CDOLobStore getLobStore(); +} diff --git a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java index 3853a9f162..da29833eab 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/internal/common/protocol/CDODataOutputImpl.java @@ -1,560 +1,566 @@ -/*
- * 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.internal.common.protocol;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
-import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.id.CDOIDReference;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
-import org.eclipse.emf.cdo.common.lock.CDOLockState;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea;
-import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade;
-import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOPackageInfo;
-import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevisable;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-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.internal.common.bundle.OM;
-import org.eclipse.emf.cdo.internal.common.messages.Messages;
-import org.eclipse.emf.cdo.internal.common.model.CDOTypeImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
-import org.eclipse.emf.cdo.spi.common.id.AbstractCDOID;
-import org.eclipse.emf.cdo.spi.common.id.InternalCDOIDObject;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.io.ExtendedDataOutput;
-import org.eclipse.net4j.util.io.StringIO;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.util.FeatureMap;
-import org.eclipse.emf.ecore.util.FeatureMap.Entry;
-import org.eclipse.emf.ecore.util.FeatureMapUtil;
-
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.Collection;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * @author Eike Stepper
- */
-public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating implements CDODataOutput
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, CDODataOutputImpl.class);
-
- public CDODataOutputImpl(ExtendedDataOutput delegate)
- {
- super(delegate);
- }
-
- public void writeCDOPackageUnit(CDOPackageUnit packageUnit, boolean withPackages) throws IOException
- {
- ((InternalCDOPackageUnit)packageUnit).write(this, withPackages);
- }
-
- public void writeCDOPackageUnits(CDOPackageUnit... packageUnits) throws IOException
- {
- int size = packageUnits.length;
- writeInt(size);
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing {0} package units", size); //$NON-NLS-1$
- }
-
- for (CDOPackageUnit packageUnit : packageUnits)
- {
- writeCDOPackageUnit(packageUnit, false);
- }
- }
-
- public void writeCDOPackageUnitType(CDOPackageUnit.Type type) throws IOException
- {
- writeByte(type.ordinal());
- }
-
- public void writeCDOPackageInfo(CDOPackageInfo packageInfo) throws IOException
- {
- ((InternalCDOPackageInfo)packageInfo).write(this);
- }
-
- public void writeCDOClassifierRef(CDOClassifierRef eClassifierRef) throws IOException
- {
- eClassifierRef.write(this);
- }
-
- public void writeCDOClassifierRef(EClassifier eClassifier) throws IOException
- {
- writeCDOClassifierRef(new CDOClassifierRef(eClassifier));
- }
-
- public void writeCDOPackageURI(String uri) throws IOException
- {
- getPackageURICompressor().write(this, uri);
- }
-
- public void writeCDOType(CDOType cdoType) throws IOException
- {
- ((CDOTypeImpl)cdoType).write(this);
- }
-
- public void writeCDOBranch(CDOBranch branch) throws IOException
- {
- writeInt(branch.getID());
- }
-
- public void writeCDOBranchPoint(CDOBranchPoint branchPoint) throws IOException
- {
- writeCDOBranch(branchPoint.getBranch());
- writeLong(branchPoint.getTimeStamp());
- }
-
- public void writeCDOBranchVersion(CDOBranchVersion branchVersion) throws IOException
- {
- writeCDOBranch(branchVersion.getBranch());
- writeInt(branchVersion.getVersion());
- }
-
- public void writeCDOChangeSetData(CDOChangeSetData changeSetData) throws IOException
- {
- Collection<CDOIDAndVersion> newObjects = changeSetData.getNewObjects();
- writeInt(newObjects.size());
- for (CDOIDAndVersion data : newObjects)
- {
- if (data instanceof CDORevision)
- {
- writeBoolean(true);
- writeCDORevision((CDORevision)data, CDORevision.UNCHUNKED);
- }
- else
- {
- writeBoolean(false);
- writeCDOIDAndVersion(data);
- }
- }
-
- Collection<CDORevisionKey> changedObjects = changeSetData.getChangedObjects();
- writeInt(changedObjects.size());
- for (CDORevisionKey data : changedObjects)
- {
- if (data instanceof CDORevisionDelta)
- {
- writeBoolean(true);
- writeCDORevisionDelta((CDORevisionDelta)data);
- }
- else
- {
- writeBoolean(false);
- writeCDORevisionKey(data);
- }
- }
-
- Collection<CDOIDAndVersion> detachedObjects = changeSetData.getDetachedObjects();
- writeInt(detachedObjects.size());
- for (CDOIDAndVersion data : detachedObjects)
- {
- writeCDOIDAndVersion(data);
- }
- }
-
- public void writeCDOCommitData(CDOCommitData commitData) throws IOException
- {
- Collection<CDOPackageUnit> newPackageUnits = commitData.getNewPackageUnits();
- writeInt(newPackageUnits.size());
- for (CDOPackageUnit data : newPackageUnits)
- {
- writeCDOPackageUnit(data, false);
- }
-
- writeCDOChangeSetData(commitData);
- }
-
- public void writeCDOCommitInfo(CDOCommitInfo commitInfo) throws IOException
- {
- writeLong(commitInfo.getTimeStamp());
- writeLong(commitInfo.getPreviousTimeStamp());
-
- CDOBranch branch = commitInfo.getBranch();
- if (branch != null)
- {
- writeBoolean(true);
- writeCDOBranch(branch);
- writeString(commitInfo.getUserID());
- writeString(commitInfo.getComment());
- writeCDOCommitData(commitInfo);
- }
- else
- {
- // FailureCommitInfo
- writeBoolean(false);
- }
- }
-
- public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException
- {
- if (lockChangeInfo.isInvalidateAll())
- {
- writeBoolean(true);
- }
- else
- {
- writeBoolean(false);
- writeCDOBranchPoint(lockChangeInfo);
- writeCDOLockOwner(lockChangeInfo.getLockOwner());
- writeEnum(lockChangeInfo.getOperation());
- writeCDOLockType(lockChangeInfo.getLockType());
-
- CDOLockState[] lockStates = lockChangeInfo.getLockStates();
- writeInt(lockStates.length);
- for (CDOLockState lockState : lockStates)
- {
- writeCDOLockState(lockState);
- }
- }
- }
-
- public void writeCDOLockArea(LockArea lockArea) throws IOException
- {
- writeString(lockArea.getDurableLockingID());
- writeCDOBranch(lockArea.getBranch());
- writeLong(lockArea.getTimeStamp());
- writeString(lockArea.getUserID());
- writeBoolean(lockArea.isReadOnly());
-
- writeInt(lockArea.getLocks().size());
- for (Map.Entry<CDOID, LockGrade> entry : lockArea.getLocks().entrySet())
- {
- writeCDOID(entry.getKey());
- writeEnum(entry.getValue());
- }
- }
-
- public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException
- {
- writeInt(lockOwner.getSessionID());
- writeInt(lockOwner.getViewID());
- writeString(lockOwner.getDurableLockingID());
- writeBoolean(lockOwner.isDurableView());
- }
-
- public void writeCDOLockState(CDOLockState lockState) throws IOException
- {
- Object o = lockState.getLockedObject();
- if (o instanceof CDOID)
- {
- writeBoolean(false);
- writeCDOID((CDOID)o);
- }
- else if (o instanceof CDOIDAndBranch)
- {
- writeBoolean(true);
- writeCDOIDAndBranch((CDOIDAndBranch)o);
- }
- else
- {
- throw new AssertionError("Unexpected type: " + o.getClass().getSimpleName());
- }
-
- Set<CDOLockOwner> readLockOwners = lockState.getReadLockOwners();
- writeInt(readLockOwners.size());
- for (CDOLockOwner readLockOwner : readLockOwners)
- {
- writeCDOLockOwner(readLockOwner);
- }
-
- CDOLockOwner writeLockOwner = lockState.getWriteLockOwner();
- if (writeLockOwner != null)
- {
- writeBoolean(true);
- writeCDOLockOwner(writeLockOwner);
- }
- else
- {
- writeBoolean(false);
- }
-
- CDOLockOwner writeOptionOwner = lockState.getWriteOptionOwner();
- if (writeOptionOwner != null)
- {
- writeBoolean(true);
- writeCDOLockOwner(writeOptionOwner);
- }
- else
- {
- writeBoolean(false);
- }
- }
-
- public void writeCDOLockType(LockType lockType) throws IOException
- {
- writeEnum(lockType);
- }
-
- public void writeCDOID(CDOID id) throws IOException
- {
- if (id == null)
- {
- id = CDOID.NULL;
- }
-
- if (id instanceof InternalCDOIDObject)
- {
- CDOID.ObjectType subType = ((InternalCDOIDObject)id).getSubType();
- int ordinal = subType.ordinal();
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing CDOIDObject of subtype {0} ({1})", ordinal, subType); //$NON-NLS-1$
- }
-
- // Negated to distinguish between the subtypes and the maintypes.
- // Note: Added 1 because ordinal start at 0
- writeByte(-ordinal - 1);
- }
- else
- {
- CDOID.Type type = id.getType();
- int ordinal = type.ordinal();
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing CDOID of type {0} ({1})", ordinal, type); //$NON-NLS-1$
- }
-
- writeByte(ordinal);
- }
-
- ((AbstractCDOID)id).write(this);
- }
-
- public void writeCDOIDReference(CDOIDReference idReference) throws IOException
- {
- idReference.write(this);
- }
-
- public void writeCDOIDAndVersion(CDOIDAndVersion idAndVersion) throws IOException
- {
- writeCDOID(idAndVersion.getID());
- writeInt(idAndVersion.getVersion());
- }
-
- public void writeCDOIDAndBranch(CDOIDAndBranch idAndBranch) throws IOException
- {
- writeCDOID(idAndBranch.getID());
- writeCDOBranch(idAndBranch.getBranch());
- }
-
- public void writeCDORevisionKey(CDORevisionKey revisionKey) throws IOException
- {
- writeCDOID(revisionKey.getID());
- writeCDOBranch(revisionKey.getBranch());
- writeInt(revisionKey.getVersion());
- }
-
- public void writeCDORevision(CDORevision revision, int referenceChunk) throws IOException
- {
- if (revision != null)
- {
- writeBoolean(true);
- ((InternalCDORevision)revision).write(this, referenceChunk);
- }
- else
- {
- writeBoolean(false);
- }
- }
-
- public void writeCDORevisable(CDORevisable revisable) throws IOException
- {
- writeCDOBranch(revisable.getBranch());
- writeInt(revisable.getVersion());
- writeLong(revisable.getTimeStamp());
- writeLong(revisable.getRevised());
- }
-
- public void writeCDOList(EClass owner, EStructuralFeature feature, CDOList list, int referenceChunk)
- throws IOException
- {
- // TODO Simon: Could most of this stuff be moved into the list?
- // (only if protected methods of this class don't need to become public)
- int size = list == null ? 0 : list.size();
- if (size > 0)
- {
- // Need to adjust the referenceChunk in case where we do not have enough value in the list.
- // Even if the referenceChunk is specified, a provider of data could have override that value.
- int sizeToLook = referenceChunk == CDORevision.UNCHUNKED ? size : Math.min(referenceChunk, size);
- for (int i = 0; i < sizeToLook; i++)
- {
- Object element = list.get(i, false);
- if (element == CDORevisionUtil.UNINITIALIZED)
- {
- referenceChunk = i;
- break;
- }
- }
- }
-
- if (referenceChunk != CDORevision.UNCHUNKED && referenceChunk < size)
- {
- // This happens only on server-side
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing feature {0}: size={1}, referenceChunk={2}", feature.getName(), size, referenceChunk); //$NON-NLS-1$
- }
-
- writeInt(-size);
- writeInt(referenceChunk);
- size = referenceChunk;
- }
- else
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing feature {0}: size={1}", feature.getName(), size); //$NON-NLS-1$
- }
-
- writeInt(size);
- }
-
- CDOIDProvider idProvider = getIDProvider();
- boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature);
- for (int j = 0; j < size; j++)
- {
- Object value = list.get(j, false);
- EStructuralFeature innerFeature = feature; // Prepare for possible feature map
- if (isFeatureMap)
- {
- Entry entry = (FeatureMap.Entry)value;
- innerFeature = entry.getEStructuralFeature();
- value = entry.getValue();
-
- int featureID = owner.getFeatureID(innerFeature);
- writeInt(featureID);
- }
-
- if (value != null && innerFeature instanceof EReference)
- {
- value = idProvider.provideCDOID(value);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.trace(" " + value); //$NON-NLS-1$
- }
-
- writeCDOFeatureValue(innerFeature, value);
- }
- }
-
- public void writeCDOFeatureValue(EStructuralFeature feature, Object value) throws IOException
- {
- CDOType type = CDOModelUtil.getType(feature);
- type.writeValue(this, value);
- }
-
- public void writeCDORevisionDelta(CDORevisionDelta revisionDelta) throws IOException
- {
- ((CDORevisionDeltaImpl)revisionDelta).write(this);
- }
-
- public void writeCDOFeatureDelta(EClass owner, CDOFeatureDelta featureDelta) throws IOException
- {
- ((CDOFeatureDeltaImpl)featureDelta).write(this, owner);
- }
-
- public void writeCDORevisionOrPrimitive(Object value) throws IOException
- {
- if (value == null)
- {
- value = CDOID.NULL;
- }
- else if (value instanceof EObject)
- {
- value = getIDProvider().provideCDOID(value);
- }
- else if (value instanceof CDORevision)
- {
- value = ((CDORevision)value).getID();
- }
-
- CDOType type = null;
- if (value instanceof CDOID)
- {
- type = CDOType.OBJECT;
- }
- else
- {
- type = CDOModelUtil.getPrimitiveType(value.getClass());
- if (type == null)
- {
- throw new IllegalArgumentException(MessageFormat.format(
- Messages.getString("CDODataOutputImpl.6"), value.getClass())); //$NON-NLS-1$
- }
- }
-
- writeCDOType(type);
- type.writeValue(this, value);
- }
-
- public void writeCDORevisionOrPrimitiveOrClassifier(Object value) throws IOException
- {
- if (value instanceof EClassifier)
- {
- writeBoolean(true);
- writeCDOClassifierRef((EClass)value);
- }
- else
- {
- writeBoolean(false);
- writeCDORevisionOrPrimitive(value);
- }
- }
-
- public CDOPackageRegistry getPackageRegistry()
- {
- return null;
- }
-
- public CDOIDProvider getIDProvider()
- {
- return null;
- }
-
- protected StringIO getPackageURICompressor()
- {
- return StringIO.DIRECT;
- }
-}
+/* + * 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.internal.common.protocol; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; +import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; +import org.eclipse.emf.cdo.common.commit.CDOCommitData; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.id.CDOIDReference; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockArea; +import org.eclipse.emf.cdo.common.lock.IDurableLockingManager.LockGrade; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageInfo; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevisable; +import org.eclipse.emf.cdo.common.revision.CDORevision; +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.CDOPermissionProvider; +import org.eclipse.emf.cdo.internal.common.bundle.OM; +import org.eclipse.emf.cdo.internal.common.messages.Messages; +import org.eclipse.emf.cdo.internal.common.model.CDOTypeImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl; +import org.eclipse.emf.cdo.spi.common.id.AbstractCDOID; +import org.eclipse.emf.cdo.spi.common.id.InternalCDOIDObject; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.io.ExtendedDataOutput; +import org.eclipse.net4j.util.io.StringIO; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMap.Entry; +import org.eclipse.emf.ecore.util.FeatureMapUtil; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +/** + * @author Eike Stepper + */ +public abstract class CDODataOutputImpl extends ExtendedDataOutput.Delegating implements CDODataOutput +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_PROTOCOL, CDODataOutputImpl.class); + + public CDODataOutputImpl(ExtendedDataOutput delegate) + { + super(delegate); + } + + public void writeCDOPackageUnit(CDOPackageUnit packageUnit, boolean withPackages) throws IOException + { + ((InternalCDOPackageUnit)packageUnit).write(this, withPackages); + } + + public void writeCDOPackageUnits(CDOPackageUnit... packageUnits) throws IOException + { + int size = packageUnits.length; + writeInt(size); + if (TRACER.isEnabled()) + { + TRACER.format("Writing {0} package units", size); //$NON-NLS-1$ + } + + for (CDOPackageUnit packageUnit : packageUnits) + { + writeCDOPackageUnit(packageUnit, false); + } + } + + public void writeCDOPackageUnitType(CDOPackageUnit.Type type) throws IOException + { + writeByte(type.ordinal()); + } + + public void writeCDOPackageInfo(CDOPackageInfo packageInfo) throws IOException + { + ((InternalCDOPackageInfo)packageInfo).write(this); + } + + public void writeCDOClassifierRef(CDOClassifierRef eClassifierRef) throws IOException + { + eClassifierRef.write(this); + } + + public void writeCDOClassifierRef(EClassifier eClassifier) throws IOException + { + writeCDOClassifierRef(new CDOClassifierRef(eClassifier)); + } + + public void writeCDOPackageURI(String uri) throws IOException + { + getPackageURICompressor().write(this, uri); + } + + public void writeCDOType(CDOType cdoType) throws IOException + { + ((CDOTypeImpl)cdoType).write(this); + } + + public void writeCDOBranch(CDOBranch branch) throws IOException + { + writeInt(branch.getID()); + } + + public void writeCDOBranchPoint(CDOBranchPoint branchPoint) throws IOException + { + writeCDOBranch(branchPoint.getBranch()); + writeLong(branchPoint.getTimeStamp()); + } + + public void writeCDOBranchVersion(CDOBranchVersion branchVersion) throws IOException + { + writeCDOBranch(branchVersion.getBranch()); + writeInt(branchVersion.getVersion()); + } + + public void writeCDOChangeSetData(CDOChangeSetData changeSetData) throws IOException + { + Collection<CDOIDAndVersion> newObjects = changeSetData.getNewObjects(); + writeInt(newObjects.size()); + for (CDOIDAndVersion data : newObjects) + { + if (data instanceof CDORevision) + { + writeBoolean(true); + writeCDORevision((CDORevision)data, CDORevision.UNCHUNKED); + } + else + { + writeBoolean(false); + writeCDOIDAndVersion(data); + } + } + + Collection<CDORevisionKey> changedObjects = changeSetData.getChangedObjects(); + writeInt(changedObjects.size()); + for (CDORevisionKey data : changedObjects) + { + if (data instanceof CDORevisionDelta) + { + writeBoolean(true); + writeCDORevisionDelta((CDORevisionDelta)data); + } + else + { + writeBoolean(false); + writeCDORevisionKey(data); + } + } + + Collection<CDOIDAndVersion> detachedObjects = changeSetData.getDetachedObjects(); + writeInt(detachedObjects.size()); + for (CDOIDAndVersion data : detachedObjects) + { + writeCDOIDAndVersion(data); + } + } + + public void writeCDOCommitData(CDOCommitData commitData) throws IOException + { + Collection<CDOPackageUnit> newPackageUnits = commitData.getNewPackageUnits(); + writeInt(newPackageUnits.size()); + for (CDOPackageUnit data : newPackageUnits) + { + writeCDOPackageUnit(data, false); + } + + writeCDOChangeSetData(commitData); + } + + public void writeCDOCommitInfo(CDOCommitInfo commitInfo) throws IOException + { + writeLong(commitInfo.getTimeStamp()); + writeLong(commitInfo.getPreviousTimeStamp()); + + CDOBranch branch = commitInfo.getBranch(); + if (branch != null) + { + writeBoolean(true); + writeCDOBranch(branch); + writeString(commitInfo.getUserID()); + writeString(commitInfo.getComment()); + writeCDOCommitData(commitInfo); + } + else + { + // FailureCommitInfo + writeBoolean(false); + } + } + + public void writeCDOLockChangeInfo(CDOLockChangeInfo lockChangeInfo) throws IOException + { + if (lockChangeInfo.isInvalidateAll()) + { + writeBoolean(true); + } + else + { + writeBoolean(false); + writeCDOBranchPoint(lockChangeInfo); + writeCDOLockOwner(lockChangeInfo.getLockOwner()); + writeEnum(lockChangeInfo.getOperation()); + writeCDOLockType(lockChangeInfo.getLockType()); + + CDOLockState[] lockStates = lockChangeInfo.getLockStates(); + writeInt(lockStates.length); + for (CDOLockState lockState : lockStates) + { + writeCDOLockState(lockState); + } + } + } + + public void writeCDOLockArea(LockArea lockArea) throws IOException + { + writeString(lockArea.getDurableLockingID()); + writeCDOBranch(lockArea.getBranch()); + writeLong(lockArea.getTimeStamp()); + writeString(lockArea.getUserID()); + writeBoolean(lockArea.isReadOnly()); + + writeInt(lockArea.getLocks().size()); + for (Map.Entry<CDOID, LockGrade> entry : lockArea.getLocks().entrySet()) + { + writeCDOID(entry.getKey()); + writeEnum(entry.getValue()); + } + } + + public void writeCDOLockOwner(CDOLockOwner lockOwner) throws IOException + { + writeInt(lockOwner.getSessionID()); + writeInt(lockOwner.getViewID()); + writeString(lockOwner.getDurableLockingID()); + writeBoolean(lockOwner.isDurableView()); + } + + public void writeCDOLockState(CDOLockState lockState) throws IOException + { + Object o = lockState.getLockedObject(); + if (o instanceof CDOID) + { + writeBoolean(false); + writeCDOID((CDOID)o); + } + else if (o instanceof CDOIDAndBranch) + { + writeBoolean(true); + writeCDOIDAndBranch((CDOIDAndBranch)o); + } + else + { + throw new AssertionError("Unexpected type: " + o.getClass().getSimpleName()); + } + + Set<CDOLockOwner> readLockOwners = lockState.getReadLockOwners(); + writeInt(readLockOwners.size()); + for (CDOLockOwner readLockOwner : readLockOwners) + { + writeCDOLockOwner(readLockOwner); + } + + CDOLockOwner writeLockOwner = lockState.getWriteLockOwner(); + if (writeLockOwner != null) + { + writeBoolean(true); + writeCDOLockOwner(writeLockOwner); + } + else + { + writeBoolean(false); + } + + CDOLockOwner writeOptionOwner = lockState.getWriteOptionOwner(); + if (writeOptionOwner != null) + { + writeBoolean(true); + writeCDOLockOwner(writeOptionOwner); + } + else + { + writeBoolean(false); + } + } + + public void writeCDOLockType(LockType lockType) throws IOException + { + writeEnum(lockType); + } + + public void writeCDOID(CDOID id) throws IOException + { + if (id == null) + { + id = CDOID.NULL; + } + + if (id instanceof InternalCDOIDObject) + { + CDOID.ObjectType subType = ((InternalCDOIDObject)id).getSubType(); + int ordinal = subType.ordinal(); + if (TRACER.isEnabled()) + { + TRACER.format("Writing CDOIDObject of subtype {0} ({1})", ordinal, subType); //$NON-NLS-1$ + } + + // Negated to distinguish between the subtypes and the maintypes. + // Note: Added 1 because ordinal start at 0 + writeByte(-ordinal - 1); + } + else + { + CDOID.Type type = id.getType(); + int ordinal = type.ordinal(); + if (TRACER.isEnabled()) + { + TRACER.format("Writing CDOID of type {0} ({1})", ordinal, type); //$NON-NLS-1$ + } + + writeByte(ordinal); + } + + ((AbstractCDOID)id).write(this); + } + + public void writeCDOIDReference(CDOIDReference idReference) throws IOException + { + idReference.write(this); + } + + public void writeCDOIDAndVersion(CDOIDAndVersion idAndVersion) throws IOException + { + writeCDOID(idAndVersion.getID()); + writeInt(idAndVersion.getVersion()); + } + + public void writeCDOIDAndBranch(CDOIDAndBranch idAndBranch) throws IOException + { + writeCDOID(idAndBranch.getID()); + writeCDOBranch(idAndBranch.getBranch()); + } + + public void writeCDORevisionKey(CDORevisionKey revisionKey) throws IOException + { + writeCDOID(revisionKey.getID()); + writeCDOBranch(revisionKey.getBranch()); + writeInt(revisionKey.getVersion()); + } + + public void writeCDORevision(CDORevision revision, int referenceChunk) throws IOException + { + if (revision != null) + { + writeBoolean(true); + ((InternalCDORevision)revision).write(this, referenceChunk); + } + else + { + writeBoolean(false); + } + } + + public void writeCDORevisable(CDORevisable revisable) throws IOException + { + writeCDOBranch(revisable.getBranch()); + writeInt(revisable.getVersion()); + writeLong(revisable.getTimeStamp()); + writeLong(revisable.getRevised()); + } + + public void writeCDOList(EClass owner, EStructuralFeature feature, CDOList list, int referenceChunk) + throws IOException + { + // TODO Simon: Could most of this stuff be moved into the list? + // (only if protected methods of this class don't need to become public) + int size = list == null ? 0 : list.size(); + if (size > 0) + { + // Need to adjust the referenceChunk in case where we do not have enough value in the list. + // Even if the referenceChunk is specified, a provider of data could have override that value. + int sizeToLook = referenceChunk == CDORevision.UNCHUNKED ? size : Math.min(referenceChunk, size); + for (int i = 0; i < sizeToLook; i++) + { + Object element = list.get(i, false); + if (element == CDORevisionUtil.UNINITIALIZED) + { + referenceChunk = i; + break; + } + } + } + + if (referenceChunk != CDORevision.UNCHUNKED && referenceChunk < size) + { + // This happens only on server-side + if (TRACER.isEnabled()) + { + TRACER.format("Writing feature {0}: size={1}, referenceChunk={2}", feature.getName(), size, referenceChunk); //$NON-NLS-1$ + } + + writeInt(-size); + writeInt(referenceChunk); + size = referenceChunk; + } + else + { + if (TRACER.isEnabled()) + { + TRACER.format("Writing feature {0}: size={1}", feature.getName(), size); //$NON-NLS-1$ + } + + writeInt(size); + } + + CDOIDProvider idProvider = getIDProvider(); + boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); + for (int j = 0; j < size; j++) + { + Object value = list.get(j, false); + EStructuralFeature innerFeature = feature; // Prepare for possible feature map + if (isFeatureMap) + { + Entry entry = (FeatureMap.Entry)value; + innerFeature = entry.getEStructuralFeature(); + value = entry.getValue(); + + int featureID = owner.getFeatureID(innerFeature); + writeInt(featureID); + } + + if (value != null && innerFeature instanceof EReference) + { + value = idProvider.provideCDOID(value); + } + + if (TRACER.isEnabled()) + { + TRACER.trace(" " + value); //$NON-NLS-1$ + } + + writeCDOFeatureValue(innerFeature, value); + } + } + + public void writeCDOFeatureValue(EStructuralFeature feature, Object value) throws IOException + { + CDOType type = CDOModelUtil.getType(feature); + type.writeValue(this, value); + } + + public void writeCDORevisionDelta(CDORevisionDelta revisionDelta) throws IOException + { + ((CDORevisionDeltaImpl)revisionDelta).write(this); + } + + public void writeCDOFeatureDelta(EClass owner, CDOFeatureDelta featureDelta) throws IOException + { + ((CDOFeatureDeltaImpl)featureDelta).write(this, owner); + } + + public void writeCDORevisionOrPrimitive(Object value) throws IOException + { + if (value == null) + { + value = CDOID.NULL; + } + else if (value instanceof EObject) + { + value = getIDProvider().provideCDOID(value); + } + else if (value instanceof CDORevision) + { + value = ((CDORevision)value).getID(); + } + + CDOType type = null; + if (value instanceof CDOID) + { + type = CDOType.OBJECT; + } + else + { + type = CDOModelUtil.getPrimitiveType(value.getClass()); + if (type == null) + { + throw new IllegalArgumentException(MessageFormat.format( + Messages.getString("CDODataOutputImpl.6"), value.getClass())); //$NON-NLS-1$ + } + } + + writeCDOType(type); + type.writeValue(this, value); + } + + public void writeCDORevisionOrPrimitiveOrClassifier(Object value) throws IOException + { + if (value instanceof EClassifier) + { + writeBoolean(true); + writeCDOClassifierRef((EClass)value); + } + else + { + writeBoolean(false); + writeCDORevisionOrPrimitive(value); + } + } + + public CDOPackageRegistry getPackageRegistry() + { + return null; + } + + public CDOIDProvider getIDProvider() + { + return null; + } + + public CDOPermissionProvider getPermissionProvider() + { + return CDORevision.PERMISSION_PROVIDER; + } + + protected StringIO getPackageURICompressor() + { + return StringIO.DIRECT; + } +} 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 f52ee0bafd..0721bbdbb9 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 @@ -14,15 +14,12 @@ */ 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; @@ -34,8 +31,6 @@ public class CDORevisionImpl extends BaseCDORevision { private Object[] values; - private transient boolean frozen; - public CDORevisionImpl(EClass eClass) { super(eClass); @@ -78,61 +73,14 @@ public class CDORevisionImpl extends BaseCDORevision } @Override - protected Object getValue(int featureIndex) + protected Object doGetValue(int featureIndex) { return values[featureIndex]; } @Override - protected void setValue(int featureIndex, Object value) + protected void doSetValue(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/revision/AbstractCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/AbstractCDORevision.java index 751821d389..e9d9fba46e 100644 --- a/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/AbstractCDORevision.java +++ b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/AbstractCDORevision.java @@ -1,204 +1,220 @@ -/*
- * 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 - bug 201266
- * Simon McDuff - bug 212958
- * Simon McDuff - bug 213402
- */
-package org.eclipse.emf.cdo.spi.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.model.CDOClassInfo;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
-import org.eclipse.emf.cdo.internal.common.messages.Messages;
-
-import org.eclipse.net4j.util.ObjectUtil;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.text.MessageFormat;
-
-/**
- * @author Eike Stepper
- * @since 2.0
- */
-public abstract class AbstractCDORevision implements InternalCDORevision
-{
- private CDOClassInfo classInfo;
-
- /**
- * @since 3.0
- */
- protected AbstractCDORevision(EClass eClass)
- {
- if (eClass != null)
- {
- if (eClass.isAbstract())
- {
- throw new IllegalArgumentException(MessageFormat.format(Messages.getString("AbstractCDORevision.0"), eClass)); //$NON-NLS-1$
- }
-
- classInfo = CDOModelUtil.getClassInfo(eClass);
- }
- }
-
- /**
- * @since 3.0
- */
- public CDOClassInfo getClassInfo()
- {
- return classInfo;
- }
-
- public EClass getEClass()
- {
- CDOClassInfo classInfo = getClassInfo();
- if (classInfo != null)
- {
- return classInfo.getEClass();
- }
-
- return null;
- }
-
- public boolean isResourceNode()
- {
- return getClassInfo().isResourceNode();
- }
-
- public boolean isResourceFolder()
- {
- return getClassInfo().isResourceFolder();
- }
-
- public boolean isResource()
- {
- return getClassInfo().isResource();
- }
-
- public CDORevisionData data()
- {
- return this;
- }
-
- public CDORevision revision()
- {
- return this;
- }
-
- /**
- * @since 3.0
- */
- public boolean isHistorical()
- {
- return getRevised() != UNSPECIFIED_DATE;
- }
-
- public boolean isValid(long timeStamp)
- {
- long startTime = getTimeStamp();
- long endTime = getRevised();
- return CDOCommonUtil.isValidTimeStamp(timeStamp, startTime, endTime);
- }
-
- /**
- * @since 4.0
- */
- public boolean isValid(CDOBranchPoint branchPoint)
- {
- return getBranch() == branchPoint.getBranch() && isValid(branchPoint.getTimeStamp());
- }
-
- /**
- * @since 3.0
- */
- public void adjustForCommit(CDOBranch branch, long timeStamp)
- {
- if (ObjectUtil.equals(branch, getBranch()))
- {
- // Same branch, increase version
- setVersion(getVersion() + 1);
- }
- else
- {
- // Different branch, start with v1
- setVersion(FIRST_VERSION);
- }
-
- setBranchPoint(branch.getPoint(timeStamp));
- setRevised(UNSPECIFIED_DATE);
- }
-
- @Override
- public int hashCode()
- {
- return getID().hashCode() ^ getBranch().hashCode() ^ getVersion();
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj == this)
- {
- return true;
- }
-
- if (obj instanceof CDORevision)
- {
- CDORevision that = (CDORevision)obj;
- return getID().equals(that.getID()) && getBranch().equals(that.getBranch()) && getVersion() == that.getVersion();
- }
-
- return false;
- }
-
- @Override
- public String toString()
- {
- EClass eClass = getEClass();
- String name = eClass == null ? "Revision" : eClass.getName();
-
- CDOBranch branch = getBranch();
- if (branch == null)
- {
- return name + "@" + getID() + "v" + getVersion();
- }
-
- return name + "@" + getID() + ":" + branch.getID() + "v" + getVersion();
- }
-
- /**
- * @since 3.0
- */
- protected void setClassInfo(CDOClassInfo classInfo)
- {
- this.classInfo = classInfo;
- }
-
- /**
- * @since 3.0
- */
- protected EStructuralFeature[] getAllPersistentFeatures()
- {
- return classInfo.getAllPersistentFeatures();
- }
-
- /**
- * @since 3.0
- */
- protected int getFeatureIndex(EStructuralFeature feature)
- {
- return classInfo.getFeatureIndex(feature);
- }
-}
+/* + * 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 - bug 201266 + * Simon McDuff - bug 212958 + * Simon McDuff - bug 213402 + */ +package org.eclipse.emf.cdo.spi.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.model.CDOClassInfo; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; +import org.eclipse.emf.cdo.common.util.CDOCommonUtil; +import org.eclipse.emf.cdo.internal.common.messages.Messages; + +import org.eclipse.net4j.util.ObjectUtil; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.text.MessageFormat; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public abstract class AbstractCDORevision implements InternalCDORevision +{ + private CDOClassInfo classInfo; + + /** + * @since 3.0 + */ + protected AbstractCDORevision(EClass eClass) + { + if (eClass != null) + { + if (eClass.isAbstract()) + { + throw new IllegalArgumentException(MessageFormat.format(Messages.getString("AbstractCDORevision.0"), eClass)); //$NON-NLS-1$ + } + + classInfo = CDOModelUtil.getClassInfo(eClass); + } + } + + /** + * @since 3.0 + */ + public CDOClassInfo getClassInfo() + { + return classInfo; + } + + public EClass getEClass() + { + CDOClassInfo classInfo = getClassInfo(); + if (classInfo != null) + { + return classInfo.getEClass(); + } + + return null; + } + + public boolean isResourceNode() + { + return getClassInfo().isResourceNode(); + } + + public boolean isResourceFolder() + { + return getClassInfo().isResourceFolder(); + } + + public boolean isResource() + { + return getClassInfo().isResource(); + } + + public CDORevisionData data() + { + return this; + } + + public CDORevision revision() + { + return this; + } + + /** + * @since 3.0 + */ + public boolean isHistorical() + { + return getRevised() != UNSPECIFIED_DATE; + } + + public boolean isValid(long timeStamp) + { + long startTime = getTimeStamp(); + long endTime = getRevised(); + return CDOCommonUtil.isValidTimeStamp(timeStamp, startTime, endTime); + } + + /** + * @since 4.0 + */ + public boolean isValid(CDOBranchPoint branchPoint) + { + return getBranch() == branchPoint.getBranch() && isValid(branchPoint.getTimeStamp()); + } + + /** + * @since 4.1 + */ + public boolean isReadable() + { + return getPermission().isReadable(); + } + + /** + * @since 4.1 + */ + public boolean isWritable() + { + return getPermission().isWritable(); + } + + /** + * @since 3.0 + */ + public void adjustForCommit(CDOBranch branch, long timeStamp) + { + if (ObjectUtil.equals(branch, getBranch())) + { + // Same branch, increase version + setVersion(getVersion() + 1); + } + else + { + // Different branch, start with v1 + setVersion(FIRST_VERSION); + } + + setBranchPoint(branch.getPoint(timeStamp)); + setRevised(UNSPECIFIED_DATE); + } + + @Override + public int hashCode() + { + return getID().hashCode() ^ getBranch().hashCode() ^ getVersion(); + } + + @Override + public boolean equals(Object obj) + { + if (obj == this) + { + return true; + } + + if (obj instanceof CDORevision) + { + CDORevision that = (CDORevision)obj; + return getID().equals(that.getID()) && getBranch().equals(that.getBranch()) && getVersion() == that.getVersion(); + } + + return false; + } + + @Override + public String toString() + { + EClass eClass = getEClass(); + String name = eClass == null ? "Revision" : eClass.getName(); + + CDOBranch branch = getBranch(); + if (branch == null) + { + return name + "@" + getID() + "v" + getVersion(); + } + + return name + "@" + getID() + ":" + branch.getID() + "v" + getVersion(); + } + + /** + * @since 3.0 + */ + protected void setClassInfo(CDOClassInfo classInfo) + { + this.classInfo = classInfo; + } + + /** + * @since 3.0 + */ + protected EStructuralFeature[] getAllPersistentFeatures() + { + return classInfo.getAllPersistentFeatures(); + } + + /** + * @since 3.0 + */ + protected int getFeatureIndex(EStructuralFeature feature) + { + return classInfo.getFeatureIndex(feature); + } +} 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 9f86573039..2608cd2f68 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 @@ -1,775 +1,928 @@ -/*
- * 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 - bug 201266
- * Simon McDuff - bug 212958
- * Simon McDuff - bug 213402
- */
-package org.eclipse.emf.cdo.spi.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.id.CDOIDTemp;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
-import org.eclipse.emf.cdo.common.model.CDOClassInfo;
-import org.eclipse.emf.cdo.common.model.CDOClassifierRef;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDOListFactory;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
-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.CDOCommonUtil;
-import org.eclipse.emf.cdo.internal.common.bundle.OM;
-import org.eclipse.emf.cdo.internal.common.messages.Messages;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
-import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
-
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-import org.eclipse.net4j.util.om.trace.PerfTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.InternalEObject.EStore;
-import org.eclipse.emf.ecore.util.FeatureMap;
-import org.eclipse.emf.ecore.util.FeatureMap.Entry;
-import org.eclipse.emf.ecore.util.FeatureMapUtil;
-
-import java.io.IOException;
-import java.text.MessageFormat;
-import java.util.Map;
-
-/**
- * @author Eike Stepper
- * @since 3.0
- */
-public abstract class BaseCDORevision extends AbstractCDORevision
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_REVISION, BaseCDORevision.class);
-
- private static final PerfTracer READING = new PerfTracer(OM.PERF_REVISION_READING, BaseCDORevision.class);
-
- private static final PerfTracer WRITING = new PerfTracer(OM.PERF_REVISION_WRITING, BaseCDORevision.class);
-
- private static final byte UNSET = 0;
-
- private static final byte SET_NULL = 1;
-
- private static final byte SET_NOT_NULL = 2;
-
- private CDOID id;
-
- private CDOBranchPoint branchPoint;
-
- private int version;
-
- private long revised;
-
- private CDOID resourceID;
-
- /**
- * On a client, between a local modification and the commit the value of this <i>ID</i> can be an EObject.
- */
- private Object containerID;
-
- private int containingFeatureID;
-
- /**
- * @since 3.0
- */
- public BaseCDORevision(EClass eClass)
- {
- super(eClass);
- if (eClass != null)
- {
- version = UNSPECIFIED_VERSION;
- revised = UNSPECIFIED_DATE;
- resourceID = CDOID.NULL;
- containerID = CDOID.NULL;
- containingFeatureID = 0;
- initValues(getAllPersistentFeatures());
- }
- }
-
- protected BaseCDORevision(BaseCDORevision source)
- {
- super(source.getEClass());
- id = source.id;
- branchPoint = source.branchPoint;
- version = source.version;
- revised = source.revised;
- resourceID = source.resourceID;
- containerID = source.containerID;
- containingFeatureID = source.containingFeatureID;
- }
-
- /**
- * @since 3.0
- */
- public void read(CDODataInput in) throws IOException
- {
- if (READING.isEnabled())
- {
- READING.start(this);
- }
-
- readSystemValues(in);
- readValues(in);
-
- if (READING.isEnabled())
- {
- READING.stop(this);
- }
- }
-
- /**
- * @since 4.0
- */
- protected void readSystemValues(CDODataInput in) throws IOException
- {
- EClassifier classifier = in.readCDOClassifierRefAndResolve();
- CDOClassInfo classInfo = CDOModelUtil.getClassInfo((EClass)classifier);
- setClassInfo(classInfo);
-
- id = in.readCDOID();
- branchPoint = in.readCDOBranchPoint();
- version = in.readInt();
- if (!id.isTemporary())
- {
- revised = in.readLong();
- }
-
- resourceID = in.readCDOID();
- containerID = in.readCDOID();
- containingFeatureID = in.readInt();
-
- if (TRACER.isEnabled())
- {
- TRACER
- .format(
- "Reading revision: ID={0}, className={1}, version={2}, branchPoint={3}, revised={4}, resource={5}, container={6}, featureID={7}", //$NON-NLS-1$
- id, getEClass().getName(), version, branchPoint, revised, resourceID, containerID, containingFeatureID);
- }
- }
-
- /**
- * @since 4.0
- */
- public void write(CDODataOutput out, int referenceChunk) throws IOException
- {
- if (WRITING.isEnabled())
- {
- WRITING.start(this);
- }
-
- writeSystemValues(out);
- writeValues(out, referenceChunk);
-
- if (WRITING.isEnabled())
- {
- WRITING.stop(this);
- }
- }
-
- /**
- * @since 4.0
- */
- protected void writeSystemValues(CDODataOutput out) throws IOException
- {
- EClass eClass = getEClass();
- CDOClassifierRef classRef = new CDOClassifierRef(eClass);
-
- if (TRACER.isEnabled())
- {
- TRACER
- .format(
- "Writing revision: ID={0}, className={1}, version={2}, branchPoint={3}, revised={4}, resource={5}, container={6}, featureID={7}", //$NON-NLS-1$
- id, eClass.getName(), getVersion(), branchPoint, revised, resourceID, containerID, containingFeatureID);
- }
-
- out.writeCDOClassifierRef(classRef);
- out.writeCDOID(id);
- out.writeCDOBranchPoint(branchPoint);
- out.writeInt(getVersion());
- if (!id.isTemporary())
- {
- out.writeLong(revised);
- }
-
- out.writeCDOID(resourceID);
- out.writeCDOID(out.getIDProvider().provideCDOID(containerID));
- out.writeInt(containingFeatureID);
- }
-
- /**
- * @see #write(CDODataOutput, int)
- * @since 3.0
- */
- public void convertEObjects(CDOIDProvider idProvider)
- {
- if (!(containerID instanceof CDOID))
- {
- containerID = idProvider.provideCDOID(containerID);
- }
-
- EStructuralFeature[] features = getAllPersistentFeatures();
- for (int i = 0; i < features.length; i++)
- {
- EStructuralFeature feature = features[i];
- if (feature.isMany())
- {
- CDOList list = getValueAsList(i);
- if (list != null)
- {
- boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature);
- for (int j = 0; j < list.size(); j++)
- {
- Object value = list.get(j, false);
- EStructuralFeature innerFeature = feature; // Prepare for possible feature map
- if (isFeatureMap)
- {
- Entry entry = (FeatureMap.Entry)value;
- innerFeature = entry.getEStructuralFeature();
- value = entry.getValue();
- }
-
- if (value != null && innerFeature instanceof EReference)
- {
- CDOID newValue = idProvider.provideCDOID(value);
- if (newValue != value)
- {
- list.set(j, newValue);
- }
- }
- }
- }
- }
- else
- {
- checkNoFeatureMap(feature);
- Object value = getValue(i);
- if (value != null && feature instanceof EReference)
- {
- CDOID newValue = idProvider.provideCDOID(value);
- if (newValue != value)
- {
- setValue(i, newValue);
- }
- }
- }
- }
- }
-
- public CDOID getID()
- {
- return id;
- }
-
- public void setID(CDOID id)
- {
- if (CDOIDUtil.isNull(id))
- {
- throw new IllegalArgumentException(Messages.getString("AbstractCDORevision.1")); //$NON-NLS-1$
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting ID: {0}", id);
- }
-
- this.id = id;
- }
-
- /**
- * @since 3.0
- */
- public CDOBranch getBranch()
- {
- if (branchPoint == null)
- {
- return null;
- }
-
- return branchPoint.getBranch();
- }
-
- /**
- * @since 3.0
- */
- public long getTimeStamp()
- {
- if (branchPoint == null)
- {
- return UNSPECIFIED_DATE;
- }
-
- return branchPoint.getTimeStamp();
- }
-
- /**
- * @since 3.0
- */
- public void setBranchPoint(CDOBranchPoint branchPoint)
- {
- branchPoint = CDOBranchUtil.copyBranchPoint(branchPoint);
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting branchPoint {0}: {1}", this, branchPoint);
- }
-
- this.branchPoint = branchPoint;
- }
-
- public int getVersion()
- {
- return version;
- }
-
- public void setVersion(int version)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting version for {0}: v{1}", this, version);
- }
-
- this.version = version;
- }
-
- public long getRevised()
- {
- return revised;
- }
-
- public void setRevised(long revised)
- {
- long created = branchPoint.getTimeStamp();
- if (revised != UNSPECIFIED_DATE && revised < Math.max(0, created))
- {
- throw new IllegalArgumentException("revision=" + this + ", created=" + CDOCommonUtil.formatTimeStamp(created)
- + ", revised=" + CDOCommonUtil.formatTimeStamp(revised));
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting revised {0}: {1}", this, CDOCommonUtil.formatTimeStamp(revised));
- }
-
- this.revised = revised;
- }
-
- public InternalCDORevisionDelta compare(CDORevision origin)
- {
- return new CDORevisionDeltaImpl(origin, this);
- }
-
- public void merge(CDORevisionDelta delta)
- {
- CDORevisionMerger applier = new CDORevisionMerger();
- applier.merge(this, delta);
- }
-
- public CDOID getResourceID()
- {
- return resourceID;
- }
-
- public void setResourceID(CDOID resourceID)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting resourceID {0}: {1}", this, resourceID);
- }
-
- this.resourceID = resourceID;
- }
-
- public Object getContainerID()
- {
- return containerID;
- }
-
- public void setContainerID(Object containerID)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting containerID {0}: {1}", this, containerID);
- }
-
- this.containerID = containerID;
- }
-
- public int getContainingFeatureID()
- {
- return containingFeatureID;
- }
-
- public void setContainingFeatureID(int containingFeatureID)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting containingFeatureID {0}: {1}", this, containingFeatureID);
- }
-
- this.containingFeatureID = containingFeatureID;
- }
-
- public int hashCode(EStructuralFeature feature)
- {
- return getValue(feature).hashCode();
- }
-
- public Object get(EStructuralFeature feature, int index)
- {
- if (feature.isMany() && index != EStore.NO_INDEX)
- {
- CDOList list = getList(feature);
- return list.get(index);
- }
-
- return getValue(feature);
- }
-
- public boolean contains(EStructuralFeature feature, Object value)
- {
- CDOList list = getList(feature);
- return list.contains(value);
- }
-
- public int indexOf(EStructuralFeature feature, Object value)
- {
- CDOList list = getList(feature);
- return list.indexOf(value);
- }
-
- public int lastIndexOf(EStructuralFeature feature, Object value)
- {
- CDOList list = getList(feature);
- return list.lastIndexOf(value);
- }
-
- public boolean isEmpty(EStructuralFeature feature)
- {
- CDOList list = getList(feature);
- return list.isEmpty();
- }
-
- public int size(EStructuralFeature feature)
- {
- CDOList list = getList(feature);
- return list.size();
- }
-
- public Object[] toArray(EStructuralFeature feature)
- {
- if (!feature.isMany())
- {
- throw new IllegalStateException("!feature.isMany()");
- }
-
- CDOList list = getList(feature);
- return list.toArray();
- }
-
- public <T> T[] toArray(EStructuralFeature feature, T[] array)
- {
- if (!feature.isMany())
- {
- throw new IllegalStateException("!feature.isMany()");
- }
-
- CDOList list = getList(feature);
- return list.toArray(array);
- }
-
- public void add(EStructuralFeature feature, int index, Object value)
- {
- CDOList list = getList(feature);
- list.add(index, value);
- }
-
- public void clear(EStructuralFeature feature)
- {
- setValue(feature, null);
- }
-
- public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex)
- {
- CDOList list = getList(feature);
- return list.move(targetIndex, sourceIndex);
- }
-
- public Object remove(EStructuralFeature feature, int index)
- {
- CDOList list = getList(feature);
- return list.remove(index);
- }
-
- public Object set(EStructuralFeature feature, int index, Object value)
- {
- if (feature.isMany())
- {
- CDOList list = getList(feature);
- return list.set(index, value);
- }
-
- return setValue(feature, value);
- }
-
- public void unset(EStructuralFeature feature)
- {
- setValue(feature, null);
- }
-
- /**
- * @since 4.0
- */
- public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Adjusting references for revision {0}", this);
- }
-
- boolean changed = false;
-
- CDOID id1 = (CDOID)referenceAdjuster.adjustReference(resourceID, CDOContainerFeatureDelta.CONTAINER_FEATURE,
- CDOFeatureDelta.NO_INDEX);
- if (id1 != resourceID)
- {
- resourceID = id1;
- changed = true;
- }
-
- Object id2 = referenceAdjuster.adjustReference(containerID, CDOContainerFeatureDelta.CONTAINER_FEATURE,
- CDOFeatureDelta.NO_INDEX);
- if (id2 != containerID)
- {
- containerID = id2;
- changed = true;
- }
-
- EStructuralFeature[] features = getAllPersistentFeatures();
- for (int i = 0; i < features.length; i++)
- {
- EStructuralFeature feature = features[i];
- if (feature instanceof EReference || FeatureMapUtil.isFeatureMap(feature))
- {
- if (feature.isMany())
- {
- InternalCDOList list = (InternalCDOList)getValueAsList(i);
- if (list != null)
- {
- changed |= list.adjustReferences(referenceAdjuster, feature);
- }
- }
- else
- {
- CDOType type = CDOModelUtil.getType(feature);
- Object oldValue = getValue(i);
- Object newValue = type.adjustReferences(referenceAdjuster, oldValue, feature, CDOFeatureDelta.NO_INDEX);
- if (oldValue != newValue) // Just an optimization for NOOP adjusters
- {
- setValue(i, newValue);
- changed = true;
- }
- }
- }
- }
-
- return changed;
- }
-
- public Object getValue(EStructuralFeature feature)
- {
- int featureIndex = getFeatureIndex(feature);
- return getValue(featureIndex);
- }
-
- public Object setValue(EStructuralFeature feature, Object value)
- {
- int featureIndex = getFeatureIndex(feature);
-
- try
- {
- Object old = getValue(featureIndex);
- setValue(featureIndex, value);
- return old;
- }
- catch (ArrayIndexOutOfBoundsException ex)
- {
- throw new IllegalArgumentException(MessageFormat.format(Messages.getString("AbstractCDORevision.20"), feature,
- getClassInfo()), ex);
- }
- }
-
- public CDOList getList(EStructuralFeature feature)
- {
- return getList(feature, 0);
- }
-
- public CDOList getList(EStructuralFeature feature, int size)
- {
- int featureIndex = getFeatureIndex(feature);
- CDOList list = (CDOList)getValue(featureIndex);
- if (list == null && size != -1)
- {
- list = CDOListFactory.DEFAULT.createList(size, 0, 0);
- setValue(featureIndex, list);
- }
-
- return list;
- }
-
- public void setList(EStructuralFeature feature, InternalCDOList list)
- {
- int featureIndex = getFeatureIndex(feature);
- setValue(featureIndex, list);
- }
-
- protected abstract void initValues(EStructuralFeature[] allPersistentFeatures);
-
- protected abstract Object getValue(int featureIndex);
-
- protected abstract void setValue(int featureIndex, Object value);
-
- private CDOList getValueAsList(int i)
- {
- return (CDOList)getValue(i);
- }
-
- private void writeValues(CDODataOutput out, int referenceChunk) throws IOException
- {
- EClass owner = getEClass();
- EStructuralFeature[] features = getAllPersistentFeatures();
- for (int i = 0; i < features.length; i++)
- {
- EStructuralFeature feature = features[i];
- Object value = getValue(i);
- if (value == null)
- {
- // Feature is NOT set
- out.writeByte(UNSET);
- continue;
- }
-
- // Feature IS set
- if (value == CDORevisionData.NIL)
- {
- // Feature IS null
- out.writeByte(SET_NULL);
- continue;
- }
-
- // Feature is NOT null
- out.writeByte(SET_NOT_NULL);
- if (feature.isMany())
- {
- CDOList list = (CDOList)value;
- out.writeCDOList(owner, feature, list, referenceChunk);
- }
- else
- {
- checkNoFeatureMap(feature);
- if (feature instanceof EReference)
- {
- value = out.getIDProvider().provideCDOID(value);
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Writing feature {0}: {1}", feature.getName(), value);
- }
-
- out.writeCDOFeatureValue(feature, value);
- }
- }
- }
-
- private void readValues(CDODataInput in) throws IOException
- {
- EClass owner = getEClass();
- EStructuralFeature[] features = getAllPersistentFeatures();
- initValues(features);
- for (int i = 0; i < features.length; i++)
- {
- Object value;
- EStructuralFeature feature = features[i];
- byte unsetState = in.readByte();
- switch (unsetState)
- {
- case UNSET:
- continue;
-
- case SET_NULL:
- setValue(i, CDORevisionData.NIL);
- continue;
- }
-
- if (feature.isMany())
- {
- value = in.readCDOList(owner, feature);
- }
- else
- {
- value = in.readCDOFeatureValue(feature);
- if (TRACER.isEnabled())
- {
- TRACER.format("Read feature {0}: {1}", feature.getName(), value);
- }
- }
-
- setValue(i, value);
- }
- }
-
- public static void checkNoFeatureMap(EStructuralFeature feature)
- {
- if (FeatureMapUtil.isFeatureMap(feature))
- {
- throw new UnsupportedOperationException("Single-valued feature maps not yet handled");
- }
- }
-
- public static Object remapID(Object value, Map<CDOID, CDOID> idMappings, boolean allowUnmappedTempIDs)
- {
- if (value instanceof CDOID)
- {
- CDOID oldID = (CDOID)value;
- if (!oldID.isNull())
- {
- CDOID newID = idMappings.get(oldID);
- if (newID != null)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Adjusting ID: {0} --> {1}", oldID, newID);
- }
-
- return newID;
- }
-
- if (oldID instanceof CDOIDTemp)
- {
- throw new IllegalStateException(MessageFormat.format(Messages.getString("AbstractCDORevision.2"), oldID));
- }
- }
- }
-
- return value;
- }
-}
+/* + * 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 - bug 201266 + * Simon McDuff - bug 212958 + * Simon McDuff - bug 213402 + */ +package org.eclipse.emf.cdo.spi.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.id.CDOIDTemp; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOClassInfo; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDOListFactory; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; +import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta; +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.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; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl; +import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; + +import org.eclipse.net4j.util.om.trace.ContextTracer; +import org.eclipse.net4j.util.om.trace.PerfTracer; + +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject.EStore; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMap.Entry; +import org.eclipse.emf.ecore.util.FeatureMapUtil; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Map; + +/** + * @author Eike Stepper + * @since 3.0 + * @noextend This class is not intended to be subclassed by clients. + */ +public abstract class BaseCDORevision extends AbstractCDORevision +{ + + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_REVISION, BaseCDORevision.class); + + private static final PerfTracer READING = new PerfTracer(OM.PERF_REVISION_READING, BaseCDORevision.class); + + private static final PerfTracer WRITING = new PerfTracer(OM.PERF_REVISION_WRITING, BaseCDORevision.class); + + private static final byte UNSET = 0; + + private static final byte SET_NULL = 1; + + private static final byte SET_NOT_NULL = 2; + + private static final byte FROZEN_FLAG = 0x04; + + private static final byte PERMISSION_MASK = 0x03; + + private CDOID id; + + private CDOBranchPoint branchPoint; + + private int version; + + private long revised; + + private CDOID resourceID; + + /** + * On a client, between a local modification and the commit the value of this <i>ID</i> can be an EObject. + */ + private Object containerID; + + private int containingFeatureID; + + private transient byte flags = CDOPermission.WRITE.getBits(); + + /** + * @since 3.0 + */ + public BaseCDORevision(EClass eClass) + { + super(eClass); + if (eClass != null) + { + version = UNSPECIFIED_VERSION; + revised = UNSPECIFIED_DATE; + resourceID = CDOID.NULL; + containerID = CDOID.NULL; + containingFeatureID = 0; + initValues(getAllPersistentFeatures()); + } + + flags = CDOPermission.WRITE.getBits(); + } + + protected BaseCDORevision(BaseCDORevision source) + { + super(source.getEClass()); + id = source.id; + branchPoint = source.branchPoint; + version = source.version; + revised = source.revised; + resourceID = source.resourceID; + containerID = source.containerID; + containingFeatureID = source.containingFeatureID; + flags = (byte)(source.flags & PERMISSION_MASK); + } + + /** + * @since 3.0 + */ + public void read(CDODataInput in) throws IOException + { + if (READING.isEnabled()) + { + READING.start(this); + } + + readSystemValues(in); + + byte permissionBits = (byte)(in.readByte() & PERMISSION_MASK); + if (permissionBits != CDOPermission.NONE.ordinal()) + { + readValues(in); + } + + flags = permissionBits; + + if (READING.isEnabled()) + { + READING.stop(this); + } + } + + /** + * @since 4.0 + */ + protected void readSystemValues(CDODataInput in) throws IOException + { + EClassifier classifier = in.readCDOClassifierRefAndResolve(); + CDOClassInfo classInfo = CDOModelUtil.getClassInfo((EClass)classifier); + setClassInfo(classInfo); + + id = in.readCDOID(); + branchPoint = in.readCDOBranchPoint(); + version = in.readInt(); + if (!id.isTemporary()) + { + revised = in.readLong(); + } + + resourceID = in.readCDOID(); + containerID = in.readCDOID(); + containingFeatureID = in.readInt(); + + if (TRACER.isEnabled()) + { + TRACER + .format( + "Reading revision: ID={0}, className={1}, version={2}, branchPoint={3}, revised={4}, resource={5}, container={6}, featureID={7}", //$NON-NLS-1$ + id, getEClass().getName(), version, branchPoint, revised, resourceID, containerID, containingFeatureID); + } + } + + /** + * @since 4.0 + */ + public void write(CDODataOutput out, int referenceChunk) throws IOException + { + if (WRITING.isEnabled()) + { + WRITING.start(this); + } + + writeSystemValues(out); + + CDOPermissionProvider permissionProvider = out.getPermissionProvider(); + CDOPermission permission = permissionProvider.getPermission(this); + out.writeByte(permission.getBits()); + + if (permission != CDOPermission.NONE) + { + writeValues(out, referenceChunk); + } + + if (WRITING.isEnabled()) + { + WRITING.stop(this); + } + } + + /** + * @since 4.0 + */ + protected void writeSystemValues(CDODataOutput out) throws IOException + { + EClass eClass = getEClass(); + CDOClassifierRef classRef = new CDOClassifierRef(eClass); + + if (TRACER.isEnabled()) + { + TRACER + .format( + "Writing revision: ID={0}, className={1}, version={2}, branchPoint={3}, revised={4}, resource={5}, container={6}, featureID={7}", //$NON-NLS-1$ + id, eClass.getName(), getVersion(), branchPoint, revised, resourceID, containerID, containingFeatureID); + } + + out.writeCDOClassifierRef(classRef); + out.writeCDOID(id); + out.writeCDOBranchPoint(branchPoint); + out.writeInt(getVersion()); + if (!id.isTemporary()) + { + out.writeLong(revised); + } + + out.writeCDOID(resourceID); + out.writeCDOID(out.getIDProvider().provideCDOID(containerID)); + out.writeInt(containingFeatureID); + } + + /** + * @see #write(CDODataOutput, int) + * @since 3.0 + */ + public void convertEObjects(CDOIDProvider idProvider) + { + if (!(containerID instanceof CDOID)) + { + containerID = idProvider.provideCDOID(containerID); + } + + EStructuralFeature[] features = getAllPersistentFeatures(); + for (int i = 0; i < features.length; i++) + { + EStructuralFeature feature = features[i]; + if (feature.isMany()) + { + CDOList list = getValueAsList(i); + if (list != null) + { + boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); + for (int j = 0; j < list.size(); j++) + { + Object value = list.get(j, false); + EStructuralFeature innerFeature = feature; // Prepare for possible feature map + if (isFeatureMap) + { + Entry entry = (FeatureMap.Entry)value; + innerFeature = entry.getEStructuralFeature(); + value = entry.getValue(); + } + + if (value != null && innerFeature instanceof EReference) + { + CDOID newValue = idProvider.provideCDOID(value); + if (newValue != value) + { + list.set(j, newValue); + } + } + } + } + } + else + { + checkNoFeatureMap(feature); + Object value = getValue(i); + if (value != null && feature instanceof EReference) + { + CDOID newValue = idProvider.provideCDOID(value); + if (newValue != value) + { + setValue(i, newValue); + } + } + } + } + } + + public CDOID getID() + { + return id; + } + + public void setID(CDOID id) + { + if (CDOIDUtil.isNull(id)) + { + throw new IllegalArgumentException(Messages.getString("AbstractCDORevision.1")); //$NON-NLS-1$ + } + + if (TRACER.isEnabled()) + { + TRACER.format("Setting ID: {0}", id); + } + + this.id = id; + } + + /** + * @since 3.0 + */ + public CDOBranch getBranch() + { + if (branchPoint == null) + { + return null; + } + + return branchPoint.getBranch(); + } + + /** + * @since 3.0 + */ + public long getTimeStamp() + { + if (branchPoint == null) + { + return UNSPECIFIED_DATE; + } + + return branchPoint.getTimeStamp(); + } + + /** + * @since 3.0 + */ + public void setBranchPoint(CDOBranchPoint branchPoint) + { + branchPoint = CDOBranchUtil.copyBranchPoint(branchPoint); + if (TRACER.isEnabled()) + { + TRACER.format("Setting branchPoint {0}: {1}", this, branchPoint); + } + + this.branchPoint = branchPoint; + } + + public int getVersion() + { + return version; + } + + public void setVersion(int version) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting version for {0}: v{1}", this, version); + } + + this.version = version; + } + + public long getRevised() + { + return revised; + } + + public void setRevised(long revised) + { + long created = branchPoint.getTimeStamp(); + if (revised != UNSPECIFIED_DATE && revised < Math.max(0, created)) + { + throw new IllegalArgumentException("revision=" + this + ", created=" + CDOCommonUtil.formatTimeStamp(created) + + ", revised=" + CDOCommonUtil.formatTimeStamp(revised)); + } + + if (TRACER.isEnabled()) + { + TRACER.format("Setting revised {0}: {1}", this, CDOCommonUtil.formatTimeStamp(revised)); + } + + this.revised = revised; + } + + public InternalCDORevisionDelta compare(CDORevision origin) + { + return new CDORevisionDeltaImpl(origin, this); + } + + public void merge(CDORevisionDelta delta) + { + CDORevisionMerger applier = new CDORevisionMerger(); + applier.merge(this, delta); + } + + public CDOID getResourceID() + { + return resourceID; + } + + public void setResourceID(CDOID resourceID) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting resourceID {0}: {1}", this, resourceID); + } + + this.resourceID = resourceID; + } + + public Object getContainerID() + { + return containerID; + } + + public void setContainerID(Object containerID) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting containerID {0}: {1}", this, containerID); + } + + this.containerID = containerID; + } + + public int getContainingFeatureID() + { + return containingFeatureID; + } + + public void setContainingFeatureID(int containingFeatureID) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting containingFeatureID {0}: {1}", this, containingFeatureID); + } + + this.containingFeatureID = containingFeatureID; + } + + public int hashCode(EStructuralFeature feature) + { + return getValue(feature).hashCode(); + } + + public Object get(EStructuralFeature feature, int index) + { + if (feature.isMany() && index != EStore.NO_INDEX) + { + CDOList list = getList(feature); + return list.get(index); + } + + return getValue(feature); + } + + public boolean contains(EStructuralFeature feature, Object value) + { + CDOList list = getList(feature); + return list.contains(value); + } + + public int indexOf(EStructuralFeature feature, Object value) + { + CDOList list = getList(feature); + return list.indexOf(value); + } + + public int lastIndexOf(EStructuralFeature feature, Object value) + { + CDOList list = getList(feature); + return list.lastIndexOf(value); + } + + public boolean isEmpty(EStructuralFeature feature) + { + CDOList list = getList(feature); + return list.isEmpty(); + } + + public int size(EStructuralFeature feature) + { + CDOList list = getList(feature); + return list.size(); + } + + public Object[] toArray(EStructuralFeature feature) + { + if (!feature.isMany()) + { + throw new IllegalStateException("!feature.isMany()"); + } + + CDOList list = getList(feature); + return list.toArray(); + } + + public <T> T[] toArray(EStructuralFeature feature, T[] array) + { + if (!feature.isMany()) + { + throw new IllegalStateException("!feature.isMany()"); + } + + CDOList list = getList(feature); + return list.toArray(array); + } + + public void add(EStructuralFeature feature, int index, Object value) + { + CDOList list = getList(feature); + list.add(index, value); + } + + public void clear(EStructuralFeature feature) + { + setValue(feature, null); + } + + public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex) + { + CDOList list = getList(feature); + return list.move(targetIndex, sourceIndex); + } + + public Object remove(EStructuralFeature feature, int index) + { + CDOList list = getList(feature); + return list.remove(index); + } + + public Object set(EStructuralFeature feature, int index, Object value) + { + if (feature.isMany()) + { + CDOList list = getList(feature); + return list.set(index, value); + } + + return setValue(feature, value); + } + + public void unset(EStructuralFeature feature) + { + setValue(feature, null); + } + + /** + * @since 4.0 + */ + public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster) + { + if (TRACER.isEnabled()) + { + TRACER.format("Adjusting references for revision {0}", this); + } + + boolean changed = false; + + CDOID id1 = (CDOID)referenceAdjuster.adjustReference(resourceID, CDOContainerFeatureDelta.CONTAINER_FEATURE, + CDOFeatureDelta.NO_INDEX); + if (id1 != resourceID) + { + resourceID = id1; + changed = true; + } + + Object id2 = referenceAdjuster.adjustReference(containerID, CDOContainerFeatureDelta.CONTAINER_FEATURE, + CDOFeatureDelta.NO_INDEX); + if (id2 != containerID) + { + containerID = id2; + changed = true; + } + + EStructuralFeature[] features = getAllPersistentFeatures(); + for (int i = 0; i < features.length; i++) + { + EStructuralFeature feature = features[i]; + if (feature instanceof EReference || FeatureMapUtil.isFeatureMap(feature)) + { + if (feature.isMany()) + { + InternalCDOList list = (InternalCDOList)getValueAsList(i); + if (list != null) + { + changed |= list.adjustReferences(referenceAdjuster, feature); + } + } + else + { + CDOType type = CDOModelUtil.getType(feature); + Object oldValue = getValue(i); + Object newValue = type.adjustReferences(referenceAdjuster, oldValue, feature, CDOFeatureDelta.NO_INDEX); + if (oldValue != newValue) // Just an optimization for NOOP adjusters + { + setValue(i, newValue); + changed = true; + } + } + } + } + + return changed; + } + + public Object getValue(EStructuralFeature feature) + { + int featureIndex = getFeatureIndex(feature); + return getValue(featureIndex); + } + + public Object setValue(EStructuralFeature feature, Object value) + { + int featureIndex = getFeatureIndex(feature); + + try + { + Object old = getValue(featureIndex); + setValue(featureIndex, value); + return old; + } + catch (ArrayIndexOutOfBoundsException ex) + { + throw new IllegalArgumentException(MessageFormat.format(Messages.getString("AbstractCDORevision.20"), feature, + getClassInfo()), ex); + } + } + + public CDOList getList(EStructuralFeature feature) + { + return getList(feature, 0); + } + + public CDOList getList(EStructuralFeature feature, int size) + { + int featureIndex = getFeatureIndex(feature); + CDOList list = (CDOList)getValue(featureIndex); + if (list == null && size != -1) + { + list = CDOListFactory.DEFAULT.createList(size, 0, 0); + + synchronized (this) + { + CDOPermission permission = getPermission(); + if (permission != CDOPermission.WRITE) + { + setPermission(CDOPermission.WRITE); + } + + try + { + setValue(featureIndex, list); + } + finally + { + if (permission != CDOPermission.WRITE) + { + setPermission(permission); + } + } + } + } + + return list; + } + + public void setList(EStructuralFeature feature, InternalCDOList list) + { + int featureIndex = getFeatureIndex(feature); + setValue(featureIndex, list); + } + + /** + * @since 4.1 + */ + public CDOPermission getPermission() + { + return CDOPermission.get(flags & PERMISSION_MASK); + } + + /** + * @since 4.1 + */ + public void setPermission(CDOPermission permission) + { + flags = (byte)(flags & ~PERMISSION_MASK | permission.getBits() & PERMISSION_MASK); + } + + /** + * @since 4.1 + */ + public void freeze() + { + flags |= FROZEN_FLAG; + + if (isReadable()) + { + EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(getEClass()); + for (int i = 0; i < features.length; i++) + { + EStructuralFeature feature = features[i]; + if (feature.isMany()) + { + InternalCDOList list = (InternalCDOList)doGetValue(i); + if (list != null) + { + list.freeze(); + } + } + } + } + } + + protected Object getValue(int featureIndex) + { + checkReadable(); + return doGetValue(featureIndex); + } + + protected void setValue(int featureIndex, Object value) + { + checkFrozen(featureIndex, value); + checkWritable(); + doSetValue(featureIndex, value); + } + + protected abstract void initValues(EStructuralFeature[] allPersistentFeatures); + + /** + * @since 4.1 + */ + protected abstract Object doGetValue(int featureIndex); + + /** + * @since 4.1 + */ + protected abstract void doSetValue(int featureIndex, Object value); + + private CDOList getValueAsList(int i) + { + return (CDOList)getValue(i); + } + + private void checkFrozen(int featureIndex, Object value) + { + if ((flags & FROZEN_FLAG) != 0) + { + Object oldValue = getValue(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"); + } + } + + 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(); + EStructuralFeature[] features = getAllPersistentFeatures(); + for (int i = 0; i < features.length; i++) + { + EStructuralFeature feature = features[i]; + Object value = getValue(i); + if (value == null) + { + // Feature is NOT set + out.writeByte(UNSET); + continue; + } + + // Feature IS set + if (value == CDORevisionData.NIL) + { + // Feature IS null + out.writeByte(SET_NULL); + continue; + } + + // Feature is NOT null + out.writeByte(SET_NOT_NULL); + if (feature.isMany()) + { + CDOList list = (CDOList)value; + out.writeCDOList(owner, feature, list, referenceChunk); + } + else + { + checkNoFeatureMap(feature); + if (feature instanceof EReference) + { + value = out.getIDProvider().provideCDOID(value); + } + + if (TRACER.isEnabled()) + { + TRACER.format("Writing feature {0}: {1}", feature.getName(), value); + } + + out.writeCDOFeatureValue(feature, value); + } + } + } + + private void readValues(CDODataInput in) throws IOException + { + EClass owner = getEClass(); + EStructuralFeature[] features = getAllPersistentFeatures(); + initValues(features); + for (int i = 0; i < features.length; i++) + { + Object value; + EStructuralFeature feature = features[i]; + byte unsetState = in.readByte(); + switch (unsetState) + { + case UNSET: + continue; + + case SET_NULL: + setValue(i, CDORevisionData.NIL); + continue; + } + + if (feature.isMany()) + { + value = in.readCDOList(owner, feature); + } + else + { + value = in.readCDOFeatureValue(feature); + if (TRACER.isEnabled()) + { + TRACER.format("Read feature {0}: {1}", feature.getName(), value); + } + } + + setValue(i, value); + } + } + + public static void checkNoFeatureMap(EStructuralFeature feature) + { + if (FeatureMapUtil.isFeatureMap(feature)) + { + throw new UnsupportedOperationException("Single-valued feature maps not yet handled"); + } + } + + public static Object remapID(Object value, Map<CDOID, CDOID> idMappings, boolean allowUnmappedTempIDs) + { + if (value instanceof CDOID) + { + CDOID oldID = (CDOID)value; + if (!oldID.isNull()) + { + CDOID newID = idMappings.get(oldID); + if (newID != null) + { + if (TRACER.isEnabled()) + { + TRACER.format("Adjusting ID: {0} --> {1}", oldID, newID); + } + + return newID; + } + + if (oldID instanceof CDOIDTemp) + { + throw new IllegalStateException(MessageFormat.format(Messages.getString("AbstractCDORevision.2"), oldID)); + } + } + } + + return value; + } +} 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 57d87a2b4e..031f06eb0a 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 @@ -1,324 +1,357 @@ -/*
- * 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
- * Caspar De Groot - bug 341081
- */
-package org.eclipse.emf.cdo.spi.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.model.CDOClassInfo;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.io.IOException;
-
-/**
- * @author Eike Stepper
- * @since 3.0
- */
-public abstract class DelegatingCDORevision implements InternalCDORevision
-{
- public DelegatingCDORevision()
- {
- }
-
- public abstract InternalCDORevision getDelegate();
-
- /**
- * @since 4.0
- */
- public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster)
- {
- return getDelegate().adjustReferences(referenceAdjuster);
- }
-
- public long getTimeStamp()
- {
- return getDelegate().getTimeStamp();
- }
-
- public CDOBranch getBranch()
- {
- return getDelegate().getBranch();
- }
-
- public boolean isHistorical()
- {
- return getDelegate().isHistorical();
- }
-
- public CDOID getID()
- {
- return getDelegate().getID();
- }
-
- public CDORevision revision()
- {
- return getDelegate().revision();
- }
-
- public CDOID getResourceID()
- {
- return getDelegate().getResourceID();
- }
-
- public Object getContainerID()
- {
- return getDelegate().getContainerID();
- }
-
- public int getContainingFeatureID()
- {
- return getDelegate().getContainingFeatureID();
- }
-
- public Object get(EStructuralFeature feature, int index)
- {
- return getDelegate().get(feature, index);
- }
-
- public EClass getEClass()
- {
- return getDelegate().getEClass();
- }
-
- public int getVersion()
- {
- return getDelegate().getVersion();
- }
-
- public int size(EStructuralFeature feature)
- {
- return getDelegate().size(feature);
- }
-
- public long getRevised()
- {
- return getDelegate().getRevised();
- }
-
- public boolean isEmpty(EStructuralFeature feature)
- {
- return getDelegate().isEmpty(feature);
- }
-
- public boolean isValid(long timeStamp)
- {
- return getDelegate().isValid(timeStamp);
- }
-
- /**
- * @since 4.0
- */
- public boolean isValid(CDOBranchPoint branchPoint)
- {
- return getDelegate().isValid(branchPoint);
- }
-
- /**
- * @since 4.0
- */
- public InternalCDORevision copy()
- {
- return null;
- }
-
- public CDOClassInfo getClassInfo()
- {
- return getDelegate().getClassInfo();
- }
-
- public void setID(CDOID id)
- {
- getDelegate().setID(id);
- }
-
- public boolean contains(EStructuralFeature feature, Object value)
- {
- return getDelegate().contains(feature, value);
- }
-
- public boolean isResourceNode()
- {
- return getDelegate().isResourceNode();
- }
-
- public void setVersion(int version)
- {
- getDelegate().setVersion(version);
- }
-
- public boolean isResourceFolder()
- {
- return getDelegate().isResourceFolder();
- }
-
- public int indexOf(EStructuralFeature feature, Object value)
- {
- return getDelegate().indexOf(feature, value);
- }
-
- public boolean isResource()
- {
- return getDelegate().isResource();
- }
-
- public void setBranchPoint(CDOBranchPoint branchPoint)
- {
- getDelegate().setBranchPoint(branchPoint);
- }
-
- public void adjustForCommit(CDOBranch branch, long timeStamp)
- {
- getDelegate().adjustForCommit(branch, timeStamp);
- }
-
- public CDORevisionData data()
- {
- return getDelegate().data();
- }
-
- public int lastIndexOf(EStructuralFeature feature, Object value)
- {
- return getDelegate().lastIndexOf(feature, value);
- }
-
- public void setRevised(long revised)
- {
- getDelegate().setRevised(revised);
- }
-
- public InternalCDORevisionDelta compare(CDORevision origin)
- {
- return getDelegate().compare(origin);
- }
-
- public void setResourceID(CDOID resourceID)
- {
- getDelegate().setResourceID(resourceID);
- }
-
- public void merge(CDORevisionDelta delta)
- {
- getDelegate().merge(delta);
- }
-
- public <T> T[] toArray(EStructuralFeature feature, T[] array)
- {
- return getDelegate().toArray(feature, array);
- }
-
- public void setContainerID(Object containerID)
- {
- getDelegate().setContainerID(containerID);
- }
-
- public void setContainingFeatureID(int containingFeatureID)
- {
- getDelegate().setContainingFeatureID(containingFeatureID);
- }
-
- public Object[] toArray(EStructuralFeature feature)
- {
- return getDelegate().toArray(feature);
- }
-
- public void add(EStructuralFeature feature, int index, Object value)
- {
- getDelegate().add(feature, index, value);
- }
-
- public int hashCode(EStructuralFeature feature)
- {
- return getDelegate().hashCode(feature);
- }
-
- public void clear(EStructuralFeature feature)
- {
- getDelegate().clear(feature);
- }
-
- public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex)
- {
- return getDelegate().move(feature, targetIndex, sourceIndex);
- }
-
- public Object remove(EStructuralFeature feature, int index)
- {
- return getDelegate().remove(feature, index);
- }
-
- public Object set(EStructuralFeature feature, int index, Object value)
- {
- return getDelegate().set(feature, index, value);
- }
-
- public void unset(EStructuralFeature feature)
- {
- getDelegate().unset(feature);
- }
-
- public Object getValue(EStructuralFeature feature)
- {
- return getDelegate().getValue(feature);
- }
-
- public Object setValue(EStructuralFeature feature, Object value)
- {
- return getDelegate().setValue(feature, value);
- }
-
- public void setList(EStructuralFeature feature, InternalCDOList list)
- {
- getDelegate().setList(feature, list);
- }
-
- public CDOList getList(EStructuralFeature feature)
- {
- return getDelegate().getList(feature);
- }
-
- public CDOList getList(EStructuralFeature feature, int size)
- {
- return getDelegate().getList(feature, size);
- }
-
- public void read(CDODataInput in) throws IOException
- {
- getDelegate().read(in);
- }
-
- public void write(CDODataOutput out, int referenceChunk) throws IOException
- {
- getDelegate().write(out, referenceChunk);
- }
-
- public void convertEObjects(CDOIDProvider oidProvider)
- {
- getDelegate().convertEObjects(oidProvider);
- }
-
- /**
- * @since 4.0
- */
- public void freeze()
- {
- getDelegate().freeze();
- }
-}
+/* + * 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 + * Caspar De Groot - bug 341081 + */ +package org.eclipse.emf.cdo.spi.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.model.CDOClassInfo; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.common.security.CDOPermission; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.io.IOException; + +/** + * @author Eike Stepper + * @since 3.0 + */ +public abstract class DelegatingCDORevision implements InternalCDORevision +{ + public DelegatingCDORevision() + { + } + + public abstract InternalCDORevision getDelegate(); + + /** + * @since 4.0 + */ + public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster) + { + return getDelegate().adjustReferences(referenceAdjuster); + } + + public long getTimeStamp() + { + return getDelegate().getTimeStamp(); + } + + public CDOBranch getBranch() + { + return getDelegate().getBranch(); + } + + public boolean isHistorical() + { + return getDelegate().isHistorical(); + } + + public CDOID getID() + { + return getDelegate().getID(); + } + + public CDORevision revision() + { + return getDelegate().revision(); + } + + public CDOID getResourceID() + { + return getDelegate().getResourceID(); + } + + public Object getContainerID() + { + return getDelegate().getContainerID(); + } + + public int getContainingFeatureID() + { + return getDelegate().getContainingFeatureID(); + } + + public Object get(EStructuralFeature feature, int index) + { + return getDelegate().get(feature, index); + } + + public EClass getEClass() + { + return getDelegate().getEClass(); + } + + public int getVersion() + { + return getDelegate().getVersion(); + } + + public int size(EStructuralFeature feature) + { + return getDelegate().size(feature); + } + + public long getRevised() + { + return getDelegate().getRevised(); + } + + public boolean isEmpty(EStructuralFeature feature) + { + return getDelegate().isEmpty(feature); + } + + public boolean isValid(long timeStamp) + { + return getDelegate().isValid(timeStamp); + } + + /** + * @since 4.0 + */ + public boolean isValid(CDOBranchPoint branchPoint) + { + return getDelegate().isValid(branchPoint); + } + + /** + * @since 4.0 + */ + public InternalCDORevision copy() + { + return null; + } + + public CDOClassInfo getClassInfo() + { + return getDelegate().getClassInfo(); + } + + public void setID(CDOID id) + { + getDelegate().setID(id); + } + + public boolean contains(EStructuralFeature feature, Object value) + { + return getDelegate().contains(feature, value); + } + + public boolean isResourceNode() + { + return getDelegate().isResourceNode(); + } + + public void setVersion(int version) + { + getDelegate().setVersion(version); + } + + public boolean isResourceFolder() + { + return getDelegate().isResourceFolder(); + } + + public int indexOf(EStructuralFeature feature, Object value) + { + return getDelegate().indexOf(feature, value); + } + + public boolean isResource() + { + return getDelegate().isResource(); + } + + public void setBranchPoint(CDOBranchPoint branchPoint) + { + getDelegate().setBranchPoint(branchPoint); + } + + public void adjustForCommit(CDOBranch branch, long timeStamp) + { + getDelegate().adjustForCommit(branch, timeStamp); + } + + public CDORevisionData data() + { + return getDelegate().data(); + } + + public int lastIndexOf(EStructuralFeature feature, Object value) + { + return getDelegate().lastIndexOf(feature, value); + } + + public void setRevised(long revised) + { + getDelegate().setRevised(revised); + } + + public InternalCDORevisionDelta compare(CDORevision origin) + { + return getDelegate().compare(origin); + } + + public void setResourceID(CDOID resourceID) + { + getDelegate().setResourceID(resourceID); + } + + public void merge(CDORevisionDelta delta) + { + getDelegate().merge(delta); + } + + public <T> T[] toArray(EStructuralFeature feature, T[] array) + { + return getDelegate().toArray(feature, array); + } + + public void setContainerID(Object containerID) + { + getDelegate().setContainerID(containerID); + } + + public void setContainingFeatureID(int containingFeatureID) + { + getDelegate().setContainingFeatureID(containingFeatureID); + } + + public Object[] toArray(EStructuralFeature feature) + { + return getDelegate().toArray(feature); + } + + public void add(EStructuralFeature feature, int index, Object value) + { + getDelegate().add(feature, index, value); + } + + public int hashCode(EStructuralFeature feature) + { + return getDelegate().hashCode(feature); + } + + public void clear(EStructuralFeature feature) + { + getDelegate().clear(feature); + } + + public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex) + { + return getDelegate().move(feature, targetIndex, sourceIndex); + } + + public Object remove(EStructuralFeature feature, int index) + { + return getDelegate().remove(feature, index); + } + + public Object set(EStructuralFeature feature, int index, Object value) + { + return getDelegate().set(feature, index, value); + } + + public void unset(EStructuralFeature feature) + { + getDelegate().unset(feature); + } + + public Object getValue(EStructuralFeature feature) + { + return getDelegate().getValue(feature); + } + + public Object setValue(EStructuralFeature feature, Object value) + { + return getDelegate().setValue(feature, value); + } + + public void setList(EStructuralFeature feature, InternalCDOList list) + { + getDelegate().setList(feature, list); + } + + public CDOList getList(EStructuralFeature feature) + { + return getDelegate().getList(feature); + } + + public CDOList getList(EStructuralFeature feature, int size) + { + return getDelegate().getList(feature, size); + } + + public void read(CDODataInput in) throws IOException + { + getDelegate().read(in); + } + + public void write(CDODataOutput out, int referenceChunk) throws IOException + { + getDelegate().write(out, referenceChunk); + } + + public void convertEObjects(CDOIDProvider oidProvider) + { + getDelegate().convertEObjects(oidProvider); + } + + /** + * @since 4.1 + */ + public CDOPermission getPermission() + { + return getDelegate().getPermission(); + } + + /** + * @since 4.1 + */ + public void setPermission(CDOPermission permission) + { + getDelegate().setPermission(permission); + } + + /** + * @since 4.1 + */ + public boolean isReadable() + { + return getDelegate().isReadable(); + } + + /** + * @since 4.1 + */ + public boolean isWritable() + { + return getDelegate().isWritable(); + } + + /** + * @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/InternalCDORevision.java b/plugins/org.eclipse.emf.cdo.common/src/org/eclipse/emf/cdo/spi/common/revision/InternalCDORevision.java index dbce8a0caf..9d646837ba 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 @@ -1,121 +1,129 @@ -/*
- * 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.cdo.spi.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.model.CDOClassInfo;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.io.IOException;
-
-/**
- * @author Eike Stepper
- * @since 2.0
- */
-public interface InternalCDORevision extends CDORevision, CDORevisionData, CDOReferenceAdjustable
-{
- /**
- * @since 3.0
- */
- public CDOClassInfo getClassInfo();
-
- public void setID(CDOID id);
-
- public void setVersion(int version);
-
- /**
- * @since 3.0
- */
- public void setBranchPoint(CDOBranchPoint branchPoint);
-
- public void setRevised(long revised);
-
- public void setResourceID(CDOID resourceID);
-
- public void setContainerID(Object containerID);
-
- public void setContainingFeatureID(int containingFeatureID);
-
- /**
- * @since 3.0
- */
- public void adjustForCommit(CDOBranch branch, long timeStamp);
-
- public void add(EStructuralFeature feature, int index, Object value);
-
- public void clear(EStructuralFeature feature);
-
- public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex);
-
- public Object remove(EStructuralFeature feature, int index);
-
- public Object set(EStructuralFeature feature, int index, Object value);
-
- public void unset(EStructuralFeature feature);
-
- /**
- * Should never return {@link InternalCDORevision#NIL}
- */
- public Object getValue(EStructuralFeature feature);
-
- public Object setValue(EStructuralFeature feature, Object value);
-
- public void setList(EStructuralFeature feature, InternalCDOList list);
-
- public CDOList getList(EStructuralFeature feature);
-
- /**
- * @param initialCapacity
- * the initialCapacity of a new list to be created if this revision has no list so far (its size will always
- * be 0), or -1 to skip list creation and return <code>null</code> in this case.
- */
- public CDOList getList(EStructuralFeature feature, int initialCapacity);
-
- /**
- * @since 3.0
- */
- public void read(CDODataInput in) throws IOException;
-
- /**
- * @since 3.0
- */
- public void write(CDODataOutput out, int referenceChunk) throws IOException;
-
- /**
- * @since 3.0
- */
- public void convertEObjects(CDOIDProvider oidProvider);
-
- /**
- * @since 3.0
- */
- public InternalCDORevisionDelta compare(CDORevision origin);
-
- /**
- * @since 3.0
- */
- public InternalCDORevision copy();
-
- /**
- * @since 4.0
- */
- public void freeze();
-}
+/* + * 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.cdo.spi.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.model.CDOClassInfo; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; +import org.eclipse.emf.cdo.common.security.CDOPermission; + +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.io.IOException; + +/** + * @author Eike Stepper + * @since 2.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface InternalCDORevision extends CDORevision, CDORevisionData, CDOReferenceAdjustable +{ + /** + * @since 3.0 + */ + public CDOClassInfo getClassInfo(); + + public void setID(CDOID id); + + public void setVersion(int version); + + /** + * @since 3.0 + */ + public void setBranchPoint(CDOBranchPoint branchPoint); + + public void setRevised(long revised); + + public void setResourceID(CDOID resourceID); + + public void setContainerID(Object containerID); + + public void setContainingFeatureID(int containingFeatureID); + + /** + * @since 3.0 + */ + public void adjustForCommit(CDOBranch branch, long timeStamp); + + public void add(EStructuralFeature feature, int index, Object value); + + public void clear(EStructuralFeature feature); + + public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex); + + public Object remove(EStructuralFeature feature, int index); + + public Object set(EStructuralFeature feature, int index, Object value); + + public void unset(EStructuralFeature feature); + + /** + * Should never return {@link InternalCDORevision#NIL} + */ + public Object getValue(EStructuralFeature feature); + + public Object setValue(EStructuralFeature feature, Object value); + + public void setList(EStructuralFeature feature, InternalCDOList list); + + public CDOList getList(EStructuralFeature feature); + + /** + * @param initialCapacity + * the initialCapacity of a new list to be created if this revision has no list so far (its size will always + * be 0), or -1 to skip list creation and return <code>null</code> in this case. + */ + public CDOList getList(EStructuralFeature feature, int initialCapacity); + + /** + * @since 3.0 + */ + public void read(CDODataInput in) throws IOException; + + /** + * @since 3.0 + */ + public void write(CDODataOutput out, int referenceChunk) throws IOException; + + /** + * @since 3.0 + */ + public void convertEObjects(CDOIDProvider oidProvider); + + /** + * @since 3.0 + */ + public InternalCDORevisionDelta compare(CDORevision origin); + + /** + * @since 3.0 + */ + public InternalCDORevision copy(); + + /** + * @since 4.1 + */ + public void setPermission(CDOPermission permission); + + /** + * @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 cc2449465c..72ffca1b96 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 @@ -1,269 +1,286 @@ -/*
- * 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.spi.common.revision;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.io.IOException;
-
-/**
- * @author Eike Stepper
- * @since 3.0
- */
-public class StubCDORevision extends AbstractCDORevision
-{
- public StubCDORevision(EClass eClass)
- {
- super(eClass);
- }
-
- public int compareTo(CDOBranchPoint o)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setID(CDOID id)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setVersion(int version)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setBranchPoint(CDOBranchPoint branchPoint)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setRevised(long revised)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setResourceID(CDOID resourceID)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setContainerID(Object containerID)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setContainingFeatureID(int containingFeatureID)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void add(EStructuralFeature feature, int index, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void clear(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object remove(EStructuralFeature feature, int index)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object set(EStructuralFeature feature, int index, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void unset(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object getValue(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object setValue(EStructuralFeature feature, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void setList(EStructuralFeature feature, InternalCDOList list)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public CDOList getList(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public CDOList getList(EStructuralFeature feature, int size)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void read(CDODataInput in) throws IOException
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void write(CDODataOutput out, int referenceChunk) throws IOException
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void convertEObjects(CDOIDProvider oidProvider)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int getVersion()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public long getRevised()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public InternalCDORevisionDelta compare(CDORevision origin)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public void merge(CDORevisionDelta delta)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public InternalCDORevision copy()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public CDOID getID()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public CDOBranch getBranch()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public long getTimeStamp()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public CDOID getResourceID()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object getContainerID()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int getContainingFeatureID()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object get(EStructuralFeature feature, int index)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int size(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public boolean isEmpty(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public boolean contains(EStructuralFeature feature, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int indexOf(EStructuralFeature feature, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int lastIndexOf(EStructuralFeature feature, Object value)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public <T> T[] toArray(EStructuralFeature feature, T[] array)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public Object[] toArray(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- public int hashCode(EStructuralFeature feature)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- /**
- * @since 4.0
- */
- public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster)
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- /**
- * @since 4.0
- */
- public void freeze()
- {
- throw new UnsupportedOperationException(getExceptionMessage());
- }
-
- private String getExceptionMessage()
- {
- return "Unsupported operation in " + this;
- }
-}
+/* + * 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.spi.common.revision; + +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.common.security.CDOPermission; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.io.IOException; + +/** + * @author Eike Stepper + * @since 3.0 + */ +public class StubCDORevision extends AbstractCDORevision +{ + public StubCDORevision(EClass eClass) + { + super(eClass); + } + + public int compareTo(CDOBranchPoint o) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setID(CDOID id) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setVersion(int version) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setBranchPoint(CDOBranchPoint branchPoint) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setRevised(long revised) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setResourceID(CDOID resourceID) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setContainerID(Object containerID) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setContainingFeatureID(int containingFeatureID) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void add(EStructuralFeature feature, int index, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void clear(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object remove(EStructuralFeature feature, int index) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object set(EStructuralFeature feature, int index, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void unset(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object getValue(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object setValue(EStructuralFeature feature, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void setList(EStructuralFeature feature, InternalCDOList list) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public CDOList getList(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public CDOList getList(EStructuralFeature feature, int size) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void read(CDODataInput in) throws IOException + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void write(CDODataOutput out, int referenceChunk) throws IOException + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void convertEObjects(CDOIDProvider oidProvider) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int getVersion() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public long getRevised() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public InternalCDORevisionDelta compare(CDORevision origin) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public void merge(CDORevisionDelta delta) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public InternalCDORevision copy() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public CDOID getID() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public CDOBranch getBranch() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public long getTimeStamp() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public CDOID getResourceID() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object getContainerID() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int getContainingFeatureID() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object get(EStructuralFeature feature, int index) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int size(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public boolean isEmpty(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public boolean contains(EStructuralFeature feature, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int indexOf(EStructuralFeature feature, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int lastIndexOf(EStructuralFeature feature, Object value) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public <T> T[] toArray(EStructuralFeature feature, T[] array) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public Object[] toArray(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + public int hashCode(EStructuralFeature feature) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + /** + * @since 4.0 + */ + public boolean adjustReferences(CDOReferenceAdjuster referenceAdjuster) + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + /** + * @since 4.1 + */ + public CDOPermission getPermission() + { + throw new UnsupportedOperationException(getExceptionMessage()); + } + + /** + * @since 4.1 + */ + public void setPermission(CDOPermission permission) + { + 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.server.hibernate.teneo/src/org/eclipse/emf/cdo/server/hibernate/teneo/CDOEntityMapper.java b/plugins/org.eclipse.emf.cdo.server.hibernate.teneo/src/org/eclipse/emf/cdo/server/hibernate/teneo/CDOEntityMapper.java index 8f3ee8987c..7ea5549f9f 100644 --- a/plugins/org.eclipse.emf.cdo.server.hibernate.teneo/src/org/eclipse/emf/cdo/server/hibernate/teneo/CDOEntityMapper.java +++ b/plugins/org.eclipse.emf.cdo.server.hibernate.teneo/src/org/eclipse/emf/cdo/server/hibernate/teneo/CDOEntityMapper.java @@ -75,7 +75,10 @@ public class CDOEntityMapper extends EntityMapper CDOHibernateConstants.CONTAINER_PROPERTY_COLUMN);
final Element versionElement = entityElement.addElement("property"); //$NON-NLS-1$
- versionElement.addAttribute("name", getHbmContext().getVersionColumnName()); //$NON-NLS-1$
+ // add cdo_teneo prefix to prop name prevent name clashes with
+ // efeatures which are accidentally called version
+ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=378050
+ versionElement.addAttribute("name", "cdo_teneo_" + getHbmContext().getVersionColumnName()); //$NON-NLS-1$
versionElement.addElement("meta").addAttribute("attribute", "version").setText("true");
versionElement.addElement("column").addAttribute("name", getHbmContext().getVersionColumnName()); //$NON-NLS-1$//$NON-NLS-2$
versionElement.addAttribute("type", Integer.class.getName()); //$NON-NLS-1$
diff --git a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerIndication.java b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerIndication.java index 79c49906cc..62b451c2c9 100644 --- a/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerIndication.java +++ b/plugins/org.eclipse.emf.cdo.server.net4j/src/org/eclipse/emf/cdo/server/internal/net4j/protocol/CDOServerIndication.java @@ -1,158 +1,165 @@ -/*
- * 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.cdo.server.internal.net4j.protocol;
-
-import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.lob.CDOLobStore;
-import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-import org.eclipse.emf.cdo.common.revision.CDOListFactory;
-import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
-import org.eclipse.emf.cdo.internal.common.protocol.CDODataInputImpl;
-import org.eclipse.emf.cdo.internal.common.protocol.CDODataOutputImpl;
-import org.eclipse.emf.cdo.internal.common.revision.CDOListImpl;
-import org.eclipse.emf.cdo.server.IStore;
-import org.eclipse.emf.cdo.spi.server.InternalRepository;
-import org.eclipse.emf.cdo.spi.server.InternalSession;
-
-import org.eclipse.net4j.signal.IndicationWithResponse;
-import org.eclipse.net4j.util.io.ExtendedDataInputStream;
-import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
-import org.eclipse.net4j.util.io.StringIO;
-import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
-
-import java.io.IOException;
-
-/**
- * @author Eike Stepper
- */
-public abstract class CDOServerIndication extends IndicationWithResponse
-{
- public CDOServerIndication(CDOServerProtocol protocol, short signalID)
- {
- super(protocol, signalID);
- }
-
- @Override
- public CDOServerProtocol getProtocol()
- {
- return (CDOServerProtocol)super.getProtocol();
- }
-
- protected InternalSession getSession()
- {
- return getProtocol().getSession();
- }
-
- protected InternalRepository getRepository()
- {
- InternalRepository repository = getSession().getManager().getRepository();
- if (!LifecycleUtil.isActive(repository))
- {
- throw new IllegalStateException("CDORepositoryInfo has been deactivated"); //$NON-NLS-1$
- }
-
- return repository;
- }
-
- protected IStore getStore()
- {
- IStore store = getRepository().getStore();
- if (!LifecycleUtil.isActive(store))
- {
- throw new IllegalStateException("Store has been deactivated"); //$NON-NLS-1$
- }
-
- return store;
- }
-
- @Override
- protected void indicating(ExtendedDataInputStream in) throws Exception
- {
- indicating(new CDODataInputImpl(in)
- {
- @Override
- protected CDOPackageRegistry getPackageRegistry()
- {
- return getRepository().getPackageRegistry();
- }
-
- @Override
- protected StringIO getPackageURICompressor()
- {
- return getProtocol().getPackageURICompressor();
- }
-
- @Override
- protected CDOBranchManager getBranchManager()
- {
- return getRepository().getBranchManager();
- }
-
- @Override
- protected CDOCommitInfoManager getCommitInfoManager()
- {
- return getRepository().getCommitInfoManager();
- }
-
- @Override
- protected CDORevisionFactory getRevisionFactory()
- {
- return getRepository().getRevisionManager().getFactory();
- }
-
- @Override
- protected CDOLobStore getLobStore()
- {
- return null; // Not used on server
- }
-
- @Override
- protected CDOListFactory getListFactory()
- {
- return CDOListImpl.FACTORY;
- }
- });
- }
-
- @Override
- protected void responding(ExtendedDataOutputStream out) throws Exception
- {
- responding(new CDODataOutputImpl(out)
- {
- @Override
- public CDOPackageRegistry getPackageRegistry()
- {
- return getRepository().getPackageRegistry();
- }
-
- @Override
- public CDOIDProvider getIDProvider()
- {
- return getSession();
- }
-
- @Override
- protected StringIO getPackageURICompressor()
- {
- return getProtocol().getPackageURICompressor();
- }
- });
- }
-
- protected abstract void indicating(CDODataInput in) throws IOException;
-
- protected abstract void responding(CDODataOutput out) throws IOException;
-}
+/* + * 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.cdo.server.internal.net4j.protocol; + +import org.eclipse.emf.cdo.common.branch.CDOBranchManager; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfoManager; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.lob.CDOLobStore; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.protocol.CDODataInput; +import org.eclipse.emf.cdo.common.protocol.CDODataOutput; +import org.eclipse.emf.cdo.common.revision.CDOListFactory; +import org.eclipse.emf.cdo.common.revision.CDORevisionFactory; +import org.eclipse.emf.cdo.common.security.CDOPermissionProvider; +import org.eclipse.emf.cdo.internal.common.protocol.CDODataInputImpl; +import org.eclipse.emf.cdo.internal.common.protocol.CDODataOutputImpl; +import org.eclipse.emf.cdo.internal.common.revision.CDOListImpl; +import org.eclipse.emf.cdo.server.IStore; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalSession; + +import org.eclipse.net4j.signal.IndicationWithResponse; +import org.eclipse.net4j.util.io.ExtendedDataInputStream; +import org.eclipse.net4j.util.io.ExtendedDataOutputStream; +import org.eclipse.net4j.util.io.StringIO; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; + +import java.io.IOException; + +/** + * @author Eike Stepper + */ +public abstract class CDOServerIndication extends IndicationWithResponse +{ + public CDOServerIndication(CDOServerProtocol protocol, short signalID) + { + super(protocol, signalID); + } + + @Override + public CDOServerProtocol getProtocol() + { + return (CDOServerProtocol)super.getProtocol(); + } + + protected InternalSession getSession() + { + return getProtocol().getSession(); + } + + protected InternalRepository getRepository() + { + InternalRepository repository = getSession().getManager().getRepository(); + if (!LifecycleUtil.isActive(repository)) + { + throw new IllegalStateException("CDORepositoryInfo has been deactivated"); //$NON-NLS-1$ + } + + return repository; + } + + protected IStore getStore() + { + IStore store = getRepository().getStore(); + if (!LifecycleUtil.isActive(store)) + { + throw new IllegalStateException("Store has been deactivated"); //$NON-NLS-1$ + } + + return store; + } + + @Override + protected void indicating(ExtendedDataInputStream in) throws Exception + { + indicating(new CDODataInputImpl(in) + { + @Override + protected CDOPackageRegistry getPackageRegistry() + { + return getRepository().getPackageRegistry(); + } + + @Override + protected StringIO getPackageURICompressor() + { + return getProtocol().getPackageURICompressor(); + } + + @Override + protected CDOBranchManager getBranchManager() + { + return getRepository().getBranchManager(); + } + + @Override + protected CDOCommitInfoManager getCommitInfoManager() + { + return getRepository().getCommitInfoManager(); + } + + @Override + protected CDORevisionFactory getRevisionFactory() + { + return getRepository().getRevisionManager().getFactory(); + } + + @Override + protected CDOLobStore getLobStore() + { + return null; // Not used on server + } + + @Override + protected CDOListFactory getListFactory() + { + return CDOListImpl.FACTORY; + } + }); + } + + @Override + protected void responding(ExtendedDataOutputStream out) throws Exception + { + responding(new CDODataOutputImpl(out) + { + @Override + public CDOPackageRegistry getPackageRegistry() + { + return getRepository().getPackageRegistry(); + } + + @Override + public CDOIDProvider getIDProvider() + { + return getSession(); + } + + @Override + public CDOPermissionProvider getPermissionProvider() + { + return getSession(); + } + + @Override + protected StringIO getPackageURICompressor() + { + return getProtocol().getPackageURICompressor(); + } + }); + } + + protected abstract void indicating(CDODataInput in) throws IOException; + + protected abstract void responding(CDODataOutput out) throws IOException; +} 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 1ab78243d4..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 @@ -1,579 +1,592 @@ -/*
- * 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 - bug 201266
- * Simon McDuff - bug 230832
- * Simon McDuff - bug 233490
- * Simon McDuff - bug 213402
- */
-package org.eclipse.emf.cdo.internal.server;
-
-import org.eclipse.emf.cdo.common.CDOCommonRepository;
-import org.eclipse.emf.cdo.common.CDOCommonSession;
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
-import org.eclipse.emf.cdo.internal.common.commit.DelegatingCommitInfo;
-import org.eclipse.emf.cdo.server.IView;
-import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
-import org.eclipse.emf.cdo.spi.server.ISessionProtocol;
-import org.eclipse.emf.cdo.spi.server.InternalSession;
-import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
-import org.eclipse.emf.cdo.spi.server.InternalTransaction;
-import org.eclipse.emf.cdo.spi.server.InternalView;
-
-import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
-import org.eclipse.net4j.util.collection.IndexedList;
-import org.eclipse.net4j.util.container.Container;
-import org.eclipse.net4j.util.event.EventUtil;
-import org.eclipse.net4j.util.event.IListener;
-import org.eclipse.net4j.util.lifecycle.ILifecycle;
-import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
-import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
-import org.eclipse.net4j.util.om.log.OMLogger;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.text.MessageFormat;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @author Eike Stepper
- */
-public class Session extends Container<IView> implements InternalSession
-{
- private InternalSessionManager manager;
-
- private ISessionProtocol protocol;
-
- private int sessionID;
-
- private String userID;
-
- private boolean passiveUpdateEnabled = true;
-
- private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS;
-
- private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS;
-
- private long lastUpdateTime;
-
- @ExcludeFromDump
- private Object lastUpdateTimeLock = new Object();
-
- private ConcurrentMap<Integer, InternalView> views = new ConcurrentHashMap<Integer, InternalView>();
-
- private AtomicInteger lastTempViewID = new AtomicInteger();
-
- @ExcludeFromDump
- private IListener protocolListener = new LifecycleEventAdapter()
- {
- @Override
- protected void onDeactivated(ILifecycle lifecycle)
- {
- deactivate();
- }
- };
-
- private boolean subscribed;
-
- /**
- * @since 2.0
- */
- public Session(InternalSessionManager manager, ISessionProtocol protocol, int sessionID, String userID)
- {
- this.manager = manager;
- this.protocol = protocol;
- this.sessionID = sessionID;
- this.userID = userID;
-
- EventUtil.addListener(protocol, protocolListener);
- activate();
- }
-
- /**
- * @since 2.0
- */
- public Options options()
- {
- return this;
- }
-
- /**
- * @since 2.0
- */
- public CDOCommonSession getContainer()
- {
- return this;
- }
-
- public InternalSessionManager getManager()
- {
- return manager;
- }
-
- public ISessionProtocol getProtocol()
- {
- return protocol;
- }
-
- public int getSessionID()
- {
- return sessionID;
- }
-
- /**
- * @since 2.0
- */
- public String getUserID()
- {
- return userID;
- }
-
- /**
- * @since 2.0
- */
- public boolean isSubscribed()
- {
- return subscribed;
- }
-
- /**
- * @since 2.0
- */
- public void setSubscribed(boolean subscribed)
- {
- checkActive();
- if (this.subscribed != subscribed)
- {
- this.subscribed = subscribed;
- byte opcode = subscribed ? CDOProtocolConstants.REMOTE_SESSION_SUBSCRIBED
- : CDOProtocolConstants.REMOTE_SESSION_UNSUBSCRIBED;
- manager.sendRemoteSessionNotification(this, opcode);
- }
- }
-
- /**
- * @since 2.0
- */
- public boolean isPassiveUpdateEnabled()
- {
- return passiveUpdateEnabled;
- }
-
- /**
- * @since 2.0
- */
- public void setPassiveUpdateEnabled(boolean passiveUpdateEnabled)
- {
- checkActive();
- this.passiveUpdateEnabled = passiveUpdateEnabled;
- }
-
- public PassiveUpdateMode getPassiveUpdateMode()
- {
- return passiveUpdateMode;
- }
-
- public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode)
- {
- checkActive();
- checkArg(passiveUpdateMode, "passiveUpdateMode");
- this.passiveUpdateMode = passiveUpdateMode;
- }
-
- public LockNotificationMode getLockNotificationMode()
- {
- return lockNotificationMode;
- }
-
- public void setLockNotificationMode(LockNotificationMode lockNotificationMode)
- {
- checkActive();
- checkArg(lockNotificationMode, "lockNotificationMode");
- this.lockNotificationMode = lockNotificationMode;
- }
-
- public long getLastUpdateTime()
- {
- synchronized (lastUpdateTimeLock)
- {
- return lastUpdateTime;
- }
- }
-
- public InternalView[] getElements()
- {
- checkActive();
- return getViews();
- }
-
- @Override
- public boolean isEmpty()
- {
- checkActive();
- return views.isEmpty();
- }
-
- public InternalView[] getViews()
- {
- checkActive();
- return getViewsArray();
- }
-
- private InternalView[] getViewsArray()
- {
- return views.values().toArray(new InternalView[views.size()]);
- }
-
- public InternalView getView(int viewID)
- {
- checkActive();
- return views.get(viewID);
- }
-
- /**
- * @since 2.0
- */
- public InternalView openView(int viewID, CDOBranchPoint branchPoint)
- {
- checkActive();
- if (viewID == TEMP_VIEW_ID)
- {
- viewID = -lastTempViewID.incrementAndGet();
- }
-
- InternalView view = new View(this, viewID, branchPoint);
- view.activate();
- addView(view);
- return view;
- }
-
- /**
- * @since 2.0
- */
- public InternalTransaction openTransaction(int viewID, CDOBranchPoint branchPoint)
- {
- checkActive();
- if (viewID == TEMP_VIEW_ID)
- {
- viewID = -lastTempViewID.incrementAndGet();
- }
-
- InternalTransaction transaction = new Transaction(this, viewID, branchPoint);
- transaction.activate();
- addView(transaction);
- return transaction;
- }
-
- private void addView(InternalView view)
- {
- checkActive();
- int viewID = view.getViewID();
- views.put(viewID, view);
- fireElementAddedEvent(view);
- }
-
- /**
- * @since 2.0
- */
- public void viewClosed(InternalView view)
- {
- int viewID = view.getViewID();
- if (views.remove(viewID) == view)
- {
- view.doClose();
- fireElementRemovedEvent(view);
- }
- }
-
- /**
- * TODO I can't see how recursion is controlled/limited
- *
- * @since 2.0
- */
- public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk,
- Set<CDOID> revisions, List<CDORevision> additionalRevisions)
- {
- InternalCDORevisionManager revisionManager = getManager().getRepository().getRevisionManager();
- EClass eClass = revision.getEClass();
- EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(eClass);
- for (int i = 0; i < features.length; i++)
- {
- EStructuralFeature feature = features[i];
- // TODO Clarify feature maps
- if (feature instanceof EReference && !feature.isMany() && ((EReference)feature).isContainment())
- {
- Object value = revision.getValue(feature);
- if (value instanceof CDOID)
- {
- CDOID id = (CDOID)value;
- if (!CDOIDUtil.isNull(id) && !revisions.contains(id))
- {
- InternalCDORevision containedRevision = revisionManager.getRevision(id, branchPoint, referenceChunk,
- CDORevision.DEPTH_NONE, true);
- revisions.add(id);
- additionalRevisions.add(containedRevision);
-
- // Recurse
- collectContainedRevisions(containedRevision, branchPoint, referenceChunk, revisions, additionalRevisions);
- }
- }
- }
- }
- }
-
- public CDOID provideCDOID(Object idObject)
- {
- return (CDOID)idObject;
- }
-
- public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
- throws Exception
- {
- if (protocol != null)
- {
- protocol.sendRepositoryTypeNotification(oldType, newType);
- }
- }
-
- @Deprecated
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState)
- throws Exception
- {
- sendRepositoryStateNotification(oldState, newState, null);
- }
-
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState,
- CDOID rootResourceID) throws Exception
- {
- if (protocol != null)
- {
- protocol.sendRepositoryStateNotification(oldState, newState, rootResourceID);
- }
- }
-
- public void sendBranchNotification(InternalCDOBranch branch) throws Exception
- {
- if (protocol != null)
- {
- protocol.sendBranchNotification(branch);
- }
- }
-
- public void sendCommitNotification(final CDOCommitInfo commitInfo) throws Exception
- {
- if (protocol == null)
- {
- return;
- }
-
- if (!isPassiveUpdateEnabled())
- {
- return;
- }
-
- final InternalView[] views = getViews();
- protocol.sendCommitNotification(new DelegatingCommitInfo()
- {
- private final PassiveUpdateMode passiveUpdateMode = getPassiveUpdateMode();
-
- private final boolean additions = passiveUpdateMode == PassiveUpdateMode.ADDITIONS;
-
- private final boolean changes = passiveUpdateMode == PassiveUpdateMode.CHANGES;
-
- @Override
- protected CDOCommitInfo getDelegate()
- {
- return commitInfo;
- }
-
- @Override
- public List<CDOIDAndVersion> getNewObjects()
- {
- final List<CDOIDAndVersion> newObjects = super.getNewObjects();
- return new IndexedList<CDOIDAndVersion>()
- {
- @Override
- public CDOIDAndVersion get(int index)
- {
- // The following will always be a CDORevision!
- CDOIDAndVersion newObject = newObjects.get(index);
- if (additions)
- {
- // Return full revisions if not in INVALIDATION mode
- return newObject;
- }
-
- // Prevent sending whole revisions by copying the id and version
- return CDOIDUtil.createIDAndVersion(newObject);
- }
-
- @Override
- public int size()
- {
- return newObjects.size();
- }
- };
- }
-
- @Override
- public List<CDORevisionKey> getChangedObjects()
- {
- final List<CDORevisionKey> changedObjects = super.getChangedObjects();
- return new IndexedList<CDORevisionKey>()
- {
- @Override
- public CDORevisionKey get(int index)
- {
- // The following will always be a CDORevisionDelta!
- CDORevisionKey changedObject = changedObjects.get(index);
- if (changes || additions || hasSubscription(changedObject.getID(), views))
- {
- return changedObject;
- }
-
- // Prevent sending whole revisions by copying the id and version
- return CDORevisionUtil.copyRevisionKey(changedObject);
- }
-
- @Override
- public int size()
- {
- return changedObjects.size();
- }
- };
- }
- });
-
- synchronized (lastUpdateTimeLock)
- {
- lastUpdateTime = commitInfo.getTimeStamp();
- }
- }
-
- public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception
- {
- if (protocol != null)
- {
- if (options().getLockNotificationMode() == LockNotificationMode.ALWAYS)
- {
- protocol.sendLockNotification(lockChangeInfo);
- return;
- }
-
- if (options().getLockNotificationMode() == LockNotificationMode.IF_REQUIRED_BY_VIEWS)
- {
- // If this session has one (or more) views configured for this branch,
- // only then do we send the lockChangeInfo.
- for (InternalView view : getViews())
- {
- if (view.options().isLockNotificationEnabled())
- {
- CDOBranch affectedBranch = lockChangeInfo.getBranch();
- if (view.getBranch().equals(affectedBranch) || affectedBranch == null)
- {
- protocol.sendLockNotification(lockChangeInfo);
- break;
- }
- }
- }
- }
- }
- }
-
- private boolean hasSubscription(CDOID id, InternalView[] views)
- {
- for (InternalView view : views)
- {
- if (view.hasSubscription(id))
- {
- return true;
- }
- }
-
- return false;
- }
-
- public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception
- {
- if (protocol != null)
- {
- protocol.sendRemoteSessionNotification(sender, opcode);
- }
- }
-
- public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception
- {
- if (protocol != null)
- {
- protocol.sendRemoteMessageNotification(sender, message);
- }
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("Session[{0}]", sessionID); //$NON-NLS-1$
- }
-
- /**
- * @since 2.0
- */
- public void close()
- {
- LifecycleUtil.deactivate(this, OMLogger.Level.DEBUG);
- }
-
- /**
- * @since 2.0
- */
- public boolean isClosed()
- {
- return !isActive();
- }
-
- @Override
- protected void doDeactivate() throws Exception
- {
- EventUtil.removeListener(protocol, protocolListener);
- protocolListener = null;
-
- LifecycleUtil.deactivate(protocol, OMLogger.Level.DEBUG);
- protocol = null;
-
- for (IView view : getViewsArray())
- {
- view.close();
- }
-
- views = null;
- manager.sessionClosed(this);
- manager = null;
- super.doDeactivate();
- }
-}
+/* + * 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 - bug 201266 + * Simon McDuff - bug 230832 + * Simon McDuff - bug 233490 + * Simon McDuff - bug 213402 + */ +package org.eclipse.emf.cdo.internal.server; + +import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.CDOCommonSession; +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionKey; +import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.security.CDOPermission; +import org.eclipse.emf.cdo.internal.common.commit.DelegatingCommitInfo; +import org.eclipse.emf.cdo.server.IPermissionManager; +import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; +import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; +import org.eclipse.emf.cdo.spi.server.ISessionProtocol; +import org.eclipse.emf.cdo.spi.server.InternalSession; +import org.eclipse.emf.cdo.spi.server.InternalSessionManager; +import org.eclipse.emf.cdo.spi.server.InternalTransaction; +import org.eclipse.emf.cdo.spi.server.InternalView; + +import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; +import org.eclipse.net4j.util.collection.IndexedList; +import org.eclipse.net4j.util.container.Container; +import org.eclipse.net4j.util.event.EventUtil; +import org.eclipse.net4j.util.event.IListener; +import org.eclipse.net4j.util.lifecycle.ILifecycle; +import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.om.log.OMLogger; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.text.MessageFormat; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @author Eike Stepper + */ +public class Session extends Container<IView> implements InternalSession +{ + private InternalSessionManager manager; + + private ISessionProtocol protocol; + + private int sessionID; + + private String userID; + + private boolean passiveUpdateEnabled = true; + + private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS; + + private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS; + + private long lastUpdateTime; + + @ExcludeFromDump + private Object lastUpdateTimeLock = new Object(); + + private ConcurrentMap<Integer, InternalView> views = new ConcurrentHashMap<Integer, InternalView>(); + + private AtomicInteger lastTempViewID = new AtomicInteger(); + + @ExcludeFromDump + private IListener protocolListener = new LifecycleEventAdapter() + { + @Override + protected void onDeactivated(ILifecycle lifecycle) + { + deactivate(); + } + }; + + private boolean subscribed; + + /** + * @since 2.0 + */ + public Session(InternalSessionManager manager, ISessionProtocol protocol, int sessionID, String userID) + { + this.manager = manager; + this.protocol = protocol; + this.sessionID = sessionID; + this.userID = userID; + + EventUtil.addListener(protocol, protocolListener); + activate(); + } + + /** + * @since 2.0 + */ + public Options options() + { + return this; + } + + /** + * @since 2.0 + */ + public CDOCommonSession getContainer() + { + return this; + } + + public InternalSessionManager getManager() + { + return manager; + } + + public ISessionProtocol getProtocol() + { + return protocol; + } + + public int getSessionID() + { + return sessionID; + } + + /** + * @since 2.0 + */ + public String getUserID() + { + return userID; + } + + /** + * @since 2.0 + */ + public boolean isSubscribed() + { + return subscribed; + } + + /** + * @since 2.0 + */ + public void setSubscribed(boolean subscribed) + { + checkActive(); + if (this.subscribed != subscribed) + { + this.subscribed = subscribed; + byte opcode = subscribed ? CDOProtocolConstants.REMOTE_SESSION_SUBSCRIBED + : CDOProtocolConstants.REMOTE_SESSION_UNSUBSCRIBED; + manager.sendRemoteSessionNotification(this, opcode); + } + } + + /** + * @since 2.0 + */ + public boolean isPassiveUpdateEnabled() + { + return passiveUpdateEnabled; + } + + /** + * @since 2.0 + */ + public void setPassiveUpdateEnabled(boolean passiveUpdateEnabled) + { + checkActive(); + this.passiveUpdateEnabled = passiveUpdateEnabled; + } + + public PassiveUpdateMode getPassiveUpdateMode() + { + return passiveUpdateMode; + } + + public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode) + { + checkActive(); + checkArg(passiveUpdateMode, "passiveUpdateMode"); + this.passiveUpdateMode = passiveUpdateMode; + } + + public LockNotificationMode getLockNotificationMode() + { + return lockNotificationMode; + } + + public void setLockNotificationMode(LockNotificationMode lockNotificationMode) + { + checkActive(); + checkArg(lockNotificationMode, "lockNotificationMode"); + this.lockNotificationMode = lockNotificationMode; + } + + public long getLastUpdateTime() + { + synchronized (lastUpdateTimeLock) + { + return lastUpdateTime; + } + } + + public InternalView[] getElements() + { + checkActive(); + return getViews(); + } + + @Override + public boolean isEmpty() + { + checkActive(); + return views.isEmpty(); + } + + public InternalView[] getViews() + { + checkActive(); + return getViewsArray(); + } + + private InternalView[] getViewsArray() + { + return views.values().toArray(new InternalView[views.size()]); + } + + public InternalView getView(int viewID) + { + checkActive(); + return views.get(viewID); + } + + /** + * @since 2.0 + */ + public InternalView openView(int viewID, CDOBranchPoint branchPoint) + { + checkActive(); + if (viewID == TEMP_VIEW_ID) + { + viewID = -lastTempViewID.incrementAndGet(); + } + + InternalView view = new View(this, viewID, branchPoint); + view.activate(); + addView(view); + return view; + } + + /** + * @since 2.0 + */ + public InternalTransaction openTransaction(int viewID, CDOBranchPoint branchPoint) + { + checkActive(); + if (viewID == TEMP_VIEW_ID) + { + viewID = -lastTempViewID.incrementAndGet(); + } + + InternalTransaction transaction = new Transaction(this, viewID, branchPoint); + transaction.activate(); + addView(transaction); + return transaction; + } + + private void addView(InternalView view) + { + checkActive(); + int viewID = view.getViewID(); + views.put(viewID, view); + fireElementAddedEvent(view); + } + + /** + * @since 2.0 + */ + public void viewClosed(InternalView view) + { + int viewID = view.getViewID(); + if (views.remove(viewID) == view) + { + view.doClose(); + fireElementRemovedEvent(view); + } + } + + /** + * TODO I can't see how recursion is controlled/limited + * + * @since 2.0 + */ + public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk, + Set<CDOID> revisions, List<CDORevision> additionalRevisions) + { + InternalCDORevisionManager revisionManager = getManager().getRepository().getRevisionManager(); + EClass eClass = revision.getEClass(); + EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(eClass); + for (int i = 0; i < features.length; i++) + { + EStructuralFeature feature = features[i]; + // TODO Clarify feature maps + if (feature instanceof EReference && !feature.isMany() && ((EReference)feature).isContainment()) + { + Object value = revision.getValue(feature); + if (value instanceof CDOID) + { + CDOID id = (CDOID)value; + if (!CDOIDUtil.isNull(id) && !revisions.contains(id)) + { + InternalCDORevision containedRevision = revisionManager.getRevision(id, branchPoint, referenceChunk, + CDORevision.DEPTH_NONE, true); + revisions.add(id); + additionalRevisions.add(containedRevision); + + // Recurse + collectContainedRevisions(containedRevision, branchPoint, referenceChunk, revisions, additionalRevisions); + } + } + } + } + } + + public CDOID provideCDOID(Object idObject) + { + return (CDOID)idObject; + } + + public CDOPermission getPermission(Object protectableObject) + { + IPermissionManager permissionManager = manager.getPermissionManager(); + if (permissionManager != null) + { + return permissionManager.getPermission(protectableObject, userID); + } + + return CDORevision.PERMISSION_PROVIDER.getPermission(protectableObject); + } + + public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType) + throws Exception + { + if (protocol != null) + { + protocol.sendRepositoryTypeNotification(oldType, newType); + } + } + + @Deprecated + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) + throws Exception + { + sendRepositoryStateNotification(oldState, newState, null); + } + + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception + { + if (protocol != null) + { + protocol.sendRepositoryStateNotification(oldState, newState, rootResourceID); + } + } + + public void sendBranchNotification(InternalCDOBranch branch) throws Exception + { + if (protocol != null) + { + protocol.sendBranchNotification(branch); + } + } + + public void sendCommitNotification(final CDOCommitInfo commitInfo) throws Exception + { + if (protocol == null) + { + return; + } + + if (!isPassiveUpdateEnabled()) + { + return; + } + + final InternalView[] views = getViews(); + protocol.sendCommitNotification(new DelegatingCommitInfo() + { + private final PassiveUpdateMode passiveUpdateMode = getPassiveUpdateMode(); + + private final boolean additions = passiveUpdateMode == PassiveUpdateMode.ADDITIONS; + + private final boolean changes = passiveUpdateMode == PassiveUpdateMode.CHANGES; + + @Override + protected CDOCommitInfo getDelegate() + { + return commitInfo; + } + + @Override + public List<CDOIDAndVersion> getNewObjects() + { + final List<CDOIDAndVersion> newObjects = super.getNewObjects(); + return new IndexedList<CDOIDAndVersion>() + { + @Override + public CDOIDAndVersion get(int index) + { + // The following will always be a CDORevision! + CDOIDAndVersion newObject = newObjects.get(index); + if (additions) + { + // Return full revisions if not in INVALIDATION mode + return newObject; + } + + // Prevent sending whole revisions by copying the id and version + return CDOIDUtil.createIDAndVersion(newObject); + } + + @Override + public int size() + { + return newObjects.size(); + } + }; + } + + @Override + public List<CDORevisionKey> getChangedObjects() + { + final List<CDORevisionKey> changedObjects = super.getChangedObjects(); + return new IndexedList<CDORevisionKey>() + { + @Override + public CDORevisionKey get(int index) + { + // The following will always be a CDORevisionDelta! + CDORevisionKey changedObject = changedObjects.get(index); + if (changes || additions || hasSubscription(changedObject.getID(), views)) + { + return changedObject; + } + + // Prevent sending whole revisions by copying the id and version + return CDORevisionUtil.copyRevisionKey(changedObject); + } + + @Override + public int size() + { + return changedObjects.size(); + } + }; + } + }); + + synchronized (lastUpdateTimeLock) + { + lastUpdateTime = commitInfo.getTimeStamp(); + } + } + + public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception + { + if (protocol != null) + { + if (options().getLockNotificationMode() == LockNotificationMode.ALWAYS) + { + protocol.sendLockNotification(lockChangeInfo); + return; + } + + if (options().getLockNotificationMode() == LockNotificationMode.IF_REQUIRED_BY_VIEWS) + { + // If this session has one (or more) views configured for this branch, + // only then do we send the lockChangeInfo. + for (InternalView view : getViews()) + { + if (view.options().isLockNotificationEnabled()) + { + CDOBranch affectedBranch = lockChangeInfo.getBranch(); + if (view.getBranch().equals(affectedBranch) || affectedBranch == null) + { + protocol.sendLockNotification(lockChangeInfo); + break; + } + } + } + } + } + } + + private boolean hasSubscription(CDOID id, InternalView[] views) + { + for (InternalView view : views) + { + if (view.hasSubscription(id)) + { + return true; + } + } + + return false; + } + + public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception + { + if (protocol != null) + { + protocol.sendRemoteSessionNotification(sender, opcode); + } + } + + public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception + { + if (protocol != null) + { + protocol.sendRemoteMessageNotification(sender, message); + } + } + + @Override + public String toString() + { + return MessageFormat.format("Session[{0}]", sessionID); //$NON-NLS-1$ + } + + /** + * @since 2.0 + */ + public void close() + { + LifecycleUtil.deactivate(this, OMLogger.Level.DEBUG); + } + + /** + * @since 2.0 + */ + public boolean isClosed() + { + return !isActive(); + } + + @Override + protected void doDeactivate() throws Exception + { + EventUtil.removeListener(protocol, protocolListener); + protocolListener = null; + + LifecycleUtil.deactivate(protocol, OMLogger.Level.DEBUG); + protocol = null; + + for (IView view : getViewsArray()) + { + view.close(); + } + + views = null; + manager.sessionClosed(this); + manager = null; + super.doDeactivate(); + } +} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java index eaa096cf8a..4aeb40e0c9 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/SessionManager.java @@ -20,6 +20,7 @@ import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; import org.eclipse.emf.cdo.internal.server.bundle.OM; +import org.eclipse.emf.cdo.server.IPermissionManager; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; import org.eclipse.emf.cdo.spi.common.CDOAuthenticationResult; @@ -72,6 +73,8 @@ public class SessionManager extends Container<ISession> implements InternalSessi private IUserManager userManager; + private IPermissionManager permissionManager; + private final Map<Integer, InternalSession> sessions = new HashMap<Integer, InternalSession>(); private final AtomicInteger lastSessionID = new AtomicInteger(); @@ -165,6 +168,16 @@ public class SessionManager extends Container<ISession> implements InternalSessi this.userManager = userManager; } + public IPermissionManager getPermissionManager() + { + return permissionManager; + } + + public void setPermissionManager(IPermissionManager permissionManager) + { + this.permissionManager = permissionManager; + } + public InternalSession[] getSessions() { synchronized (sessions) diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java index 7781a0dac6..2644eae146 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/internal/server/TransactionCommitContext.java @@ -1,1500 +1,1506 @@ -/*
- * 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:
- * Simon McDuff - initial API and implementation
- * Eike Stepper - maintenance
- * Martin Fluegge - maintenance, bug 318518
- */
-package org.eclipse.emf.cdo.internal.server;
-
-import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
-import org.eclipse.emf.cdo.common.branch.CDOBranch;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.commit.CDOCommitData;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDObject;
-import org.eclipse.emf.cdo.common.id.CDOIDReference;
-import org.eclipse.emf.cdo.common.id.CDOIDUtil;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation;
-import org.eclipse.emf.cdo.common.lock.CDOLockOwner;
-import org.eclipse.emf.cdo.common.lock.CDOLockState;
-import org.eclipse.emf.cdo.common.lock.CDOLockUtil;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch;
-import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
-import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor;
-import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
-import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
-import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
-import org.eclipse.emf.cdo.common.util.CDOQueryInfo;
-import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl;
-import org.eclipse.emf.cdo.internal.common.commit.FailureCommitInfo;
-import org.eclipse.emf.cdo.internal.common.model.CDOPackageRegistryImpl;
-import org.eclipse.emf.cdo.internal.server.bundle.OM;
-import org.eclipse.emf.cdo.server.ContainmentCycleDetectedException;
-import org.eclipse.emf.cdo.server.IStoreAccessor;
-import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext;
-import org.eclipse.emf.cdo.server.IView;
-import org.eclipse.emf.cdo.server.StoreThreadLocal;
-import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
-import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl;
-import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper;
-import org.eclipse.emf.cdo.spi.common.revision.CDOReferenceAdjuster;
-import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
-import org.eclipse.emf.cdo.spi.common.revision.StubCDORevision;
-import org.eclipse.emf.cdo.spi.server.InternalCommitContext;
-import org.eclipse.emf.cdo.spi.server.InternalLockManager;
-import org.eclipse.emf.cdo.spi.server.InternalRepository;
-import org.eclipse.emf.cdo.spi.server.InternalSession;
-import org.eclipse.emf.cdo.spi.server.InternalTransaction;
-
-import org.eclipse.net4j.util.CheckUtil;
-import org.eclipse.net4j.util.ObjectUtil;
-import org.eclipse.net4j.util.StringUtil;
-import org.eclipse.net4j.util.collection.IndexedList;
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState;
-import org.eclipse.net4j.util.io.ExtendedDataInputStream;
-import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
-import org.eclipse.net4j.util.om.monitor.Monitor;
-import org.eclipse.net4j.util.om.monitor.OMMonitor;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-/**
- * @author Simon McDuff
- * @since 2.0
- */
-public class TransactionCommitContext implements InternalCommitContext
-{
- private static final InternalCDORevision DETACHED = new StubCDORevision(null);
-
- private final InternalTransaction transaction;
-
- private InternalRepository repository;
-
- private InternalCDORevisionManager revisionManager;
-
- private InternalLockManager lockManager;
-
- private InternalCDOPackageRegistry repositoryPackageRegistry;
-
- private boolean packageRegistryLocked;
-
- private TransactionPackageRegistry packageRegistry;
-
- private IStoreAccessor accessor;
-
- private long timeStamp = CDORevision.UNSPECIFIED_DATE;
-
- private long previousTimeStamp = CDORevision.UNSPECIFIED_DATE;
-
- private String commitComment;
-
- private InternalCDOPackageUnit[] newPackageUnits = new InternalCDOPackageUnit[0];
-
- private CDOLockState[] locksOnNewObjects = new CDOLockState[0];
-
- private InternalCDORevision[] newObjects = new InternalCDORevision[0];
-
- private InternalCDORevisionDelta[] dirtyObjectDeltas = new InternalCDORevisionDelta[0];
-
- private CDOID[] detachedObjects = new CDOID[0];
-
- private Map<CDOID, EClass> detachedObjectTypes;
-
- private InternalCDORevision[] dirtyObjects = new InternalCDORevision[0];
-
- private InternalCDORevision[] cachedDetachedRevisions = new InternalCDORevision[0];
-
- private Map<CDOID, InternalCDORevision> cachedRevisions;
-
- private Set<Object> lockedObjects = new HashSet<Object>();
-
- private List<CDOID> lockedTargets;
-
- private ConcurrentMap<CDOID, CDOID> idMappings = new ConcurrentHashMap<CDOID, CDOID>();
-
- private CDOReferenceAdjuster idMapper = new CDOIDMapper(idMappings);
-
- private String rollbackMessage;
-
- private List<CDOIDReference> xRefs;
-
- private List<LockState<Object, IView>> postCommitLockStates;
-
- private boolean ensuringReferentialIntegrity;
-
- private boolean autoReleaseLocksEnabled;
-
- private ExtendedDataInputStream lobs;
-
- public TransactionCommitContext(InternalTransaction transaction)
- {
- this.transaction = transaction;
-
- repository = transaction.getRepository();
- revisionManager = repository.getRevisionManager();
- lockManager = repository.getLockingManager();
- ensuringReferentialIntegrity = repository.isEnsuringReferentialIntegrity();
-
- repositoryPackageRegistry = repository.getPackageRegistry(false);
- packageRegistry = new TransactionPackageRegistry(repositoryPackageRegistry);
- packageRegistry.activate();
- }
-
- public InternalTransaction getTransaction()
- {
- return transaction;
- }
-
- public CDOBranchPoint getBranchPoint()
- {
- return transaction.getBranch().getPoint(timeStamp);
- }
-
- public String getUserID()
- {
- return transaction.getSession().getUserID();
- }
-
- public String getCommitComment()
- {
- return commitComment;
- }
-
- public boolean isAutoReleaseLocksEnabled()
- {
- return autoReleaseLocksEnabled;
- }
-
- public String getRollbackMessage()
- {
- return rollbackMessage;
- }
-
- public List<CDOIDReference> getXRefs()
- {
- return xRefs;
- }
-
- public InternalCDOPackageRegistry getPackageRegistry()
- {
- return packageRegistry;
- }
-
- public InternalCDOPackageUnit[] getNewPackageUnits()
- {
- return newPackageUnits;
- }
-
- public CDOLockState[] getLocksOnNewObjects()
- {
- return locksOnNewObjects;
- }
-
- public InternalCDORevision[] getNewObjects()
- {
- return newObjects;
- }
-
- public InternalCDORevision[] getDirtyObjects()
- {
- return dirtyObjects;
- }
-
- public CDOID[] getDetachedObjects()
- {
- return detachedObjects;
- }
-
- public Map<CDOID, EClass> getDetachedObjectTypes()
- {
- return detachedObjectTypes;
- }
-
- public InternalCDORevision[] getDetachedRevisions()
- {
- // This array can contain null values as they only come from the cache!
- for (InternalCDORevision cachedDetachedRevision : cachedDetachedRevisions)
- {
- if (cachedDetachedRevision == null)
- {
- throw new AssertionError("Detached revisions are incomplete");
- }
- }
-
- return cachedDetachedRevisions;
- }
-
- public InternalCDORevisionDelta[] getDirtyObjectDeltas()
- {
- return dirtyObjectDeltas;
- }
-
- public CDORevision getRevision(CDOID id)
- {
- if (cachedRevisions == null)
- {
- cachedRevisions = cacheRevisions();
- }
-
- // Try "after state"
- InternalCDORevision revision = cachedRevisions.get(id);
- if (revision == DETACHED)
- {
- return null;
- }
-
- if (revision != null)
- {
- return revision;
- }
-
- // Fall back to "before state"
- return transaction.getRevision(id);
- }
-
- private Map<CDOID, InternalCDORevision> cacheRevisions()
- {
- Map<CDOID, InternalCDORevision> cache = new HashMap<CDOID, InternalCDORevision>();
- if (newObjects != null)
- {
- for (int i = 0; i < newObjects.length; i++)
- {
- InternalCDORevision revision = newObjects[i];
- cache.put(revision.getID(), revision);
- }
- }
-
- if (dirtyObjects != null)
- {
- for (int i = 0; i < dirtyObjects.length; i++)
- {
- InternalCDORevision revision = dirtyObjects[i];
- cache.put(revision.getID(), revision);
- }
- }
-
- if (detachedObjects != null)
- {
- for (int i = 0; i < detachedObjects.length; i++)
- {
- cache.put(detachedObjects[i], DETACHED);
- }
- }
-
- return cache;
- }
-
- public Map<CDOID, CDOID> getIDMappings()
- {
- return Collections.unmodifiableMap(idMappings);
- }
-
- public void addIDMapping(CDOID oldID, CDOID newID)
- {
- if (CDOIDUtil.isNull(newID) || newID.isTemporary())
- {
- throw new IllegalStateException("newID=" + newID); //$NON-NLS-1$
- }
-
- CDOID previousMapping = idMappings.putIfAbsent(oldID, newID);
- if (previousMapping != null)
- {
- throw new IllegalStateException("previousMapping != null"); //$NON-NLS-1$
- }
- }
-
- public void applyIDMappings(OMMonitor monitor)
- {
- boolean mapIDs = !idMappings.isEmpty();
- monitor.begin(1 + (mapIDs ? newObjects.length + dirtyObjects.length + dirtyObjectDeltas.length : 0));
-
- try
- {
- if (mapIDs)
- {
- applyIDMappings(newObjects, monitor.fork(newObjects.length));
- applyIDMappings(dirtyObjects, monitor.fork(dirtyObjects.length));
- for (CDORevisionDelta dirtyObjectDelta : dirtyObjectDeltas)
- {
- ((InternalCDORevisionDelta)dirtyObjectDelta).adjustReferences(idMapper);
- monitor.worked();
- }
- }
-
- // Do not notify handlers before the IDs are fully mapped!
- notifyBeforeCommitting(monitor);
- }
- finally
- {
- monitor.done();
- }
- }
-
- protected void notifyBeforeCommitting(OMMonitor monitor)
- {
- repository.notifyWriteAccessHandlers(transaction, this, true, monitor.fork());
- }
-
- public void preWrite()
- {
- // Allocate a store writer
- accessor = repository.getStore().getWriter(transaction);
-
- // Make the store writer available in a ThreadLocal variable
- StoreThreadLocal.setAccessor(accessor);
- StoreThreadLocal.setCommitContext(this);
- }
-
- public void setNewPackageUnits(InternalCDOPackageUnit[] newPackageUnits)
- {
- this.newPackageUnits = newPackageUnits;
- }
-
- public void setLocksOnNewObjects(CDOLockState[] locksOnNewObjects)
- {
- this.locksOnNewObjects = locksOnNewObjects;
- }
-
- public void setNewObjects(InternalCDORevision[] newObjects)
- {
- this.newObjects = newObjects;
- }
-
- public void setDirtyObjectDeltas(InternalCDORevisionDelta[] dirtyObjectDeltas)
- {
- this.dirtyObjectDeltas = dirtyObjectDeltas;
- }
-
- public void setDetachedObjects(CDOID[] detachedObjects)
- {
- this.detachedObjects = detachedObjects;
- }
-
- public void setDetachedObjectTypes(Map<CDOID, EClass> detachedObjectTypes)
- {
- this.detachedObjectTypes = detachedObjectTypes;
- }
-
- public void setAutoReleaseLocksEnabled(boolean on)
- {
- autoReleaseLocksEnabled = on;
- }
-
- public void setCommitComment(String commitComment)
- {
- this.commitComment = commitComment;
- }
-
- public ExtendedDataInputStream getLobs()
- {
- return lobs;
- }
-
- public void setLobs(ExtendedDataInputStream in)
- {
- lobs = in;
- }
-
- /**
- * @since 2.0
- */
- public void write(OMMonitor monitor)
- {
- try
- {
- monitor.begin(107);
- dirtyObjects = new InternalCDORevision[dirtyObjectDeltas.length];
-
- if (newPackageUnits.length != 0)
- {
- repository.getPackageRegistryCommitLock().acquire();
- packageRegistryLocked = true;
-
- List<InternalCDOPackageUnit> noDuplicates = new ArrayList<InternalCDOPackageUnit>();
- for (InternalCDOPackageUnit newPackageUnit : newPackageUnits)
- {
- String id = newPackageUnit.getID();
- if (!repositoryPackageRegistry.containsKey(id))
- {
- noDuplicates.add(newPackageUnit);
- }
- }
-
- int newSize = noDuplicates.size();
- if (newPackageUnits.length != newSize)
- {
- newPackageUnits = noDuplicates.toArray(new InternalCDOPackageUnit[newSize]);
- }
- }
-
- lockObjects(); // Can take long and must come before setTimeStamp()
- monitor.worked();
-
- setTimeStamp(monitor.fork());
-
- adjustForCommit();
- monitor.worked();
-
- computeDirtyObjects(monitor.fork());
-
- checkXRefs();
- monitor.worked();
-
- if (rollbackMessage == null)
- {
- detachObjects(monitor.fork());
- accessor.write(this, monitor.fork(100));
- }
- }
- catch (Throwable t)
- {
- handleException(t);
- }
- finally
- {
- finishMonitor(monitor);
- }
- }
-
- public void commit(OMMonitor monitor)
- {
- try
- {
- monitor.begin(101);
- accessor.commit(monitor.fork(100));
- updateInfraStructure(monitor.fork());
-
- // Bugzilla 297940
- repository.endCommit(timeStamp);
- }
- catch (Throwable ex)
- {
- handleException(ex);
- }
- finally
- {
- finishMonitor(monitor);
- }
- }
-
- public List<LockState<Object, IView>> getPostCommmitLockStates()
- {
- return postCommitLockStates;
- }
-
- private void handleException(Throwable ex)
- {
- try
- {
- OM.LOG.error(ex);
- String storeClass = repository.getStore().getClass().getSimpleName();
- rollback("Rollback in " + storeClass + ": " + StringUtil.formatException(ex)); //$NON-NLS-1$ //$NON-NLS-2$
- }
- catch (Exception ex1)
- {
- if (rollbackMessage == null)
- {
- rollbackMessage = ex1.getMessage();
- }
-
- try
- {
- OM.LOG.error(ex1);
- }
- catch (Exception ignore)
- {
- }
- }
- }
-
- private void finishMonitor(OMMonitor monitor)
- {
- try
- {
- monitor.done();
- }
- catch (Exception ex)
- {
- try
- {
- OM.LOG.warn(ex);
- }
- catch (Exception ignore)
- {
- }
- }
- }
-
- private void setTimeStamp(OMMonitor mmonitor)
- {
- long[] times = createTimeStamp(mmonitor); // Could throw an exception
- timeStamp = times[0];
- previousTimeStamp = times[1];
- CheckUtil.checkState(timeStamp != CDOBranchPoint.UNSPECIFIED_DATE, "Commit timestamp must not be 0");
- }
-
- protected long[] createTimeStamp(OMMonitor monitor)
- {
- return repository.createCommitTimeStamp(monitor);
- }
-
- protected long getTimeStamp()
- {
- return timeStamp;
- }
-
- protected void setTimeStamp(long timeStamp)
- {
- repository.forceCommitTimeStamp(timeStamp, new Monitor());
- this.timeStamp = timeStamp;
- }
-
- public long getPreviousTimeStamp()
- {
- return previousTimeStamp;
- }
-
- public void postCommit(boolean success)
- {
- if (packageRegistryLocked)
- {
- repository.getPackageRegistryCommitLock().release();
- }
-
- try
- {
- InternalSession sender = transaction.getSession();
- CDOCommitInfo commitInfo = success ? createCommitInfo() : createFailureCommitInfo();
-
- repository.sendCommitNotification(sender, commitInfo);
- }
- catch (Exception ex)
- {
- OM.LOG.warn("A problem occured while notifying other sessions", ex);
- }
- finally
- {
- StoreThreadLocal.release();
- accessor = null;
- lockedTargets = null;
-
- if (packageRegistry != null)
- {
- packageRegistry.deactivate();
- packageRegistry = null;
- }
- }
- }
-
- public CDOCommitInfo createCommitInfo()
- {
- CDOBranch branch = transaction.getBranch();
- String userID = transaction.getSession().getUserID();
- CDOCommitData commitData = createCommitData();
-
- InternalCDOCommitInfoManager commitInfoManager = repository.getCommitInfoManager();
- return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, commitComment, commitData);
- }
-
- public CDOCommitInfo createFailureCommitInfo()
- {
- return new FailureCommitInfo(timeStamp, previousTimeStamp);
- }
-
- private CDOCommitData createCommitData()
- {
- List<CDOPackageUnit> newPackageUnitsCollection = new IndexedList.ArrayBacked<CDOPackageUnit>()
- {
- @Override
- protected CDOPackageUnit[] getArray()
- {
- return newPackageUnits;
- }
- };
-
- List<CDOIDAndVersion> newObjectsCollection = new IndexedList.ArrayBacked<CDOIDAndVersion>()
- {
- @Override
- protected CDOIDAndVersion[] getArray()
- {
- return newObjects;
- }
- };
-
- List<CDORevisionKey> changedObjectsCollection = new IndexedList.ArrayBacked<CDORevisionKey>()
- {
- @Override
- protected CDORevisionKey[] getArray()
- {
- return dirtyObjectDeltas;
- }
- };
-
- List<CDOIDAndVersion> detachedObjectsCollection = new IndexedList<CDOIDAndVersion>()
- {
- @Override
- public CDOIDAndVersion get(int i)
- {
- if (cachedDetachedRevisions[i] != null)
- {
- return cachedDetachedRevisions[i];
- }
-
- return CDOIDUtil.createIDAndVersion(detachedObjects[i], CDORevision.UNSPECIFIED_VERSION);
- }
-
- @Override
- public int size()
- {
- return detachedObjects.length;
- }
- };
-
- return new CDOCommitDataImpl(newPackageUnitsCollection, newObjectsCollection, changedObjectsCollection,
- detachedObjectsCollection);
- }
-
- protected void adjustForCommit()
- {
- for (InternalCDOPackageUnit newPackageUnit : newPackageUnits)
- {
- newPackageUnit.setTimeStamp(timeStamp);
- }
-
- CDOBranch branch = transaction.getBranch();
- for (InternalCDORevision newObject : newObjects)
- {
- newObject.adjustForCommit(branch, timeStamp);
- }
- }
-
- protected void lockObjects() throws InterruptedException
- {
- lockedObjects.clear();
- lockedTargets = null;
-
- try
- {
- final boolean supportingBranches = repository.isSupportingBranches();
-
- CDOFeatureDeltaVisitor deltaTargetLocker = null;
- if (ensuringReferentialIntegrity)
- {
- final Set<CDOID> newIDs = new HashSet<CDOID>();
- for (int i = 0; i < newObjects.length; i++)
- {
- InternalCDORevision newRevision = newObjects[i];
- CDOID newID = newRevision.getID();
- if (newID instanceof CDOIDObject)
- {
- // After merges newObjects may contain non-TEMP ids
- newIDs.add(newID);
- }
- }
-
- deltaTargetLocker = new CDOFeatureDeltaVisitorImpl()
- {
- @Override
- public void visit(CDOAddFeatureDelta delta)
- {
- lockTarget(delta.getValue(), newIDs, supportingBranches);
- }
-
- @Override
- public void visit(CDOSetFeatureDelta delta)
- {
- lockTarget(delta.getValue(), newIDs, supportingBranches);
- }
- };
-
- CDOReferenceAdjuster revisionTargetLocker = new CDOReferenceAdjuster()
- {
- public Object adjustReference(Object value, EStructuralFeature feature, int index)
- {
- lockTarget(value, newIDs, supportingBranches);
- return value;
- }
- };
-
- for (int i = 0; i < newObjects.length; i++)
- {
- InternalCDORevision newRevision = newObjects[i];
- newRevision.adjustReferences(revisionTargetLocker);
- }
- }
-
- for (int i = 0; i < dirtyObjectDeltas.length; i++)
- {
- InternalCDORevisionDelta delta = dirtyObjectDeltas[i];
- CDOID id = delta.getID();
- Object key = lockManager.getLockKey(id, transaction.getBranch());
- lockedObjects.add(new DeltaLockWrapper(key, delta));
-
- if (hasContainmentChanges(delta))
- {
- if (isContainerLocked(delta))
- {
- throw new ContainmentCycleDetectedException("Parent (" + key
- + ") is already locked for containment changes");
- }
- }
- }
-
- for (int i = 0; i < dirtyObjectDeltas.length; i++)
- {
- InternalCDORevisionDelta delta = dirtyObjectDeltas[i];
- if (deltaTargetLocker != null)
- {
- delta.accept(deltaTargetLocker);
- }
- }
-
- for (int i = 0; i < detachedObjects.length; i++)
- {
- CDOID id = detachedObjects[i];
- Object key = lockManager.getLockKey(id, transaction.getBranch());
- lockedObjects.add(key);
- }
-
- if (!lockedObjects.isEmpty())
- {
- // First lock all objects (incl. possible ref targets).
- // This is a transient operation, it does not check for existance!
- lockManager.lock2(LockType.WRITE, transaction, lockedObjects, 1000);
-
- // If all locks could be acquired, check if locked targets do still exist
- if (lockedTargets != null)
- {
- for (CDOID id : lockedTargets)
- {
- InternalCDORevision revision = //
- revisionManager.getRevision(id, transaction, CDORevision.UNCHUNKED, CDORevision.DEPTH_NONE, true);
-
- if (revision == null || revision instanceof DetachedCDORevision)
- {
- throw new IllegalStateException("Object " + id
- + " can not be referenced anymore because it has been detached");
- }
- }
- }
- }
- }
- catch (RuntimeException ex)
- {
- lockedObjects.clear();
- lockedTargets = null;
- throw ex;
- }
- }
-
- /**
- * Iterates up the eContainers of an object and returns <code>true</code> on the first parent locked by another view.
- *
- * @return <code>true</code> if any parent is locked, <code>false</code> otherwise.
- */
- private boolean isContainerLocked(InternalCDORevisionDelta delta)
- {
- CDOID id = delta.getID();
- InternalCDORevision revision = revisionManager.getRevisionByVersion(id, delta, CDORevision.UNCHUNKED, true);
- if (revision == null)
- {
- // Can happen with non-auditing cache
- throw new ConcurrentModificationException("Attempt by " + transaction + " to modify historical revision: "
- + CDORevisionUtil.copyRevisionKey(delta));
- }
-
- return isContainerLocked(revision);
- }
-
- private boolean isContainerLocked(InternalCDORevision revision)
- {
- CDOID id = (CDOID)revision.getContainerID();
- if (CDOIDUtil.isNull(id))
- {
- return false;
- }
-
- Object key = lockManager.getLockKey(id, transaction.getBranch());
- DeltaLockWrapper lockWrapper = new DeltaLockWrapper(key, null);
-
- if (lockManager.hasLockByOthers(LockType.WRITE, transaction, lockWrapper))
- {
- Object object = lockManager.getLockEntryObject(lockWrapper);
- if (object instanceof DeltaLockWrapper)
- {
- InternalCDORevisionDelta delta = ((DeltaLockWrapper)object).getDelta();
- if (delta != null && hasContainmentChanges(delta))
- {
- return true;
- }
- }
- }
-
- InternalCDORevision parent = revisionManager.getRevision(id, transaction, CDORevision.UNCHUNKED,
- CDORevision.DEPTH_NONE, true);
-
- if (parent != null)
- {
- return isContainerLocked(parent);
- }
-
- return false;
- }
-
- private boolean hasContainmentChanges(InternalCDORevisionDelta delta)
- {
- for (CDOFeatureDelta featureDelta : delta.getFeatureDeltas())
- {
- EStructuralFeature feature = featureDelta.getFeature();
- if (feature instanceof EReference)
- {
- if (((EReference)feature).isContainment())
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- private void lockTarget(Object value, Set<CDOID> newIDs, boolean supportingBranches)
- {
- if (value instanceof CDOIDObject)
- {
- CDOIDObject id = (CDOIDObject)value;
- if (id.isNull())
- {
- return;
- }
-
- if (newIDs.contains(id))
- {
- // After merges newObjects may contain non-TEMP ids
- return;
- }
-
- if (detachedObjectTypes != null && detachedObjectTypes.containsKey(id))
- {
- throw new IllegalStateException("This commit deletes object " + id + " and adds a reference at the same time");
- }
-
- // Let this object be locked
- Object key = lockManager.getLockKey(id, transaction.getBranch());
- lockedObjects.add(key);
-
- // Let this object be checked for existance after it has been locked
- if (lockedTargets == null)
- {
- lockedTargets = new ArrayList<CDOID>();
- }
-
- lockedTargets.add(id);
- }
- }
-
- protected void checkXRefs()
- {
- if (ensuringReferentialIntegrity && detachedObjectTypes != null)
- {
- XRefContext context = new XRefContext();
- xRefs = context.getXRefs(accessor);
- if (!xRefs.isEmpty())
- {
- rollbackMessage = "Referential integrity violated";
- }
- }
- }
-
- private synchronized void unlockObjects()
- {
- if (!lockedObjects.isEmpty())
- {
- lockManager.unlock2(LockType.WRITE, transaction, lockedObjects);
- lockedObjects.clear();
- }
-
- if (detachedObjects.length > 0)
- {
- boolean branching = getTransaction().getRepository().isSupportingBranches();
- Collection<? extends Object> unlockables = null;
- if (branching)
- {
- List<CDOIDAndBranch> keys = new LinkedList<CDOIDAndBranch>();
- for (CDOID id : detachedObjects)
- {
- CDOIDAndBranch idAndBranch = CDOIDUtil.createIDAndBranch(id, transaction.getBranch());
- keys.add(idAndBranch);
- }
-
- unlockables = keys;
- }
- else
- {
- unlockables = Arrays.asList(detachedObjects);
- }
-
- lockManager.unlock2(transaction, unlockables);
- }
- }
-
- private void computeDirtyObjects(OMMonitor monitor)
- {
- try
- {
- monitor.begin(dirtyObjectDeltas.length);
- for (int i = 0; i < dirtyObjectDeltas.length; i++)
- {
- dirtyObjects[i] = computeDirtyObject(dirtyObjectDeltas[i]);
- if (dirtyObjects[i] == null)
- {
- throw new IllegalStateException("Can not retrieve origin revision for " + dirtyObjectDeltas[i]); //$NON-NLS-1$
- }
-
- monitor.worked();
- }
- }
- finally
- {
- monitor.done();
- }
- }
-
- private InternalCDORevision computeDirtyObject(InternalCDORevisionDelta delta)
- {
- CDOBranch branch = transaction.getBranch();
- CDOID id = delta.getID();
-
- InternalCDORevision oldRevision = null;
-
- try
- {
- oldRevision = revisionManager.getRevisionByVersion(id, delta, CDORevision.UNCHUNKED, true);
- if (oldRevision != null)
- {
- if (ObjectUtil.equals(oldRevision.getBranch(), branch) && oldRevision.isHistorical())
- {
- oldRevision = null;
- }
- }
- }
- catch (Exception ex)
- {
- OM.LOG.error(ex);
- oldRevision = null;
- }
-
- if (oldRevision == null)
- {
- throw new ConcurrentModificationException("Attempt by " + transaction + " to modify historical revision: "
- + delta);
- }
-
- // Make sure all chunks are loaded
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(oldRevision.getEClass()))
- {
- if (feature.isMany())
- {
- repository.ensureChunk(oldRevision, feature, 0, oldRevision.getList(feature).size());
- }
- }
-
- InternalCDORevision newRevision = oldRevision.copy();
- newRevision.adjustForCommit(branch, timeStamp);
-
- delta.apply(newRevision);
- return newRevision;
- }
-
- private void applyIDMappings(InternalCDORevision[] revisions, OMMonitor monitor)
- {
- try
- {
- monitor.begin(revisions.length);
- for (InternalCDORevision revision : revisions)
- {
- if (revision != null)
- {
- CDOID newID = idMappings.get(revision.getID());
- if (newID != null)
- {
- revision.setID(newID);
- }
-
- revision.adjustReferences(idMapper);
- monitor.worked();
- }
- }
- }
- finally
- {
- monitor.done();
- }
- }
-
- public synchronized void rollback(String message)
- {
- // Check if we already rolled back
- if (rollbackMessage == null)
- {
- rollbackMessage = message;
- unlockObjects();
- if (accessor != null)
- {
- try
- {
- accessor.rollback();
- }
- catch (RuntimeException ex)
- {
- OM.LOG.warn("Problem while rolling back the transaction", ex); //$NON-NLS-1$
- }
- finally
- {
- repository.failCommit(timeStamp);
- }
- }
- }
- }
-
- protected IStoreAccessor getAccessor()
- {
- return accessor;
- }
-
- private void updateInfraStructure(OMMonitor monitor)
- {
- try
- {
- monitor.begin(8);
- addNewPackageUnits(monitor.fork());
- addRevisions(newObjects, monitor.fork());
- addRevisions(dirtyObjects, monitor.fork());
- reviseDetachedObjects(monitor.fork());
-
- unlockObjects();
- monitor.worked();
-
- applyLocksOnNewObjects();
- monitor.worked();
-
- if (isAutoReleaseLocksEnabled())
- {
- postCommitLockStates = repository.getLockingManager().unlock2(true, transaction);
- if (!postCommitLockStates.isEmpty())
- {
- // TODO (CD) Does doing this here make sense?
- // The commit notifications get sent later, from postCommit.
- sendLockNotifications(postCommitLockStates);
- }
- }
-
- monitor.worked();
- repository.notifyWriteAccessHandlers(transaction, this, false, monitor.fork());
- }
- catch (Throwable t)
- {
- handleException(t);
- }
- finally
- {
- monitor.done();
- }
- }
-
- private void applyLocksOnNewObjects() throws InterruptedException
- {
- final CDOLockOwner owner = CDOLockUtil.createLockOwner(transaction);
-
- for (CDOLockState lockState : locksOnNewObjects)
- {
- Object target = lockState.getLockedObject();
-
- if (transaction.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE)
- {
- CDOIDAndBranch idAndBranch = target instanceof CDOIDAndBranch ? (CDOIDAndBranch)target : null;
- CDOID id = idAndBranch != null ? ((CDOIDAndBranch)target).getID() : (CDOID)target;
- CDOID newID = idMappings.get(id);
- CheckUtil.checkNull(newID, "newID");
-
- target = idAndBranch != null ? CDOIDUtil.createIDAndBranch(newID, idAndBranch.getBranch()) : newID;
- }
-
- for (LockType type : LockType.values())
- {
- if (lockState.isLocked(type, owner, false))
- {
- lockManager.lock2(type, transaction, Collections.singleton(target), 0);
- }
- }
- }
- }
-
- private void sendLockNotifications(List<LockState<Object, IView>> newLockStates)
- {
- CDOLockState[] newStates = Repository.toCDOLockStates(newLockStates);
-
- long timeStamp = getTimeStamp();
- InternalTransaction tx = getTransaction();
- CDOBranch branch = tx.getBranch();
- Operation unlock = Operation.UNLOCK;
-
- CDOLockChangeInfo info = CDOLockUtil.createLockChangeInfo(timeStamp, tx, branch, unlock, null, newStates);
- repository.getSessionManager().sendLockNotification(tx.getSession(), info);
- }
-
- private void addNewPackageUnits(OMMonitor monitor)
- {
- InternalCDOPackageRegistry repositoryPackageRegistry = repository.getPackageRegistry(false);
- synchronized (repositoryPackageRegistry)
- {
- try
- {
- monitor.begin(newPackageUnits.length);
- for (int i = 0; i < newPackageUnits.length; i++)
- {
- newPackageUnits[i].setState(CDOPackageUnit.State.LOADED);
- repositoryPackageRegistry.putPackageUnit(newPackageUnits[i]);
- monitor.worked();
- }
- }
- finally
- {
- monitor.done();
- }
- }
- }
-
- private void addRevisions(CDORevision[] revisions, OMMonitor monitor)
- {
- try
- {
- monitor.begin(revisions.length);
- for (CDORevision revision : revisions)
- {
- if (revision != null)
- {
- revisionManager.addRevision(revision);
- }
-
- monitor.worked();
- }
- }
- finally
- {
- monitor.done();
- }
- }
-
- private void reviseDetachedObjects(OMMonitor monitor)
- {
- try
- {
- monitor.begin(cachedDetachedRevisions.length);
- long revised = getBranchPoint().getTimeStamp() - 1;
- for (InternalCDORevision revision : cachedDetachedRevisions)
- {
- if (revision != null)
- {
- revision.setRevised(revised);
- }
-
- monitor.worked();
- }
- }
- finally
- {
- monitor.done();
- }
- }
-
- private void detachObjects(OMMonitor monitor)
- {
- int size = detachedObjects.length;
- cachedDetachedRevisions = new InternalCDORevision[size];
-
- CDOID[] detachedObjects = getDetachedObjects();
-
- try
- {
- monitor.begin(size);
- for (int i = 0; i < size; i++)
- {
- CDOID id = detachedObjects[i];
-
- // Remember the cached revision that must be revised after successful commit through updateInfraStructure
- cachedDetachedRevisions[i] = (InternalCDORevision)revisionManager.getCache().getRevision(id, transaction);
- monitor.worked();
- }
- }
- finally
- {
- monitor.done();
- }
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("TransactionCommitContext[{0}, {1}, {2}]", transaction.getSession(), transaction, //$NON-NLS-1$
- CDOCommonUtil.formatTimeStamp(timeStamp));
- }
-
- /**
- * @author Eike Stepper
- */
- public static final class TransactionPackageRegistry extends CDOPackageRegistryImpl
- {
- private static final long serialVersionUID = 1L;
-
- public TransactionPackageRegistry(InternalCDOPackageRegistry repositoryPackageRegistry)
- {
- delegateRegistry = repositoryPackageRegistry;
- setPackageLoader(repositoryPackageRegistry.getPackageLoader());
- }
-
- @Override
- public synchronized void putPackageUnit(InternalCDOPackageUnit packageUnit)
- {
- LifecycleUtil.checkActive(this);
- packageUnit.setPackageRegistry(this);
- for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos())
- {
- EPackage ePackage = packageInfo.getEPackage();
- basicPut(ePackage.getNsURI(), ePackage);
- }
-
- resetInternalCaches();
- }
-
- @Override
- protected void disposePackageUnits()
- {
- // Do nothing
- }
-
- @Override
- public Collection<Object> values()
- {
- throw new UnsupportedOperationException();
- }
- }
-
- /**
- * @author Martin Fluegge
- */
- private static final class DeltaLockWrapper implements CDOIDAndBranch
- {
- private Object key;
-
- private InternalCDORevisionDelta delta;
-
- public DeltaLockWrapper(Object key, InternalCDORevisionDelta delta)
- {
- this.key = key;
- this.delta = delta;
- }
-
- public Object getKey()
- {
- return key;
- }
-
- public InternalCDORevisionDelta getDelta()
- {
- return delta;
- }
-
- public CDOID getID()
- {
- return key instanceof CDOIDAndBranch ? ((CDOIDAndBranch)key).getID() : (CDOID)key;
- }
-
- public CDOBranch getBranch()
- {
- return key instanceof CDOIDAndBranch ? ((CDOIDAndBranch)key).getBranch() : null;
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (obj instanceof DeltaLockWrapper)
- {
- DeltaLockWrapper wrapper = (DeltaLockWrapper)obj;
- return key.equals(wrapper.getKey());
- }
-
- return key.equals(obj);
- }
-
- @Override
- public int hashCode()
- {
- return key.hashCode();
- }
-
- @Override
- public String toString()
- {
- return key.toString();
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class XRefContext implements QueryXRefsContext
- {
- private Map<EClass, List<EReference>> sourceCandidates = new HashMap<EClass, List<EReference>>();
-
- private Set<CDOID> detachedIDs = new HashSet<CDOID>();
-
- private Set<CDOID> dirtyIDs = new HashSet<CDOID>();
-
- private List<CDOIDReference> result = new ArrayList<CDOIDReference>();
-
- public XRefContext()
- {
- XRefsQueryHandler.collectSourceCandidates(transaction, detachedObjectTypes.values(), sourceCandidates);
-
- for (CDOID id : detachedObjects)
- {
- detachedIDs.add(id);
- }
-
- for (InternalCDORevision revision : dirtyObjects)
- {
- dirtyIDs.add(revision.getID());
- }
- }
-
- public List<CDOIDReference> getXRefs(IStoreAccessor accessor)
- {
- accessor.queryXRefs(this);
- checkDirtyObjects();
- return result;
- }
-
- private void checkDirtyObjects()
- {
- final CDOID[] dirtyID = { null };
- CDOReferenceAdjuster dirtyObjectChecker = new CDOReferenceAdjuster()
- {
- public Object adjustReference(Object targetID, EStructuralFeature feature, int index)
- {
- if (feature != CDOContainerFeatureDelta.CONTAINER_FEATURE)
- {
- if (detachedIDs.contains(targetID))
- {
- result.add(new CDOIDReference((CDOID)targetID, dirtyID[0], feature, index));
- }
-
- }
-
- return targetID;
- }
- };
-
- for (InternalCDORevision dirtyObject : dirtyObjects)
- {
- dirtyID[0] = dirtyObject.getID();
- dirtyObject.adjustReferences(dirtyObjectChecker);
- }
- }
-
- public long getTimeStamp()
- {
- return CDOBranchPoint.UNSPECIFIED_DATE;
- }
-
- public CDOBranch getBranch()
- {
- return transaction.getBranch();
- }
-
- public Map<CDOID, EClass> getTargetObjects()
- {
- return detachedObjectTypes;
- }
-
- public EReference[] getSourceReferences()
- {
- return new EReference[0];
- }
-
- public Map<EClass, List<EReference>> getSourceCandidates()
- {
- return sourceCandidates;
- }
-
- public int getMaxResults()
- {
- return CDOQueryInfo.UNLIMITED_RESULTS;
- }
-
- public boolean addXRef(CDOID targetID, CDOID sourceID, EReference sourceReference, int sourceIndex)
- {
- if (CDOIDUtil.isNull(targetID))
- {
- // Compensate potential issues with the XRef implementation in the store accessor.
- return true;
- }
-
- if (detachedIDs.contains(sourceID))
- {
- // Ignore XRefs from objects that are about to be detached themselves by this commit.
- return true;
- }
-
- if (dirtyIDs.contains(sourceID))
- {
- // Ignore XRefs from objects that are about to be modified by this commit. They're handled later in getXRefs().
- return true;
- }
-
- result.add(new CDOIDReference(targetID, sourceID, sourceReference, sourceIndex));
- return true;
- }
- }
-}
+/* + * 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: + * Simon McDuff - initial API and implementation + * Eike Stepper - maintenance + * Martin Fluegge - maintenance, bug 318518 + */ +package org.eclipse.emf.cdo.internal.server; + +import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation; +import org.eclipse.emf.cdo.common.branch.CDOBranch; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.commit.CDOCommitData; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDObject; +import org.eclipse.emf.cdo.common.id.CDOIDReference; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; +import org.eclipse.emf.cdo.common.lock.CDOLockOwner; +import org.eclipse.emf.cdo.common.lock.CDOLockState; +import org.eclipse.emf.cdo.common.lock.CDOLockUtil; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; +import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionKey; +import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta; +import org.eclipse.emf.cdo.common.security.NoPermissionException; +import org.eclipse.emf.cdo.common.util.CDOCommonUtil; +import org.eclipse.emf.cdo.common.util.CDOQueryInfo; +import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl; +import org.eclipse.emf.cdo.internal.common.commit.FailureCommitInfo; +import org.eclipse.emf.cdo.internal.common.model.CDOPackageRegistryImpl; +import org.eclipse.emf.cdo.internal.server.bundle.OM; +import org.eclipse.emf.cdo.server.ContainmentCycleDetectedException; +import org.eclipse.emf.cdo.server.IStoreAccessor; +import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; +import org.eclipse.emf.cdo.server.IView; +import org.eclipse.emf.cdo.server.StoreThreadLocal; +import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; +import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl; +import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper; +import org.eclipse.emf.cdo.spi.common.revision.CDOReferenceAdjuster; +import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; +import org.eclipse.emf.cdo.spi.common.revision.StubCDORevision; +import org.eclipse.emf.cdo.spi.server.InternalCommitContext; +import org.eclipse.emf.cdo.spi.server.InternalLockManager; +import org.eclipse.emf.cdo.spi.server.InternalRepository; +import org.eclipse.emf.cdo.spi.server.InternalSession; +import org.eclipse.emf.cdo.spi.server.InternalTransaction; + +import org.eclipse.net4j.util.CheckUtil; +import org.eclipse.net4j.util.ObjectUtil; +import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.collection.IndexedList; +import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; +import org.eclipse.net4j.util.concurrent.RWOLockManager.LockState; +import org.eclipse.net4j.util.io.ExtendedDataInputStream; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.om.monitor.Monitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.ConcurrentModificationException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * @author Simon McDuff + * @since 2.0 + */ +public class TransactionCommitContext implements InternalCommitContext +{ + private static final InternalCDORevision DETACHED = new StubCDORevision(null); + + private final InternalTransaction transaction; + + private InternalRepository repository; + + private InternalCDORevisionManager revisionManager; + + private InternalLockManager lockManager; + + private InternalCDOPackageRegistry repositoryPackageRegistry; + + private boolean packageRegistryLocked; + + private TransactionPackageRegistry packageRegistry; + + private IStoreAccessor accessor; + + private long timeStamp = CDORevision.UNSPECIFIED_DATE; + + private long previousTimeStamp = CDORevision.UNSPECIFIED_DATE; + + private String commitComment; + + private InternalCDOPackageUnit[] newPackageUnits = new InternalCDOPackageUnit[0]; + + private CDOLockState[] locksOnNewObjects = new CDOLockState[0]; + + private InternalCDORevision[] newObjects = new InternalCDORevision[0]; + + private InternalCDORevisionDelta[] dirtyObjectDeltas = new InternalCDORevisionDelta[0]; + + private CDOID[] detachedObjects = new CDOID[0]; + + private Map<CDOID, EClass> detachedObjectTypes; + + private InternalCDORevision[] dirtyObjects = new InternalCDORevision[0]; + + private InternalCDORevision[] cachedDetachedRevisions = new InternalCDORevision[0]; + + private Map<CDOID, InternalCDORevision> cachedRevisions; + + private Set<Object> lockedObjects = new HashSet<Object>(); + + private List<CDOID> lockedTargets; + + private ConcurrentMap<CDOID, CDOID> idMappings = new ConcurrentHashMap<CDOID, CDOID>(); + + private CDOReferenceAdjuster idMapper = new CDOIDMapper(idMappings); + + private String rollbackMessage; + + private List<CDOIDReference> xRefs; + + private List<LockState<Object, IView>> postCommitLockStates; + + private boolean ensuringReferentialIntegrity; + + private boolean autoReleaseLocksEnabled; + + private ExtendedDataInputStream lobs; + + public TransactionCommitContext(InternalTransaction transaction) + { + this.transaction = transaction; + + repository = transaction.getRepository(); + revisionManager = repository.getRevisionManager(); + lockManager = repository.getLockingManager(); + ensuringReferentialIntegrity = repository.isEnsuringReferentialIntegrity(); + + repositoryPackageRegistry = repository.getPackageRegistry(false); + packageRegistry = new TransactionPackageRegistry(repositoryPackageRegistry); + packageRegistry.activate(); + } + + public InternalTransaction getTransaction() + { + return transaction; + } + + public CDOBranchPoint getBranchPoint() + { + return transaction.getBranch().getPoint(timeStamp); + } + + public String getUserID() + { + return transaction.getSession().getUserID(); + } + + public String getCommitComment() + { + return commitComment; + } + + public boolean isAutoReleaseLocksEnabled() + { + return autoReleaseLocksEnabled; + } + + public String getRollbackMessage() + { + return rollbackMessage; + } + + public List<CDOIDReference> getXRefs() + { + return xRefs; + } + + public InternalCDOPackageRegistry getPackageRegistry() + { + return packageRegistry; + } + + public InternalCDOPackageUnit[] getNewPackageUnits() + { + return newPackageUnits; + } + + public CDOLockState[] getLocksOnNewObjects() + { + return locksOnNewObjects; + } + + public InternalCDORevision[] getNewObjects() + { + return newObjects; + } + + public InternalCDORevision[] getDirtyObjects() + { + return dirtyObjects; + } + + public CDOID[] getDetachedObjects() + { + return detachedObjects; + } + + public Map<CDOID, EClass> getDetachedObjectTypes() + { + return detachedObjectTypes; + } + + public InternalCDORevision[] getDetachedRevisions() + { + // This array can contain null values as they only come from the cache! + for (InternalCDORevision cachedDetachedRevision : cachedDetachedRevisions) + { + if (cachedDetachedRevision == null) + { + throw new AssertionError("Detached revisions are incomplete"); + } + } + + return cachedDetachedRevisions; + } + + public InternalCDORevisionDelta[] getDirtyObjectDeltas() + { + return dirtyObjectDeltas; + } + + public CDORevision getRevision(CDOID id) + { + if (cachedRevisions == null) + { + cachedRevisions = cacheRevisions(); + } + + // Try "after state" + InternalCDORevision revision = cachedRevisions.get(id); + if (revision == DETACHED) + { + return null; + } + + if (revision != null) + { + return revision; + } + + // Fall back to "before state" + return transaction.getRevision(id); + } + + private Map<CDOID, InternalCDORevision> cacheRevisions() + { + Map<CDOID, InternalCDORevision> cache = new HashMap<CDOID, InternalCDORevision>(); + if (newObjects != null) + { + for (int i = 0; i < newObjects.length; i++) + { + InternalCDORevision revision = newObjects[i]; + cache.put(revision.getID(), revision); + } + } + + if (dirtyObjects != null) + { + for (int i = 0; i < dirtyObjects.length; i++) + { + InternalCDORevision revision = dirtyObjects[i]; + cache.put(revision.getID(), revision); + } + } + + if (detachedObjects != null) + { + for (int i = 0; i < detachedObjects.length; i++) + { + cache.put(detachedObjects[i], DETACHED); + } + } + + return cache; + } + + public Map<CDOID, CDOID> getIDMappings() + { + return Collections.unmodifiableMap(idMappings); + } + + public void addIDMapping(CDOID oldID, CDOID newID) + { + if (CDOIDUtil.isNull(newID) || newID.isTemporary()) + { + throw new IllegalStateException("newID=" + newID); //$NON-NLS-1$ + } + + CDOID previousMapping = idMappings.putIfAbsent(oldID, newID); + if (previousMapping != null) + { + throw new IllegalStateException("previousMapping != null"); //$NON-NLS-1$ + } + } + + public void applyIDMappings(OMMonitor monitor) + { + boolean mapIDs = !idMappings.isEmpty(); + monitor.begin(1 + (mapIDs ? newObjects.length + dirtyObjects.length + dirtyObjectDeltas.length : 0)); + + try + { + if (mapIDs) + { + applyIDMappings(newObjects, monitor.fork(newObjects.length)); + applyIDMappings(dirtyObjects, monitor.fork(dirtyObjects.length)); + for (CDORevisionDelta dirtyObjectDelta : dirtyObjectDeltas) + { + ((InternalCDORevisionDelta)dirtyObjectDelta).adjustReferences(idMapper); + monitor.worked(); + } + } + + // Do not notify handlers before the IDs are fully mapped! + notifyBeforeCommitting(monitor); + } + finally + { + monitor.done(); + } + } + + protected void notifyBeforeCommitting(OMMonitor monitor) + { + repository.notifyWriteAccessHandlers(transaction, this, true, monitor.fork()); + } + + public void preWrite() + { + // Allocate a store writer + accessor = repository.getStore().getWriter(transaction); + + // Make the store writer available in a ThreadLocal variable + StoreThreadLocal.setAccessor(accessor); + StoreThreadLocal.setCommitContext(this); + } + + public void setNewPackageUnits(InternalCDOPackageUnit[] newPackageUnits) + { + this.newPackageUnits = newPackageUnits; + } + + public void setLocksOnNewObjects(CDOLockState[] locksOnNewObjects) + { + this.locksOnNewObjects = locksOnNewObjects; + } + + public void setNewObjects(InternalCDORevision[] newObjects) + { + this.newObjects = newObjects; + } + + public void setDirtyObjectDeltas(InternalCDORevisionDelta[] dirtyObjectDeltas) + { + this.dirtyObjectDeltas = dirtyObjectDeltas; + } + + public void setDetachedObjects(CDOID[] detachedObjects) + { + this.detachedObjects = detachedObjects; + } + + public void setDetachedObjectTypes(Map<CDOID, EClass> detachedObjectTypes) + { + this.detachedObjectTypes = detachedObjectTypes; + } + + public void setAutoReleaseLocksEnabled(boolean on) + { + autoReleaseLocksEnabled = on; + } + + public void setCommitComment(String commitComment) + { + this.commitComment = commitComment; + } + + public ExtendedDataInputStream getLobs() + { + return lobs; + } + + public void setLobs(ExtendedDataInputStream in) + { + lobs = in; + } + + /** + * @since 2.0 + */ + public void write(OMMonitor monitor) + { + try + { + monitor.begin(107); + dirtyObjects = new InternalCDORevision[dirtyObjectDeltas.length]; + + if (newPackageUnits.length != 0) + { + repository.getPackageRegistryCommitLock().acquire(); + packageRegistryLocked = true; + + List<InternalCDOPackageUnit> noDuplicates = new ArrayList<InternalCDOPackageUnit>(); + for (InternalCDOPackageUnit newPackageUnit : newPackageUnits) + { + String id = newPackageUnit.getID(); + if (!repositoryPackageRegistry.containsKey(id)) + { + noDuplicates.add(newPackageUnit); + } + } + + int newSize = noDuplicates.size(); + if (newPackageUnits.length != newSize) + { + newPackageUnits = noDuplicates.toArray(new InternalCDOPackageUnit[newSize]); + } + } + + lockObjects(); // Can take long and must come before setTimeStamp() + monitor.worked(); + + setTimeStamp(monitor.fork()); + + adjustForCommit(); + monitor.worked(); + + computeDirtyObjects(monitor.fork()); + + checkXRefs(); + monitor.worked(); + + if (rollbackMessage == null) + { + detachObjects(monitor.fork()); + accessor.write(this, monitor.fork(100)); + } + } + catch (Throwable t) + { + handleException(t); + } + finally + { + finishMonitor(monitor); + } + } + + public void commit(OMMonitor monitor) + { + try + { + monitor.begin(101); + accessor.commit(monitor.fork(100)); + updateInfraStructure(monitor.fork()); + + // Bugzilla 297940 + repository.endCommit(timeStamp); + } + catch (Throwable ex) + { + handleException(ex); + } + finally + { + finishMonitor(monitor); + } + } + + public List<LockState<Object, IView>> getPostCommmitLockStates() + { + return postCommitLockStates; + } + + private void handleException(Throwable ex) + { + try + { + OM.LOG.error(ex); + String storeClass = repository.getStore().getClass().getSimpleName(); + rollback("Rollback in " + storeClass + ": " + StringUtil.formatException(ex)); //$NON-NLS-1$ //$NON-NLS-2$ + } + catch (Exception ex1) + { + if (rollbackMessage == null) + { + rollbackMessage = ex1.getMessage(); + } + + try + { + OM.LOG.error(ex1); + } + catch (Exception ignore) + { + } + } + } + + private void finishMonitor(OMMonitor monitor) + { + try + { + monitor.done(); + } + catch (Exception ex) + { + try + { + OM.LOG.warn(ex); + } + catch (Exception ignore) + { + } + } + } + + private void setTimeStamp(OMMonitor mmonitor) + { + long[] times = createTimeStamp(mmonitor); // Could throw an exception + timeStamp = times[0]; + previousTimeStamp = times[1]; + CheckUtil.checkState(timeStamp != CDOBranchPoint.UNSPECIFIED_DATE, "Commit timestamp must not be 0"); + } + + protected long[] createTimeStamp(OMMonitor monitor) + { + return repository.createCommitTimeStamp(monitor); + } + + protected long getTimeStamp() + { + return timeStamp; + } + + protected void setTimeStamp(long timeStamp) + { + repository.forceCommitTimeStamp(timeStamp, new Monitor()); + this.timeStamp = timeStamp; + } + + public long getPreviousTimeStamp() + { + return previousTimeStamp; + } + + public void postCommit(boolean success) + { + if (packageRegistryLocked) + { + repository.getPackageRegistryCommitLock().release(); + } + + try + { + InternalSession sender = transaction.getSession(); + CDOCommitInfo commitInfo = success ? createCommitInfo() : createFailureCommitInfo(); + + repository.sendCommitNotification(sender, commitInfo); + } + catch (Exception ex) + { + OM.LOG.warn("A problem occured while notifying other sessions", ex); + } + finally + { + StoreThreadLocal.release(); + accessor = null; + lockedTargets = null; + + if (packageRegistry != null) + { + packageRegistry.deactivate(); + packageRegistry = null; + } + } + } + + public CDOCommitInfo createCommitInfo() + { + CDOBranch branch = transaction.getBranch(); + String userID = transaction.getSession().getUserID(); + CDOCommitData commitData = createCommitData(); + + InternalCDOCommitInfoManager commitInfoManager = repository.getCommitInfoManager(); + return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, commitComment, commitData); + } + + public CDOCommitInfo createFailureCommitInfo() + { + return new FailureCommitInfo(timeStamp, previousTimeStamp); + } + + private CDOCommitData createCommitData() + { + List<CDOPackageUnit> newPackageUnitsCollection = new IndexedList.ArrayBacked<CDOPackageUnit>() + { + @Override + protected CDOPackageUnit[] getArray() + { + return newPackageUnits; + } + }; + + List<CDOIDAndVersion> newObjectsCollection = new IndexedList.ArrayBacked<CDOIDAndVersion>() + { + @Override + protected CDOIDAndVersion[] getArray() + { + return newObjects; + } + }; + + List<CDORevisionKey> changedObjectsCollection = new IndexedList.ArrayBacked<CDORevisionKey>() + { + @Override + protected CDORevisionKey[] getArray() + { + return dirtyObjectDeltas; + } + }; + + List<CDOIDAndVersion> detachedObjectsCollection = new IndexedList<CDOIDAndVersion>() + { + @Override + public CDOIDAndVersion get(int i) + { + if (cachedDetachedRevisions[i] != null) + { + return cachedDetachedRevisions[i]; + } + + return CDOIDUtil.createIDAndVersion(detachedObjects[i], CDORevision.UNSPECIFIED_VERSION); + } + + @Override + public int size() + { + return detachedObjects.length; + } + }; + + return new CDOCommitDataImpl(newPackageUnitsCollection, newObjectsCollection, changedObjectsCollection, + detachedObjectsCollection); + } + + protected void adjustForCommit() + { + for (InternalCDOPackageUnit newPackageUnit : newPackageUnits) + { + newPackageUnit.setTimeStamp(timeStamp); + } + + CDOBranch branch = transaction.getBranch(); + for (InternalCDORevision newObject : newObjects) + { + newObject.adjustForCommit(branch, timeStamp); + } + } + + protected void lockObjects() throws InterruptedException + { + lockedObjects.clear(); + lockedTargets = null; + + try + { + final boolean supportingBranches = repository.isSupportingBranches(); + + CDOFeatureDeltaVisitor deltaTargetLocker = null; + if (ensuringReferentialIntegrity) + { + final Set<CDOID> newIDs = new HashSet<CDOID>(); + for (int i = 0; i < newObjects.length; i++) + { + InternalCDORevision newRevision = newObjects[i]; + CDOID newID = newRevision.getID(); + if (newID instanceof CDOIDObject) + { + // After merges newObjects may contain non-TEMP ids + newIDs.add(newID); + } + } + + deltaTargetLocker = new CDOFeatureDeltaVisitorImpl() + { + @Override + public void visit(CDOAddFeatureDelta delta) + { + lockTarget(delta.getValue(), newIDs, supportingBranches); + } + + @Override + public void visit(CDOSetFeatureDelta delta) + { + lockTarget(delta.getValue(), newIDs, supportingBranches); + } + }; + + CDOReferenceAdjuster revisionTargetLocker = new CDOReferenceAdjuster() + { + public Object adjustReference(Object value, EStructuralFeature feature, int index) + { + lockTarget(value, newIDs, supportingBranches); + return value; + } + }; + + for (int i = 0; i < newObjects.length; i++) + { + InternalCDORevision newRevision = newObjects[i]; + newRevision.adjustReferences(revisionTargetLocker); + } + } + + for (int i = 0; i < dirtyObjectDeltas.length; i++) + { + InternalCDORevisionDelta delta = dirtyObjectDeltas[i]; + CDOID id = delta.getID(); + Object key = lockManager.getLockKey(id, transaction.getBranch()); + lockedObjects.add(new DeltaLockWrapper(key, delta)); + + if (hasContainmentChanges(delta)) + { + if (isContainerLocked(delta)) + { + throw new ContainmentCycleDetectedException("Parent (" + key + + ") is already locked for containment changes"); + } + } + } + + for (int i = 0; i < dirtyObjectDeltas.length; i++) + { + InternalCDORevisionDelta delta = dirtyObjectDeltas[i]; + if (deltaTargetLocker != null) + { + delta.accept(deltaTargetLocker); + } + } + + for (int i = 0; i < detachedObjects.length; i++) + { + CDOID id = detachedObjects[i]; + Object key = lockManager.getLockKey(id, transaction.getBranch()); + lockedObjects.add(key); + } + + if (!lockedObjects.isEmpty()) + { + // First lock all objects (incl. possible ref targets). + // This is a transient operation, it does not check for existance! + lockManager.lock2(LockType.WRITE, transaction, lockedObjects, 1000); + + // If all locks could be acquired, check if locked targets do still exist + if (lockedTargets != null) + { + for (CDOID id : lockedTargets) + { + InternalCDORevision revision = // + revisionManager.getRevision(id, transaction, CDORevision.UNCHUNKED, CDORevision.DEPTH_NONE, true); + + if (revision == null || revision instanceof DetachedCDORevision) + { + throw new IllegalStateException("Object " + id + + " can not be referenced anymore because it has been detached"); + } + } + } + } + } + catch (RuntimeException ex) + { + lockedObjects.clear(); + lockedTargets = null; + throw ex; + } + } + + /** + * Iterates up the eContainers of an object and returns <code>true</code> on the first parent locked by another view. + * + * @return <code>true</code> if any parent is locked, <code>false</code> otherwise. + */ + private boolean isContainerLocked(InternalCDORevisionDelta delta) + { + CDOID id = delta.getID(); + InternalCDORevision revision = revisionManager.getRevisionByVersion(id, delta, CDORevision.UNCHUNKED, true); + if (revision == null) + { + // Can happen with non-auditing cache + throw new ConcurrentModificationException("Attempt by " + transaction + " to modify historical revision: " + + CDORevisionUtil.copyRevisionKey(delta)); + } + + return isContainerLocked(revision); + } + + private boolean isContainerLocked(InternalCDORevision revision) + { + CDOID id = (CDOID)revision.getContainerID(); + if (CDOIDUtil.isNull(id)) + { + return false; + } + + Object key = lockManager.getLockKey(id, transaction.getBranch()); + DeltaLockWrapper lockWrapper = new DeltaLockWrapper(key, null); + + if (lockManager.hasLockByOthers(LockType.WRITE, transaction, lockWrapper)) + { + Object object = lockManager.getLockEntryObject(lockWrapper); + if (object instanceof DeltaLockWrapper) + { + InternalCDORevisionDelta delta = ((DeltaLockWrapper)object).getDelta(); + if (delta != null && hasContainmentChanges(delta)) + { + return true; + } + } + } + + InternalCDORevision parent = revisionManager.getRevision(id, transaction, CDORevision.UNCHUNKED, + CDORevision.DEPTH_NONE, true); + + if (parent != null) + { + return isContainerLocked(parent); + } + + return false; + } + + private boolean hasContainmentChanges(InternalCDORevisionDelta delta) + { + for (CDOFeatureDelta featureDelta : delta.getFeatureDeltas()) + { + EStructuralFeature feature = featureDelta.getFeature(); + if (feature instanceof EReference) + { + if (((EReference)feature).isContainment()) + { + return true; + } + } + } + + return false; + } + + private void lockTarget(Object value, Set<CDOID> newIDs, boolean supportingBranches) + { + if (value instanceof CDOIDObject) + { + CDOIDObject id = (CDOIDObject)value; + if (id.isNull()) + { + return; + } + + if (newIDs.contains(id)) + { + // After merges newObjects may contain non-TEMP ids + return; + } + + if (detachedObjectTypes != null && detachedObjectTypes.containsKey(id)) + { + throw new IllegalStateException("This commit deletes object " + id + " and adds a reference at the same time"); + } + + // Let this object be locked + Object key = lockManager.getLockKey(id, transaction.getBranch()); + lockedObjects.add(key); + + // Let this object be checked for existance after it has been locked + if (lockedTargets == null) + { + lockedTargets = new ArrayList<CDOID>(); + } + + lockedTargets.add(id); + } + } + + protected void checkXRefs() + { + if (ensuringReferentialIntegrity && detachedObjectTypes != null) + { + XRefContext context = new XRefContext(); + xRefs = context.getXRefs(accessor); + if (!xRefs.isEmpty()) + { + rollbackMessage = "Referential integrity violated"; + } + } + } + + private synchronized void unlockObjects() + { + if (!lockedObjects.isEmpty()) + { + lockManager.unlock2(LockType.WRITE, transaction, lockedObjects); + lockedObjects.clear(); + } + + if (detachedObjects.length > 0) + { + boolean branching = getTransaction().getRepository().isSupportingBranches(); + Collection<? extends Object> unlockables = null; + if (branching) + { + List<CDOIDAndBranch> keys = new LinkedList<CDOIDAndBranch>(); + for (CDOID id : detachedObjects) + { + CDOIDAndBranch idAndBranch = CDOIDUtil.createIDAndBranch(id, transaction.getBranch()); + keys.add(idAndBranch); + } + + unlockables = keys; + } + else + { + unlockables = Arrays.asList(detachedObjects); + } + + lockManager.unlock2(transaction, unlockables); + } + } + + private void computeDirtyObjects(OMMonitor monitor) + { + try + { + monitor.begin(dirtyObjectDeltas.length); + for (int i = 0; i < dirtyObjectDeltas.length; i++) + { + dirtyObjects[i] = computeDirtyObject(dirtyObjectDeltas[i]); + if (dirtyObjects[i] == null) + { + throw new IllegalStateException("Can not retrieve origin revision for " + dirtyObjectDeltas[i]); //$NON-NLS-1$ + } + + if (!dirtyObjects[i].isWritable()) + { + throw new NoPermissionException(dirtyObjects[i]); + } + + monitor.worked(); + } + } + finally + { + monitor.done(); + } + } + + private InternalCDORevision computeDirtyObject(InternalCDORevisionDelta delta) + { + CDOBranch branch = transaction.getBranch(); + CDOID id = delta.getID(); + + InternalCDORevision oldRevision = null; + + try + { + oldRevision = revisionManager.getRevisionByVersion(id, delta, CDORevision.UNCHUNKED, true); + if (oldRevision != null) + { + if (ObjectUtil.equals(oldRevision.getBranch(), branch) && oldRevision.isHistorical()) + { + oldRevision = null; + } + } + } + catch (Exception ex) + { + OM.LOG.error(ex); + oldRevision = null; + } + + if (oldRevision == null) + { + throw new ConcurrentModificationException("Attempt by " + transaction + " to modify historical revision: " + + delta); + } + + // Make sure all chunks are loaded + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(oldRevision.getEClass())) + { + if (feature.isMany()) + { + repository.ensureChunk(oldRevision, feature, 0, oldRevision.getList(feature).size()); + } + } + + InternalCDORevision newRevision = oldRevision.copy(); + newRevision.adjustForCommit(branch, timeStamp); + + delta.apply(newRevision); + return newRevision; + } + + private void applyIDMappings(InternalCDORevision[] revisions, OMMonitor monitor) + { + try + { + monitor.begin(revisions.length); + for (InternalCDORevision revision : revisions) + { + if (revision != null) + { + CDOID newID = idMappings.get(revision.getID()); + if (newID != null) + { + revision.setID(newID); + } + + revision.adjustReferences(idMapper); + monitor.worked(); + } + } + } + finally + { + monitor.done(); + } + } + + public synchronized void rollback(String message) + { + // Check if we already rolled back + if (rollbackMessage == null) + { + rollbackMessage = message; + unlockObjects(); + if (accessor != null) + { + try + { + accessor.rollback(); + } + catch (RuntimeException ex) + { + OM.LOG.warn("Problem while rolling back the transaction", ex); //$NON-NLS-1$ + } + finally + { + repository.failCommit(timeStamp); + } + } + } + } + + protected IStoreAccessor getAccessor() + { + return accessor; + } + + private void updateInfraStructure(OMMonitor monitor) + { + try + { + monitor.begin(8); + addNewPackageUnits(monitor.fork()); + addRevisions(newObjects, monitor.fork()); + addRevisions(dirtyObjects, monitor.fork()); + reviseDetachedObjects(monitor.fork()); + + unlockObjects(); + monitor.worked(); + + applyLocksOnNewObjects(); + monitor.worked(); + + if (isAutoReleaseLocksEnabled()) + { + postCommitLockStates = repository.getLockingManager().unlock2(true, transaction); + if (!postCommitLockStates.isEmpty()) + { + // TODO (CD) Does doing this here make sense? + // The commit notifications get sent later, from postCommit. + sendLockNotifications(postCommitLockStates); + } + } + + monitor.worked(); + repository.notifyWriteAccessHandlers(transaction, this, false, monitor.fork()); + } + catch (Throwable t) + { + handleException(t); + } + finally + { + monitor.done(); + } + } + + private void applyLocksOnNewObjects() throws InterruptedException + { + final CDOLockOwner owner = CDOLockUtil.createLockOwner(transaction); + + for (CDOLockState lockState : locksOnNewObjects) + { + Object target = lockState.getLockedObject(); + + if (transaction.getRepository().getIDGenerationLocation() == IDGenerationLocation.STORE) + { + CDOIDAndBranch idAndBranch = target instanceof CDOIDAndBranch ? (CDOIDAndBranch)target : null; + CDOID id = idAndBranch != null ? ((CDOIDAndBranch)target).getID() : (CDOID)target; + CDOID newID = idMappings.get(id); + CheckUtil.checkNull(newID, "newID"); + + target = idAndBranch != null ? CDOIDUtil.createIDAndBranch(newID, idAndBranch.getBranch()) : newID; + } + + for (LockType type : LockType.values()) + { + if (lockState.isLocked(type, owner, false)) + { + lockManager.lock2(type, transaction, Collections.singleton(target), 0); + } + } + } + } + + private void sendLockNotifications(List<LockState<Object, IView>> newLockStates) + { + CDOLockState[] newStates = Repository.toCDOLockStates(newLockStates); + + long timeStamp = getTimeStamp(); + InternalTransaction tx = getTransaction(); + CDOBranch branch = tx.getBranch(); + Operation unlock = Operation.UNLOCK; + + CDOLockChangeInfo info = CDOLockUtil.createLockChangeInfo(timeStamp, tx, branch, unlock, null, newStates); + repository.getSessionManager().sendLockNotification(tx.getSession(), info); + } + + private void addNewPackageUnits(OMMonitor monitor) + { + InternalCDOPackageRegistry repositoryPackageRegistry = repository.getPackageRegistry(false); + synchronized (repositoryPackageRegistry) + { + try + { + monitor.begin(newPackageUnits.length); + for (int i = 0; i < newPackageUnits.length; i++) + { + newPackageUnits[i].setState(CDOPackageUnit.State.LOADED); + repositoryPackageRegistry.putPackageUnit(newPackageUnits[i]); + monitor.worked(); + } + } + finally + { + monitor.done(); + } + } + } + + private void addRevisions(CDORevision[] revisions, OMMonitor monitor) + { + try + { + monitor.begin(revisions.length); + for (CDORevision revision : revisions) + { + if (revision != null) + { + revisionManager.addRevision(revision); + } + + monitor.worked(); + } + } + finally + { + monitor.done(); + } + } + + private void reviseDetachedObjects(OMMonitor monitor) + { + try + { + monitor.begin(cachedDetachedRevisions.length); + long revised = getBranchPoint().getTimeStamp() - 1; + for (InternalCDORevision revision : cachedDetachedRevisions) + { + if (revision != null) + { + revision.setRevised(revised); + } + + monitor.worked(); + } + } + finally + { + monitor.done(); + } + } + + private void detachObjects(OMMonitor monitor) + { + int size = detachedObjects.length; + cachedDetachedRevisions = new InternalCDORevision[size]; + + CDOID[] detachedObjects = getDetachedObjects(); + + try + { + monitor.begin(size); + for (int i = 0; i < size; i++) + { + CDOID id = detachedObjects[i]; + + // Remember the cached revision that must be revised after successful commit through updateInfraStructure + cachedDetachedRevisions[i] = (InternalCDORevision)revisionManager.getCache().getRevision(id, transaction); + monitor.worked(); + } + } + finally + { + monitor.done(); + } + } + + @Override + public String toString() + { + return MessageFormat.format("TransactionCommitContext[{0}, {1}, {2}]", transaction.getSession(), transaction, //$NON-NLS-1$ + CDOCommonUtil.formatTimeStamp(timeStamp)); + } + + /** + * @author Eike Stepper + */ + public static final class TransactionPackageRegistry extends CDOPackageRegistryImpl + { + private static final long serialVersionUID = 1L; + + public TransactionPackageRegistry(InternalCDOPackageRegistry repositoryPackageRegistry) + { + delegateRegistry = repositoryPackageRegistry; + setPackageLoader(repositoryPackageRegistry.getPackageLoader()); + } + + @Override + public synchronized void putPackageUnit(InternalCDOPackageUnit packageUnit) + { + LifecycleUtil.checkActive(this); + packageUnit.setPackageRegistry(this); + for (InternalCDOPackageInfo packageInfo : packageUnit.getPackageInfos()) + { + EPackage ePackage = packageInfo.getEPackage(); + basicPut(ePackage.getNsURI(), ePackage); + } + + resetInternalCaches(); + } + + @Override + protected void disposePackageUnits() + { + // Do nothing + } + + @Override + public Collection<Object> values() + { + throw new UnsupportedOperationException(); + } + } + + /** + * @author Martin Fluegge + */ + private static final class DeltaLockWrapper implements CDOIDAndBranch + { + private Object key; + + private InternalCDORevisionDelta delta; + + public DeltaLockWrapper(Object key, InternalCDORevisionDelta delta) + { + this.key = key; + this.delta = delta; + } + + public Object getKey() + { + return key; + } + + public InternalCDORevisionDelta getDelta() + { + return delta; + } + + public CDOID getID() + { + return key instanceof CDOIDAndBranch ? ((CDOIDAndBranch)key).getID() : (CDOID)key; + } + + public CDOBranch getBranch() + { + return key instanceof CDOIDAndBranch ? ((CDOIDAndBranch)key).getBranch() : null; + } + + @Override + public boolean equals(Object obj) + { + if (obj instanceof DeltaLockWrapper) + { + DeltaLockWrapper wrapper = (DeltaLockWrapper)obj; + return key.equals(wrapper.getKey()); + } + + return key.equals(obj); + } + + @Override + public int hashCode() + { + return key.hashCode(); + } + + @Override + public String toString() + { + return key.toString(); + } + } + + /** + * @author Eike Stepper + */ + private final class XRefContext implements QueryXRefsContext + { + private Map<EClass, List<EReference>> sourceCandidates = new HashMap<EClass, List<EReference>>(); + + private Set<CDOID> detachedIDs = new HashSet<CDOID>(); + + private Set<CDOID> dirtyIDs = new HashSet<CDOID>(); + + private List<CDOIDReference> result = new ArrayList<CDOIDReference>(); + + public XRefContext() + { + XRefsQueryHandler.collectSourceCandidates(transaction, detachedObjectTypes.values(), sourceCandidates); + + for (CDOID id : detachedObjects) + { + detachedIDs.add(id); + } + + for (InternalCDORevision revision : dirtyObjects) + { + dirtyIDs.add(revision.getID()); + } + } + + public List<CDOIDReference> getXRefs(IStoreAccessor accessor) + { + accessor.queryXRefs(this); + checkDirtyObjects(); + return result; + } + + private void checkDirtyObjects() + { + final CDOID[] dirtyID = { null }; + CDOReferenceAdjuster dirtyObjectChecker = new CDOReferenceAdjuster() + { + public Object adjustReference(Object targetID, EStructuralFeature feature, int index) + { + if (feature != CDOContainerFeatureDelta.CONTAINER_FEATURE) + { + if (detachedIDs.contains(targetID)) + { + result.add(new CDOIDReference((CDOID)targetID, dirtyID[0], feature, index)); + } + + } + + return targetID; + } + }; + + for (InternalCDORevision dirtyObject : dirtyObjects) + { + dirtyID[0] = dirtyObject.getID(); + dirtyObject.adjustReferences(dirtyObjectChecker); + } + } + + public long getTimeStamp() + { + return CDOBranchPoint.UNSPECIFIED_DATE; + } + + public CDOBranch getBranch() + { + return transaction.getBranch(); + } + + public Map<CDOID, EClass> getTargetObjects() + { + return detachedObjectTypes; + } + + public EReference[] getSourceReferences() + { + return new EReference[0]; + } + + public Map<EClass, List<EReference>> getSourceCandidates() + { + return sourceCandidates; + } + + public int getMaxResults() + { + return CDOQueryInfo.UNLIMITED_RESULTS; + } + + public boolean addXRef(CDOID targetID, CDOID sourceID, EReference sourceReference, int sourceIndex) + { + if (CDOIDUtil.isNull(targetID)) + { + // Compensate potential issues with the XRef implementation in the store accessor. + return true; + } + + if (detachedIDs.contains(sourceID)) + { + // Ignore XRefs from objects that are about to be detached themselves by this commit. + return true; + } + + if (dirtyIDs.contains(sourceID)) + { + // Ignore XRefs from objects that are about to be modified by this commit. They're handled later in getXRefs(). + return true; + } + + result.add(new CDOIDReference(targetID, sourceID, sourceReference, sourceIndex)); + return true; + } + } +} 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 new file mode 100644 index 0000000000..69f9d01f8d --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/server/IPermissionManager.java @@ -0,0 +1,24 @@ +/* + * 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.server; + +import org.eclipse.emf.cdo.common.security.CDOPermission; + +/** + * 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 protectableObject, String userID); +} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java index 44022132e2..73af757b30 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSession.java @@ -1,86 +1,87 @@ -/*
- * 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.spi.server;
-
-import org.eclipse.emf.cdo.common.CDOCommonRepository;
-import org.eclipse.emf.cdo.common.CDOCommonSession;
-import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.id.CDOIDProvider;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.server.ISession;
-import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author Eike Stepper
- * @since 3.0
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface InternalSession extends ISession, CDOIDProvider, CDOCommonSession.Options
-{
- public static final int TEMP_VIEW_ID = 0;
-
- public InternalSessionManager getManager();
-
- public InternalView[] getViews();
-
- public InternalView getView(int viewID);
-
- public InternalView openView(int viewID, CDOBranchPoint branchPoint);
-
- public InternalTransaction openTransaction(int viewID, CDOBranchPoint branchPoint);
-
- public void viewClosed(InternalView view);
-
- public void setSubscribed(boolean subscribed);
-
- public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk,
- Set<CDOID> revisions, List<CDORevision> additionalRevisions);
-
- public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType)
- throws Exception;
-
- /**
- * @deprecated use
- * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)}
- * instead
- */
- @Deprecated
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState)
- throws Exception;
-
- /**
- * @since 4.1
- */
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState,
- CDOID rootResourceID) throws Exception;
-
- public void sendBranchNotification(InternalCDOBranch branch) throws Exception;
-
- public void sendCommitNotification(CDOCommitInfo commitInfo) throws Exception;
-
- public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception;
-
- public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception;
-
- /**
- * @since 4.1
- */
- public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception;
-}
+/* + * 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.spi.server; + +import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.CDOCommonSession; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDProvider; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.security.CDOPermissionProvider; +import org.eclipse.emf.cdo.server.ISession; +import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; +import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import java.util.List; +import java.util.Set; + +/** + * @author Eike Stepper + * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface InternalSession extends ISession, CDOIDProvider, CDOPermissionProvider, CDOCommonSession.Options +{ + public static final int TEMP_VIEW_ID = 0; + + public InternalSessionManager getManager(); + + public InternalView[] getViews(); + + public InternalView getView(int viewID); + + public InternalView openView(int viewID, CDOBranchPoint branchPoint); + + public InternalTransaction openTransaction(int viewID, CDOBranchPoint branchPoint); + + public void viewClosed(InternalView view); + + public void setSubscribed(boolean subscribed); + + public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk, + Set<CDOID> revisions, List<CDORevision> additionalRevisions); + + public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType) + throws Exception; + + /** + * @deprecated use + * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)} + * instead + */ + @Deprecated + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) + throws Exception; + + /** + * @since 4.1 + */ + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID) throws Exception; + + public void sendBranchNotification(InternalCDOBranch branch) throws Exception; + + public void sendCommitNotification(CDOCommitInfo commitInfo) throws Exception; + + public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception; + + public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception; + + /** + * @since 4.1 + */ + public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception; +} diff --git a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java index eb04653aab..aabf53ee71 100644 --- a/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java +++ b/plugins/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/InternalSessionManager.java @@ -1,79 +1,95 @@ -/*
- * 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.spi.server;
-
-import org.eclipse.emf.cdo.common.CDOCommonRepository;
-import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo;
-import org.eclipse.emf.cdo.server.ISessionManager;
-import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
-import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
-
-import org.eclipse.net4j.util.security.IUserManager;
-
-import java.util.List;
-
-/**
- * @author Eike Stepper
- * @since 3.0
- * @noextend This interface is not intended to be extended by clients.
- * @noimplement This interface is not intended to be implemented by clients.
- */
-public interface InternalSessionManager extends ISessionManager
-{
- public InternalRepository getRepository();
-
- public void setRepository(InternalRepository repository);
-
- public void setUserManager(IUserManager userManager);
-
- public InternalSession[] getSessions();
-
- public InternalSession getSession(int sessionID);
-
- /**
- * @return Never <code>null</code>
- */
- public InternalSession openSession(ISessionProtocol sessionProtocol);
-
- public void sessionClosed(InternalSession session);
-
- public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType);
-
- /**
- * @deprecated use
- * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)}
- * instead
- */
- @Deprecated
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState);
-
- /**
- * @since 4.1
- */
- public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState,
- CDOID rootResourceID);
-
- public void sendBranchNotification(InternalSession sender, InternalCDOBranch branch);
-
- public void sendCommitNotification(InternalSession sender, CDOCommitInfo commitInfo);
-
- /**
- * @since 4.1
- */
- public void sendLockNotification(InternalSession sender, CDOLockChangeInfo lockChangeInfo);
-
- public void sendRemoteSessionNotification(InternalSession sender, byte opcode);
-
- public List<Integer> sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message,
- int[] recipients);
-}
+/* + * 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.spi.server; + +import org.eclipse.emf.cdo.common.CDOCommonRepository; +import org.eclipse.emf.cdo.common.commit.CDOCommitInfo; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; +import org.eclipse.emf.cdo.server.IPermissionManager; +import org.eclipse.emf.cdo.server.ISessionManager; +import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; +import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; + +import org.eclipse.net4j.util.security.IUserManager; + +import java.util.List; + +/** + * @author Eike Stepper + * @since 3.0 + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface InternalSessionManager extends ISessionManager +{ + public InternalRepository getRepository(); + + public void setRepository(InternalRepository repository); + + /** + * @since 4.1 + */ + public IUserManager getUserManager(); + + public void setUserManager(IUserManager userManager); + + /** + * @since 4.1 + */ + public IPermissionManager getPermissionManager(); + + /** + * @since 4.1 + */ + public void setPermissionManager(IPermissionManager permissionManager); + + public InternalSession[] getSessions(); + + public InternalSession getSession(int sessionID); + + /** + * @return Never <code>null</code> + */ + public InternalSession openSession(ISessionProtocol sessionProtocol); + + public void sessionClosed(InternalSession session); + + public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType); + + /** + * @deprecated use + * {@link #sendRepositoryStateNotification(org.eclipse.emf.cdo.common.CDOCommonRepository.State, org.eclipse.emf.cdo.common.CDOCommonRepository.State, CDOID)} + * instead + */ + @Deprecated + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState); + + /** + * @since 4.1 + */ + public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, + CDOID rootResourceID); + + public void sendBranchNotification(InternalSession sender, InternalCDOBranch branch); + + public void sendCommitNotification(InternalSession sender, CDOCommitInfo commitInfo); + + /** + * @since 4.1 + */ + public void sendLockNotification(InternalSession sender, CDOLockChangeInfo lockChangeInfo); + + public void sendRemoteSessionNotification(InternalSession sender, byte opcode); + + public List<Integer> sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message, + int[] recipients); +} diff --git a/plugins/org.eclipse.emf.cdo.tests.db/build.properties b/plugins/org.eclipse.emf.cdo.tests.db/build.properties index 65455211eb..d3d1d56ff7 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db/build.properties +++ b/plugins/org.eclipse.emf.cdo.tests.db/build.properties @@ -1,31 +1,34 @@ -# 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
-
-bin.includes = .,\
- META-INF/,\
- plugin.properties,\
- copyright.txt,\
- about.html,\
- .options
-jars.compile.order = .
-source.. = src/
-output.. = bin/
-src.includes = about.html,\
- copyright.txt,\
- CDO AllTests (DB2 non-audit).launch,\
- CDO AllTests (Derby).launch,\
- CDO AllTests (H2 audit).launch,\
- CDO AllTests (H2 branching).launch,\
- CDO AllTests (H2 non-audit).launch,\
- CDO AllTests (H2 offline).launch,\
- CDO AllTests (Hsqldb audit).launch,\
- CDO AllTests (Hsqldb non-audit).launch,\
- CDO AllTests (Mysql).launch,\
- CDO AllTests (PostgreSQL non-audit).launch,\
- CDO AllTests (DBStore).launch
+# 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 + +bin.includes = .,\ + META-INF/,\ + plugin.properties,\ + copyright.txt,\ + about.html,\ + .options +jars.compile.order = . +source.. = src/ +output.. = bin/ +src.includes = about.html,\ + copyright.txt,\ + CDO AllTests (DB2 non-audit).launch,\ + CDO AllTests (Derby).launch,\ + CDO AllTests (H2 audit).launch,\ + CDO AllTests (H2 branching).launch,\ + CDO AllTests (H2 non-audit).launch,\ + CDO AllTests (H2 offline).launch,\ + CDO AllTests (Hsqldb audit).launch,\ + CDO AllTests (Hsqldb non-audit).launch,\ + CDO AllTests (Mysql).launch,\ + CDO AllTests (PostgreSQL non-audit).launch,\ + CDO AllTests (DBStore).launch,\ + CDO AllTests (H2 ALL).launch,\ + CDO AllTests (H2 UUIDs).launch,\ + CDO Performance Tests (H2 non-audit).launch diff --git a/plugins/org.eclipse.emf.cdo.tests.db4o/build.properties b/plugins/org.eclipse.emf.cdo.tests.db4o/build.properties index 5f4117fa8e..54175284a4 100644 --- a/plugins/org.eclipse.emf.cdo.tests.db4o/build.properties +++ b/plugins/org.eclipse.emf.cdo.tests.db4o/build.properties @@ -1,21 +1,22 @@ -# 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
-
-# NLS_MESSAGEFORMAT_VAR
-
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
- .,\
- copyright.txt,\
- about.html,\
- plugin.properties
-src.includes = about.html,\
- CDO AllTests (DB4O).launch,\
- copyright.txt
+# 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 + +# NLS_MESSAGEFORMAT_VAR + +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + copyright.txt,\ + about.html,\ + plugin.properties +src.includes = about.html,\ + CDO AllTests (DB4O).launch,\ + copyright.txt,\ + CDO AllTests (MEMDB4O).launch diff --git a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF index aaf6b433e7..c94d9103c0 100644 --- a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF @@ -33,7 +33,8 @@ Require-Bundle: org.eclipse.net4j.tests;bundle-version="[4.0.0,5.0.0)";visibilit org.eclipse.emf.cdo.defs;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.server.ocl;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, org.eclipse.emf.cdo.workspace;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, - org.eclipse.gmf.runtime.notation;bundle-version="[1.5.0,2.0.0)";visibility:=reexport + org.eclipse.gmf.runtime.notation;bundle-version="[1.5.0,2.0.0)";visibility:=reexport, + org.eclipse.ocl.ecore;bundle-version="[3.0.0,4.0.0)" Import-Package: org.apache.derby.jdbc;version="[10.0.0,11.0.0)", org.h2.jdbcx;version="[1.0.0,2.0.0)" Export-Package: base;version="4.0.100"; diff --git a/plugins/org.eclipse.emf.cdo.tests/build.properties b/plugins/org.eclipse.emf.cdo.tests/build.properties index ab8efcc53c..900c2988b8 100644 --- a/plugins/org.eclipse.emf.cdo.tests/build.properties +++ b/plugins/org.eclipse.emf.cdo.tests/build.properties @@ -1,49 +1,39 @@ -# 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
-
-bin.includes = .,\
- model/,\
- META-INF/,\
- plugin.xml,\
- plugin.properties,\
- copyright.txt,\
- about.html,\
- about.ini,\
- about.mappings,\
- about.properties,\
- defs/,\
- ecore/,\
- model1.ecore,\
- modeling32.png,\
- model2.ecore,\
- test.xml,\
- uml2/,\
- My.ecore,\
- .options,\
- sslKey/,\
- SubclassTest1.ecore,\
- SubclassTest2.ecore,\
- logic/
-jars.compile.order = .
-source.. = src/,\
- model/
-output.. = bin/
-src.includes = about.html,\
- copyright.txt,\
- launches/CDO AllTests (MEM audit).launch,\
- launches/CDO AllTests (MEM branching SSL).launch,\
- launches/CDO AllTests (MEM branching TCP).launch,\
- launches/CDO AllTests (MEM branching UUIDs).launch,\
- launches/CDO AllTests (MEM branching).launch,\
- launches/CDO AllTests (MEM embedded).launch,\
- launches/CDO AllTests (MEM legacy).launch,\
- launches/CDO AllTests (MEM non-audit).launch,\
- launches/CDO AllTests (MEM offline).launch,\
- launches/CDO AllTests.launch,\
- launches/CDO PerformanceTests.launch
+# 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 + +bin.includes = .,\ + model/,\ + META-INF/,\ + plugin.xml,\ + plugin.properties,\ + copyright.txt,\ + about.html,\ + about.ini,\ + about.mappings,\ + about.properties,\ + defs/,\ + ecore/,\ + model1.ecore,\ + modeling32.png,\ + model2.ecore,\ + test.xml,\ + uml2/,\ + My.ecore,\ + .options,\ + sslKey/,\ + SubclassTest1.ecore,\ + SubclassTest2.ecore,\ + logic/ +jars.compile.order = . +source.. = src/,\ + model/ +output.. = bin/ +src.includes = about.html,\ + copyright.txt,\ + launches/ 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..bc6f93ce26 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_343084_Test.java @@ -0,0 +1,240 @@ +/* + * 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.ConfigTest.CleanRepositoriesAfter; +import org.eclipse.emf.cdo.tests.config.impl.ModelConfig; +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 + */ +@CleanRepositoriesAfter +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 + } + } + + @Skips(ModelConfig.CAPABILITY_LEGACY) + 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/object/CDOLegacyWrapper.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java index cbb116fbf9..1d93cabcbd 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/object/CDOLegacyWrapper.java @@ -1,1140 +1,1158 @@ -/*
- * 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
- * Martin Fluegge - bug 247226: Transparently support legacy models
- */
-package org.eclipse.emf.internal.cdo.object;
-
-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.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.model.EMFUtil;
-import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
-import org.eclipse.emf.cdo.common.revision.CDOElementProxy;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionData;
-import org.eclipse.emf.cdo.common.util.CDOException;
-import org.eclipse.emf.cdo.eresource.CDOResource;
-import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.util.CDOUtil;
-
-import org.eclipse.emf.internal.cdo.CDOObjectImpl;
-import org.eclipse.emf.internal.cdo.bundle.OM;
-import org.eclipse.emf.internal.cdo.view.CDOStateMachine;
-
-import org.eclipse.net4j.util.ReflectUtil;
-import org.eclipse.net4j.util.WrappedException;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.common.notify.Adapter;
-import org.eclipse.emf.common.util.EList;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EAttribute;
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EClassifier;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.resource.Resource;
-import org.eclipse.emf.ecore.util.InternalEList;
-import org.eclipse.emf.spi.cdo.CDOStore;
-import org.eclipse.emf.spi.cdo.FSMUtil;
-import org.eclipse.emf.spi.cdo.InternalCDOObject;
-import org.eclipse.emf.spi.cdo.InternalCDOView;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * @author Eike Stepper
- * @author Martin Fluegge
- * @since 2.0
- */
-public abstract class CDOLegacyWrapper extends CDOObjectWrapper
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyWrapper.class);
-
- /**
- * This ThreadLocal map stores all pre-registered objects. This avoids a never-ending loop when setting the container
- * of an object.
- */
- private static ThreadLocal<Map<CDOID, CDOLegacyWrapper>> wrapperRegistry = new InheritableThreadLocal<Map<CDOID, CDOLegacyWrapper>>()
- {
- @Override
- protected Map<CDOID, CDOLegacyWrapper> initialValue()
- {
- return new HashMap<CDOID, CDOLegacyWrapper>();
- }
- };
-
- private static ThreadLocal<Counter> recursionCounter = new InheritableThreadLocal<Counter>()
- {
- @Override
- protected Counter initialValue()
- {
- return new Counter();
- }
- };
-
- protected CDOState state;
-
- protected InternalCDORevision revision;
-
- /**
- * It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method
- * will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another
- * <i>revisionToInstance()</i> call while the first call has not finished. This is certainly not so cool. That's why
- * <b>underConstruction</b> will flag that <i>revisionToInstance()</i> is still running and avoid the second call.
- *
- * @since 3.0
- */
- private boolean underConstruction;
-
- public CDOLegacyWrapper(InternalEObject instance)
- {
- this.instance = instance;
- state = CDOState.TRANSIENT;
- }
-
- public CDOState cdoState()
- {
- return state;
- }
-
- public InternalCDORevision cdoRevision()
- {
- return revision;
- }
-
- @Override
- public CDOResourceImpl cdoResource()
- {
- revisionToInstanceResource();
- return super.cdoResource();
- }
-
- public void cdoReload()
- {
- CDOStateMachine.INSTANCE.reload(this);
- }
-
- public CDOState cdoInternalSetState(CDOState state)
- {
- if (this.state != state)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting state {0} for {1}", state, this); //$NON-NLS-1$
- }
-
- CDOState oldState = this.state;
- this.state = state;
- adjustEProxy();
-
- if (view != null)
- {
- view.handleObjectStateChanged(this, oldState, state);
- }
-
- return oldState;
- }
-
- return null;
- }
-
- public void cdoInternalSetRevision(CDORevision revision)
- {
- if (TRACER.isEnabled())
- {
- TRACER.trace("Setting revision: " + revision); //$NON-NLS-1$
- }
-
- this.revision = (InternalCDORevision)revision;
- }
-
- public void cdoInternalPostAttach()
- {
- instanceToRevision();
-
- for (Adapter adapter : eAdapters())
- {
- if (!(adapter instanceof CDOObjectWrapper))
- {
- view.handleAddAdapter(this, adapter);
- view.subscribe(this, adapter);
- }
- }
- }
-
- public void cdoInternalPostDetach(boolean remote)
- {
- if (remote)
- {
- // Do nothing??
- return;
- }
-
- EClass eClass = revision.getEClass();
-
- // This loop adjusts the opposite wrapper objects to support dangling references. See Bugzilla_251263_Test
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass))
- {
- EReference oppositeReference = ((EStructuralFeature.Internal)feature).getEOpposite();
- if (oppositeReference != null && !oppositeReference.isContainment() && EMFUtil.isPersistent(oppositeReference))
- {
- if (feature.isMany())
- {
- int size = revision.size(feature);
- for (int i = 0; i < size; i++)
- {
- EObject object = (EObject)getValueFromRevision(feature, i);
- adjustPersistentOppositeReference(this, object, oppositeReference);
- }
- }
- else
- {
- EObject oppositeObject = (EObject)instance.eGet(feature);
- if (oppositeObject != null)
- {
- adjustPersistentOppositeReference(this, oppositeObject, oppositeReference);
- }
- }
- }
- }
- }
-
- /**
- * @since 3.0
- */
- public void cdoInternalPostRollback()
- {
- CDOStateMachine.INSTANCE.read(this);
- }
-
- /**
- * CDO persists the isUnset state of an eObject in the database. The indicator for this is that the feature is null in
- * the revision (see CDOStore.isSet()). When committing a legacy object all values in the instance for native
- * attributes are set with the java default values. So, these values will be stored in the revision and CDO cannot
- * distinguish whether the feature is set or not. This method must ensure that the value will be set to null if the
- * feature is not set.
- */
- public void cdoInternalPreCommit()
- {
- // We have to set this here because the CDOLegacyAdapter will not be notified when the instance is the target of a
- // single-directional containment reference.
- // If the container is not an legacy Object the system will get no information
- instanceToRevisionContainment();
-
- EClass eClass = revision.getEClass();
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass))
- {
- if (feature.isUnsettable())
- {
- if (!instance.eIsSet(feature))
- {
- if (feature.isMany())
- {
- @SuppressWarnings("unchecked")
- InternalEList<Object> list = (InternalEList<Object>)instance.eGet(feature);
- clearEList(list);
- }
- else
- {
- revision.set(feature, EStore.NO_INDEX, null);
- }
- }
- else if (instance.eGet(feature) == null)
- {
- // Must be single-valued!
- revision.set(feature, EStore.NO_INDEX, CDORevisionData.NIL);
- }
- }
- }
- }
-
- public void cdoInternalPreLoad()
- {
- // Do nothing
- }
-
- public void cdoInternalPostLoad()
- {
- // TODO Consider not remembering the revision after copying it to the instance (spare 1/2 of the space)
- revisionToInstance();
- }
-
- public void cdoInternalPostInvalidate()
- {
- if (cdoState() != CDOState.CLEAN)
- {
- InternalCDORevision revision = cdoView().getRevision(cdoID(), true);
- cdoInternalSetRevision(revision);
- }
-
- revisionToInstance();
- cdoInternalSetState(CDOState.CLEAN);
- }
-
- @Override
- public boolean equals(Object obj)
- {
- return obj == this || obj == instance;
- }
-
- @Override
- public int hashCode()
- {
- if (instance != null)
- {
- return instance.hashCode();
- }
-
- return super.hashCode();
- }
-
- @Override
- public String toString()
- {
- return "CDOLegacyWrapper[" + instance.getClass().getSimpleName() + "@" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- protected void instanceToRevision()
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Transfering instance to revision: {0} --> {1}", instance, revision); //$NON-NLS-1$
- }
-
- // Handle containment
- instanceToRevisionContainment();
-
- // Handle values
- CDOPackageRegistry packageRegistry = cdoView().getSession().getPackageRegistry();
- EClass eClass = revision.getEClass();
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass))
- {
- instanceToRevisionFeature(feature, packageRegistry);
- }
- }
-
- protected void instanceToRevisionContainment()
- {
- CDOResource resource = (CDOResource)getInstanceResource(instance);
- revision.setResourceID(resource == null ? CDOID.NULL : resource.cdoID());
-
- InternalEObject eContainer = getInstanceContainer(instance);
- if (eContainer == null)
- {
- revision.setContainerID(CDOID.NULL);
- revision.setContainingFeatureID(0);
- }
- else
- {
- CDOObject cdoContainer = FSMUtil.adapt(eContainer, view);
- revision.setContainerID(cdoContainer);
- revision.setContainingFeatureID(getInstanceContainerFeatureID(instance));
- }
- }
-
- protected void instanceToRevisionFeature(EStructuralFeature feature, CDOPackageRegistry packageRegistry)
- {
- Object instanceValue = getInstanceValue(instance, feature, packageRegistry);
- CDOObjectImpl.instanceToRevisionFeature(view, this, feature, instanceValue);
- }
-
- protected void revisionToInstance()
- {
- if (underConstruction)
- {
- // Return if revisionToInstance was called before to avoid doubled calls
- return;
- }
-
- underConstruction = true;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Transfering revision to instance: {0} --> {1}", revision, instance); //$NON-NLS-1$
- }
-
- boolean deliver = instance.eDeliver();
- if (deliver)
- {
- instance.eSetDeliver(false);
- }
-
- Counter counter = recursionCounter.get();
- try
- {
- registerWrapper(this);
- counter.increment();
- view.registerObject(this);
-
- revisionToInstanceContainer();
-
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(revision.getEClass()))
- {
- revisionToInstanceFeature(feature);
- }
-
- revisionToInstanceResource();
- }
- catch (RuntimeException ex)
- {
- OM.LOG.error(ex);
- throw ex;
- }
- catch (Exception ex)
- {
- OM.LOG.error(ex);
- throw new CDOException(ex);
- }
- finally
- {
- if (deliver)
- {
- instance.eSetDeliver(true);
- }
-
- counter.decrement();
- unregisterWrapper(this);
- underConstruction = false;
- }
- }
-
- /**
- * @since 4.0
- */
- protected void revisionToInstanceContainer()
- {
- Object containerID = revision.getContainerID();
- InternalEObject container = getEObjectFromPotentialID(view, null, containerID);
-
- EObject oldContainer = instance.eContainer();
- if (oldContainer != container)
- {
- setInstanceContainer(container, revision.getContainingFeatureID());
- }
- }
-
- /**
- * @since 4.0
- */
- protected void revisionToInstanceResource()
- {
- if (revision != null)
- {
- CDOID resourceID = revision.getResourceID();
- InternalEObject resource = getEObjectFromPotentialID(view, null, resourceID);
- setInstanceResource((Resource.Internal)resource);
- if (resource != null)
- {
- view.registerObject((InternalCDOObject)resource);
- }
- }
- }
-
- /**
- * @since 3.0
- */
- protected void revisionToInstanceFeature(EStructuralFeature feature)
- {
- if (feature.isUnsettable() && !view.getStore().isSet(this, feature))
- {
- // Clarify if this is sufficient for bidirectional references
- instance.eUnset(feature);
- return;
- }
-
- if (feature.isMany())
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("State of Object (" + this + "/" + instance + ") is : " + state); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- if (state == CDOState.CLEAN || state == CDOState.PROXY || state == CDOState.NEW || state == CDOState.DIRTY)
- {
- int size = revision.size(feature);
-
- @SuppressWarnings("unchecked")
- InternalEList<Object> list = (InternalEList<Object>)instance.eGet(feature);
-
- clearEList(list);
- for (int i = 0; i < size; i++)
- {
- Object object = getValueFromRevision(feature, i);
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Adding " + object + " to feature " + feature + "in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- list.basicAdd(object, null);
- }
- }
- }
- else
- {
- // !feature.isMany()
- Object object = getValueFromRevision(feature, 0);
- if (feature instanceof EAttribute)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting attribute value " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- // Just fake it for the store :(
- if (feature.isUnsettable() && object.equals(CDORevisionData.NIL))
- {
- eSet(feature, null);
- }
- else
- {
- eSet(feature, object);
- }
- }
- else
- {
- // EReferences
- if (TRACER.isEnabled())
- {
- TRACER.format("Adding object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
-
- int featureID = instance.eClass().getFeatureID(feature);
- Class<? extends Object> baseClass = object == null ? null : object.getClass();
- EStructuralFeature.Internal internalFeature = (EStructuralFeature.Internal)feature;
- EReference oppositeReference = internalFeature.getEOpposite();
-
- if (oppositeReference != null)
- {
- if (object != null)
- {
- // If you have a containment reference but the container is not set, but the object is attached to a
- // resource
- // do not set the feature to null. Otherwise the object will be removed from the container which is the
- // resource instead of the original container. As a result the object will be detached. See
- // MapTest.testEObjectToEObjectValueContainedMap for more information
- if (object != instance.eContainer())
- {
- instance.eInverseAdd((InternalEObject)object, featureID, baseClass, null);
- }
-
- if (!EMFUtil.isPersistent(oppositeReference))
- {
- adjustTransientOppositeReference(instance, (InternalEObject)object, oppositeReference);
- }
- }
- }
- else
- {
- if (object != CDORevisionData.NIL)
- {
- EReference reference = (EReference)feature;
- if (reference.isContainment())
- {
- if (object != null)
- {
- // Calling eSet it not the optimal approach, but currently there is no other way to set the value here.
- // To avoid attaching already processed (clean) objects a check was introduced to
- // CDOResourceImpl.attached(EObject).
- // If we find a way to avoid the call of eSet and if we are able to only set the feature value directly
- // this check can be removed from CDOResourceImpl. See also Bug 352204.
- instance.eSet(feature, object);
- }
- else
- {
- instance.eSet(feature, null);
- }
- }
- else
- {
- instance.eSet(feature, object);
- }
- }
- else
- {
- instance.eSet(feature, null);
- }
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Added object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
- }
- }
- }
- }
-
- /**
- * This method retrieves the value from the feature at the given index. It retrieves the value either from the views's
- * store or the internal pre-registration Map.
- *
- * @param feature
- * the feature to retrieve the value from
- * @param index
- * the given index of the object in the feature
- * @return the value from the feature at the given index
- */
- private Object getValueFromRevision(EStructuralFeature feature, int index)
- {
- Object object = revision.get(feature, index);
- if (object == null)
- {
- return null;
- }
-
- if (object instanceof CDOElementProxy)
- {
- // Resolve proxy
- CDOElementProxy proxy = (CDOElementProxy)object;
- object = view.getSession().resolveElementProxy(revision, feature, index, proxy.getIndex());
- }
-
- if (object instanceof CDOLegacyWrapper)
- {
- return ((CDOLegacyWrapper)object).cdoInternalInstance();
- }
-
- CDOType type = CDOModelUtil.getType(feature.getEType());
- object = view.getStore().convertToEMF(instance, revision, feature, index, object);
-
- if (type == CDOType.OBJECT)
- {
- if (object instanceof CDOID)
- {
- CDOID id = (CDOID)object;
- if (id.isNull())
- {
- return null;
- }
-
- object = getRegisteredWrapper(id);
- if (object != null)
- {
- return ((CDOLegacyWrapper)object).cdoInternalInstance();
- }
-
- if (id.isExternal())
- {
- object = view.getResourceSet().getEObject(URI.createURI(id.toURIFragment()), true);
- }
- else
- {
- object = view.getObject(id);
- }
-
- if (object instanceof CDOObjectWrapper)
- {
- return ((CDOObjectWrapper)object).cdoInternalInstance();
- }
- }
- }
-
- return object;
- }
-
- protected Resource.Internal getInstanceResource(InternalEObject instance)
- {
- return instance.eDirectResource();
- }
-
- protected InternalEObject getInstanceContainer(InternalEObject instance)
- {
- return instance.eInternalContainer();
- }
-
- protected int getInstanceContainerFeatureID(InternalEObject instance)
- {
- return instance.eContainerFeatureID();
- }
-
- protected Object getInstanceValue(InternalEObject instance, EStructuralFeature feature,
- CDOPackageRegistry packageRegistry)
- {
- return instance.eGet(feature);
- }
-
- protected void setInstanceResource(Resource.Internal resource)
- {
- Method method = ReflectUtil.getMethod(instance.getClass(), "eSetDirectResource", Resource.Internal.class); //$NON-NLS-1$
- ReflectUtil.invokeMethod(method, instance, resource);
- }
-
- protected void setInstanceContainer(InternalEObject container, int containerFeatureID)
- {
- Method method = ReflectUtil.getMethod(instance.getClass(), "eBasicSetContainer", InternalEObject.class, int.class); //$NON-NLS-1$
- ReflectUtil.invokeMethod(method, instance, container, containerFeatureID);
- }
-
- protected void setInstanceValue(InternalEObject instance, EStructuralFeature feature, Object value)
- {
- instance.eSet(feature, value);
- }
-
- /**
- * @param feature
- * in case that a proxy has to be created the feature that will determine the interface type of the proxy and
- * that will be used later to resolve the proxy. <code>null</code> indicates that proxy creation will be
- * avoided!
- */
- protected InternalEObject getEObjectFromPotentialID(InternalCDOView view, EStructuralFeature feature,
- Object potentialID)
- {
- CDOLegacyWrapper wrapper;
- if (potentialID instanceof CDOID && (wrapper = getRegisteredWrapper((CDOID)potentialID)) != null)
- {
- potentialID = wrapper.instance;
-
- if (TRACER.isEnabled())
- {
- TRACER.format("Getting Object (" + potentialID + ") from localThread instead of the view"); //$NON-NLS-1$ //$NON-NLS-2$
- }
- }
- else
- {
- if (potentialID instanceof CDOID)
- {
- CDOID id = (CDOID)potentialID;
- if (id.isNull())
- {
- return null;
- }
-
- if (id.isExternal())
- {
- URI uri = URI.createURI(id.toURIFragment());
- InternalEObject eObject = (InternalEObject)view.getResourceSet().getEObject(uri, true);
- return eObject;
- }
-
- boolean loadOnDemand = feature == null;
- potentialID = view.getObject(id, loadOnDemand);
- if (potentialID == null && !loadOnDemand)
- {
- return createProxy(view, feature, id);
- }
- }
-
- if (potentialID instanceof InternalCDOObject)
- {
- return ((InternalCDOObject)potentialID).cdoInternalInstance();
- }
- }
-
- return (InternalEObject)potentialID;
- }
-
- /**
- * Creates and returns a <em>proxy</em> object. The usage of a proxy object is strongly limited. The only guarantee
- * that can be made is that the following methods are callable and will behave in the expected way:
- * <ul>
- * <li>{@link CDOObject#cdoID()} will return the {@link CDOID} of the target object
- * <li>{@link CDOObject#cdoState()} will return {@link CDOState#PROXY PROXY}
- * <li>{@link InternalEObject#eIsProxy()} will return <code>true</code>
- * <li>{@link InternalEObject#eProxyURI()} will return the EMF proxy URI of the target object
- * </ul>
- * Calling any other method on the proxy object will result in an {@link UnsupportedOperationException} being thrown
- * at runtime. Note also that the proxy object might even not be cast to the concrete type of the target object. The
- * proxy can only guaranteed to be of <em>any</em> concrete subtype of the declared type of the given feature.
- * <p>
- * TODO {@link InternalEObject#eResolveProxy(InternalEObject)}
- */
- protected InternalEObject createProxy(InternalCDOView view, EStructuralFeature feature, CDOID id)
- {
- EClassifier eType = feature.getEType();
- Class<?> instanceClass = eType.getInstanceClass();
-
- Class<?>[] interfaces = { instanceClass, InternalEObject.class, LegacyProxy.class };
- ClassLoader classLoader = CDOLegacyWrapper.class.getClassLoader();
- LegacyProxyInvocationHandler handler = new LegacyProxyInvocationHandler(this, id);
- return (InternalEObject)Proxy.newProxyInstance(classLoader, interfaces, handler);
- }
-
- protected void clearEList(InternalEList<?> list)
- {
- for (int i = list.size() - 1; i >= 0; --i)
- {
- Object obj = list.get(i);
- list.basicRemove(obj, null);
- }
- }
-
- /**
- * TODO Consider using only EMF concepts for resolving proxies!
- */
- protected void resolveAllProxies()
- {
- CDOPackageRegistry packageRegistry = cdoView().getSession().getPackageRegistry();
- EClass eClass = revision.getEClass();
- for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass))
- {
- if (feature instanceof EReference)
- {
- resolveProxies(feature, packageRegistry);
- }
- }
- }
-
- /**
- * IMPORTANT: Compile errors in this method might indicate an old version of EMF. Legacy support is only enabled for
- * EMF with fixed bug #247130. These compile errors do not affect native models!
- */
- protected void resolveProxies(EStructuralFeature feature, CDOPackageRegistry packageRegistry)
- {
- Object value = getInstanceValue(instance, feature, packageRegistry);
- if (value != null)
- {
- if (feature.isMany())
- {
- @SuppressWarnings("unchecked")
- InternalEList<Object> list = (InternalEList<Object>)value;
- int size = list.size();
-
- boolean deliver = instance.eDeliver();
- if (deliver)
- {
- instance.eSetDeliver(false);
- }
-
- for (int i = 0; i < size; i++)
- {
- Object element = list.get(i);
- if (element instanceof LegacyProxy)
- {
- CDOID id = ((LegacyProxy)element).getID();
- InternalCDOObject resolved = (InternalCDOObject)view.getObject(id);
- InternalEObject instance = resolved.cdoInternalInstance();
-
- // TODO LEGACY
- // // TODO Is InternalEList.basicSet() needed???
- // if (list instanceof
- // org.eclipse.emf.ecore.util.DelegatingInternalEList)
- // {
- // list =
- // ((org.eclipse.emf.ecore.util.DelegatingInternalEList)list).getDelegateInternalEList();
- // }
-
- // if (list instanceof NotifyingListImpl<?>)
- // {
- // ((NotifyingListImpl<Object>)list).basicSet(i, instance, null);
- // }
- // else
- // {
- list.set(i, instance);
- // }
- }
- }
-
- if (deliver)
- {
- instance.eSetDeliver(true);
- }
- }
- else
- {
- if (value instanceof LegacyProxy)
- {
- CDOID id = ((LegacyProxy)value).getID();
- InternalCDOObject resolved = (InternalCDOObject)view.getObject(id);
- InternalEObject instance = resolved.cdoInternalInstance();
- setInstanceValue(instance, feature, instance);
- }
- }
- }
- }
-
- protected void adjustEProxy()
- {
- // Setting eProxyURI is necessary to prevent content adapters from
- // loading the whole content tree.
- // TODO Does not have the desired effect ;-( see CDOEditor.createModel()
- if (state == CDOState.PROXY)
- {
- if (!instance.eIsProxy())
- {
- URI uri = URI.createURI(CDOProtocolConstants.PROTOCOL_NAME + ":proxy#" + id); //$NON-NLS-1$
- if (TRACER.isEnabled())
- {
- TRACER.format("Setting proxyURI {0} for {1}", uri, instance); //$NON-NLS-1$
- }
-
- instance.eSetProxyURI(uri);
- }
- }
- else
- {
- if (instance.eIsProxy())
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Unsetting proxyURI for {0}", instance); //$NON-NLS-1$
- }
-
- instance.eSetProxyURI(null);
- }
- }
- }
-
- @Override
- public synchronized EList<Adapter> eAdapters()
- {
- EList<Adapter> adapters = instance.eAdapters();
- for (Adapter adapter : adapters)
- {
- if (!FSMUtil.isTransient(this) && !(adapter instanceof CDOLegacyWrapper))
- {
- cdoView().handleAddAdapter(this, adapter);
- }
- }
-
- return adapters;
- }
-
- public static boolean isLegacyProxy(Object object)
- {
- return object instanceof LegacyProxy;
- }
-
- protected static int getEFlagMask(Class<?> instanceClass, String flagName)
- {
- Field field = ReflectUtil.getField(instanceClass, flagName);
- if (!field.isAccessible())
- {
- field.setAccessible(true);
- }
-
- try
- {
- return (Integer)field.get(null);
- }
- catch (IllegalAccessException ex)
- {
- throw WrappedException.wrap(ex);
- }
- }
-
- /**
- * @since 3.0
- */
- protected static CDOLegacyWrapper getRegisteredWrapper(CDOID id)
- {
- return wrapperRegistry.get().get(id);
- }
-
- /**
- * Adds an object to the pre-registered objects list which hold all created objects even if they are not registered in
- * the view
- *
- * @since 3.0
- */
- protected static void registerWrapper(CDOLegacyWrapper wrapper)
- {
- wrapperRegistry.get().put(wrapper.cdoID(), wrapper);
- }
-
- /**
- * @since 3.0
- */
- protected static void unregisterWrapper(CDOLegacyWrapper wrapper)
- {
- wrapperRegistry.get().remove(wrapper.cdoID());
- }
-
- /**
- * @since 3.0
- */
- protected static boolean isRegisteredWrapper(CDOLegacyWrapper wrapper)
- {
- return wrapperRegistry.get().containsKey(wrapper.cdoID());
- }
-
- // TODO: Remove this method if it is ensured that ist is not needed anymore
- // private void adjustOppositeReference(InternalCDOObject cdoObject, EObject oppositeObject, EReference
- // oppositeReference)
- // {
- // if (oppositeObject != null)
- // {
- // InternalCDOObject oppositeCDOObject = (InternalCDOObject)CDOUtil.getCDOObject(oppositeObject);
- //
- // if (!FSMUtil.isTransient(oppositeCDOObject) && !EMFUtil.isPersistent(oppositeReference))
- // {
- // adjustPersistentOppositeReference(cdoObject, oppositeObject, oppositeReference);
- // }
- // else
- // {
- // if (oppositeReference.isResolveProxies())
- // {
- // adjustTransientOppositeReference(instance, (InternalEObject)oppositeObject, oppositeReference);
- // }
- // }
- // }
- // }
-
- private void adjustPersistentOppositeReference(InternalCDOObject cdoObject, EObject oppositeObject,
- EReference oppositeReference)
- {
- InternalCDOObject oppositeCDOObject = (InternalCDOObject)CDOUtil.getCDOObject(oppositeObject);
- if (oppositeCDOObject != null)
- {
- InternalCDOView view = oppositeCDOObject.cdoView();
- if (view != null)
- {
- CDOStore store = view.getStore();
- if (store != null)
- {
- if (oppositeReference.isMany())
- {
- EObject eObject = oppositeCDOObject.cdoInternalInstance();
-
- @SuppressWarnings("unchecked")
- EList<Object> list = (EList<Object>)eObject.eGet(oppositeReference);
- int index = list.indexOf(instance);
-
- if (!store.isEmpty(oppositeCDOObject, oppositeReference) && index != EStore.NO_INDEX)
- {
- store.set(oppositeCDOObject, oppositeReference, index, cdoObject);
- }
- }
- else
- {
- store.set(oppositeCDOObject, oppositeReference, 0, cdoObject);
- }
- }
- }
- }
- }
-
- private void adjustTransientOppositeReference(InternalEObject instance, InternalEObject object,
- EReference oppositeReference)
- {
- boolean wasDeliver = object.eDeliver(); // Disable notifications
- if (wasDeliver)
- {
- object.eSetDeliver(false);
- }
-
- try
- {
- if (oppositeReference.isMany())
- {
- @SuppressWarnings("unchecked")
- InternalEList<Object> list = (InternalEList<Object>)object.eGet(oppositeReference);
- list.basicAdd(instance, null);
- }
- else
- {
- if (object.eGet(oppositeReference) != instance)
- {
- object.eInverseAdd(instance, oppositeReference.getFeatureID(), ((EObject)instance).getClass(), null);
- }
- }
- }
- finally
- {
- if (wasDeliver)
- {
- object.eSetDeliver(true);
- }
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private static interface LegacyProxy
- {
- public CDOID getID();
- }
-
- /**
- * @author Eike Stepper
- */
- private static final class LegacyProxyInvocationHandler implements InvocationHandler, LegacyProxy
- {
- private static final Method getIDMethod = ReflectUtil.getMethod(LegacyProxy.class, "getID"); //$NON-NLS-1$
-
- private static final Method eIsProxyMethod = ReflectUtil.getMethod(EObject.class, "eIsProxy"); //$NON-NLS-1$
-
- private static final Method eProxyURIMethod = ReflectUtil.getMethod(InternalEObject.class, "eProxyURI"); //$NON-NLS-1$
-
- private CDOLegacyWrapper wrapper;
-
- private CDOID id;
-
- public LegacyProxyInvocationHandler(CDOLegacyWrapper wrapper, CDOID id)
- {
- this.wrapper = wrapper;
- this.id = id;
- }
-
- public CDOID getID()
- {
- return id;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- {
- if (method.equals(getIDMethod))
- {
- return id;
- }
-
- if (method.equals(eIsProxyMethod))
- {
- return true;
- }
-
- if (method.equals(eProxyURIMethod))
- {
- // Use container's resource because it's guaranteed to be in the same CDOView as the resource of the target!
- Resource resource = wrapper.eResource();
-
- // TODO Consider using a "fake" Resource implementation. See Resource.getEObject(...)
- return resource.getURI().appendFragment(id.toURIFragment());
- }
-
- // A client must have invoked the proxy while being told not to do so!
- throw new UnsupportedOperationException(method.getName());
- }
- }
-
- /**
- * @author Martin Fluegge
- */
- private static final class Counter
- {
- private int value;
-
- public Counter()
- {
- }
-
- public void increment()
- {
- ++value;
- }
-
- public int decrement()
- {
- return --value;
- }
- }
-}
+/* + * 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 + * Martin Fluegge - bug 247226: Transparently support legacy models + */ +package org.eclipse.emf.internal.cdo.object; + +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.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants; +import org.eclipse.emf.cdo.common.revision.CDOElementProxy; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionData; +import org.eclipse.emf.cdo.common.security.CDOPermission; +import org.eclipse.emf.cdo.common.util.CDOException; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.util.CDOUtil; + +import org.eclipse.emf.internal.cdo.CDOObjectImpl; +import org.eclipse.emf.internal.cdo.bundle.OM; +import org.eclipse.emf.internal.cdo.view.CDOStateMachine; + +import org.eclipse.net4j.util.ReflectUtil; +import org.eclipse.net4j.util.WrappedException; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.common.notify.Adapter; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.InternalEList; +import org.eclipse.emf.spi.cdo.CDOStore; +import org.eclipse.emf.spi.cdo.FSMUtil; +import org.eclipse.emf.spi.cdo.InternalCDOObject; +import org.eclipse.emf.spi.cdo.InternalCDOView; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Eike Stepper + * @author Martin Fluegge + * @since 2.0 + */ +public abstract class CDOLegacyWrapper extends CDOObjectWrapper +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOLegacyWrapper.class); + + /** + * This ThreadLocal map stores all pre-registered objects. This avoids a never-ending loop when setting the container + * of an object. + */ + private static ThreadLocal<Map<CDOID, CDOLegacyWrapper>> wrapperRegistry = new InheritableThreadLocal<Map<CDOID, CDOLegacyWrapper>>() + { + @Override + protected Map<CDOID, CDOLegacyWrapper> initialValue() + { + return new HashMap<CDOID, CDOLegacyWrapper>(); + } + }; + + private static ThreadLocal<Counter> recursionCounter = new InheritableThreadLocal<Counter>() + { + @Override + protected Counter initialValue() + { + return new Counter(); + } + }; + + protected CDOState state; + + protected InternalCDORevision revision; + + /** + * It could happen that while <i>revisionToInstance()</i> is executed externally the <i>internalPostLoad()</i> method + * will be called. This happens for example if <i>internalPostInvalidate()</i> is called. The leads to another + * <i>revisionToInstance()</i> call while the first call has not finished. This is certainly not so cool. That's why + * <b>underConstruction</b> will flag that <i>revisionToInstance()</i> is still running and avoid the second call. + * + * @since 3.0 + */ + private boolean underConstruction; + + public CDOLegacyWrapper(InternalEObject instance) + { + this.instance = instance; + state = CDOState.TRANSIENT; + } + + public CDOState cdoState() + { + return state; + } + + public InternalCDORevision cdoRevision() + { + return revision; + } + + @Override + public CDOResourceImpl cdoResource() + { + revisionToInstanceResource(); + return super.cdoResource(); + } + + public void cdoReload() + { + CDOStateMachine.INSTANCE.reload(this); + } + + public CDOState cdoInternalSetState(CDOState state) + { + if (this.state != state) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting state {0} for {1}", state, this); //$NON-NLS-1$ + } + + CDOState oldState = this.state; + this.state = state; + adjustEProxy(); + + if (view != null) + { + view.handleObjectStateChanged(this, oldState, state); + } + + return oldState; + } + + return null; + } + + public void cdoInternalSetRevision(CDORevision revision) + { + if (TRACER.isEnabled()) + { + TRACER.trace("Setting revision: " + revision); //$NON-NLS-1$ + } + + this.revision = (InternalCDORevision)revision; + } + + public void cdoInternalPostAttach() + { + instanceToRevision(); + + for (Adapter adapter : eAdapters()) + { + if (!(adapter instanceof CDOObjectWrapper)) + { + view.handleAddAdapter(this, adapter); + view.subscribe(this, adapter); + } + } + } + + public void cdoInternalPostDetach(boolean remote) + { + if (remote) + { + // Do nothing?? + return; + } + + EClass eClass = revision.getEClass(); + + // This loop adjusts the opposite wrapper objects to support dangling references. See Bugzilla_251263_Test + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) + { + EReference oppositeReference = ((EStructuralFeature.Internal)feature).getEOpposite(); + if (oppositeReference != null && !oppositeReference.isContainment() && EMFUtil.isPersistent(oppositeReference)) + { + if (feature.isMany()) + { + int size = revision.size(feature); + for (int i = 0; i < size; i++) + { + EObject object = (EObject)getValueFromRevision(feature, i); + adjustPersistentOppositeReference(this, object, oppositeReference); + } + } + else + { + EObject oppositeObject = (EObject)instance.eGet(feature); + if (oppositeObject != null) + { + adjustPersistentOppositeReference(this, oppositeObject, oppositeReference); + } + } + } + } + } + + /** + * @since 3.0 + */ + public void cdoInternalPostRollback() + { + CDOStateMachine.INSTANCE.read(this); + } + + /** + * CDO persists the isUnset state of an eObject in the database. The indicator for this is that the feature is null in + * the revision (see CDOStore.isSet()). When committing a legacy object all values in the instance for native + * attributes are set with the java default values. So, these values will be stored in the revision and CDO cannot + * distinguish whether the feature is set or not. This method must ensure that the value will be set to null if the + * feature is not set. + */ + public void cdoInternalPreCommit() + { + // We have to set this here because the CDOLegacyAdapter will not be notified when the instance is the target of a + // single-directional containment reference. + // If the container is not an legacy Object the system will get no information + instanceToRevisionContainment(); + + EClass eClass = revision.getEClass(); + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) + { + if (feature.isUnsettable()) + { + if (!instance.eIsSet(feature)) + { + if (feature.isMany()) + { + @SuppressWarnings("unchecked") + InternalEList<Object> list = (InternalEList<Object>)instance.eGet(feature); + clearEList(list); + } + else + { + revision.set(feature, EStore.NO_INDEX, null); + } + } + else if (instance.eGet(feature) == null) + { + // Must be single-valued! + revision.set(feature, EStore.NO_INDEX, CDORevisionData.NIL); + } + } + } + } + + public void cdoInternalPreLoad() + { + // Do nothing + } + + public void cdoInternalPostLoad() + { + // TODO Consider not remembering the revision after copying it to the instance (spare 1/2 of the space) + revisionToInstance(); + } + + public void cdoInternalPostInvalidate() + { + if (cdoState() != CDOState.CLEAN) + { + InternalCDORevision revision = cdoView().getRevision(cdoID(), true); + cdoInternalSetRevision(revision); + } + + revisionToInstance(); + cdoInternalSetState(CDOState.CLEAN); + } + + @Override + public boolean equals(Object obj) + { + return obj == this || obj == instance; + } + + @Override + public int hashCode() + { + if (instance != null) + { + return instance.hashCode(); + } + + return super.hashCode(); + } + + @Override + public String toString() + { + return "CDOLegacyWrapper[" + instance.getClass().getSimpleName() + "@" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + protected void instanceToRevision() + { + if (TRACER.isEnabled()) + { + TRACER.format("Transfering instance to revision: {0} --> {1}", instance, revision); //$NON-NLS-1$ + } + + // Handle containment + instanceToRevisionContainment(); + + // Handle values + CDOPackageRegistry packageRegistry = cdoView().getSession().getPackageRegistry(); + EClass eClass = revision.getEClass(); + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) + { + instanceToRevisionFeature(feature, packageRegistry); + } + } + + protected void instanceToRevisionContainment() + { + CDOResource resource = (CDOResource)getInstanceResource(instance); + revision.setResourceID(resource == null ? CDOID.NULL : resource.cdoID()); + + InternalEObject eContainer = getInstanceContainer(instance); + if (eContainer == null) + { + revision.setContainerID(CDOID.NULL); + revision.setContainingFeatureID(0); + } + else + { + CDOObject cdoContainer = FSMUtil.adapt(eContainer, view); + revision.setContainerID(cdoContainer); + revision.setContainingFeatureID(getInstanceContainerFeatureID(instance)); + } + } + + protected void instanceToRevisionFeature(EStructuralFeature feature, CDOPackageRegistry packageRegistry) + { + Object instanceValue = getInstanceValue(instance, feature, packageRegistry); + CDOObjectImpl.instanceToRevisionFeature(view, this, feature, instanceValue); + } + + protected void revisionToInstance() + { + + if (underConstruction) + { + // Return if revisionToInstance was called before to avoid doubled calls + return; + } + + underConstruction = true; + + if (TRACER.isEnabled()) + { + TRACER.format("Transfering revision to instance: {0} --> {1}", revision, instance); //$NON-NLS-1$ + } + + boolean deliver = instance.eDeliver(); + if (deliver) + { + instance.eSetDeliver(false); + } + + Counter counter = recursionCounter.get(); + + try + { + registerWrapper(this); + counter.increment(); + view.registerObject(this); + + revisionToInstanceContainer(); + + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(revision.getEClass())) + { + revisionToInstanceFeature(feature); + } + + revisionToInstanceResource(); + } + catch (RuntimeException ex) + { + OM.LOG.error(ex); + throw ex; + } + catch (Exception ex) + { + OM.LOG.error(ex); + throw new CDOException(ex); + } + finally + { + if (deliver) + { + instance.eSetDeliver(true); + } + + counter.decrement(); + unregisterWrapper(this); + underConstruction = false; + } + } + + /** + * @since 4.0 + */ + protected void revisionToInstanceContainer() + { + CDOPermission permission = revision.getPermission(); + if (permission != CDOPermission.WRITE) + { + revision.setPermission(CDOPermission.WRITE); + } + + try + { + Object containerID = revision.getContainerID(); + InternalEObject container = getEObjectFromPotentialID(view, null, containerID); + EObject oldContainer = instance.eContainer(); + if (oldContainer != container) + { + setInstanceContainer(container, revision.getContainingFeatureID()); + } + } + finally + { + if (permission != CDOPermission.WRITE) + { + revision.setPermission(permission); + } + } + } + + /** + * @since 4.0 + */ + protected void revisionToInstanceResource() + { + if (revision != null) + { + CDOID resourceID = revision.getResourceID(); + InternalEObject resource = getEObjectFromPotentialID(view, null, resourceID); + setInstanceResource((Resource.Internal)resource); + if (resource != null) + { + view.registerObject((InternalCDOObject)resource); + } + } + } + + /** + * @since 3.0 + */ + protected void revisionToInstanceFeature(EStructuralFeature feature) + { + if (feature.isUnsettable() && !view.getStore().isSet(this, feature)) + { + // Clarify if this is sufficient for bidirectional references + instance.eUnset(feature); + return; + } + + if (feature.isMany()) + { + if (TRACER.isEnabled()) + { + TRACER.format("State of Object (" + this + "/" + instance + ") is : " + state); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + if (state == CDOState.CLEAN || state == CDOState.PROXY || state == CDOState.NEW || state == CDOState.DIRTY) + { + int size = revision.size(feature); + + @SuppressWarnings("unchecked") + InternalEList<Object> list = (InternalEList<Object>)instance.eGet(feature); + + clearEList(list); + for (int i = 0; i < size; i++) + { + Object object = getValueFromRevision(feature, i); + + if (TRACER.isEnabled()) + { + TRACER.format("Adding " + object + " to feature " + feature + "in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + list.basicAdd(object, null); + } + } + } + else + { + // !feature.isMany() + Object object = getValueFromRevision(feature, 0); + if (feature instanceof EAttribute) + { + if (TRACER.isEnabled()) + { + TRACER.format("Setting attribute value " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + // Just fake it for the store :( + if (feature.isUnsettable() && object.equals(CDORevisionData.NIL)) + { + eSet(feature, null); + } + else + { + eSet(feature, object); + } + } + else + { + // EReferences + if (TRACER.isEnabled()) + { + TRACER.format("Adding object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + int featureID = instance.eClass().getFeatureID(feature); + Class<? extends Object> baseClass = object == null ? null : object.getClass(); + EStructuralFeature.Internal internalFeature = (EStructuralFeature.Internal)feature; + EReference oppositeReference = internalFeature.getEOpposite(); + + if (oppositeReference != null) + { + if (object != null) + { + // If you have a containment reference but the container is not set, but the object is attached to a + // resource + // do not set the feature to null. Otherwise the object will be removed from the container which is the + // resource instead of the original container. As a result the object will be detached. See + // MapTest.testEObjectToEObjectValueContainedMap for more information + if (object != instance.eContainer()) + { + instance.eInverseAdd((InternalEObject)object, featureID, baseClass, null); + } + + if (!EMFUtil.isPersistent(oppositeReference)) + { + adjustTransientOppositeReference(instance, (InternalEObject)object, oppositeReference); + } + } + } + else + { + if (object != CDORevisionData.NIL) + { + EReference reference = (EReference)feature; + if (reference.isContainment()) + { + if (object != null) + { + // Calling eSet it not the optimal approach, but currently there is no other way to set the value here. + // To avoid attaching already processed (clean) objects a check was introduced to + // CDOResourceImpl.attached(EObject). + // If we find a way to avoid the call of eSet and if we are able to only set the feature value directly + // this check can be removed from CDOResourceImpl. See also Bug 352204. + instance.eSet(feature, object); + } + else + { + instance.eSet(feature, null); + } + } + else + { + instance.eSet(feature, object); + } + } + else + { + instance.eSet(feature, null); + } + } + + if (TRACER.isEnabled()) + { + TRACER.format("Added object " + object + " to feature " + feature + " in instance " + instance); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + } + } + } + + /** + * This method retrieves the value from the feature at the given index. It retrieves the value either from the views's + * store or the internal pre-registration Map. + * + * @param feature + * the feature to retrieve the value from + * @param index + * the given index of the object in the feature + * @return the value from the feature at the given index + */ + private Object getValueFromRevision(EStructuralFeature feature, int index) + { + Object object = revision.get(feature, index); + if (object == null) + { + return null; + } + + if (object instanceof CDOElementProxy) + { + // Resolve proxy + CDOElementProxy proxy = (CDOElementProxy)object; + object = view.getSession().resolveElementProxy(revision, feature, index, proxy.getIndex()); + } + + if (object instanceof CDOLegacyWrapper) + { + return ((CDOLegacyWrapper)object).cdoInternalInstance(); + } + + CDOType type = CDOModelUtil.getType(feature.getEType()); + object = view.getStore().convertToEMF(instance, revision, feature, index, object); + + if (type == CDOType.OBJECT) + { + if (object instanceof CDOID) + { + CDOID id = (CDOID)object; + if (id.isNull()) + { + return null; + } + + object = getRegisteredWrapper(id); + if (object != null) + { + return ((CDOLegacyWrapper)object).cdoInternalInstance(); + } + + if (id.isExternal()) + { + object = view.getResourceSet().getEObject(URI.createURI(id.toURIFragment()), true); + } + else + { + object = view.getObject(id); + } + + if (object instanceof CDOObjectWrapper) + { + return ((CDOObjectWrapper)object).cdoInternalInstance(); + } + } + } + + return object; + } + + protected Resource.Internal getInstanceResource(InternalEObject instance) + { + return instance.eDirectResource(); + } + + protected InternalEObject getInstanceContainer(InternalEObject instance) + { + return instance.eInternalContainer(); + } + + protected int getInstanceContainerFeatureID(InternalEObject instance) + { + return instance.eContainerFeatureID(); + } + + protected Object getInstanceValue(InternalEObject instance, EStructuralFeature feature, + CDOPackageRegistry packageRegistry) + { + return instance.eGet(feature); + } + + protected void setInstanceResource(Resource.Internal resource) + { + Method method = ReflectUtil.getMethod(instance.getClass(), "eSetDirectResource", Resource.Internal.class); //$NON-NLS-1$ + ReflectUtil.invokeMethod(method, instance, resource); + } + + protected void setInstanceContainer(InternalEObject container, int containerFeatureID) + { + Method method = ReflectUtil.getMethod(instance.getClass(), "eBasicSetContainer", InternalEObject.class, int.class); //$NON-NLS-1$ + ReflectUtil.invokeMethod(method, instance, container, containerFeatureID); + } + + protected void setInstanceValue(InternalEObject instance, EStructuralFeature feature, Object value) + { + instance.eSet(feature, value); + } + + /** + * @param feature + * in case that a proxy has to be created the feature that will determine the interface type of the proxy and + * that will be used later to resolve the proxy. <code>null</code> indicates that proxy creation will be + * avoided! + */ + protected InternalEObject getEObjectFromPotentialID(InternalCDOView view, EStructuralFeature feature, + Object potentialID) + { + CDOLegacyWrapper wrapper; + if (potentialID instanceof CDOID && (wrapper = getRegisteredWrapper((CDOID)potentialID)) != null) + { + potentialID = wrapper.instance; + + if (TRACER.isEnabled()) + { + TRACER.format("Getting Object (" + potentialID + ") from localThread instead of the view"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + else + { + if (potentialID instanceof CDOID) + { + CDOID id = (CDOID)potentialID; + if (id.isNull()) + { + return null; + } + + if (id.isExternal()) + { + URI uri = URI.createURI(id.toURIFragment()); + InternalEObject eObject = (InternalEObject)view.getResourceSet().getEObject(uri, true); + return eObject; + } + + boolean loadOnDemand = feature == null; + potentialID = view.getObject(id, loadOnDemand); + if (potentialID == null && !loadOnDemand) + { + return createProxy(view, feature, id); + } + } + + if (potentialID instanceof InternalCDOObject) + { + return ((InternalCDOObject)potentialID).cdoInternalInstance(); + } + } + + return (InternalEObject)potentialID; + } + + /** + * Creates and returns a <em>proxy</em> object. The usage of a proxy object is strongly limited. The only guarantee + * that can be made is that the following methods are callable and will behave in the expected way: + * <ul> + * <li>{@link CDOObject#cdoID()} will return the {@link CDOID} of the target object + * <li>{@link CDOObject#cdoState()} will return {@link CDOState#PROXY PROXY} + * <li>{@link InternalEObject#eIsProxy()} will return <code>true</code> + * <li>{@link InternalEObject#eProxyURI()} will return the EMF proxy URI of the target object + * </ul> + * Calling any other method on the proxy object will result in an {@link UnsupportedOperationException} being thrown + * at runtime. Note also that the proxy object might even not be cast to the concrete type of the target object. The + * proxy can only guaranteed to be of <em>any</em> concrete subtype of the declared type of the given feature. + * <p> + * TODO {@link InternalEObject#eResolveProxy(InternalEObject)} + */ + protected InternalEObject createProxy(InternalCDOView view, EStructuralFeature feature, CDOID id) + { + EClassifier eType = feature.getEType(); + Class<?> instanceClass = eType.getInstanceClass(); + + Class<?>[] interfaces = { instanceClass, InternalEObject.class, LegacyProxy.class }; + ClassLoader classLoader = CDOLegacyWrapper.class.getClassLoader(); + LegacyProxyInvocationHandler handler = new LegacyProxyInvocationHandler(this, id); + return (InternalEObject)Proxy.newProxyInstance(classLoader, interfaces, handler); + } + + protected void clearEList(InternalEList<?> list) + { + for (int i = list.size() - 1; i >= 0; --i) + { + Object obj = list.get(i); + list.basicRemove(obj, null); + } + } + + /** + * TODO Consider using only EMF concepts for resolving proxies! + */ + protected void resolveAllProxies() + { + CDOPackageRegistry packageRegistry = cdoView().getSession().getPackageRegistry(); + EClass eClass = revision.getEClass(); + for (EStructuralFeature feature : CDOModelUtil.getAllPersistentFeatures(eClass)) + { + if (feature instanceof EReference) + { + resolveProxies(feature, packageRegistry); + } + } + } + + /** + * IMPORTANT: Compile errors in this method might indicate an old version of EMF. Legacy support is only enabled for + * EMF with fixed bug #247130. These compile errors do not affect native models! + */ + protected void resolveProxies(EStructuralFeature feature, CDOPackageRegistry packageRegistry) + { + Object value = getInstanceValue(instance, feature, packageRegistry); + if (value != null) + { + if (feature.isMany()) + { + @SuppressWarnings("unchecked") + InternalEList<Object> list = (InternalEList<Object>)value; + int size = list.size(); + + boolean deliver = instance.eDeliver(); + if (deliver) + { + instance.eSetDeliver(false); + } + + for (int i = 0; i < size; i++) + { + Object element = list.get(i); + if (element instanceof LegacyProxy) + { + CDOID id = ((LegacyProxy)element).getID(); + InternalCDOObject resolved = (InternalCDOObject)view.getObject(id); + InternalEObject instance = resolved.cdoInternalInstance(); + + // TODO LEGACY + // // TODO Is InternalEList.basicSet() needed??? + // if (list instanceof + // org.eclipse.emf.ecore.util.DelegatingInternalEList) + // { + // list = + // ((org.eclipse.emf.ecore.util.DelegatingInternalEList)list).getDelegateInternalEList(); + // } + + // if (list instanceof NotifyingListImpl<?>) + // { + // ((NotifyingListImpl<Object>)list).basicSet(i, instance, null); + // } + // else + // { + list.set(i, instance); + // } + } + } + + if (deliver) + { + instance.eSetDeliver(true); + } + } + else + { + if (value instanceof LegacyProxy) + { + CDOID id = ((LegacyProxy)value).getID(); + InternalCDOObject resolved = (InternalCDOObject)view.getObject(id); + InternalEObject instance = resolved.cdoInternalInstance(); + setInstanceValue(instance, feature, instance); + } + } + } + } + + protected void adjustEProxy() + { + // Setting eProxyURI is necessary to prevent content adapters from + // loading the whole content tree. + // TODO Does not have the desired effect ;-( see CDOEditor.createModel() + if (state == CDOState.PROXY) + { + if (!instance.eIsProxy()) + { + URI uri = URI.createURI(CDOProtocolConstants.PROTOCOL_NAME + ":proxy#" + id); //$NON-NLS-1$ + if (TRACER.isEnabled()) + { + TRACER.format("Setting proxyURI {0} for {1}", uri, instance); //$NON-NLS-1$ + } + + instance.eSetProxyURI(uri); + } + } + else + { + if (instance.eIsProxy()) + { + if (TRACER.isEnabled()) + { + TRACER.format("Unsetting proxyURI for {0}", instance); //$NON-NLS-1$ + } + + instance.eSetProxyURI(null); + } + } + } + + @Override + public synchronized EList<Adapter> eAdapters() + { + EList<Adapter> adapters = instance.eAdapters(); + for (Adapter adapter : adapters) + { + if (!FSMUtil.isTransient(this) && !(adapter instanceof CDOLegacyWrapper)) + { + cdoView().handleAddAdapter(this, adapter); + } + } + + return adapters; + } + + public static boolean isLegacyProxy(Object object) + { + return object instanceof LegacyProxy; + } + + protected static int getEFlagMask(Class<?> instanceClass, String flagName) + { + Field field = ReflectUtil.getField(instanceClass, flagName); + if (!field.isAccessible()) + { + field.setAccessible(true); + } + + try + { + return (Integer)field.get(null); + } + catch (IllegalAccessException ex) + { + throw WrappedException.wrap(ex); + } + } + + /** + * @since 3.0 + */ + protected static CDOLegacyWrapper getRegisteredWrapper(CDOID id) + { + return wrapperRegistry.get().get(id); + } + + /** + * Adds an object to the pre-registered objects list which hold all created objects even if they are not registered in + * the view + * + * @since 3.0 + */ + protected static void registerWrapper(CDOLegacyWrapper wrapper) + { + wrapperRegistry.get().put(wrapper.cdoID(), wrapper); + } + + /** + * @since 3.0 + */ + protected static void unregisterWrapper(CDOLegacyWrapper wrapper) + { + wrapperRegistry.get().remove(wrapper.cdoID()); + } + + /** + * @since 3.0 + */ + protected static boolean isRegisteredWrapper(CDOLegacyWrapper wrapper) + { + return wrapperRegistry.get().containsKey(wrapper.cdoID()); + } + + // TODO: Remove this method if it is ensured that ist is not needed anymore + // private void adjustOppositeReference(InternalCDOObject cdoObject, EObject oppositeObject, EReference + // oppositeReference) + // { + // if (oppositeObject != null) + // { + // InternalCDOObject oppositeCDOObject = (InternalCDOObject)CDOUtil.getCDOObject(oppositeObject); + // + // if (!FSMUtil.isTransient(oppositeCDOObject) && !EMFUtil.isPersistent(oppositeReference)) + // { + // adjustPersistentOppositeReference(cdoObject, oppositeObject, oppositeReference); + // } + // else + // { + // if (oppositeReference.isResolveProxies()) + // { + // adjustTransientOppositeReference(instance, (InternalEObject)oppositeObject, oppositeReference); + // } + // } + // } + // } + + private void adjustPersistentOppositeReference(InternalCDOObject cdoObject, EObject oppositeObject, + EReference oppositeReference) + { + InternalCDOObject oppositeCDOObject = (InternalCDOObject)CDOUtil.getCDOObject(oppositeObject); + if (oppositeCDOObject != null) + { + InternalCDOView view = oppositeCDOObject.cdoView(); + if (view != null) + { + CDOStore store = view.getStore(); + if (store != null) + { + if (oppositeReference.isMany()) + { + EObject eObject = oppositeCDOObject.cdoInternalInstance(); + + @SuppressWarnings("unchecked") + EList<Object> list = (EList<Object>)eObject.eGet(oppositeReference); + int index = list.indexOf(instance); + + if (!store.isEmpty(oppositeCDOObject, oppositeReference) && index != EStore.NO_INDEX) + { + store.set(oppositeCDOObject, oppositeReference, index, cdoObject); + } + } + else + { + store.set(oppositeCDOObject, oppositeReference, 0, cdoObject); + } + } + } + } + } + + private void adjustTransientOppositeReference(InternalEObject instance, InternalEObject object, + EReference oppositeReference) + { + boolean wasDeliver = object.eDeliver(); // Disable notifications + if (wasDeliver) + { + object.eSetDeliver(false); + } + + try + { + if (oppositeReference.isMany()) + { + @SuppressWarnings("unchecked") + InternalEList<Object> list = (InternalEList<Object>)object.eGet(oppositeReference); + list.basicAdd(instance, null); + } + else + { + if (object.eGet(oppositeReference) != instance) + { + object.eInverseAdd(instance, oppositeReference.getFeatureID(), ((EObject)instance).getClass(), null); + } + } + } + finally + { + if (wasDeliver) + { + object.eSetDeliver(true); + } + } + } + + /** + * @author Eike Stepper + */ + private static interface LegacyProxy + { + public CDOID getID(); + } + + /** + * @author Eike Stepper + */ + private static final class LegacyProxyInvocationHandler implements InvocationHandler, LegacyProxy + { + private static final Method getIDMethod = ReflectUtil.getMethod(LegacyProxy.class, "getID"); //$NON-NLS-1$ + + private static final Method eIsProxyMethod = ReflectUtil.getMethod(EObject.class, "eIsProxy"); //$NON-NLS-1$ + + private static final Method eProxyURIMethod = ReflectUtil.getMethod(InternalEObject.class, "eProxyURI"); //$NON-NLS-1$ + + private CDOLegacyWrapper wrapper; + + private CDOID id; + + public LegacyProxyInvocationHandler(CDOLegacyWrapper wrapper, CDOID id) + { + this.wrapper = wrapper; + this.id = id; + } + + public CDOID getID() + { + return id; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + if (method.equals(getIDMethod)) + { + return id; + } + + if (method.equals(eIsProxyMethod)) + { + return true; + } + + if (method.equals(eProxyURIMethod)) + { + // Use container's resource because it's guaranteed to be in the same CDOView as the resource of the target! + Resource resource = wrapper.eResource(); + + // TODO Consider using a "fake" Resource implementation. See Resource.getEObject(...) + return resource.getURI().appendFragment(id.toURIFragment()); + } + + // A client must have invoked the proxy while being told not to do so! + throw new UnsupportedOperationException(method.getName()); + } + } + + /** + * @author Martin Fluegge + */ + private static final class Counter + { + private int value; + + public Counter() + { + } + + public void increment() + { + ++value; + } + + public int decrement() + { + return --value; + } + } +} 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 +} diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java index 672b103e39..3134378695 100644 --- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java +++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/view/CDOStoreImpl.java @@ -1,711 +1,716 @@ -/*
- * 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 - bug 201266
- * Eike Stepper & Simon McDuff - bug 204890
- * Simon McDuff - bug 246705
- * Simon McDuff - bug 246622
- */
-package org.eclipse.emf.internal.cdo.view;
-
-import org.eclipse.emf.cdo.common.id.CDOID;
-import org.eclipse.emf.cdo.common.model.CDOModelUtil;
-import org.eclipse.emf.cdo.common.model.CDOType;
-import org.eclipse.emf.cdo.common.revision.CDOElementProxy;
-import org.eclipse.emf.cdo.common.revision.CDOList;
-import org.eclipse.emf.cdo.common.revision.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
-import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
-import org.eclipse.emf.cdo.eresource.CDOResource;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl;
-import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
-import org.eclipse.emf.cdo.util.ObjectNotFoundException;
-import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer;
-import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy;
-
-import org.eclipse.emf.internal.cdo.bundle.OM;
-
-import org.eclipse.net4j.util.ObjectUtil;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-
-import org.eclipse.emf.ecore.EClass;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.EcorePackage;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.InternalEObject.EStore;
-import org.eclipse.emf.ecore.util.FeatureMap;
-import org.eclipse.emf.ecore.util.FeatureMapUtil;
-import org.eclipse.emf.spi.cdo.CDOStore;
-import org.eclipse.emf.spi.cdo.FSMUtil;
-import org.eclipse.emf.spi.cdo.InternalCDOObject;
-import org.eclipse.emf.spi.cdo.InternalCDOView;
-
-import java.text.MessageFormat;
-import java.util.List;
-
-/**
- * CDORevision needs to follow these rules:<br>
- * - Keep CDOID only when the object (!isNew && !isTransient) // Only when CDOID will not changed.<br>
- * - Keep EObject for external reference, new, transient and that until commit time.<br>
- * It is important since these objects could changed and we need to keep a reference to {@link EObject} until the end.
- * It is the reason why {@link CDOStoreImpl} always call {@link InternalCDOView#convertObjectToID(Object, boolean)} with
- * true.
- *
- * @author Eike Stepper
- */
-public final class CDOStoreImpl implements CDOStore
-{
- private final ContextTracer TRACER = new ContextTracer(OM.DEBUG_STORE, CDOStoreImpl.class);
-
- private InternalCDOView view;
-
- /**
- * @since 2.0
- */
- public CDOStoreImpl(InternalCDOView view)
- {
- this.view = view;
- }
-
- /**
- * @since 2.0
- */
- public InternalCDOView getView()
- {
- return view;
- }
-
- /**
- * @since 2.0
- */
- public void setContainer(InternalEObject eObject, CDOResource newResource, InternalEObject newEContainer,
- int newContainerFeatureID)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("setContainer({0}, {1}, {2}, {3})", cdoObject, newResource, newEContainer, newContainerFeatureID); //$NON-NLS-1$
- }
-
- Object newContainerID = newEContainer == null ? CDOID.NULL : cdoObject.cdoView().convertObjectToID(newEContainer,
- true);
- CDOID newResourceID = newResource == null ? CDOID.NULL : newResource.cdoID();
-
- CDOFeatureDelta delta = new CDOContainerFeatureDeltaImpl(newResourceID, newContainerID, newContainerFeatureID);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- revision.setResourceID(newResourceID);
- revision.setContainerID(newContainerID);
- revision.setContainingFeatureID(newContainerFeatureID);
- }
- }
-
- public InternalEObject getContainer(InternalEObject eObject)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("getContainer({0})", cdoObject); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return (InternalEObject)convertIDToObject(cdoObject.cdoView(), cdoObject,
- EcorePackage.eINSTANCE.eContainingFeature(), -1, revision.getContainerID());
- }
- }
-
- public int getContainingFeatureID(InternalEObject eObject)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("getContainingFeatureID({0})", cdoObject); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.getContainingFeatureID();
- }
- }
-
- /**
- * @since 2.0
- */
- public InternalEObject getResource(InternalEObject eObject)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("getResource({0})", cdoObject); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return (InternalEObject)convertIDToObject(cdoObject.cdoView(), cdoObject,
- EcorePackage.eINSTANCE.eContainingFeature(), -1, revision.getResourceID());
- }
- }
-
- public EStructuralFeature getContainingFeature(InternalEObject eObject)
- {
- throw new UnsupportedOperationException("Use getContainingFeatureID() instead"); //$NON-NLS-1$
- }
-
- public Object get(InternalEObject eObject, EStructuralFeature feature, int index)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("get({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$
- }
-
- CDOFeatureAnalyzer featureAnalyzer = view.options().getFeatureAnalyzer();
-
- featureAnalyzer.preTraverseFeature(cdoObject, feature, index);
- InternalCDORevision revision = getRevisionForReading(cdoObject);
-
- Object value = revision.get(feature, index);
- value = convertToEMF(eObject, revision, feature, index, value);
-
- featureAnalyzer.postTraverseFeature(cdoObject, feature, index, value);
- return value;
- }
- }
-
- public boolean isSet(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("isSet({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- if (!feature.isUnsettable())
- {
- if (feature.isMany())
- {
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- CDOList list = revision.getList(feature);
- return list != null && !list.isEmpty();
- }
-
- Object value = eObject.eGet(feature);
- Object defaultValue = feature.getDefaultValue();
- return !ObjectUtil.equals(value, defaultValue);
- }
-
- // TODO This get() may not work for lists, see above
- Object value = get(eObject, feature, NO_INDEX);
- return value != null;
- }
- }
-
- public int size(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("size({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.size(feature);
- }
- }
-
- public boolean isEmpty(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("isEmpty({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.isEmpty(feature);
- }
- }
-
- public boolean contains(InternalEObject eObject, EStructuralFeature feature, Object value)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("contains({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$
- }
-
- Object convertedValue = convertToCDO(cdoObject, feature, value);
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- boolean result = revision.contains(feature, convertedValue);
-
- // Special handling of detached (TRANSIENT) objects, see bug 354395
- if (!result && value != convertedValue && value instanceof EObject)
- {
- result = revision.contains(feature, value);
- }
-
- return result;
- }
- }
-
- public int indexOf(InternalEObject eObject, EStructuralFeature feature, Object value)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("indexOf({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$
- }
-
- value = convertToCDO(cdoObject, feature, value);
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.indexOf(feature, value);
- }
- }
-
- public int lastIndexOf(InternalEObject eObject, EStructuralFeature feature, Object value)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("lastIndexOf({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$
- }
-
- value = convertToCDO(cdoObject, feature, value);
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.lastIndexOf(feature, value);
- }
- }
-
- public int hashCode(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("hashCode({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- return revision.hashCode(feature);
- }
- }
-
- public Object[] toArray(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("toArray({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- InternalCDORevision revision = getRevisionForReading(cdoObject);
- Object[] result = revision.toArray(feature);
- for (int i = 0; i < result.length; i++)
- {
- result[i] = convertToEMF(eObject, revision, feature, i, result[i]);
- }
-
- // // TODO Clarify feature maps
- // if (feature instanceof EReference)
- // {
- // for (int i = 0; i < result.length; i++)
- // {
- // result[i] = resolveProxy(revision, feature, i, result[i]);
- // result[i] = convertIdToObject(cdoObject.cdoView(), eObject, feature, i, result[i]);
- // }
- // }
-
- return result;
- }
- }
-
- @SuppressWarnings("unchecked")
- public <T> T[] toArray(InternalEObject eObject, EStructuralFeature feature, T[] a)
- {
- synchronized (view)
- {
- Object[] array = toArray(eObject, feature);
- int size = array.length;
-
- if (a.length < size)
- {
- a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
- }
-
- System.arraycopy(array, 0, a, 0, size);
- if (a.length > size)
- {
- a[size] = null;
- }
-
- return a;
- }
- }
-
- public Object set(InternalEObject eObject, EStructuralFeature feature, int index, Object value)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("set({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$
- }
-
- value = convertToCDO(cdoObject, feature, value);
-
- InternalCDORevision oldRevision = getRevisionForReading(cdoObject);
- Object oldValue = oldRevision.get(feature, index);
- oldValue = convertToEMF(eObject, oldRevision, feature, index, oldValue);
-
- CDOFeatureDelta delta = new CDOSetFeatureDeltaImpl(feature, index, value, oldValue);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- revision.set(feature, index, value);
-
- return oldValue;
- }
- }
-
- public void unset(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("unset({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- CDOFeatureDelta delta = new CDOUnsetFeatureDeltaImpl(feature);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
-
- if (feature.isUnsettable())
- {
- revision.unset(feature);
- }
- else
- {
- if (feature.isMany())
- {
- Object value = revision.getValue(feature);
-
- @SuppressWarnings("unchecked")
- List<Object> list = (List<Object>)value;
- list.clear();
- }
- else
- {
- Object defaultValue = convertToCDO(cdoObject, feature, feature.getDefaultValue());
- revision.set(feature, NO_INDEX, defaultValue);
- }
- }
- }
- }
-
- public void add(InternalEObject eObject, EStructuralFeature feature, int index, Object value)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("add({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$
- }
-
- if (feature.isMany())
- {
- value = convertToCDO(cdoObject, feature, value);
- }
- else
- {
- throw new UnsupportedOperationException("ADD is not supported for single-valued features");
- }
-
- CDOFeatureDelta delta = new CDOAddFeatureDeltaImpl(feature, index, value);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- revision.add(feature, index, value);
- }
- }
-
- public Object remove(InternalEObject eObject, EStructuralFeature feature, int index)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("remove({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$
- }
-
- Object oldValue = null;
-
- // Bugzilla 293283 / 314387
- if (feature.isMany())
- {
- InternalCDORevision readLockedRevision = getRevisionForReading(cdoObject);
- CDOList list = readLockedRevision.getList(feature);
- int size = list.size();
- if (index < 0 || size <= index)
- {
- throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
- }
- }
- else
- {
- throw new UnsupportedOperationException("REMOVE is not supported for single-valued features");
- }
-
- CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(feature, index);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
-
- oldValue = revision.remove(feature, index);
- return convertToEMF(eObject, revision, feature, index, oldValue);
- }
- }
-
- public void clear(InternalEObject eObject, EStructuralFeature feature)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("clear({0}, {1})", cdoObject, feature); //$NON-NLS-1$
- }
-
- CDOFeatureDelta delta = new CDOClearFeatureDeltaImpl(feature);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- // TODO Handle containment remove!!!
- revision.clear(feature);
- }
- }
-
- public Object move(InternalEObject eObject, EStructuralFeature feature, int target, int source)
- {
- synchronized (view)
- {
- InternalCDOObject cdoObject = getCDOObject(eObject);
- if (TRACER.isEnabled())
- {
- TRACER.format("move({0}, {1}, {2}, {3})", cdoObject, feature, target, source); //$NON-NLS-1$
- }
-
- CDOFeatureDelta delta = new CDOMoveFeatureDeltaImpl(feature, target, source);
- InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
- Object result = revision.move(feature, target, source);
-
- result = convertToEMF(eObject, revision, feature, EStore.NO_INDEX, result);
- return result;
- }
- }
-
- public EObject create(EClass eClass)
- {
- throw new UnsupportedOperationException("Use the generated factory to create objects"); //$NON-NLS-1$
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("CDOStore[{0}]", view); //$NON-NLS-1$
- }
-
- /**
- * @since 2.0
- */
- public Object resolveProxy(InternalCDORevision revision, EStructuralFeature feature, int index, Object value)
- {
- synchronized (view)
- {
- if (value instanceof CDOElementProxy)
- {
- // Resolve proxy
- CDOElementProxy proxy = (CDOElementProxy)value;
- value = view.getSession().resolveElementProxy(revision, feature, index, proxy.getIndex());
- }
-
- return value;
- }
- }
-
- /**
- * @since 3.0
- */
- public Object convertToCDO(InternalCDOObject object, EStructuralFeature feature, Object value)
- {
- synchronized (view)
- {
- if (value != null)
- {
- if (feature instanceof EReference)
- {
- value = view.convertObjectToID(value, true);
- }
- else if (FeatureMapUtil.isFeatureMap(feature))
- {
- FeatureMap.Entry entry = (FeatureMap.Entry)value;
- EStructuralFeature innerFeature = entry.getEStructuralFeature();
- Object innerValue = entry.getValue();
- Object convertedValue = view.convertObjectToID(innerValue);
- if (convertedValue != innerValue)
- {
- value = CDORevisionUtil.createFeatureMapEntry(innerFeature, convertedValue);
- }
- }
- else
- {
- CDOType type = CDOModelUtil.getType(feature.getEType());
- if (type != null)
- {
- value = type.convertToCDO(feature.getEType(), value);
- }
- }
- }
-
- return value;
- }
- }
-
- /**
- * @since 2.0
- */
- public Object convertToEMF(EObject eObject, InternalCDORevision revision, EStructuralFeature feature, int index,
- Object value)
- {
- synchronized (view)
- {
- if (value != null)
- {
- if (feature.isMany() && index != EStore.NO_INDEX)
- {
- value = resolveProxy(revision, feature, index, value);
- if (value instanceof CDOID)
- {
- CDOID id = (CDOID)value;
- CDOList list = revision.getList(feature);
- CDORevisionPrefetchingPolicy policy = view.options().getRevisionPrefetchingPolicy();
- InternalCDORevisionManager revisionManager = view.getSession().getRevisionManager();
- List<CDOID> listOfIDs = policy.loadAhead(revisionManager, view, eObject, feature, list, index, id);
- if (!listOfIDs.isEmpty())
- {
- int initialChunkSize = view.getSession().options().getCollectionLoadingPolicy().getInitialChunkSize();
- revisionManager.getRevisions(listOfIDs, view, initialChunkSize, CDORevision.DEPTH_NONE, true);
- }
- }
- }
-
- if (feature instanceof EReference)
- {
- value = convertIDToObject(view, eObject, feature, index, value);
- }
- else if (FeatureMapUtil.isFeatureMap(feature))
- {
- FeatureMap.Entry entry = (FeatureMap.Entry)value;
- EStructuralFeature innerFeature = entry.getEStructuralFeature();
- Object innerValue = entry.getValue();
- Object convertedValue = convertIDToObject(view, eObject, feature, index, innerValue);
- if (convertedValue != innerValue)
- {
- value = FeatureMapUtil.createEntry(innerFeature, convertedValue);
- }
- }
- else
- {
- CDOType type = CDOModelUtil.getType(feature.getEType());
- if (type != null)
- {
- value = type.convertToEMF(feature.getEType(), value);
- }
- }
- }
-
- return value;
- }
- }
-
- private Object convertIDToObject(InternalCDOView view, EObject eObject, EStructuralFeature feature, int index,
- Object value)
- {
- try
- {
- value = view.convertIDToObject(value);
- }
- catch (ObjectNotFoundException ex)
- {
- if (value instanceof CDOID)
- {
- value = view.options().getStaleReferencePolicy().processStaleReference(eObject, feature, index, ex.getID());
- }
- }
-
- return value;
- }
-
- private InternalCDOObject getCDOObject(Object object)
- {
- return FSMUtil.adapt(object, view);
- }
-
- private static InternalCDORevision getRevisionForReading(InternalCDOObject cdoObject)
- {
- CDOStateMachine.INSTANCE.read(cdoObject);
- return getRevision(cdoObject);
- }
-
- private static InternalCDORevision getRevisionForWriting(InternalCDOObject cdoObject, CDOFeatureDelta delta)
- {
- CDOStateMachine.INSTANCE.write(cdoObject, delta);
- return getRevision(cdoObject);
- }
-
- private static InternalCDORevision getRevision(InternalCDOObject cdoObject)
- {
- InternalCDORevision revision = cdoObject.cdoRevision();
- if (revision == null)
- {
- throw new IllegalStateException("revision == null");
- }
-
- return revision;
- }
-}
+/* + * 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 - bug 201266 + * Eike Stepper & Simon McDuff - bug 204890 + * Simon McDuff - bug 246705 + * Simon McDuff - bug 246622 + */ +package org.eclipse.emf.internal.cdo.view; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.revision.CDOElementProxy; +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; +import org.eclipse.emf.cdo.eresource.CDOResource; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl; +import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; +import org.eclipse.emf.cdo.util.ObjectNotFoundException; +import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer; +import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy; + +import org.eclipse.emf.internal.cdo.bundle.OM; + +import org.eclipse.net4j.util.ObjectUtil; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.InternalEObject; +import org.eclipse.emf.ecore.InternalEObject.EStore; +import org.eclipse.emf.ecore.util.FeatureMap; +import org.eclipse.emf.ecore.util.FeatureMapUtil; +import org.eclipse.emf.spi.cdo.CDOStore; +import org.eclipse.emf.spi.cdo.FSMUtil; +import org.eclipse.emf.spi.cdo.InternalCDOObject; +import org.eclipse.emf.spi.cdo.InternalCDOView; + +import java.text.MessageFormat; +import java.util.List; + +/** + * CDORevision needs to follow these rules:<br> + * - Keep CDOID only when the object (!isNew && !isTransient) // Only when CDOID will not changed.<br> + * - Keep EObject for external reference, new, transient and that until commit time.<br> + * It is important since these objects could changed and we need to keep a reference to {@link EObject} until the end. + * It is the reason why {@link CDOStoreImpl} always call {@link InternalCDOView#convertObjectToID(Object, boolean)} with + * true. + * + * @author Eike Stepper + */ +public final class CDOStoreImpl implements CDOStore +{ + private final ContextTracer TRACER = new ContextTracer(OM.DEBUG_STORE, CDOStoreImpl.class); + + private InternalCDOView view; + + /** + * @since 2.0 + */ + public CDOStoreImpl(InternalCDOView view) + { + this.view = view; + } + + /** + * @since 2.0 + */ + public InternalCDOView getView() + { + return view; + } + + /** + * @since 2.0 + */ + public void setContainer(InternalEObject eObject, CDOResource newResource, InternalEObject newEContainer, + int newContainerFeatureID) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("setContainer({0}, {1}, {2}, {3})", cdoObject, newResource, newEContainer, newContainerFeatureID); //$NON-NLS-1$ + } + + Object newContainerID = newEContainer == null ? CDOID.NULL : cdoObject.cdoView().convertObjectToID(newEContainer, + true); + CDOID newResourceID = newResource == null ? CDOID.NULL : newResource.cdoID(); + + CDOFeatureDelta delta = new CDOContainerFeatureDeltaImpl(newResourceID, newContainerID, newContainerFeatureID); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + revision.setResourceID(newResourceID); + revision.setContainerID(newContainerID); + revision.setContainingFeatureID(newContainerFeatureID); + } + } + + public InternalEObject getContainer(InternalEObject eObject) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("getContainer({0})", cdoObject); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return (InternalEObject)convertIDToObject(cdoObject.cdoView(), cdoObject, + EcorePackage.eINSTANCE.eContainingFeature(), -1, revision.getContainerID()); + } + } + + public int getContainingFeatureID(InternalEObject eObject) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("getContainingFeatureID({0})", cdoObject); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.getContainingFeatureID(); + } + } + + /** + * @since 2.0 + */ + public InternalEObject getResource(InternalEObject eObject) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("getResource({0})", cdoObject); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return (InternalEObject)convertIDToObject(cdoObject.cdoView(), cdoObject, + EcorePackage.eINSTANCE.eContainingFeature(), -1, revision.getResourceID()); + } + } + + public EStructuralFeature getContainingFeature(InternalEObject eObject) + { + throw new UnsupportedOperationException("Use getContainingFeatureID() instead"); //$NON-NLS-1$ + } + + public Object get(InternalEObject eObject, EStructuralFeature feature, int index) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("get({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$ + } + + CDOFeatureAnalyzer featureAnalyzer = view.options().getFeatureAnalyzer(); + + featureAnalyzer.preTraverseFeature(cdoObject, feature, index); + InternalCDORevision revision = getRevisionForReading(cdoObject); + + Object value = revision.get(feature, index); + value = convertToEMF(eObject, revision, feature, index, value); + + featureAnalyzer.postTraverseFeature(cdoObject, feature, index, value); + return value; + } + } + + public boolean isSet(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("isSet({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + if (!feature.isUnsettable()) + { + if (feature.isMany()) + { + InternalCDORevision revision = getRevisionForReading(cdoObject); + CDOList list = revision.getList(feature); + return list != null && !list.isEmpty(); + } + + Object value = eObject.eGet(feature); + Object defaultValue = feature.getDefaultValue(); + return !ObjectUtil.equals(value, defaultValue); + } + + // TODO This get() may not work for lists, see above + Object value = get(eObject, feature, NO_INDEX); + return value != null; + } + } + + public int size(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("size({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.size(feature); + } + } + + public boolean isEmpty(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("isEmpty({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.isEmpty(feature); + } + } + + public boolean contains(InternalEObject eObject, EStructuralFeature feature, Object value) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("contains({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$ + } + + Object convertedValue = convertToCDO(cdoObject, feature, value); + + InternalCDORevision revision = getRevisionForReading(cdoObject); + boolean result = revision.contains(feature, convertedValue); + + // Special handling of detached (TRANSIENT) objects, see bug 354395 + if (!result && value != convertedValue && value instanceof EObject) + { + result = revision.contains(feature, value); + } + + return result; + } + } + + public int indexOf(InternalEObject eObject, EStructuralFeature feature, Object value) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("indexOf({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$ + } + + value = convertToCDO(cdoObject, feature, value); + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.indexOf(feature, value); + } + } + + public int lastIndexOf(InternalEObject eObject, EStructuralFeature feature, Object value) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("lastIndexOf({0}, {1}, {2})", cdoObject, feature, value); //$NON-NLS-1$ + } + + value = convertToCDO(cdoObject, feature, value); + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.lastIndexOf(feature, value); + } + } + + public int hashCode(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("hashCode({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + return revision.hashCode(feature); + } + } + + public Object[] toArray(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("toArray({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + InternalCDORevision revision = getRevisionForReading(cdoObject); + Object[] result = revision.toArray(feature); + for (int i = 0; i < result.length; i++) + { + result[i] = convertToEMF(eObject, revision, feature, i, result[i]); + } + + // // TODO Clarify feature maps + // if (feature instanceof EReference) + // { + // for (int i = 0; i < result.length; i++) + // { + // result[i] = resolveProxy(revision, feature, i, result[i]); + // result[i] = convertIdToObject(cdoObject.cdoView(), eObject, feature, i, result[i]); + // } + // } + + return result; + } + } + + @SuppressWarnings("unchecked") + public <T> T[] toArray(InternalEObject eObject, EStructuralFeature feature, T[] a) + { + synchronized (view) + { + Object[] array = toArray(eObject, feature); + int size = array.length; + + if (a.length < size) + { + a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); + } + + System.arraycopy(array, 0, a, 0, size); + if (a.length > size) + { + a[size] = null; + } + + return a; + } + } + + public Object set(InternalEObject eObject, EStructuralFeature feature, int index, Object value) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("set({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$ + } + + value = convertToCDO(cdoObject, feature, value); + + InternalCDORevision oldRevision = getRevisionForReading(cdoObject); + Object oldValue = oldRevision.get(feature, index); + oldValue = convertToEMF(eObject, oldRevision, feature, index, oldValue); + + CDOFeatureDelta delta = new CDOSetFeatureDeltaImpl(feature, index, value, oldValue); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + revision.set(feature, index, value); + + return oldValue; + } + } + + public void unset(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("unset({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + CDOFeatureDelta delta = new CDOUnsetFeatureDeltaImpl(feature); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + + if (feature.isUnsettable()) + { + revision.unset(feature); + } + else + { + if (feature.isMany()) + { + Object value = revision.getValue(feature); + + @SuppressWarnings("unchecked") + List<Object> list = (List<Object>)value; + list.clear(); + } + else + { + Object defaultValue = convertToCDO(cdoObject, feature, feature.getDefaultValue()); + revision.set(feature, NO_INDEX, defaultValue); + } + } + } + } + + public void add(InternalEObject eObject, EStructuralFeature feature, int index, Object value) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("add({0}, {1}, {2}, {3})", cdoObject, feature, index, value); //$NON-NLS-1$ + } + + if (feature.isMany()) + { + value = convertToCDO(cdoObject, feature, value); + } + else + { + throw new UnsupportedOperationException("ADD is not supported for single-valued features"); + } + + CDOFeatureDelta delta = new CDOAddFeatureDeltaImpl(feature, index, value); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + revision.add(feature, index, value); + } + } + + public Object remove(InternalEObject eObject, EStructuralFeature feature, int index) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("remove({0}, {1}, {2})", cdoObject, feature, index); //$NON-NLS-1$ + } + + Object oldValue = null; + + // Bugzilla 293283 / 314387 + if (feature.isMany()) + { + InternalCDORevision readLockedRevision = getRevisionForReading(cdoObject); + CDOList list = readLockedRevision.getList(feature); + int size = list.size(); + if (index < 0 || size <= index) + { + throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size); + } + } + else + { + throw new UnsupportedOperationException("REMOVE is not supported for single-valued features"); + } + + CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(feature, index); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + + oldValue = revision.remove(feature, index); + return convertToEMF(eObject, revision, feature, index, oldValue); + } + } + + public void clear(InternalEObject eObject, EStructuralFeature feature) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("clear({0}, {1})", cdoObject, feature); //$NON-NLS-1$ + } + + CDOFeatureDelta delta = new CDOClearFeatureDeltaImpl(feature); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + // TODO Handle containment remove!!! + revision.clear(feature); + } + } + + public Object move(InternalEObject eObject, EStructuralFeature feature, int target, int source) + { + synchronized (view) + { + InternalCDOObject cdoObject = getCDOObject(eObject); + if (TRACER.isEnabled()) + { + TRACER.format("move({0}, {1}, {2}, {3})", cdoObject, feature, target, source); //$NON-NLS-1$ + } + + CDOFeatureDelta delta = new CDOMoveFeatureDeltaImpl(feature, target, source); + InternalCDORevision revision = getRevisionForWriting(cdoObject, delta); + Object result = revision.move(feature, target, source); + + result = convertToEMF(eObject, revision, feature, EStore.NO_INDEX, result); + return result; + } + } + + public EObject create(EClass eClass) + { + throw new UnsupportedOperationException("Use the generated factory to create objects"); //$NON-NLS-1$ + } + + @Override + public String toString() + { + return MessageFormat.format("CDOStore[{0}]", view); //$NON-NLS-1$ + } + + /** + * @since 2.0 + */ + public Object resolveProxy(InternalCDORevision revision, EStructuralFeature feature, int index, Object value) + { + synchronized (view) + { + if (value instanceof CDOElementProxy) + { + // Resolve proxy + CDOElementProxy proxy = (CDOElementProxy)value; + value = view.getSession().resolveElementProxy(revision, feature, index, proxy.getIndex()); + } + + return value; + } + } + + /** + * @since 3.0 + */ + public Object convertToCDO(InternalCDOObject object, EStructuralFeature feature, Object value) + { + synchronized (view) + { + if (value != null) + { + if (feature instanceof EReference) + { + value = view.convertObjectToID(value, true); + } + else if (FeatureMapUtil.isFeatureMap(feature)) + { + FeatureMap.Entry entry = (FeatureMap.Entry)value; + EStructuralFeature innerFeature = entry.getEStructuralFeature(); + Object innerValue = entry.getValue(); + Object convertedValue = view.convertObjectToID(innerValue); + if (convertedValue != innerValue) + { + value = CDORevisionUtil.createFeatureMapEntry(innerFeature, convertedValue); + } + } + else + { + CDOType type = CDOModelUtil.getType(feature.getEType()); + if (type != null) + { + value = type.convertToCDO(feature.getEType(), value); + } + } + } + + return value; + } + } + + /** + * @since 2.0 + */ + public Object convertToEMF(EObject eObject, InternalCDORevision revision, EStructuralFeature feature, int index, + Object value) + { + synchronized (view) + { + if (value != null) + { + if (feature.isMany()) + { + if (index == EStore.NO_INDEX) + { + return value; + } + + value = resolveProxy(revision, feature, index, value); + if (value instanceof CDOID) + { + CDOID id = (CDOID)value; + CDOList list = revision.getList(feature); + CDORevisionPrefetchingPolicy policy = view.options().getRevisionPrefetchingPolicy(); + InternalCDORevisionManager revisionManager = view.getSession().getRevisionManager(); + List<CDOID> listOfIDs = policy.loadAhead(revisionManager, view, eObject, feature, list, index, id); + if (!listOfIDs.isEmpty()) + { + int initialChunkSize = view.getSession().options().getCollectionLoadingPolicy().getInitialChunkSize(); + revisionManager.getRevisions(listOfIDs, view, initialChunkSize, CDORevision.DEPTH_NONE, true); + } + } + } + + if (feature instanceof EReference) + { + value = convertIDToObject(view, eObject, feature, index, value); + } + else if (FeatureMapUtil.isFeatureMap(feature)) + { + FeatureMap.Entry entry = (FeatureMap.Entry)value; + EStructuralFeature innerFeature = entry.getEStructuralFeature(); + Object innerValue = entry.getValue(); + Object convertedValue = convertIDToObject(view, eObject, feature, index, innerValue); + if (convertedValue != innerValue) + { + value = FeatureMapUtil.createEntry(innerFeature, convertedValue); + } + } + else + { + CDOType type = CDOModelUtil.getType(feature.getEType()); + if (type != null) + { + value = type.convertToEMF(feature.getEType(), value); + } + } + } + + return value; + } + } + + private Object convertIDToObject(InternalCDOView view, EObject eObject, EStructuralFeature feature, int index, + Object value) + { + try + { + value = view.convertIDToObject(value); + } + catch (ObjectNotFoundException ex) + { + if (value instanceof CDOID) + { + value = view.options().getStaleReferencePolicy().processStaleReference(eObject, feature, index, ex.getID()); + } + } + + return value; + } + + private InternalCDOObject getCDOObject(Object object) + { + return FSMUtil.adapt(object, view); + } + + private static InternalCDORevision getRevisionForReading(InternalCDOObject cdoObject) + { + CDOStateMachine.INSTANCE.read(cdoObject); + return getRevision(cdoObject); + } + + private static InternalCDORevision getRevisionForWriting(InternalCDOObject cdoObject, CDOFeatureDelta delta) + { + CDOStateMachine.INSTANCE.write(cdoObject, delta); + return getRevision(cdoObject); + } + + private static InternalCDORevision getRevision(InternalCDOObject cdoObject) + { + InternalCDORevision revision = cdoObject.cdoRevision(); + if (revision == null) + { + throw new IllegalStateException("revision == null"); + } + + return revision; + } +} |