Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2012-04-19 18:24:17 +0000
committerEike Stepper2012-04-19 18:24:17 +0000
commit8bcfb2190e11eb139e8453a3b484294cfe57d66e (patch)
tree59e1bbc5b456f3316baa4206ba161fa431d9ced1
parent7f68932502ef0eb6a2265014cf31c316850092de (diff)
downloadcdo-8bcfb2190e11eb139e8453a3b484294cfe57d66e.tar.gz
cdo-8bcfb2190e11eb139e8453a3b484294cfe57d66e.tar.xz
cdo-8bcfb2190e11eb139e8453a3b484294cfe57d66e.zip
[377212] Provide a CDOBalancedTree as object storage with list size optimization
https://bugs.eclipse.org/bugs/show_bug.cgi?id=377212
-rw-r--r--plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_377212_Test.java73
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOBalancedTree.java215
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java6375
3 files changed, 3483 insertions, 3180 deletions
diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_377212_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_377212_Test.java
new file mode 100644
index 0000000000..d0f7d29c13
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_377212_Test.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util.CDOException;
+import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
+import org.eclipse.emf.cdo.session.CDOSession;
+import org.eclipse.emf.cdo.tests.AbstractCDOTest;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.util.CDOBalancedTree;
+
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * @author Eike Stepper
+ */
+public class Bugzilla_377212_Test extends AbstractCDOTest
+{
+ public void testBalancedTree() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResourceFolder root = transaction.createResourceFolder(getResourcePath("tree"));
+
+ CDOBalancedTree tree = new CDOBalancedTree(root);
+
+ for (int i = 0; i < 10000; i++)
+ {
+ EObject object = getModel1Factory().createSupplier();
+ tree.addObject(object);
+ }
+
+ transaction.commit();
+ msg("Committed transaction");
+ }
+
+ public void testBalancedTreeLocked() throws Exception
+ {
+ CDOSession session = openSession();
+ CDOTransaction transaction = session.openTransaction();
+ CDOResourceFolder root = transaction.createResourceFolder(getResourcePath("tree"));
+ transaction.commit();
+
+ CDOTransaction transaction2 = session.openTransaction();
+ CDOResourceFolder root2 = transaction2.getObject(root);
+ root2.cdoWriteLock().lock();
+
+ CDOBalancedTree tree = new CDOBalancedTree(root);
+ tree.setLockAttempts(3);
+
+ EObject object = getModel1Factory().createSupplier();
+
+ try
+ {
+ tree.addObject(object);
+ }
+ catch (CDOException ex)
+ {
+ assertEquals(true, ex.getMessage().startsWith("Unable to aquire write lock on balanced tree"));
+ return;
+ }
+
+ fail("CDOException expected");
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOBalancedTree.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOBalancedTree.java
new file mode 100644
index 0000000000..7b8a8d4f66
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/cdo/util/CDOBalancedTree.java
@@ -0,0 +1,215 @@
+/*
+ * 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.util;
+
+import org.eclipse.emf.cdo.common.util.CDOException;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
+import org.eclipse.emf.cdo.eresource.CDOResourceNode;
+
+import org.eclipse.net4j.util.io.IOUtil;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.EObject;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * @author Eike Stepper
+ * @since 4.1
+ */
+public class CDOBalancedTree
+{
+ public static final int DEFAULT_CAPACITY = 20;
+
+ public static final int DEFAULT_LOCK_TIMEOUT = 1000;
+
+ private static final boolean TRACE = false;
+
+ private final CDOResourceFolder root;
+
+ private final int folderCapacity;
+
+ private final int resourceCapacity;
+
+ private int lockAttempts;
+
+ private long lockTimeout = DEFAULT_LOCK_TIMEOUT;
+
+ public CDOBalancedTree(CDOResourceFolder root, int folderCapacity, int resourceCapacity)
+ {
+ this.root = root;
+ this.folderCapacity = folderCapacity;
+ this.resourceCapacity = resourceCapacity;
+ }
+
+ public CDOBalancedTree(CDOResourceFolder root, int nodeCapacity)
+ {
+ this(root, nodeCapacity, nodeCapacity);
+ }
+
+ public CDOBalancedTree(CDOResourceFolder root)
+ {
+ this(root, DEFAULT_CAPACITY);
+ }
+
+ public final CDOResourceFolder getRoot()
+ {
+ return root;
+ }
+
+ public final int getFolderCapacity()
+ {
+ return folderCapacity;
+ }
+
+ public final int getResourceCapacity()
+ {
+ return resourceCapacity;
+ }
+
+ public final int getLockAttempts()
+ {
+ return lockAttempts;
+ }
+
+ public final void setLockAttempts(int lockAttempts)
+ {
+ this.lockAttempts = lockAttempts;
+ }
+
+ public final long getLockTimeout()
+ {
+ return lockTimeout;
+ }
+
+ public final void setLockTimeout(long lockTimeout)
+ {
+ this.lockTimeout = lockTimeout;
+ }
+
+ public void addObject(EObject object)
+ {
+ if (lockAttempts == 0)
+ {
+ addObjectToRoot(object);
+ return;
+ }
+
+ int attempts = lockAttempts;
+ while (attempts-- != 0)
+ {
+ try
+ {
+ root.cdoWriteLock().lock(lockTimeout);
+ addObjectToRoot(object);
+ return;
+ }
+ catch (Exception ex)
+ {
+ // Try again, if not all attempts have been made
+ }
+ }
+
+ throw new CDOException("Unable to aquire write lock on balanced tree " + root.getPath());
+ }
+
+ private void addObjectToRoot(EObject object)
+ {
+ CDOResource firstResource = null;
+
+ Queue<CDOResourceFolder> folders = new LinkedList<CDOResourceFolder>();
+ CDOResourceFolder folder = root;
+ while (folder != null)
+ {
+ EList<CDOResourceNode> nodes = folder.getNodes();
+ for (CDOResourceNode node : nodes)
+ {
+ if (node instanceof CDOResourceFolder)
+ {
+ folders.offer((CDOResourceFolder)node);
+ }
+ else if (node instanceof CDOResource)
+ {
+ if (firstResource == null)
+ {
+ firstResource = (CDOResource)node;
+ }
+
+ if (addObjectToResource(object, (CDOResource)node))
+ {
+ return;
+ }
+ }
+ }
+
+ int size = nodes.size();
+ if (size < folderCapacity)
+ {
+ String name = getResourceName(size + 1);
+ CDOResource resource = folder.addResource(name);
+
+ if (TRACE)
+ {
+ IOUtil.OUT().println("Added resource " + resource.getPath());
+ }
+
+ addObjectToResource(object, resource);
+ return;
+ }
+
+ folder = folders.poll();
+ }
+
+ CDOResource resource = addObjectWithSplit(firstResource);
+ addObjectToResource(object, resource);
+ }
+
+ private boolean addObjectToResource(EObject object, CDOResource resource)
+ {
+ EList<EObject> contents = resource.getContents();
+ if (contents.size() < resourceCapacity)
+ {
+ contents.add(object);
+ if (TRACE)
+ {
+ IOUtil.OUT().println("Added object to resource " + resource.getPath());
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ private CDOResource addObjectWithSplit(CDOResource resource)
+ {
+ String path = resource.getPath();
+ String name = resource.getName();
+ resource.setName("_" + name);
+
+ CDOResourceFolder splitFolder = resource.getFolder().addResourceFolder(name);
+ splitFolder.getNodes().add(resource);
+ resource.setName(getResourceName(1));
+ if (TRACE)
+ {
+ IOUtil.OUT().println("Moved resource " + path + " to " + resource.getPath());
+ }
+
+ return splitFolder.addResource(getResourceName(2));
+ }
+
+ private String getResourceName(int n)
+ {
+ return Integer.toString(n);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
index dafa7c791e..da4a45e3ef 100644
--- a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
@@ -1,3180 +1,3195 @@
-/*
- * 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
- * Victor Roldan Betancort - maintenance
- * Gonzague Reydet - bug 298334
- * Andre Dietisheim - bug 256649
- * Caspar De Groot - bug 290032 (Sticky views)
- */
-package org.eclipse.emf.internal.cdo.transaction;
-
-import org.eclipse.emf.cdo.CDOObject;
-import org.eclipse.emf.cdo.CDOState;
-import org.eclipse.emf.cdo.common.CDOCommonRepository;
-import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
-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.CDOChangeSet;
-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.CDOIDGenerator;
-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.lob.CDOLob;
-import org.eclipse.emf.cdo.common.lob.CDOLobStore;
-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.CDOPackageRegistry;
-import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
-import org.eclipse.emf.cdo.common.model.EMFUtil;
-import org.eclipse.emf.cdo.common.protocol.CDODataInput;
-import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
-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.CDORevision;
-import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
-import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
-import org.eclipse.emf.cdo.common.revision.CDORevisionProvider;
-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.CDOException;
-import org.eclipse.emf.cdo.eresource.CDOResource;
-import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
-import org.eclipse.emf.cdo.eresource.CDOResourceNode;
-import org.eclipse.emf.cdo.eresource.EresourceFactory;
-import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl;
-import org.eclipse.emf.cdo.eresource.impl.CDOResourceNodeImpl;
-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.protocol.CDODataInputImpl;
-import org.eclipse.emf.cdo.internal.common.protocol.CDODataOutputImpl;
-import org.eclipse.emf.cdo.internal.common.revision.CDOListWithElementProxiesImpl;
-import org.eclipse.emf.cdo.session.CDORepositoryInfo;
-import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
-import org.eclipse.emf.cdo.spi.common.commit.CDORevisionAvailabilityInfo;
-import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
-import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
-import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
-import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
-import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
-import org.eclipse.emf.cdo.transaction.CDOCommitContext;
-import org.eclipse.emf.cdo.transaction.CDOConflictResolver;
-import org.eclipse.emf.cdo.transaction.CDOConflictResolver2;
-import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler1;
-import org.eclipse.emf.cdo.transaction.CDOMerger;
-import org.eclipse.emf.cdo.transaction.CDOSavepoint;
-import org.eclipse.emf.cdo.transaction.CDOTransaction;
-import org.eclipse.emf.cdo.transaction.CDOTransactionConflictEvent;
-import org.eclipse.emf.cdo.transaction.CDOTransactionFinishedEvent;
-import org.eclipse.emf.cdo.transaction.CDOTransactionHandler;
-import org.eclipse.emf.cdo.transaction.CDOTransactionHandler1;
-import org.eclipse.emf.cdo.transaction.CDOTransactionHandler2;
-import org.eclipse.emf.cdo.transaction.CDOTransactionHandler3;
-import org.eclipse.emf.cdo.transaction.CDOTransactionHandlerBase;
-import org.eclipse.emf.cdo.transaction.CDOTransactionStartedEvent;
-import org.eclipse.emf.cdo.transaction.CDOUserSavepoint;
-import org.eclipse.emf.cdo.util.CDOURIUtil;
-import org.eclipse.emf.cdo.util.CDOUtil;
-import org.eclipse.emf.cdo.util.CommitException;
-import org.eclipse.emf.cdo.util.LegacyModeNotEnabledException;
-import org.eclipse.emf.cdo.util.ObjectNotFoundException;
-import org.eclipse.emf.cdo.view.CDOView;
-
-import org.eclipse.emf.internal.cdo.bundle.OM;
-import org.eclipse.emf.internal.cdo.messages.Messages;
-import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder;
-import org.eclipse.emf.internal.cdo.object.CDOObjectMerger;
-import org.eclipse.emf.internal.cdo.object.CDOObjectWrapper;
-import org.eclipse.emf.internal.cdo.query.CDOQueryImpl;
-import org.eclipse.emf.internal.cdo.util.CommitIntegrityCheck;
-import org.eclipse.emf.internal.cdo.util.CompletePackageClosure;
-import org.eclipse.emf.internal.cdo.util.IPackageClosure;
-import org.eclipse.emf.internal.cdo.view.CDOStateMachine;
-import org.eclipse.emf.internal.cdo.view.CDOViewImpl;
-
-import org.eclipse.net4j.util.CheckUtil;
-import org.eclipse.net4j.util.ObjectUtil;
-import org.eclipse.net4j.util.WrappedException;
-import org.eclipse.net4j.util.collection.ByteArrayWrapper;
-import org.eclipse.net4j.util.collection.ConcurrentArray;
-import org.eclipse.net4j.util.collection.Pair;
-import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
-import org.eclipse.net4j.util.event.IEvent;
-import org.eclipse.net4j.util.event.IListener;
-import org.eclipse.net4j.util.io.ExtendedDataInputStream;
-import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
-import org.eclipse.net4j.util.om.trace.ContextTracer;
-import org.eclipse.net4j.util.options.OptionsEvent;
-import org.eclipse.net4j.util.transaction.TransactionException;
-
-import org.eclipse.emf.common.notify.NotificationChain;
-import org.eclipse.emf.common.util.URI;
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.EPackage;
-import org.eclipse.emf.ecore.EReference;
-import org.eclipse.emf.ecore.EStructuralFeature;
-import org.eclipse.emf.ecore.EStructuralFeature.Setting;
-import org.eclipse.emf.ecore.InternalEObject;
-import org.eclipse.emf.ecore.InternalEObject.EStore;
-import org.eclipse.emf.ecore.impl.EClassImpl.FeatureSubsetSupplier;
-import org.eclipse.emf.ecore.util.EContentsEList.FeatureIterator;
-import org.eclipse.emf.ecore.util.ECrossReferenceEList;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
-import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
-import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
-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.core.runtime.IProgressMonitor;
-import org.eclipse.core.runtime.NullProgressMonitor;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * @author Eike Stepper
- */
-public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransaction
-{
- private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_TRANSACTION, CDOTransactionImpl.class);
-
- private Object transactionHandlersLock = new Object();
-
- private ConcurrentArray<CDOTransactionHandler1> transactionHandlers1 = new ConcurrentArray<CDOTransactionHandler1>()
- {
- @Override
- protected CDOTransactionHandler1[] newArray(int length)
- {
- return new CDOTransactionHandler1[length];
- }
- };
-
- private ConcurrentArray<CDOTransactionHandler2> transactionHandlers2 = new ConcurrentArray<CDOTransactionHandler2>()
- {
- @Override
- protected CDOTransactionHandler2[] newArray(int length)
- {
- return new CDOTransactionHandler2[length];
- }
- };
-
- private InternalCDOSavepoint lastSavepoint = createSavepoint(null);
-
- private InternalCDOSavepoint firstSavepoint = lastSavepoint;
-
- private boolean dirty;
-
- private int conflict;
-
- private CDOTransactionStrategy transactionStrategy;
-
- private CDOIDGenerator idGenerator;
-
- private volatile long lastCommitTime = UNSPECIFIED_DATE;
-
- private String commitComment;
-
- // Bug 283985 (Re-attachment)
- private final ThreadLocal<Boolean> providingCDOID = new InheritableThreadLocal<Boolean>()
- {
- @Override
- protected Boolean initialValue()
- {
- return false;
- }
- };
-
- /**
- * An optional set to specify which objects in this TX are to be committed by {@link #commit()}
- */
- private Set<? extends EObject> committables;
-
- /**
- * A map to hold a clean (i.e. unmodified) revision for objects that have been modified or detached.
- */
- private Map<InternalCDOObject, InternalCDORevision> cleanRevisions = new ResolvingRevisionMap();
-
- public CDOTransactionImpl(CDOBranch branch)
- {
- super(branch, UNSPECIFIED_DATE);
- }
-
- public CDOTransactionImpl(String durableLockingID)
- {
- super(durableLockingID);
- }
-
- /**
- * @since 2.0
- */
- @Override
- public OptionsImpl options()
- {
- return (OptionsImpl)super.options();
- }
-
- /**
- * @since 2.0
- */
- @Override
- protected OptionsImpl createOptions()
- {
- return new OptionsImpl();
- }
-
- @Override
- public boolean isReadOnly()
- {
- return false;
- }
-
- @Override
- public synchronized boolean setBranchPoint(CDOBranchPoint branchPoint)
- {
- if (branchPoint.getTimeStamp() != UNSPECIFIED_DATE)
- {
- throw new IllegalArgumentException("Changing the target time is not supported by transactions");
- }
-
- if (isDirty() && !getBranch().equals(branchPoint.getBranch()))
- {
- throw new IllegalStateException("Changing the target branch is impossible while transaction is dirty");
- }
-
- return super.setBranchPoint(branchPoint);
- }
-
- public void addTransactionHandler(CDOTransactionHandlerBase handler)
- {
- synchronized (transactionHandlersLock)
- {
- if (handler instanceof CDOTransactionHandler1)
- {
- transactionHandlers1.add((CDOTransactionHandler1)handler);
- }
-
- if (handler instanceof CDOTransactionHandler2)
- {
- transactionHandlers2.add((CDOTransactionHandler2)handler);
- }
- }
- }
-
- public void removeTransactionHandler(CDOTransactionHandlerBase handler)
- {
- synchronized (transactionHandlersLock)
- {
- if (handler instanceof CDOTransactionHandler1)
- {
- transactionHandlers1.remove((CDOTransactionHandler1)handler);
- }
-
- if (handler instanceof CDOTransactionHandler2)
- {
- transactionHandlers2.remove((CDOTransactionHandler2)handler);
- }
- }
- }
-
- public CDOTransactionHandler[] getTransactionHandlers()
- {
- Set<CDOTransactionHandler> result = new HashSet<CDOTransactionHandler>();
- synchronized (transactionHandlersLock)
- {
- CDOTransactionHandler1[] handlers1 = transactionHandlers1.get();
- if (handlers1 != null)
- {
- for (CDOTransactionHandler1 handler : handlers1)
- {
- if (handler instanceof CDOTransactionHandler)
- {
- result.add((CDOTransactionHandler)handler);
- }
- }
- }
-
- CDOTransactionHandler2[] handlers2 = transactionHandlers2.get();
- if (handlers2 != null)
- {
- for (CDOTransactionHandler2 handler : handlers2)
- {
- if (handler instanceof CDOTransactionHandler)
- {
- result.add((CDOTransactionHandler)handler);
- }
- }
- }
- }
-
- return result.toArray(new CDOTransactionHandler[result.size()]);
- }
-
- public CDOTransactionHandler1[] getTransactionHandlers1()
- {
- synchronized (transactionHandlersLock)
- {
- return transactionHandlers1.get();
- }
- }
-
- public CDOTransactionHandler2[] getTransactionHandlers2()
- {
- synchronized (transactionHandlersLock)
- {
- return transactionHandlers2.get();
- }
- }
-
- @Override
- public synchronized boolean isDirty()
- {
- if (isClosed())
- {
- return false;
- }
-
- return dirty;
- }
-
- @Override
- public synchronized boolean hasConflict()
- {
- checkActive();
- return conflict != 0;
- }
-
- public void setConflict(InternalCDOObject object)
- {
- IEvent event = null;
- synchronized (this)
- {
- event = new ConflictEvent(object, conflict == 0);
- ++conflict;
- }
-
- fireEvent(event);
- }
-
- /**
- * @since 2.0
- */
- public synchronized Set<CDOObject> getConflicts()
- {
- Set<CDOObject> conflicts = new HashSet<CDOObject>();
- for (CDOObject object : getDirtyObjects().values())
- {
- if (object.cdoConflict())
- {
- conflicts.add(object);
- }
- }
-
- for (CDOObject object : getDetachedObjects().values())
- {
- if (object.cdoConflict())
- {
- conflicts.add(object);
- }
- }
-
- return conflicts;
- }
-
- public synchronized CDOChangeSetData getChangeSetData()
- {
- checkActive();
- return lastSavepoint.getAllChangeSetData();
- }
-
- public synchronized CDOChangeSetData merge(CDOBranchPoint source, CDOMerger merger)
- {
- return merge(source, null, merger);
- }
-
- public synchronized CDOChangeSetData merge(CDOBranchPoint source, CDOBranchPoint sourceBase, CDOMerger merger)
- {
- if (isDirty())
- {
- throw new IllegalStateException("Merging into dirty transactions not yet supported");
- }
-
- long now = getLastUpdateTime();
- CDOBranchPoint target = getBranch().getPoint(now);
-
- if (source.getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE)
- {
- source = source.getBranch().getPoint(now);
- }
-
- if (CDOBranchUtil.isContainedBy(source, target))
- {
- throw new IllegalArgumentException("Source is already contained in " + target);
- }
-
- if (sourceBase != null && CDOBranchUtil.isContainedBy(sourceBase, source))
- {
- throw new IllegalArgumentException("Source base is not contained in " + source);
- }
-
- CDOBranchPoint ancestor = CDOBranchUtil.getAncestor(target, source);
-
- InternalCDOSession session = getSession();
- CDORevisionAvailabilityInfo ancestorInfo = session.createRevisionAvailabilityInfo(ancestor);
- CDORevisionAvailabilityInfo targetInfo = session.createRevisionAvailabilityInfo(target);
- CDORevisionAvailabilityInfo sourceInfo = session.createRevisionAvailabilityInfo(source);
- CDORevisionAvailabilityInfo baseInfo = sourceBase != null ? session.createRevisionAvailabilityInfo(sourceBase)
- : null;
-
- CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
- Set<CDOID> ids = sessionProtocol.loadMergeData(targetInfo, sourceInfo, ancestorInfo, baseInfo);
-
- session.cacheRevisions(targetInfo);
- session.cacheRevisions(sourceInfo);
- session.cacheRevisions(ancestorInfo);
-
- if (baseInfo != null)
- {
- session.cacheRevisions(baseInfo);
- }
- else
- {
- baseInfo = ancestorInfo;
- }
-
- CDOChangeSet targetChanges = createChangeSet(ids, ancestorInfo, targetInfo);
- CDOChangeSet sourceChanges = createChangeSet(ids, baseInfo, sourceInfo);
-
- CDOChangeSetData result = merger.merge(targetChanges, sourceChanges);
- if (result == null)
- {
- return null;
- }
-
- return applyChangeSet(result, ancestorInfo, targetInfo, source, false).getChangeSetData();
- }
-
- private CDOChangeSet createChangeSet(Set<CDOID> ids, CDORevisionAvailabilityInfo startInfo,
- CDORevisionAvailabilityInfo endInfo)
- {
- CDOChangeSetData data = CDORevisionUtil.createChangeSetData(ids, startInfo, endInfo);
- return CDORevisionUtil.createChangeSet(startInfo.getBranchPoint(), endInfo.getBranchPoint(), data);
- }
-
- @Deprecated
- public Pair<CDOChangeSetData, Pair<Map<CDOID, CDOID>, List<CDOID>>> applyChangeSetData(
- CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider,
- CDOBranchPoint source)
- {
- throw new UnsupportedOperationException();
- }
-
- public synchronized ApplyChangeSetResult applyChangeSet(CDOChangeSetData changeSetData,
- CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, CDOBranchPoint source,
- boolean keepVersions) throws ChangeSetOutdatedException
- {
- ApplyChangeSetResult result = new ApplyChangeSetResult();
-
- // Merges from local offline branches may require additional ID mappings: localID -> tempID
- if (source != null && source.getBranch().isLocal())
- {
- applyLocalIDMapping(changeSetData, result);
- }
-
- // New objects
- applyNewObjects(changeSetData.getNewObjects(), result.getChangeSetData().getNewObjects());
-
- // Detached objects
- Set<CDOObject> detachedSet = applyDetachedObjects(changeSetData.getDetachedObjects(), result.getChangeSetData()
- .getDetachedObjects());
-
- // Changed objects
- Map<CDOID, InternalCDORevision> oldRevisions = applyChangedObjects(changeSetData.getChangedObjects(),
- ancestorProvider, targetProvider, keepVersions, result.getChangeSetData().getChangedObjects());
-
- // Delta notifications
- Collection<CDORevisionDelta> notificationDeltas = lastSavepoint.getRevisionDeltas().values();
- if (!notificationDeltas.isEmpty() || !detachedSet.isEmpty())
- {
- sendDeltaNotifications(notificationDeltas, detachedSet, oldRevisions);
- }
-
- return result;
- }
-
- private void applyLocalIDMapping(CDOChangeSetData changeSetData, ApplyChangeSetResult result)
- {
- Map<CDOID, CDOID> idMappings = result.getIDMappings();
-
- // Collect needed ID mappings
- for (CDOIDAndVersion key : changeSetData.getNewObjects())
- {
- InternalCDORevision revision = (InternalCDORevision)key;
- if (revision.getBranch().isLocal())
- {
- CDOID oldID = revision.getID();
- CDOID newID = createIDForNewObject(null);
- idMappings.put(oldID, newID);
-
- revision.setID(newID);
- revision.setVersion(0);
- }
- }
-
- if (!idMappings.isEmpty())
- {
- // Apply collected ID mappings
- CDOIDMapper idMapper = new CDOIDMapper(idMappings);
- idMapper.setAllowUnmappedTempIDs(true);
-
- for (CDOIDAndVersion key : changeSetData.getNewObjects())
- {
- InternalCDORevision revision = (InternalCDORevision)key;
- revision.adjustReferences(idMapper);
- }
-
- for (CDORevisionKey key : changeSetData.getChangedObjects())
- {
- InternalCDORevisionDelta revisionDelta = (InternalCDORevisionDelta)key;
- if (revisionDelta.adjustReferences(idMapper))
- {
- result.getAdjustedObjects().add(revisionDelta.getID());
- }
- }
- }
- }
-
- private void applyNewObjects(List<CDOIDAndVersion> newObjects, List<CDOIDAndVersion> result)
- {
- for (CDOIDAndVersion key : newObjects)
- {
- InternalCDORevision revision = (InternalCDORevision)key;
- CDOID id = revision.getID();
- if (getObjectIfExists(id) == null)
- {
- InternalCDOObject object = newInstance(revision.getEClass());
- object.cdoInternalSetView(this);
- object.cdoInternalSetRevision(revision);
- object.cdoInternalSetID(id);
- object.cdoInternalSetState(CDOState.NEW);
- object.cdoInternalPostLoad();
-
- registerObject(object);
- registerAttached(object, true);
- result.add(revision);
- dirty = true;
- }
- }
- }
-
- private Set<CDOObject> applyDetachedObjects(List<CDOIDAndVersion> detachedObjects, List<CDOIDAndVersion> result)
- {
- Set<CDOObject> detachedSet = new HashSet<CDOObject>();
- for (CDOIDAndVersion key : detachedObjects)
- {
- CDOID id = key.getID();
- InternalCDOObject object = getObjectIfExists(id);
- if (object != null)
- {
- result.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION));
- CDOStateMachine.INSTANCE.detach(object);
- detachedSet.add(object);
- dirty = true;
- }
- }
-
- return detachedSet;
- }
-
- private Map<CDOID, InternalCDORevision> applyChangedObjects(List<CDORevisionKey> changedObjects,
- CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, boolean keepVersions,
- List<CDORevisionKey> result) throws ChangeSetOutdatedException
- {
- Map<CDOID, InternalCDORevision> oldRevisions = new HashMap<CDOID, InternalCDORevision>();
-
- Map<CDOID, CDOObject> dirtyObjects = lastSavepoint.getDirtyObjects();
- ConcurrentMap<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas();
-
- for (CDORevisionKey key : changedObjects)
- {
- InternalCDORevisionDelta ancestorGoalDelta = (InternalCDORevisionDelta)key;
- ancestorGoalDelta.setTarget(null);
- CDOID id = ancestorGoalDelta.getID();
- InternalCDORevision ancestorRevision = (InternalCDORevision)ancestorProvider.getRevision(id);
-
- InternalCDOObject object = getObject(id);
- boolean revisionChanged = false;
-
- InternalCDORevision targetRevision = object.cdoRevision();
- if (targetRevision == null)
- {
- targetRevision = (InternalCDORevision)targetProvider.getRevision(id);
- object.cdoInternalSetRevision(targetRevision);
- revisionChanged = true;
- }
-
- oldRevisions.put(id, targetRevision);
-
- InternalCDORevision goalRevision = ancestorRevision.copy();
- goalRevision.setBranchPoint(this);
- if (!keepVersions)
- {
- goalRevision.setVersion(targetRevision.getVersion());
- }
-
- goalRevision.setRevised(CDOBranchPoint.UNSPECIFIED_DATE);
- ancestorGoalDelta.apply(goalRevision);
-
- InternalCDORevisionDelta targetGoalDelta = goalRevision.compare(targetRevision);
- targetGoalDelta.setTarget(null);
-
- if (!targetGoalDelta.isEmpty())
- {
- if (keepVersions && targetGoalDelta.getVersion() != ancestorRevision.getVersion())
- {
- throw new ChangeSetOutdatedException();
- }
-
- revisionDeltas.put(id, targetGoalDelta);
- result.add(targetGoalDelta);
-
- // handle reattached objects.
- if (lastSavepoint.getDetachedObjects().containsKey(id))
- {
- CDOStateMachine.INSTANCE.attach(object, this);
- }
-
- object.cdoInternalSetState(CDOState.DIRTY);
- object.cdoInternalSetRevision(goalRevision);
- revisionChanged = true;
-
- dirtyObjects.put(id, object);
- dirty = true;
- }
-
- if (revisionChanged)
- {
- object.cdoInternalPostLoad();
- }
- }
-
- return oldRevisions;
- }
-
- private InternalCDOObject getObjectIfExists(CDOID id)
- {
- try
- {
- return getObject(id);
- }
- catch (ObjectNotFoundException ex)
- {
- return null;
- }
- }
-
- /*
- * Synchronized through InvalidationRunnable.run()
- */
- @Override
- protected synchronized void handleConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
- List<CDORevisionDelta> deltas)
- {
- CDOConflictResolver[] resolvers = options().getConflictResolvers();
- if (resolvers.length == 0)
- {
- return;
- }
-
- // Remember original state to be able to restore it after an exception
- List<CDOState> states = new ArrayList<CDOState>(conflicts.size());
- List<CDORevision> revisions = new ArrayList<CDORevision>(conflicts.size());
- for (CDOObject conflict : conflicts.keySet())
- {
- states.add(conflict.cdoState());
- revisions.add(conflict.cdoRevision());
- }
-
- int resolved = 0;
-
- try
- {
- Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> remaining = new HashMap<CDOObject, Pair<CDORevision, CDORevisionDelta>>(
- conflicts);
- for (CDOConflictResolver resolver : resolvers)
- {
- if (resolver instanceof CDOConflictResolver2)
- {
- ((CDOConflictResolver2)resolver).resolveConflicts(Collections.unmodifiableMap(remaining), deltas);
- }
- else
- {
- resolver.resolveConflicts(Collections.unmodifiableSet(remaining.keySet()));
- }
-
- for (Iterator<CDOObject> it = remaining.keySet().iterator(); it.hasNext();)
- {
- CDOObject object = it.next();
- if (!object.cdoConflict())
- {
- ++resolved;
- it.remove();
- }
- }
- }
- }
- catch (Exception ex)
- {
- // Restore original state
- Iterator<CDOState> state = states.iterator();
- Iterator<CDORevision> revision = revisions.iterator();
- for (CDOObject object : conflicts.keySet())
- {
- ((InternalCDOObject)object).cdoInternalSetState(state.next());
- ((InternalCDOObject)object).cdoInternalSetRevision(revision.next());
- }
-
- throw WrappedException.wrap(ex);
- }
-
- conflict -= resolved;
- }
-
- /**
- * @deprecated {@link #createIDForNewObject(EObject object)} is called since 4.1.
- */
- @Deprecated
- public synchronized CDOIDTemp getNextTemporaryID()
- {
- throw new UnsupportedOperationException();
- }
-
- public CDOID createIDForNewObject(EObject object)
- {
- return idGenerator.generateCDOID(object);
- }
-
- public synchronized CDOResourceFolder createResourceFolder(String path)
- {
- CDOResourceFolder folder = EresourceFactory.eINSTANCE.createCDOResourceFolder();
- int pos = path.lastIndexOf(CDOURIUtil.SEGMENT_SEPARATOR_CHAR);
- if (pos <= 0)
- {
- String name = path.substring(pos == 0 ? 1 : 0);
- folder.setName(name);
-
- getRootResource().getContents().add(folder);
- }
- else
- {
- String name = path.substring(pos + 1);
- folder.setName(name);
-
- path = path.substring(0, pos);
- CDOResourceNode parent = getResourceNode(path);
- if (parent instanceof CDOResourceFolder)
- {
- ((CDOResourceFolder)parent).getNodes().add(folder);
- }
- else
- {
- throw new CDOException("Parent is not a folder: " + parent);
- }
- }
-
- return folder;
- }
-
- public synchronized CDOResource createResource(String path)
- {
- checkActive();
- URI uri = CDOURIUtil.createResourceURI(this, path);
- return (CDOResource)getResourceSet().createResource(uri);
- }
-
- public synchronized CDOResource getOrCreateResource(String path)
- {
- checkActive();
-
- try
- {
- CDOID id = getResourceNodeID(path);
- if (!CDOIDUtil.isNull(id))
- {
- return (CDOResource)getObject(id);
- }
- }
- catch (Exception ignore)
- {
- // Just create the missing resource
- }
-
- return createResource(path);
- }
-
- /**
- * @since 2.0
- */
- @Override
- public synchronized void attachResource(CDOResourceImpl resource)
- {
- if (resource.isExisting())
- {
- super.attachResource(resource);
- }
- else
- {
- // ResourceSet.createResource(uri) was called!!
- attachNewResource(resource);
- }
- }
-
- private void attachNewResource(CDOResourceImpl resource)
- {
- URI uri = resource.getURI();
- List<String> names = CDOURIUtil.analyzePath(uri);
- String resourceName = names.isEmpty() ? null : names.remove(names.size() - 1);
-
- CDOResourceFolder folder = getOrCreateResourceFolder(names);
- attachNewResourceNode(folder, resourceName, resource);
- }
-
- public synchronized CDOResourceFolder getOrCreateResourceFolder(String path)
- {
- checkActive();
-
- try
- {
- CDOID id = getResourceNodeID(path);
- if (!CDOIDUtil.isNull(id))
- {
- return (CDOResourceFolder)getObject(id);
- }
- }
- catch (Exception ignore)
- {
- // Just create the missing folder
- }
-
- return createResourceFolder(path);
- }
-
- /**
- * @return never <code>null</code>;
- * @since 2.0
- */
- public synchronized CDOResourceFolder getOrCreateResourceFolder(List<String> names)
- {
- CDOResourceFolder folder = null;
- for (String name : names)
- {
- CDOResourceNode node;
-
- try
- {
- CDOID folderID = folder == null ? null : folder.cdoID();
- node = getResourceNode(folderID, name);
- }
- catch (CDOException ex)
- {
- node = EresourceFactory.eINSTANCE.createCDOResourceFolder();
- attachNewResourceNode(folder, name, node);
- }
-
- if (node instanceof CDOResourceFolder)
- {
- folder = (CDOResourceFolder)node;
- }
- else
- {
- throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.0"), node)); //$NON-NLS-1$
- }
- }
-
- return folder;
- }
-
- private void attachNewResourceNode(CDOResourceFolder folder, String name, CDOResourceNode newNode)
- {
- CDOResourceNodeImpl node = (CDOResourceNodeImpl)newNode;
- node.basicSetName(name, false);
- if (folder == null)
- {
- if (node.isRoot())
- {
- CDOStateMachine.INSTANCE.attach(node, this);
- }
- else
- {
- getRootResource().getContents().add(node);
- }
- }
- else
- {
- node.basicSetFolder(folder, false);
- }
- }
-
- /**
- * @since 2.0
- */
- public synchronized void detach(CDOResourceImpl cdoResource)
- {
- CDOStateMachine.INSTANCE.detach(cdoResource);
- }
-
- /**
- * @since 4.1
- */
- public InternalCDOSavepoint getFirstSavepoint()
- {
- return firstSavepoint;
- }
-
- /**
- * @since 2.0
- */
- public synchronized InternalCDOSavepoint getLastSavepoint()
- {
- checkActive();
- return lastSavepoint;
- }
-
- /**
- * @since 2.0
- */
- public synchronized CDOTransactionStrategy getTransactionStrategy()
- {
- if (transactionStrategy == null)
- {
- transactionStrategy = CDOTransactionStrategy.DEFAULT;
- transactionStrategy.setTarget(this);
- }
-
- return transactionStrategy;
- }
-
- /**
- * @since 2.0
- */
- public synchronized void setTransactionStrategy(CDOTransactionStrategy transactionStrategy)
- {
- if (this.transactionStrategy != null)
- {
- this.transactionStrategy.unsetTarget(this);
- }
-
- this.transactionStrategy = transactionStrategy;
-
- if (this.transactionStrategy != null)
- {
- this.transactionStrategy.setTarget(this);
- }
- }
-
- /**
- * @since 2.0
- */
- @Override
- protected synchronized CDOID getRootOrTopLevelResourceNodeID(String name)
- {
- if (dirty)
- {
- CDOResourceNode node = getRootResourceNode(name, getDirtyObjects().values());
- if (node != null)
- {
- return node.cdoID();
- }
-
- node = getRootResourceNode(name, getNewObjects().values());
- if (node != null)
- {
- return node.cdoID();
- }
- }
-
- CDOID id = super.getRootOrTopLevelResourceNodeID(name);
- if (getLastSavepoint().getAllDetachedObjects().containsKey(id) || getDirtyObjects().containsKey(id))
- {
- throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.1"), name)); //$NON-NLS-1$
- }
-
- return id;
- }
-
- private CDOResourceNode getRootResourceNode(String name, Collection<? extends CDOObject> objects)
- {
- for (CDOObject object : objects)
- {
- if (object instanceof CDOResourceNode)
- {
- CDOResourceNode node = (CDOResourceNode)object;
- if (node.getFolder() == null && ObjectUtil.equals(name, node.getName()))
- {
- return node;
- }
- }
- }
-
- return null;
- }
-
- /**
- * @since 2.0
- */
- @Override
- public synchronized InternalCDOObject getObject(CDOID id, boolean loadOnDemand)
- {
- checkActive();
- if (CDOIDUtil.isNull(id))
- {
- return null;
- }
-
- if (isObjectNew(id) && isObjectDetached(id))
- {
- throw new ObjectNotFoundException(id, this);
- }
-
- return super.getObject(id, loadOnDemand);
- }
-
- @Override
- public boolean isObjectNew(CDOID id)
- {
- return lastSavepoint.isNewObject(id);
- }
-
- private boolean isObjectDetached(CDOID id)
- {
- return lastSavepoint.getAllDetachedObjects().containsKey(id);
- }
-
- /**
- * @since 2.0
- */
- public synchronized InternalCDOCommitContext createCommitContext()
- {
- return new CDOCommitContextImpl(this);
- }
-
- /**
- * @since 2.0
- */
- public synchronized CDOCommitInfo commit(IProgressMonitor progressMonitor) throws CommitException
- {
- try
- {
- checkActive();
- if (hasConflict())
- {
- throw new CommitException(Messages.getString("CDOTransactionImpl.2")); //$NON-NLS-1$
- }
-
- if (progressMonitor == null)
- {
- progressMonitor = new NullProgressMonitor();
- }
-
- CDOTransactionStrategy transactionStrategy = getTransactionStrategy();
- CDOCommitInfo info = transactionStrategy.commit(this, progressMonitor);
- if (info != null)
- {
- lastCommitTime = info.getTimeStamp();
- }
-
- return info;
- }
- catch (CommitException ex)
- {
- throw ex;
- }
- catch (Throwable t)
- {
- throw new CommitException(t);
- }
- }
-
- public synchronized CDOCommitInfo commit() throws CommitException
- {
- return commit(null);
- }
-
- /**
- * @since 2.0
- */
- public synchronized void rollback()
- {
- checkActive();
- getTransactionStrategy().rollback(this, firstSavepoint);
- cleanUp(null);
- }
-
- private void removeObject(CDOID id, final CDOObject object)
- {
- ((InternalCDOObject)object).cdoInternalSetState(CDOState.TRANSIENT);
- removeObject(id);
-
- if (object instanceof CDOResource)
- {
- getViewSet().executeWithoutNotificationHandling(new Callable<Boolean>()
- {
- public Boolean call() throws Exception
- {
- getResourceSet().getResources().remove(object);
- return true;
- }
- });
- }
-
- ((InternalCDOObject)object).cdoInternalSetID(null);
- ((InternalCDOObject)object).cdoInternalSetRevision(null);
- ((InternalCDOObject)object).cdoInternalSetView(null);
- }
-
- private Set<CDOID> rollbackCompletely(CDOUserSavepoint savepoint)
- {
- Set<CDOID> idsOfNewObjectsWithDeltas = new HashSet<CDOID>();
-
- // Start from the last savepoint and come back up to the active
- for (InternalCDOSavepoint itrSavepoint = lastSavepoint; itrSavepoint != null; itrSavepoint = itrSavepoint
- .getPreviousSavepoint())
- {
- // Rollback new objects attached after the save point
- Map<CDOID, CDOObject> newObjectsMap = itrSavepoint.getNewObjects();
- for (CDOID id : newObjectsMap.keySet())
- {
- CDOObject object = newObjectsMap.get(id);
- removeObject(id, object);
- }
-
- // Rollback new objects re-attached after the save point
- Map<CDOID, CDOObject> reattachedObjectsMap = itrSavepoint.getReattachedObjects();
- Set<CDOID> detachedIDs = itrSavepoint.getDetachedObjects().keySet();
- for (CDOObject reattachedObject : reattachedObjectsMap.values())
- {
- CDOID id = reattachedObject.cdoID();
- if (!detachedIDs.contains(id))
- {
- removeObject(id, reattachedObject);
- }
- }
-
- Map<CDOID, CDORevisionDelta> revisionDeltas = itrSavepoint.getRevisionDeltas();
- if (!revisionDeltas.isEmpty())
- {
- for (CDORevisionDelta dirtyObject : revisionDeltas.values())
- {
- CDOID id = dirtyObject.getID();
- if (isObjectNew(id))
- {
- idsOfNewObjectsWithDeltas.add(id);
- }
- }
- }
-
- // Rollback all detached objects
- Map<CDOID, CDOObject> detachedObjectsMap = itrSavepoint.getDetachedObjects();
- if (!detachedObjectsMap.isEmpty())
- {
- for (Entry<CDOID, CDOObject> detachedObjectEntry : detachedObjectsMap.entrySet())
- {
- CDOID id = detachedObjectEntry.getKey();
- if (isObjectNew(id))
- {
- idsOfNewObjectsWithDeltas.add(id);
- }
- else
- {
- InternalCDOObject detachedObject = (InternalCDOObject)detachedObjectEntry.getValue();
- InternalCDORevision cleanRev = cleanRevisions.get(detachedObject);
- cleanObject(detachedObject, cleanRev);
- }
- }
- }
-
- for (Entry<CDOID, CDOObject> entryDirtyObject : itrSavepoint.getDirtyObjects().entrySet())
- {
- CDOID id = entryDirtyObject.getKey();
- if (!isObjectNew(id))
- {
- InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirtyObject.getValue();
-
- // Bug 283985 (Re-attachment): Skip objects that were reattached, because
- // they were already reset to TRANSIENT earlier in this method
- if (!reattachedObjectsMap.values().contains(internalDirtyObject))
- {
- CDOStateMachine.INSTANCE.rollback(internalDirtyObject);
- }
- }
- }
-
- if (savepoint == itrSavepoint)
- {
- break;
- }
- }
-
- return idsOfNewObjectsWithDeltas;
- }
-
- private void loadSavepoint(CDOSavepoint savepoint, Set<CDOID> idsOfNewObjectWithDeltas)
- {
- Map<CDOID, CDOObject> dirtyObjects = getDirtyObjects();
- Map<CDOID, CDOObject> newObjMaps = getNewObjects();
- Map<CDOID, CDORevision> newBaseRevision = getBaseNewObjects();
- Map<CDOID, CDOObject> detachedObjects = getDetachedObjects();
-
- // Reload the objects (NEW) with their base.
- for (CDOID id : idsOfNewObjectWithDeltas)
- {
- if (detachedObjects.containsKey(id))
- {
- continue;
- }
-
- InternalCDOObject object = (InternalCDOObject)newObjMaps.get(id);
- CDORevision revision = newBaseRevision.get(id);
- if (revision != null)
- {
- object.cdoInternalSetRevision(revision.copy());
- object.cdoInternalSetView(this);
- object.cdoInternalSetID(revision.getID());
- object.cdoInternalSetState(CDOState.NEW);
-
- // Load the object from revision to EObject
- object.cdoInternalPostLoad();
- if (super.getObject(object.cdoID(), false) == null)
- {
- registerObject(object);
- }
- }
- }
-
- // We need to register back new objects that are not removed anymore there.
- for (Entry<CDOID, CDOObject> entryNewObject : newObjMaps.entrySet())
- {
- InternalCDOObject object = (InternalCDOObject)entryNewObject.getValue();
-
- // Go back to the previous state
- cleanObject(object, object.cdoRevision());
- object.cdoInternalSetState(CDOState.NEW);
- }
-
- for (Entry<CDOID, CDOObject> entryDirtyObject : dirtyObjects.entrySet())
- {
- if (detachedObjects.containsKey(entryDirtyObject.getKey()))
- {
- continue;
- }
-
- // Rollback every persisted objects
- InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirtyObject.getValue();
- cleanObject(internalDirtyObject, getRevision(entryDirtyObject.getKey(), true));
- }
-
- CDOObjectMerger merger = new CDOObjectMerger();
- for (InternalCDOSavepoint itrSavepoint = firstSavepoint; itrSavepoint != savepoint; itrSavepoint = itrSavepoint
- .getNextSavepoint())
- {
- for (CDORevisionDelta delta : itrSavepoint.getRevisionDeltas().values())
- {
- CDOID id = delta.getID();
- boolean isNew = isObjectNew(id);
- if (isNew && !idsOfNewObjectWithDeltas.contains(id) || detachedObjects.containsKey(id))
- {
- continue;
- }
-
- Map<CDOID, CDOObject> map = isNew ? newObjMaps : dirtyObjects;
- InternalCDOObject object = (InternalCDOObject)map.get(id);
-
- // Change state of the objects
- merger.merge(object, delta);
-
- // Load the object from revision to EObject
- object.cdoInternalPostLoad();
- }
- }
-
- dirty = savepoint.wasDirty();
- }
-
- /**
- * @since 2.0
- */
- public synchronized void detachObject(InternalCDOObject object)
- {
- CDOTransactionHandler1[] handlers = getTransactionHandlers1();
- for (int i = 0; i < handlers.length; i++)
- {
- CDOTransactionHandler1 handler = handlers[i];
- handler.detachingObject(this, object);
- }
-
- // deregister object
- CDOID id = object.cdoID();
- if (object.cdoState() == CDOState.NEW)
- {
- Map<CDOID, CDOObject> map = getLastSavepoint().getNewObjects();
-
- // Determine if we added object
- if (map.containsKey(id))
- {
- map.remove(id);
- }
- else
- {
- getLastSavepoint().getDetachedObjects().put(id, object);
- }
-
- // deregister object
- deregisterObject(object);
- }
- else
- {
- getLastSavepoint().getDetachedObjects().put(id, object);
-
- if (!cleanRevisions.containsKey(object))
- {
- cleanRevisions.put(object, object.cdoRevision());
- }
-
- // Object may have been reattached previously, in which case it must
- // here be removed from the collection of reattached objects
- lastSavepoint.getReattachedObjects().remove(id);
- }
-
- if (!dirty)
- {
- dirty = true;
- IListener[] listeners = getListeners();
- if (listeners != null)
- {
- fireEvent(new StartedEvent(), listeners);
- }
- }
- }
-
- /**
- * @since 2.0
- */
- public synchronized void handleRollback(InternalCDOSavepoint savepoint)
- {
- if (savepoint == null)
- {
- throw new IllegalArgumentException(Messages.getString("CDOTransactionImpl.3")); //$NON-NLS-1$
- }
-
- if (savepoint.getTransaction() != this)
- {
- throw new IllegalArgumentException(MessageFormat.format(Messages.getString("CDOTransactionImpl.4"), savepoint)); //$NON-NLS-1$
- }
-
- if (!savepoint.isValid())
- {
- throw new IllegalArgumentException(MessageFormat.format(Messages.getString("CDOTransactionImpl.6"), savepoint)); //$NON-NLS-1$
- }
-
- if (TRACER.isEnabled())
- {
- TRACER.trace("handleRollback()"); //$NON-NLS-1$
- }
-
- try
- {
- // Remember current revisions
- Map<CDOObject, CDORevision> oldRevisions = new HashMap<CDOObject, CDORevision>();
- for (CDOObject object : getDirtyObjects().values())
- {
- CDORevision oldRevision = object.cdoRevision();
- if (oldRevision != null)
- {
- oldRevisions.put(object, oldRevision);
- }
- }
-
- // Rollback objects
- Set<CDOID> idsOfNewObjectWithDeltas = rollbackCompletely(savepoint);
-
- lastSavepoint = savepoint;
- lastSavepoint.setNextSavepoint(null);
- lastSavepoint.clear();
-
- // Load from first savepoint up to current savepoint
- loadSavepoint(lastSavepoint, idsOfNewObjectWithDeltas);
-
- if (lastSavepoint == firstSavepoint && options().isAutoReleaseLocksEnabled())
- {
- CDORepositoryInfo repositoryInfo = getSession().getRepositoryInfo();
- if (isDurableView() && repositoryInfo.getState() == CDOCommonRepository.State.ONLINE
- || repositoryInfo.getType() == CDOCommonRepository.Type.MASTER)
- {
- // Unlock all objects
- unlockObjects(null, null);
- }
- }
-
- // Send notifications
- for (Entry<CDOObject, CDORevision> entry : oldRevisions.entrySet())
- {
- InternalCDOObject object = (InternalCDOObject)entry.getKey();
- if (FSMUtil.isTransient(object))
- {
- continue;
- }
-
- InternalCDORevision oldRevision = (InternalCDORevision)entry.getValue();
- InternalCDORevision newRevision = object.cdoRevision();
- if (newRevision == null)
- {
- newRevision = getRevision(oldRevision.getID(), true);
- object.cdoInternalSetRevision(newRevision);
- object.cdoInternalSetState(CDOState.CLEAN);
- }
-
- if (newRevision != null)
- {
- InternalCDORevisionDelta delta = newRevision.compare(oldRevision);
- if (!delta.isEmpty())
- {
- Set<CDOObject> detachedObjects = Collections.emptySet();
-
- CDONotificationBuilder builder = new CDONotificationBuilder(this);
- NotificationChain notification = builder.buildNotification(object, oldRevision, delta, detachedObjects);
- if (notification != null)
- {
- notification.dispatch();
- }
- }
- }
- }
-
- Map<CDOID, CDOID> idMappings = Collections.emptyMap();
- IListener[] listeners = getListeners();
- if (listeners != null)
- {
- fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.ROLLED_BACK, idMappings), listeners);
- }
-
- CDOTransactionHandler2[] handlers = getTransactionHandlers2();
- for (int i = 0; i < handlers.length; i++)
- {
- CDOTransactionHandler2 handler = handlers[i];
-
- try
- {
- handler.rolledBackTransaction(this);
- }
- catch (RuntimeException ex)
- {
- OM.LOG.error(ex);
- }
- }
- }
- catch (RuntimeException ex)
- {
- throw ex;
- }
- catch (Exception ex)
- {
- throw new TransactionException(ex);
- }
- }
-
- /**
- * @since 2.0
- */
- public synchronized InternalCDOSavepoint handleSetSavepoint()
- {
- addToBase(lastSavepoint.getNewObjects());
- lastSavepoint = createSavepoint(lastSavepoint);
- return lastSavepoint;
- }
-
- private CDOSavepointImpl createSavepoint(InternalCDOSavepoint lastSavepoint)
- {
- return new CDOSavepointImpl(this, lastSavepoint);
- }
-
- /**
- * @since 2.0
- */
- public synchronized InternalCDOSavepoint setSavepoint()
- {
- checkActive();
- return (InternalCDOSavepoint)getTransactionStrategy().setSavepoint(this);
- }
-
- private void addToBase(Map<CDOID, CDOObject> objects)
- {
- for (CDOObject object : objects.values())
- {
- // Load instance to revision
- ((InternalCDOObject)object).cdoInternalPreCommit();
- lastSavepoint.getBaseNewObjects().put(object.cdoID(), object.cdoRevision().copy());
- }
- }
-
- @Override
- protected String getClassName()
- {
- return "CDOTransaction"; //$NON-NLS-1$
- }
-
- public synchronized void registerAttached(InternalCDOObject object, boolean isNew)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Registering new object {0}", object); //$NON-NLS-1$
- }
-
- if (isNew)
- {
- registerNewPackage(object.eClass().getEPackage());
- }
-
- CDOTransactionHandler1[] handlers = getTransactionHandlers1();
- for (int i = 0; i < handlers.length; i++)
- {
- CDOTransactionHandler1 handler = handlers[i];
- handler.attachingObject(this, object);
- }
-
- if (isNew)
- {
- registerNew(lastSavepoint.getNewObjects(), object);
- }
- }
-
- private void registerNewPackage(EPackage ePackage)
- {
- CDOPackageRegistry packageRegistry = getSession().getPackageRegistry();
- if (!packageRegistry.containsKey(ePackage.getNsURI()))
- {
- packageRegistry.putEPackage(ePackage);
- }
- }
-
- /**
- * Receives notification for new and dirty objects
- */
- public synchronized void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta)
- {
- CDOID id = object.cdoID();
- boolean needToSaveFeatureDelta = true;
-
- if (object.cdoState() == CDOState.NEW)
- {
- // Register Delta for new objects only if objectA doesn't belong to
- // this savepoint
- if (getLastSavepoint().getPreviousSavepoint() == null || featureDelta == null)
- {
- needToSaveFeatureDelta = false;
- }
- else
- {
- Map<CDOID, CDOObject> map = getLastSavepoint().getNewObjects();
- needToSaveFeatureDelta = !map.containsKey(id);
- }
- }
-
- if (needToSaveFeatureDelta)
- {
- CDORevisionDelta revisionDelta = lastSavepoint.getRevisionDeltas().get(id);
- if (revisionDelta == null)
- {
- revisionDelta = CDORevisionUtil.createDelta(object.cdoRevision());
- lastSavepoint.getRevisionDeltas().put(id, revisionDelta);
- }
-
- ((InternalCDORevisionDelta)revisionDelta).addFeatureDelta(featureDelta);
- }
-
- CDOTransactionHandler1[] handlers = getTransactionHandlers1();
- for (int i = 0; i < handlers.length; i++)
- {
- CDOTransactionHandler1 handler = handlers[i];
- handler.modifyingObject(this, object, featureDelta);
- }
- }
-
- public synchronized void registerRevisionDelta(CDORevisionDelta revisionDelta)
- {
- lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta);
- }
-
- public synchronized void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta)
- {
- if (TRACER.isEnabled())
- {
- TRACER.format("Registering dirty object {0}", object); //$NON-NLS-1$
- }
-
- if (featureDelta != null)
- {
- registerFeatureDelta(object, featureDelta);
- }
-
- registerNew(lastSavepoint.getDirtyObjects(), object);
- }
-
- /**
- * TODO Simon: Should this method go to CDOSavePointImpl?
- */
- @SuppressWarnings({ "rawtypes", "unchecked" })
- private void registerNew(Map map, InternalCDOObject object)
- {
- Object old = map.put(object.cdoID(), object);
- if (old != null)
- {
- throw new IllegalStateException(MessageFormat.format(Messages.getString("CDOTransactionImpl.10"), object)); //$NON-NLS-1$
- }
-
- if (!dirty)
- {
- dirty = true;
- IListener[] listeners = getListeners();
- if (listeners != null)
- {
- fireEvent(new StartedEvent(), listeners);
- }
- }
- }
-
- public synchronized List<CDOPackageUnit> analyzeNewPackages()
- {
- CDOPackageRegistry packageRegistry = getSession().getPackageRegistry();
- Set<EPackage> usedPackages = new HashSet<EPackage>();
- Set<EPackage> usedNewPackages = new HashSet<EPackage>();
- for (CDOObject object : getNewObjects().values())
- {
- EPackage ePackage = object.eClass().getEPackage();
- if (usedPackages.add(ePackage))
- {
- EPackage topLevelPackage = EMFUtil.getTopLevelPackage(ePackage);
- if (ePackage == topLevelPackage || usedPackages.add(topLevelPackage))
- {
- // if (!CDOModelUtil.isSystemPackage(topLevelPackage))
- {
- CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(topLevelPackage);
- if (packageUnit.getState() == CDOPackageUnit.State.NEW)
- {
- usedNewPackages.add(topLevelPackage);
- }
- }
- }
- }
- }
-
- if (usedNewPackages.size() > 0)
- {
- Set<CDOPackageUnit> result = new HashSet<CDOPackageUnit>();
- for (EPackage usedNewPackage : analyzeNewPackages(usedNewPackages, packageRegistry))
- {
- CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(usedNewPackage);
- result.add(packageUnit);
- }
-
- return new ArrayList<CDOPackageUnit>(result);
- }
-
- return Collections.emptyList();
- }
-
- private static List<EPackage> analyzeNewPackages(Collection<EPackage> usedTopLevelPackages,
- CDOPackageRegistry packageRegistry)
- {
- // Determine which of the corresdonding EPackages are new
- List<EPackage> newPackages = new ArrayList<EPackage>();
-
- IPackageClosure closure = new CompletePackageClosure();
- usedTopLevelPackages = closure.calculate(usedTopLevelPackages);
-
- for (EPackage usedPackage : usedTopLevelPackages)
- {
- // if (!CDOModelUtil.isSystemPackage(usedPackage))
- {
- CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(usedPackage);
- if (packageUnit == null)
- {
- throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.11"), usedPackage)); //$NON-NLS-1$
- }
-
- if (packageUnit.getState() == CDOPackageUnit.State.NEW)
- {
- newPackages.add(usedPackage);
- }
- }
- }
-
- return newPackages;
- }
-
- private void cleanUp(CDOCommitContext commitContext)
- {
- if (commitContext == null || !commitContext.isPartialCommit())
- {
- lastSavepoint = firstSavepoint;
- firstSavepoint.clear();
- firstSavepoint.setNextSavepoint(null);
-
- cleanRevisions.clear();
- dirty = false;
- conflict = 0;
- idGenerator.reset();
- }
- else
- {
- collapseSavepoints(commitContext);
-
- for (CDOObject object : commitContext.getDetachedObjects().values())
- {
- cleanRevisions.remove(object);
- }
-
- for (CDOObject object : commitContext.getDirtyObjects().values())
- {
- cleanRevisions.remove(object);
- }
- }
-
- // Reset partial-commit filter
- committables = null;
- }
-
- private void collapseSavepoints(CDOCommitContext commitContext)
- {
- InternalCDOSavepoint newSavepoint = createSavepoint(null);
- copyUncommitted(lastSavepoint.getAllNewObjects(), commitContext.getNewObjects(), newSavepoint.getNewObjects());
- copyUncommitted(lastSavepoint.getAllDirtyObjects(), commitContext.getDirtyObjects(), newSavepoint.getDirtyObjects());
- copyUncommitted(lastSavepoint.getAllRevisionDeltas(), commitContext.getRevisionDeltas(),
- newSavepoint.getRevisionDeltas());
- copyUncommitted(lastSavepoint.getAllDetachedObjects(), commitContext.getDetachedObjects(),
- newSavepoint.getDetachedObjects());
- lastSavepoint = newSavepoint;
- firstSavepoint = lastSavepoint;
- }
-
- private <T> void copyUncommitted(Map<CDOID, T> oldSavepointMap, Map<CDOID, T> commitContextMap,
- Map<CDOID, T> newSavepointMap)
- {
- for (Entry<CDOID, T> entry : oldSavepointMap.entrySet())
- {
- if (!commitContextMap.containsKey(entry.getKey()))
- {
- newSavepointMap.put(entry.getKey(), entry.getValue());
- }
- }
- }
-
- public synchronized CDOSavepoint[] exportChanges(OutputStream stream) throws IOException
- {
- CDODataOutput out = new CDODataOutputImpl(new ExtendedDataOutputStream(stream))
- {
- @Override
- public CDOIDProvider getIDProvider()
- {
- return CDOTransactionImpl.this;
- }
-
- @Override
- public CDOPackageRegistry getPackageRegistry()
- {
- return getSession().getPackageRegistry();
- }
- };
-
- List<CDOSavepoint> savepoints = new ArrayList<CDOSavepoint>();
- int totalNewObjects = 0;
-
- InternalCDOSavepoint savepoint = firstSavepoint;
- while (savepoint != null)
- {
- Collection<CDOObject> newObjects = savepoint.getNewObjects().values();
- totalNewObjects += newObjects.size();
-
- savepoint = savepoint.getNextSavepoint();
- }
-
- out.writeInt(totalNewObjects);
-
- savepoint = firstSavepoint;
- while (savepoint != null)
- {
- Collection<CDOObject> newObjects = savepoint.getNewObjects().values();
- Collection<CDORevisionDelta> revisionDeltas = savepoint.getRevisionDeltas().values();
- if (newObjects.isEmpty() && revisionDeltas.isEmpty())
- {
- savepoint = savepoint.getNextSavepoint();
- continue;
- }
-
- savepoints.add(savepoint);
- out.writeBoolean(true);
-
- out.writeInt(newObjects.size());
- for (CDOObject newObject : newObjects)
- {
- out.writeCDORevision(newObject.cdoRevision(), CDORevision.UNCHUNKED);
- }
-
- out.writeInt(revisionDeltas.size());
- for (CDORevisionDelta revisionDelta : revisionDeltas)
- {
- out.writeCDORevisionDelta(revisionDelta);
- }
-
- savepoint = savepoint.getNextSavepoint();
- }
-
- out.writeBoolean(false);
- return savepoints.toArray(new CDOSavepoint[savepoints.size()]);
- }
-
- public synchronized CDOSavepoint[] importChanges(InputStream stream, boolean reconstructSavepoints)
- throws IOException
- {
- List<CDOSavepoint> savepoints = new ArrayList<CDOSavepoint>();
- if (stream.available() > 0)
- {
- CDODataInput in = new CDODataInputImpl(new ExtendedDataInputStream(stream))
- {
- @Override
- protected CDOPackageRegistry getPackageRegistry()
- {
- return getSession().getPackageRegistry();
- }
-
- @Override
- protected CDOBranchManager getBranchManager()
- {
- return getSession().getBranchManager();
- }
-
- @Override
- protected CDOCommitInfoManager getCommitInfoManager()
- {
- return getSession().getCommitInfoManager();
- }
-
- @Override
- protected CDORevisionFactory getRevisionFactory()
- {
- return getSession().getRevisionManager().getFactory();
- }
-
- @Override
- protected CDOLobStore getLobStore()
- {
- return getSession().getLobStore();
- }
-
- @Override
- protected CDOListFactory getListFactory()
- {
- return CDOListWithElementProxiesImpl.FACTORY;
- }
- };
-
- // Increase the internal tempID counter to prevent ID collisions during mapping
- int totalNewObjects = in.readInt();
- for (int i = 0; i < totalNewObjects; i++)
- {
- createIDForNewObject(null);
- }
-
- Map<CDOID, CDOID> idMappings = new HashMap<CDOID, CDOID>();
- while (in.readBoolean())
- {
- if (reconstructSavepoints)
- {
- InternalCDOSavepoint savepoint = setSavepoint();
- savepoints.add(savepoint);
- }
-
- // Import revisions and deltas
- List<InternalCDORevision> revisions = new ArrayList<InternalCDORevision>();
- importNewRevisions(in, revisions, idMappings);
- List<InternalCDORevisionDelta> revisionDeltas = importRevisionDeltas(in);
-
- // Re-map temp IDs
- CDOIDMapper idMapper = new CDOIDMapper(idMappings);
- for (InternalCDORevision revision : revisions)
- {
- revision.adjustReferences(idMapper);
- }
-
- for (InternalCDORevisionDelta delta : revisionDeltas)
- {
- delta.adjustReferences(idMapper);
- }
-
- // Create new objects
- List<InternalCDOObject> newObjects = new ArrayList<InternalCDOObject>();
- for (InternalCDORevision revision : revisions)
- {
- InternalCDOObject object = newInstance(revision);
- registerObject(object);
- registerAttached(object, true);
-
- newObjects.add(object);
- }
-
- // Post-load new objects (important for legacy objects!)
- for (InternalCDOObject object : newObjects)
- {
- object.cdoInternalPostLoad();
- }
-
- // Apply deltas
- CDOObjectMerger merger = new CDOObjectMerger();
- for (InternalCDORevisionDelta delta : revisionDeltas)
- {
- InternalCDOObject object = getObject(delta.getID());
- int oldVersion = object.cdoRevision().getVersion();
-
- merger.merge(object, delta);
- registerRevisionDelta(delta);
- registerDirty(object, null);
-
- if (delta.getVersion() < oldVersion)
- {
- setConflict(object);
- }
- }
- }
- }
-
- return savepoints.toArray(new CDOSavepoint[savepoints.size()]);
- }
-
- private void importNewRevisions(CDODataInput in, List<InternalCDORevision> revisions, Map<CDOID, CDOID> idMappings)
- throws IOException
- {
- int size = in.readInt();
- for (int i = 0; i < size; i++)
- {
- InternalCDORevision revision = (InternalCDORevision)in.readCDORevision(false);
-
- CDOID oldID = revision.getID();
- if (oldID.isTemporary())
- {
- CDOID newID = createIDForNewObject(null);
- idMappings.put(oldID, newID);
- revision.setID(newID);
- }
-
- revisions.add(revision);
- }
- }
-
- private List<InternalCDORevisionDelta> importRevisionDeltas(CDODataInput in) throws IOException
- {
- int size = in.readInt();
- List<InternalCDORevisionDelta> deltas = new ArrayList<InternalCDORevisionDelta>(size);
- for (int i = 0; i < size; i++)
- {
- InternalCDORevisionDelta delta = (InternalCDORevisionDelta)in.readCDORevisionDelta();
- deltas.add(delta);
- }
-
- return deltas;
- }
-
- private InternalCDOObject newInstance(InternalCDORevision revision)
- {
- InternalCDOObject object = newInstance(revision.getEClass());
- object.cdoInternalSetID(revision.getID());
- object.cdoInternalSetRevision(revision);
- object.cdoInternalSetState(CDOState.NEW);
- object.cdoInternalSetView(this);
- return object;
- }
-
- public synchronized Map<CDOID, CDOObject> getDirtyObjects()
- {
- checkActive();
- return lastSavepoint.getAllDirtyObjects();
- }
-
- public synchronized Map<CDOID, CDOObject> getNewObjects()
- {
- checkActive();
- return lastSavepoint.getAllNewObjects();
- }
-
- /**
- * @since 2.0
- */
- public synchronized Map<CDOID, CDORevision> getBaseNewObjects()
- {
- checkActive();
- return lastSavepoint.getAllBaseNewObjects();
- }
-
- public synchronized Map<CDOID, CDORevisionDelta> getRevisionDeltas()
- {
- checkActive();
- return lastSavepoint.getAllRevisionDeltas();
- }
-
- /**
- * @since 2.0
- */
- public synchronized Map<CDOID, CDOObject> getDetachedObjects()
- {
- checkActive();
- return lastSavepoint.getAllDetachedObjects();
- }
-
- @Override
- protected synchronized CDOID getXRefTargetID(CDOObject target)
- {
- CDORevisionKey key = cleanRevisions.get(target);
- if (key != null)
- {
- return key.getID();
- }
-
- return super.getXRefTargetID(target);
- }
-
- @Override
- protected synchronized CDOID getID(InternalCDOObject object, boolean onlyPersistedID)
- {
- CDOID id = super.getID(object, onlyPersistedID);
-
- // If super returned a good result, return immediately
- if (id != null)
- {
- return id;
- }
-
- // Don't perform the trickery that follows later in this method, if we are being called
- // indirectly through provideCDOID. This occurs when deltas or revisions are
- // being written out to a stream; in which case null must be returned (for transients) so that
- // the caller will detect a dangling reference
- if (providingCDOID.get())
- {
- return null;
- }
-
- // The super implementation will return null for a transient (unattached) object;
- // but in a tx, an transient object may previously have been attached. So we consult
- // the cleanRevisions if that's the case.
- CDORevisionKey revKey = cleanRevisions.get(object);
- if (revKey != null && getDetachedObjects().containsValue(object))
- {
- id = revKey.getID();
- }
-
- return id;
- }
-
- @Override
- public synchronized CDOID provideCDOID(Object idOrObject)
- {
- try
- {
- providingCDOID.set(true);
- return super.provideCDOID(idOrObject);
- }
- finally
- {
- providingCDOID.set(false);
- }
- }
-
- @Override
- public synchronized CDOQueryImpl createQuery(String language, String queryString, Object context)
- {
- return createQuery(language, queryString, context, false);
- }
-
- public synchronized CDOQueryImpl createQuery(String language, String queryString, boolean considerDirtyState)
- {
- return createQuery(language, queryString, null, considerDirtyState);
- }
-
- public synchronized CDOQueryImpl createQuery(String language, String queryString, Object context,
- boolean considerDirtyState)
- {
- CDOQueryImpl query = super.createQuery(language, queryString, context);
- if (considerDirtyState && isDirty())
- {
- query.setChangeSetData(getChangeSetData());
- }
-
- return query;
- }
-
- @Override
- protected void doActivate() throws Exception
- {
- super.doActivate();
-
- InternalCDOSession session = getSession();
- if (session.getRepositoryInfo().getIDGenerationLocation() == IDGenerationLocation.STORE)
- {
- idGenerator = new TempIDGenerator();
- }
- else
- {
- idGenerator = session.getIDGenerator();
- if (idGenerator == null)
- {
- idGenerator = CDOIDGenerator.UUID;
- }
- }
- }
-
- /**
- * @since 2.0
- */
- @Override
- protected void doDeactivate() throws Exception
- {
- options().disposeConflictResolvers();
- lastSavepoint = null;
- firstSavepoint = null;
- transactionStrategy = null;
- idGenerator = null;
- super.doDeactivate();
- }
-
- /**
- * Bug 298561: This override removes references to remotely detached objects that are present in any DIRTY or NEW
- * objects.
- *
- * @since 3.0
- */
- /*
- * Synchronized through InvlidationRunner.run()
- */
- @Override
- protected Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> invalidate(long lastUpdateTime,
- List<CDORevisionKey> allChangedObjects, List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas,
- Map<CDOObject, CDORevisionDelta> revisionDeltas, Set<CDOObject> detachedObjects)
- {
- if (!allDetachedObjects.isEmpty())
- {
- Set<CDOID> referencedOIDs = new HashSet<CDOID>();
- for (CDOIDAndVersion key : allDetachedObjects)
- {
- referencedOIDs.add(key.getID());
- }
-
- Collection<CDOObject> cachedDirtyObjects = getDirtyObjects().values();
- removeCrossReferences(cachedDirtyObjects, referencedOIDs);
-
- Collection<CDOObject> cachedNewObjects = getNewObjects().values();
- removeCrossReferences(cachedNewObjects, referencedOIDs);
- }
-
- // Bug 290032 - Sticky views
- InternalCDOSession session = getSession();
- if (session.isSticky())
- {
- session.clearCommittedSinceLastRefresh();
- }
-
- return super.invalidate(lastUpdateTime, allChangedObjects, allDetachedObjects, deltas, revisionDeltas,
- detachedObjects);
- }
-
- private void removeCrossReferences(Collection<CDOObject> referencers, Set<CDOID> referencedOIDs)
- {
- List<Pair<Setting, EObject>> objectsToBeRemoved = new LinkedList<Pair<Setting, EObject>>();
- for (CDOObject referencer : referencers)
- {
- FeatureIterator<EObject> it = getChangeableCrossReferences(referencer);
- while (it.hasNext())
- {
- EObject referencedObject = it.next();
- CDOID referencedOID = CDOUtil.getCDOObject(referencedObject).cdoID();
-
- if (referencedOIDs.contains(referencedOID))
- {
- EReference reference = (EReference)it.feature();
-
- // In the case of DIRTY, we must investigate further: Is the referencer dirty
- // because a reference to the referencedObject was added? Only in this case
- // should we remove it. If this is not the case (i.e. it is dirty in a different
- // way), we skip it. (If the reference is not persistent, then this exception
- // doesn't apply: it must be removed for sure.)
- if (referencer.cdoState() == CDOState.DIRTY && EMFUtil.isPersistent(reference))
- {
- InternalCDORevision cleanRevision = cleanRevisions.get(referencer);
-
- Object value = cleanRevision.get(reference, EStore.NO_INDEX);
- if (value instanceof CDOObject && value == referencedObject || //
- value instanceof CDOID && value.equals(referencedOID) || //
- value instanceof CDOList && ((CDOList)value).contains(referencedOID))
- {
- continue;
- }
- }
-
- Setting setting = ((InternalEObject)referencer).eSetting(reference);
- objectsToBeRemoved.add(new Pair<Setting, EObject>(setting, referencedObject));
- }
- }
- }
-
- for (Pair<Setting, EObject> pair : objectsToBeRemoved)
- {
- EcoreUtil.remove(pair.getElement1(), pair.getElement2());
- }
- }
-
- private FeatureIterator<EObject> getChangeableCrossReferences(EObject object)
- {
- FeatureSubsetSupplier features = (FeatureSubsetSupplier)object.eClass().getEAllStructuralFeatures();
- EStructuralFeature[] crossReferences = features.crossReferences();
- if (crossReferences != null)
- {
- List<EStructuralFeature> changeableReferences = new ArrayList<EStructuralFeature>();
- for (int i = 0; i < crossReferences.length; i++)
- {
- EStructuralFeature reference = crossReferences[i];
-
- // Filter out derived references
- if (reference.isDerived())
- {
- continue;
- }
-
- // Filter out unchangeable references
- if (!reference.isChangeable())
- {
- continue;
- }
-
- changeableReferences.add(reference);
- }
-
- if (!changeableReferences.isEmpty())
- {
- EStructuralFeature[] collectedStructuralFeatures = changeableReferences
- .toArray(new EStructuralFeature[changeableReferences.size()]);
- return (FeatureIterator<EObject>)new ECrossReferenceEListDerived(object, collectedStructuralFeatures)
- .iterator();
- }
- }
-
- return (FeatureIterator<EObject>)ECrossReferenceEList.<EObject> emptyContentsEList().iterator();
- }
-
- public synchronized long getLastCommitTime()
- {
- return lastCommitTime;
- }
-
- public synchronized String getCommitComment()
- {
- return commitComment;
- }
-
- public synchronized void setCommitComment(String comment)
- {
- commitComment = comment;
- }
-
- public synchronized void setCommittables(Set<? extends EObject> committables)
- {
- this.committables = committables;
- }
-
- public synchronized Set<? extends EObject> getCommittables()
- {
- return committables;
- }
-
- public synchronized Map<InternalCDOObject, InternalCDORevision> getCleanRevisions()
- {
- return cleanRevisions;
- }
-
- @Override
- protected InternalCDORevision getViewedRevision(InternalCDOObject object)
- {
- InternalCDORevision rev = super.getViewedRevision(object);
-
- // Bug 336590: If we have a clean revision for this object, return that instead
- if (rev != null)
- {
- InternalCDORevision cleanRev = cleanRevisions.get(object);
- if (cleanRev != null)
- {
- return cleanRev;
- }
- }
-
- return rev;
- }
-
- @Override
- protected InternalCDORevision getRevision(CDOObject object)
- {
- if (object.cdoState() == CDOState.TRANSIENT)
- {
- InternalCDORevision revision = cleanRevisions.get(object);
- if (revision == null)
- {
- throw new IllegalStateException("No revision for transient object " + object);
- }
-
- return revision;
- }
-
- return super.getRevision(object);
- }
-
- @Override
- protected InternalCDOLockState createUpdatedLockStateForNewObject(CDOObject object, LockType lockType, boolean on)
- {
- CheckUtil.checkState(FSMUtil.isNew(object), "Object is not in NEW state");
- CheckUtil.checkArg(lockType, "lockType");
-
- InternalCDOLockState lockState = (InternalCDOLockState)getLockState(object);
- if (lockState == null)
- {
- CheckUtil.checkArg(on == true, "on != true");
- Object lockTarget = getLockTarget(object);
- lockState = (InternalCDOLockState)CDOLockUtil.createLockState(lockTarget);
- }
- else
- {
- lockState = (InternalCDOLockState)CDOLockUtil.copyLockState(lockState);
- }
-
- CDOLockOwner lockOwner = CDOLockUtil.createLockOwner(this);
-
- if (on)
- {
- switch (lockType)
- {
- case READ:
- lockState.addReadLockOwner(lockOwner);
- break;
- case WRITE:
- lockState.setWriteLockOwner(lockOwner);
- break;
- case OPTION:
- lockState.setWriteOptionOwner(lockOwner);
- break;
- default:
- throw new IllegalArgumentException("Unknown lock type " + lockType);
- }
- }
- else
- {
- switch (lockType)
- {
- case READ:
- lockState.removeReadLockOwner(lockOwner);
- break;
- case WRITE:
- lockState.setWriteLockOwner(null);
- break;
- case OPTION:
- lockState.setWriteOptionOwner(null);
- break;
- default:
- throw new IllegalArgumentException("Unknown lock type " + lockType);
- }
- }
-
- return lockState;
- }
-
- @Override
- protected List<CDOLockState> createUnlockedLockStatesForAllNewObjects()
- {
- List<CDOLockState> locksOnNewObjects = new LinkedList<CDOLockState>();
- for (CDOObject object : getNewObjects().values())
- {
- Object lockTarget = getLockTarget(object);
- CDOLockState lockState = CDOLockUtil.createLockState(lockTarget);
- locksOnNewObjects.add(lockState);
- }
-
- return locksOnNewObjects;
- }
-
- private static Object getLockTarget(CDOObject object)
- {
- CDOView view = object.cdoView();
- if (view == null)
- {
- return null;
- }
-
- CDOID id = object.cdoID();
- boolean branching = view.getSession().getRepositoryInfo().isSupportingBranches();
- if (branching)
- {
- return CDOIDUtil.createIDAndBranch(id, view.getBranch());
- }
-
- return id;
- }
-
- private final class ResolvingRevisionMap extends HashMap<InternalCDOObject, InternalCDORevision>
- {
- private static final long serialVersionUID = 1L;
-
- public ResolvingRevisionMap()
- {
- }
-
- @Override
- public InternalCDORevision get(Object cdoObject)
- {
- InternalCDORevision revision = super.get(cdoObject);
- if (revision != null)
- {
- getSession().resolveAllElementProxies(revision);
- }
-
- return revision;
- }
- }
-
- /**
- * Generates {@link CDOIDTemp temporary} ID values.
- *
- * @author Eike Stepper
- */
- private static final class TempIDGenerator implements CDOIDGenerator
- {
- private AtomicInteger lastTemporaryID = new AtomicInteger();
-
- public TempIDGenerator()
- {
- }
-
- public CDOID generateCDOID(EObject object)
- {
- return CDOIDUtil.createTempObject(lastTemporaryID.incrementAndGet());
- }
-
- public void reset()
- {
- lastTemporaryID.set(0);
- }
- }
-
- /**
- * @author Simon McDuff
- */
- private final class CDOCommitContextImpl implements InternalCDOCommitContext
- {
- private InternalCDOTransaction transaction;
-
- /**
- * Tracks whether this commit is *actually* partial or not. (Having tx.committables != null does not in itself mean
- * that the commit will be partial, because the committables could cover all dirty/new/detached objects. But this
- * boolean gets set to reflect whether the commit will really commit less than all dirty/new/detached objects.)
- */
- private boolean isPartialCommit;
-
- private CDOCommitData commitData;
-
- private Collection<CDOLockState> locksOnNewObjects;
-
- private Map<CDOID, CDOObject> newObjects;
-
- private Map<CDOID, CDOObject> detachedObjects;
-
- private Map<CDOID, CDORevisionDelta> revisionDeltas;
-
- private Map<CDOID, CDOObject> dirtyObjects;
-
- private Map<ByteArrayWrapper, CDOLob<?>> lobs = new HashMap<ByteArrayWrapper, CDOLob<?>>();
-
- public CDOCommitContextImpl(InternalCDOTransaction transaction)
- {
- this.transaction = transaction;
- calculateCommitData();
- }
-
- private void calculateCommitData()
- {
- List<CDOPackageUnit> newPackageUnits = analyzeNewPackages();
- newObjects = filterCommittables(transaction.getNewObjects());
- List<CDOIDAndVersion> revisions = new ArrayList<CDOIDAndVersion>(newObjects.size());
- for (CDOObject newObject : newObjects.values())
- {
- revisions.add(newObject.cdoRevision());
- }
-
- revisionDeltas = filterCommittables(transaction.getRevisionDeltas());
- List<CDORevisionKey> deltas = new ArrayList<CDORevisionKey>(revisionDeltas.size());
- for (CDORevisionDelta delta : revisionDeltas.values())
- {
- deltas.add(delta);
- }
-
- detachedObjects = filterCommittables(transaction.getDetachedObjects());
- List<CDOIDAndVersion> detached = new ArrayList<CDOIDAndVersion>(detachedObjects.size());
- for (CDOID id : detachedObjects.keySet())
- {
- // Add "version-less" key.
- // CDOSessionImpl.reviseRevisions() will call reviseLatest() accordingly.
- detached.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION));
- }
-
- dirtyObjects = filterCommittables(transaction.getDirtyObjects());
-
- CDOLockState[] locksOnNewObjectsArray = getLockStates(newObjects.keySet(), false);
- locksOnNewObjects = Arrays.asList(locksOnNewObjectsArray);
-
- commitData = new CDOCommitDataImpl(newPackageUnits, revisions, deltas, detached);
- }
-
- private <T> Map<CDOID, T> filterCommittables(Map<CDOID, T> map)
- {
- if (committables == null)
- {
- // No partial commit filter -- nothing to do
- return map;
- }
-
- Map<CDOID, T> newMap = new HashMap<CDOID, T>();
- for (Entry<CDOID, T> entry : map.entrySet())
- {
- CDOID id = entry.getKey();
- CDOObject o = getObject(id);
- if (committables.contains(o))
- {
- newMap.put(id, entry.getValue());
- }
- else
- {
- isPartialCommit = true;
- }
- }
-
- return newMap;
- }
-
- public String getUserID()
- {
- return transaction.getSession().getUserID();
- }
-
- public int getViewID()
- {
- return transaction.getViewID();
- }
-
- public CDOBranch getBranch()
- {
- return transaction.getBranch();
- }
-
- public InternalCDOTransaction getTransaction()
- {
- return transaction;
- }
-
- public boolean isPartialCommit()
- {
- return isPartialCommit;
- }
-
- public boolean isAutoReleaseLocks()
- {
- return transaction.options().isAutoReleaseLocksEnabled();
- }
-
- public String getCommitComment()
- {
- return transaction.getCommitComment();
- }
-
- public CDOCommitData getCommitData()
- {
- return commitData;
- }
-
- public Map<CDOID, CDOObject> getDirtyObjects()
- {
- return dirtyObjects;
- }
-
- public Map<CDOID, CDOObject> getNewObjects()
- {
- return newObjects;
- }
-
- public List<CDOPackageUnit> getNewPackageUnits()
- {
- return commitData.getNewPackageUnits();
- }
-
- public Collection<CDOLockState> getLocksOnNewObjects()
- {
- return locksOnNewObjects;
- }
-
- public Map<CDOID, CDOObject> getDetachedObjects()
- {
- return detachedObjects;
- }
-
- public Map<CDOID, CDORevisionDelta> getRevisionDeltas()
- {
- return revisionDeltas;
- }
-
- public Collection<CDOLob<?>> getLobs()
- {
- return lobs.values();
- }
-
- public void preCommit()
- {
- if (isDirty())
- {
- if (TRACER.isEnabled())
- {
- TRACER.trace("commit()"); //$NON-NLS-1$
- }
-
- CDOTransactionHandler2[] handlers = getTransactionHandlers2();
- if (handlers.length != 0)
- {
- final boolean[] modifiedAgain = { false };
- CDOTransactionHandler1 modifiedAgainHandler = new CDODefaultTransactionHandler1()
- {
- @Override
- public void modifyingObject(CDOTransaction transaction, CDOObject object, CDOFeatureDelta featureChange)
- {
- modifiedAgain[0] = true;
- }
- };
-
- addTransactionHandler(modifiedAgainHandler);
-
- try
- {
- for (int i = 0; i < handlers.length; i++)
- {
- modifiedAgain[0] = false;
- CDOTransactionHandler2 handler = handlers[i];
- handler.committingTransaction(getTransaction(), this);
- if (modifiedAgain[0])
- {
- calculateCommitData();
- }
- }
- }
- finally
- {
- removeTransactionHandler(modifiedAgainHandler);
- }
- }
-
- try
- {
- // TODO (CD) It might be wise to always do the checks,
- // instead of only for partial commits
- if (isPartialCommit)
- {
- new CommitIntegrityCheck(this, CommitIntegrityCheck.Style.EXCEPTION_FAST).check();
- }
-
- preCommit(getNewObjects(), lobs);
- preCommit(getDirtyObjects(), lobs);
-
- if (!lobs.isEmpty())
- {
- CDOSessionProtocol sessionProtocol = getSession().getSessionProtocol();
- List<byte[]> alreadyKnown = sessionProtocol.queryLobs(ByteArrayWrapper.toByteArray(lobs.keySet()));
-
- for (byte[] id : alreadyKnown)
- {
- lobs.remove(new ByteArrayWrapper(id));
- }
- }
- }
- catch (RuntimeException ex)
- {
- throw ex;
- }
- catch (Exception ex)
- {
- throw new TransactionException(ex);
- }
- }
- }
-
- public void postCommit(CommitTransactionResult result)
- {
- try
- {
- InternalCDOSession session = getSession();
- long timeStamp = result.getTimeStamp();
-
- if (result.getRollbackMessage() != null)
- {
- CDOCommitInfo commitInfo = new FailureCommitInfo(timeStamp, result.getPreviousTimeStamp());
- session.invalidate(commitInfo, transaction);
- return;
- }
-
- CDOBranch branch = result.getBranch();
- boolean branchChanged = !ObjectUtil.equals(branch, getBranch());
- if (branchChanged)
- {
- basicSetBranchPoint(branch.getHead());
- }
-
- for (CDOPackageUnit newPackageUnit : getNewPackageUnits())
- {
- ((InternalCDOPackageUnit)newPackageUnit).setState(CDOPackageUnit.State.LOADED);
- }
-
- postCommit(getNewObjects(), result);
- postCommit(getDirtyObjects(), result);
-
- for (CDORevisionDelta delta : getRevisionDeltas().values())
- {
- ((InternalCDORevisionDelta)delta).adjustReferences(result.getReferenceAdjuster());
- }
-
- for (CDOID id : getDetachedObjects().keySet())
- {
- removeObject(id);
- }
-
- CDOCommitInfo commitInfo = makeCommitInfo(timeStamp, result.getPreviousTimeStamp());
- session.invalidate(commitInfo, transaction);
-
- // Bug 290032 - Sticky views
- if (session.isSticky())
- {
- CDOBranchPoint commitBranchPoint = CDOBranchUtil.copyBranchPoint(result);
- for (CDOObject object : getNewObjects().values()) // Note: keyset() does not work because ID mappings are
- // not applied there!
- {
- session.setCommittedSinceLastRefresh(object.cdoID(), commitBranchPoint);
- }
-
- for (CDOID id : getDirtyObjects().keySet())
- {
- session.setCommittedSinceLastRefresh(id, commitBranchPoint);
- }
-
- for (CDOID id : getDetachedObjects().keySet())
- {
- session.setCommittedSinceLastRefresh(id, commitBranchPoint);
- }
- }
-
- CDOTransactionHandler2[] handlers = getTransactionHandlers2();
- for (int i = 0; i < handlers.length; i++)
- {
- CDOTransactionHandler2 handler = handlers[i];
- if (handler instanceof CDOTransactionHandler3)
- {
- CDOTransactionHandler3 handler3 = (CDOTransactionHandler3)handler;
- handler3.committedTransaction(transaction, this, commitInfo);
- }
- else
- {
- handler.committedTransaction(transaction, this);
- }
- }
-
- getChangeSubscriptionManager().committedTransaction(transaction, this);
- getAdapterManager().committedTransaction(transaction, this);
-
- cleanUp(this);
- Map<CDOID, CDOID> idMappings = result.getIDMappings();
- IListener[] listeners = getListeners();
- if (listeners != null)
- {
- if (branchChanged)
- {
- fireViewTargetChangedEvent(listeners);
- }
-
- fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners);
- }
-
- CDOLockState[] newLockStates = result.getNewLockStates();
- if (newLockStates != null)
- {
- updateAndNotifyLockStates(Operation.UNLOCK, null, result.getTimeStamp(), newLockStates);
- }
- }
- catch (RuntimeException ex)
- {
- throw ex;
- }
- catch (Exception ex)
- {
- throw new TransactionException(ex);
- }
- }
-
- private CDOCommitInfo makeCommitInfo(long timeStamp, long previousTimeStamp)
- {
- InternalCDOSession session = getSession();
- CDOBranch branch = getBranch();
- String userID = session.getUserID();
- String comment = getCommitComment();
-
- InternalCDOCommitInfoManager commitInfoManager = session.getCommitInfoManager();
- return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData);
- }
-
- private void preCommit(Map<CDOID, CDOObject> objects, Map<ByteArrayWrapper, CDOLob<?>> lobs)
- {
- if (!objects.isEmpty())
- {
- boolean noLegacy = !isLegacyModeEnabled();
- for (CDOObject object : objects.values())
- {
- if (noLegacy && object instanceof CDOObjectWrapper)
- {
- throw new LegacyModeNotEnabledException();
- }
-
- collectLobs((InternalCDORevision)object.cdoRevision(), lobs);
- ((InternalCDOObject)object).cdoInternalPreCommit();
- }
- }
- }
-
- private void collectLobs(InternalCDORevision revision, Map<ByteArrayWrapper, CDOLob<?>> lobs)
- {
- EStructuralFeature[] features = revision.getClassInfo().getAllPersistentFeatures();
- for (int i = 0; i < features.length; i++)
- {
- EStructuralFeature feature = features[i];
- if (CDOModelUtil.isLob(feature.getEType()))
- {
- CDOLob<?> lob = (CDOLob<?>)revision.getValue(feature);
- if (lob != null)
- {
- lobs.put(new ByteArrayWrapper(lob.getID()), lob);
- }
- }
- }
- }
-
- private void postCommit(Map<CDOID, CDOObject> objects, CommitTransactionResult result)
- {
- if (!objects.isEmpty())
- {
- for (CDOObject object : objects.values())
- {
- CDOStateMachine.INSTANCE.commit((InternalCDOObject)object, result);
- }
- }
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class StartedEvent extends Event implements CDOTransactionStartedEvent
- {
- private static final long serialVersionUID = 1L;
-
- private StartedEvent()
- {
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("CDOTransactionStartedEvent[source={0}]", getSource()); //$NON-NLS-1$
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class FinishedEvent extends Event implements CDOTransactionFinishedEvent
- {
- private static final long serialVersionUID = 1L;
-
- private Type type;
-
- private Map<CDOID, CDOID> idMappings;
-
- private FinishedEvent(Type type, Map<CDOID, CDOID> idMappings)
- {
- this.type = type;
- this.idMappings = idMappings;
- }
-
- public Type getType()
- {
- return type;
- }
-
- public Map<CDOID, CDOID> getIDMappings()
- {
- return idMappings;
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("CDOTransactionFinishedEvent[source={0}, type={1}, idMappings={2}]", getSource(), //$NON-NLS-1$
- getType(), idMappings == null ? 0 : idMappings.size());
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class ConflictEvent extends Event implements CDOTransactionConflictEvent
- {
- private static final long serialVersionUID = 1L;
-
- private InternalCDOObject conflictingObject;
-
- private boolean firstConflict;
-
- public ConflictEvent(InternalCDOObject conflictingObject, boolean firstConflict)
- {
- this.conflictingObject = conflictingObject;
- this.firstConflict = firstConflict;
- }
-
- public InternalCDOObject getConflictingObject()
- {
- return conflictingObject;
- }
-
- public boolean isFirstConflict()
- {
- return firstConflict;
- }
-
- @Override
- public String toString()
- {
- return MessageFormat.format("CDOTransactionConflictEvent[source={0}, conflictingObject={1}, firstConflict={2}]", //$NON-NLS-1$
- getSource(), getConflictingObject(), isFirstConflict());
- }
- }
-
- /**
- * @author Eike Stepper
- * @since 2.0
- */
- protected final class OptionsImpl extends CDOViewImpl.OptionsImpl implements CDOTransaction.Options
- {
- private List<CDOConflictResolver> conflictResolvers = new ArrayList<CDOConflictResolver>();
-
- private boolean autoReleaseLocksEnabled = true;
-
- public OptionsImpl()
- {
- }
-
- @Override
- public CDOTransactionImpl getContainer()
- {
- return (CDOTransactionImpl)super.getContainer();
- }
-
- public CDOConflictResolver[] getConflictResolvers()
- {
- synchronized (CDOTransactionImpl.this)
- {
- return conflictResolvers.toArray(new CDOConflictResolver[conflictResolvers.size()]);
- }
- }
-
- public void setConflictResolvers(CDOConflictResolver[] resolvers)
- {
- synchronized (CDOTransactionImpl.this)
- {
- for (CDOConflictResolver resolver : conflictResolvers)
- {
- resolver.setTransaction(null);
- }
-
- conflictResolvers.clear();
-
- for (CDOConflictResolver resolver : resolvers)
- {
- validateResolver(resolver);
- conflictResolvers.add(resolver);
- }
- }
-
- fireEvent(new ConflictResolversEventImpl());
- }
-
- public void addConflictResolver(CDOConflictResolver resolver)
- {
- IEvent event = null;
- synchronized (CDOTransactionImpl.this)
- {
- validateResolver(resolver);
- conflictResolvers.add(resolver);
- event = new ConflictResolversEventImpl();
- }
-
- fireEvent(event);
- }
-
- public void removeConflictResolver(CDOConflictResolver resolver)
- {
- IEvent event = null;
- synchronized (CDOTransactionImpl.this)
- {
- if (conflictResolvers.remove(resolver))
- {
- resolver.setTransaction(null);
- event = new ConflictResolversEventImpl();
- }
- }
-
- fireEvent(event);
- }
-
- public void disposeConflictResolvers()
- {
- try
- {
- // Do not call getConflictResolvers() because that method may block!
- CDOConflictResolver[] array = conflictResolvers.toArray(new CDOConflictResolver[conflictResolvers.size()]);
- for (CDOConflictResolver resolver : array)
- {
- try
- {
- resolver.setTransaction(null);
- }
- catch (Exception ignore)
- {
- }
- }
- }
- catch (Exception ignore)
- {
- }
- }
-
- private void validateResolver(CDOConflictResolver resolver)
- {
- if (resolver.getTransaction() != null)
- {
- throw new IllegalArgumentException(Messages.getString("CDOTransactionImpl.17")); //$NON-NLS-1$
- }
-
- resolver.setTransaction(CDOTransactionImpl.this);
- }
-
- public boolean isAutoReleaseLocksEnabled()
- {
- return autoReleaseLocksEnabled;
- }
-
- public void setAutoReleaseLocksEnabled(boolean on)
- {
- IEvent event = null;
- synchronized (CDOTransactionImpl.this)
- {
- if (autoReleaseLocksEnabled != on)
- {
- autoReleaseLocksEnabled = on;
- event = new AutoReleaseLocksEventImpl();
- }
- }
-
- fireEvent(event);
- }
-
- /**
- * @author Eike Stepper
- */
- private final class ConflictResolversEventImpl extends OptionsEvent implements ConflictResolversEvent
- {
- private static final long serialVersionUID = 1L;
-
- public ConflictResolversEventImpl()
- {
- super(OptionsImpl.this);
- }
- }
-
- /**
- * @author Eike Stepper
- */
- private final class AutoReleaseLocksEventImpl extends OptionsEvent implements AutoReleaseLocksEvent
- {
- private static final long serialVersionUID = 1L;
-
- public AutoReleaseLocksEventImpl()
- {
- super(OptionsImpl.this);
- }
- }
- }
-
- public static class ECrossReferenceEListDerived extends ECrossReferenceEList<EObject>
- {
-
- public ECrossReferenceEListDerived(EObject eObject)
- {
- super(eObject);
- }
-
- public ECrossReferenceEListDerived(EObject eObject, EStructuralFeature[] eStructuralFeatures)
- {
- super(eObject, eStructuralFeatures);
- }
- }
-
-}
+/*
+ * 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
+ * Victor Roldan Betancort - maintenance
+ * Gonzague Reydet - bug 298334
+ * Andre Dietisheim - bug 256649
+ * Caspar De Groot - bug 290032 (Sticky views)
+ */
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.CDOState;
+import org.eclipse.emf.cdo.common.CDOCommonRepository;
+import org.eclipse.emf.cdo.common.CDOCommonRepository.IDGenerationLocation;
+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.CDOChangeSet;
+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.CDOIDGenerator;
+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.lob.CDOLob;
+import org.eclipse.emf.cdo.common.lob.CDOLobStore;
+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.CDOPackageRegistry;
+import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
+import org.eclipse.emf.cdo.common.model.EMFUtil;
+import org.eclipse.emf.cdo.common.protocol.CDODataInput;
+import org.eclipse.emf.cdo.common.protocol.CDODataOutput;
+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.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
+import org.eclipse.emf.cdo.common.revision.CDORevisionProvider;
+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.CDOException;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.eresource.CDOResourceFolder;
+import org.eclipse.emf.cdo.eresource.CDOResourceNode;
+import org.eclipse.emf.cdo.eresource.EresourceFactory;
+import org.eclipse.emf.cdo.eresource.impl.CDOResourceImpl;
+import org.eclipse.emf.cdo.eresource.impl.CDOResourceNodeImpl;
+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.protocol.CDODataInputImpl;
+import org.eclipse.emf.cdo.internal.common.protocol.CDODataOutputImpl;
+import org.eclipse.emf.cdo.internal.common.revision.CDOListWithElementProxiesImpl;
+import org.eclipse.emf.cdo.session.CDORepositoryInfo;
+import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil;
+import org.eclipse.emf.cdo.spi.common.commit.CDORevisionAvailabilityInfo;
+import org.eclipse.emf.cdo.spi.common.commit.InternalCDOCommitInfoManager;
+import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.common.revision.CDOIDMapper;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.transaction.CDOCommitContext;
+import org.eclipse.emf.cdo.transaction.CDOConflictResolver;
+import org.eclipse.emf.cdo.transaction.CDOConflictResolver2;
+import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler1;
+import org.eclipse.emf.cdo.transaction.CDOMerger;
+import org.eclipse.emf.cdo.transaction.CDOSavepoint;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.transaction.CDOTransactionConflictEvent;
+import org.eclipse.emf.cdo.transaction.CDOTransactionFinishedEvent;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandler;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandler1;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandler2;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandler3;
+import org.eclipse.emf.cdo.transaction.CDOTransactionHandlerBase;
+import org.eclipse.emf.cdo.transaction.CDOTransactionStartedEvent;
+import org.eclipse.emf.cdo.transaction.CDOUserSavepoint;
+import org.eclipse.emf.cdo.util.CDOURIUtil;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.util.CommitException;
+import org.eclipse.emf.cdo.util.LegacyModeNotEnabledException;
+import org.eclipse.emf.cdo.util.ObjectNotFoundException;
+import org.eclipse.emf.cdo.view.CDOView;
+
+import org.eclipse.emf.internal.cdo.bundle.OM;
+import org.eclipse.emf.internal.cdo.messages.Messages;
+import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder;
+import org.eclipse.emf.internal.cdo.object.CDOObjectMerger;
+import org.eclipse.emf.internal.cdo.object.CDOObjectWrapper;
+import org.eclipse.emf.internal.cdo.query.CDOQueryImpl;
+import org.eclipse.emf.internal.cdo.util.CommitIntegrityCheck;
+import org.eclipse.emf.internal.cdo.util.CompletePackageClosure;
+import org.eclipse.emf.internal.cdo.util.IPackageClosure;
+import org.eclipse.emf.internal.cdo.view.CDOStateMachine;
+import org.eclipse.emf.internal.cdo.view.CDOViewImpl;
+
+import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.collection.ByteArrayWrapper;
+import org.eclipse.net4j.util.collection.ConcurrentArray;
+import org.eclipse.net4j.util.collection.Pair;
+import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType;
+import org.eclipse.net4j.util.event.IEvent;
+import org.eclipse.net4j.util.event.IListener;
+import org.eclipse.net4j.util.io.ExtendedDataInputStream;
+import org.eclipse.net4j.util.io.ExtendedDataOutputStream;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+import org.eclipse.net4j.util.options.OptionsEvent;
+import org.eclipse.net4j.util.transaction.TransactionException;
+
+import org.eclipse.emf.common.notify.NotificationChain;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.EStructuralFeature.Setting;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.InternalEObject.EStore;
+import org.eclipse.emf.ecore.impl.EClassImpl.FeatureSubsetSupplier;
+import org.eclipse.emf.ecore.util.EContentsEList.FeatureIterator;
+import org.eclipse.emf.ecore.util.ECrossReferenceEList;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol;
+import org.eclipse.emf.spi.cdo.CDOSessionProtocol.CommitTransactionResult;
+import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
+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.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Eike Stepper
+ */
+public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransaction
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_TRANSACTION, CDOTransactionImpl.class);
+
+ private Object transactionHandlersLock = new Object();
+
+ private ConcurrentArray<CDOTransactionHandler1> transactionHandlers1 = new ConcurrentArray<CDOTransactionHandler1>()
+ {
+ @Override
+ protected CDOTransactionHandler1[] newArray(int length)
+ {
+ return new CDOTransactionHandler1[length];
+ }
+ };
+
+ private ConcurrentArray<CDOTransactionHandler2> transactionHandlers2 = new ConcurrentArray<CDOTransactionHandler2>()
+ {
+ @Override
+ protected CDOTransactionHandler2[] newArray(int length)
+ {
+ return new CDOTransactionHandler2[length];
+ }
+ };
+
+ private InternalCDOSavepoint lastSavepoint = createSavepoint(null);
+
+ private InternalCDOSavepoint firstSavepoint = lastSavepoint;
+
+ private boolean dirty;
+
+ private int conflict;
+
+ private CDOTransactionStrategy transactionStrategy;
+
+ private CDOIDGenerator idGenerator;
+
+ private volatile long lastCommitTime = UNSPECIFIED_DATE;
+
+ private String commitComment;
+
+ // Bug 283985 (Re-attachment)
+ private final ThreadLocal<Boolean> providingCDOID = new InheritableThreadLocal<Boolean>()
+ {
+ @Override
+ protected Boolean initialValue()
+ {
+ return false;
+ }
+ };
+
+ /**
+ * An optional set to specify which objects in this TX are to be committed by {@link #commit()}
+ */
+ private Set<? extends EObject> committables;
+
+ /**
+ * A map to hold a clean (i.e. unmodified) revision for objects that have been modified or detached.
+ */
+ private Map<InternalCDOObject, InternalCDORevision> cleanRevisions = new ResolvingRevisionMap();
+
+ public CDOTransactionImpl(CDOBranch branch)
+ {
+ super(branch, UNSPECIFIED_DATE);
+ }
+
+ public CDOTransactionImpl(String durableLockingID)
+ {
+ super(durableLockingID);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public OptionsImpl options()
+ {
+ return (OptionsImpl)super.options();
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected OptionsImpl createOptions()
+ {
+ return new OptionsImpl();
+ }
+
+ @Override
+ public boolean isReadOnly()
+ {
+ return false;
+ }
+
+ @Override
+ public synchronized boolean setBranchPoint(CDOBranchPoint branchPoint)
+ {
+ if (branchPoint.getTimeStamp() != UNSPECIFIED_DATE)
+ {
+ throw new IllegalArgumentException("Changing the target time is not supported by transactions");
+ }
+
+ if (isDirty() && !getBranch().equals(branchPoint.getBranch()))
+ {
+ throw new IllegalStateException("Changing the target branch is impossible while transaction is dirty");
+ }
+
+ return super.setBranchPoint(branchPoint);
+ }
+
+ public void addTransactionHandler(CDOTransactionHandlerBase handler)
+ {
+ synchronized (transactionHandlersLock)
+ {
+ if (handler instanceof CDOTransactionHandler1)
+ {
+ transactionHandlers1.add((CDOTransactionHandler1)handler);
+ }
+
+ if (handler instanceof CDOTransactionHandler2)
+ {
+ transactionHandlers2.add((CDOTransactionHandler2)handler);
+ }
+ }
+ }
+
+ public void removeTransactionHandler(CDOTransactionHandlerBase handler)
+ {
+ synchronized (transactionHandlersLock)
+ {
+ if (handler instanceof CDOTransactionHandler1)
+ {
+ transactionHandlers1.remove((CDOTransactionHandler1)handler);
+ }
+
+ if (handler instanceof CDOTransactionHandler2)
+ {
+ transactionHandlers2.remove((CDOTransactionHandler2)handler);
+ }
+ }
+ }
+
+ public CDOTransactionHandler[] getTransactionHandlers()
+ {
+ Set<CDOTransactionHandler> result = new HashSet<CDOTransactionHandler>();
+ synchronized (transactionHandlersLock)
+ {
+ CDOTransactionHandler1[] handlers1 = transactionHandlers1.get();
+ if (handlers1 != null)
+ {
+ for (CDOTransactionHandler1 handler : handlers1)
+ {
+ if (handler instanceof CDOTransactionHandler)
+ {
+ result.add((CDOTransactionHandler)handler);
+ }
+ }
+ }
+
+ CDOTransactionHandler2[] handlers2 = transactionHandlers2.get();
+ if (handlers2 != null)
+ {
+ for (CDOTransactionHandler2 handler : handlers2)
+ {
+ if (handler instanceof CDOTransactionHandler)
+ {
+ result.add((CDOTransactionHandler)handler);
+ }
+ }
+ }
+ }
+
+ return result.toArray(new CDOTransactionHandler[result.size()]);
+ }
+
+ public CDOTransactionHandler1[] getTransactionHandlers1()
+ {
+ synchronized (transactionHandlersLock)
+ {
+ return transactionHandlers1.get();
+ }
+ }
+
+ public CDOTransactionHandler2[] getTransactionHandlers2()
+ {
+ synchronized (transactionHandlersLock)
+ {
+ return transactionHandlers2.get();
+ }
+ }
+
+ @Override
+ public synchronized boolean isDirty()
+ {
+ if (isClosed())
+ {
+ return false;
+ }
+
+ return dirty;
+ }
+
+ @Override
+ public synchronized boolean hasConflict()
+ {
+ checkActive();
+ return conflict != 0;
+ }
+
+ public void setConflict(InternalCDOObject object)
+ {
+ IEvent event = null;
+ synchronized (this)
+ {
+ event = new ConflictEvent(object, conflict == 0);
+ ++conflict;
+ }
+
+ fireEvent(event);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized Set<CDOObject> getConflicts()
+ {
+ Set<CDOObject> conflicts = new HashSet<CDOObject>();
+ for (CDOObject object : getDirtyObjects().values())
+ {
+ if (object.cdoConflict())
+ {
+ conflicts.add(object);
+ }
+ }
+
+ for (CDOObject object : getDetachedObjects().values())
+ {
+ if (object.cdoConflict())
+ {
+ conflicts.add(object);
+ }
+ }
+
+ return conflicts;
+ }
+
+ public synchronized CDOChangeSetData getChangeSetData()
+ {
+ checkActive();
+ return lastSavepoint.getAllChangeSetData();
+ }
+
+ public synchronized CDOChangeSetData merge(CDOBranchPoint source, CDOMerger merger)
+ {
+ return merge(source, null, merger);
+ }
+
+ public synchronized CDOChangeSetData merge(CDOBranchPoint source, CDOBranchPoint sourceBase, CDOMerger merger)
+ {
+ if (isDirty())
+ {
+ throw new IllegalStateException("Merging into dirty transactions not yet supported");
+ }
+
+ long now = getLastUpdateTime();
+ CDOBranchPoint target = getBranch().getPoint(now);
+
+ if (source.getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE)
+ {
+ source = source.getBranch().getPoint(now);
+ }
+
+ if (CDOBranchUtil.isContainedBy(source, target))
+ {
+ throw new IllegalArgumentException("Source is already contained in " + target);
+ }
+
+ if (sourceBase != null && CDOBranchUtil.isContainedBy(sourceBase, source))
+ {
+ throw new IllegalArgumentException("Source base is not contained in " + source);
+ }
+
+ CDOBranchPoint ancestor = CDOBranchUtil.getAncestor(target, source);
+
+ InternalCDOSession session = getSession();
+ CDORevisionAvailabilityInfo ancestorInfo = session.createRevisionAvailabilityInfo(ancestor);
+ CDORevisionAvailabilityInfo targetInfo = session.createRevisionAvailabilityInfo(target);
+ CDORevisionAvailabilityInfo sourceInfo = session.createRevisionAvailabilityInfo(source);
+ CDORevisionAvailabilityInfo baseInfo = sourceBase != null ? session.createRevisionAvailabilityInfo(sourceBase)
+ : null;
+
+ CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
+ Set<CDOID> ids = sessionProtocol.loadMergeData(targetInfo, sourceInfo, ancestorInfo, baseInfo);
+
+ session.cacheRevisions(targetInfo);
+ session.cacheRevisions(sourceInfo);
+ session.cacheRevisions(ancestorInfo);
+
+ if (baseInfo != null)
+ {
+ session.cacheRevisions(baseInfo);
+ }
+ else
+ {
+ baseInfo = ancestorInfo;
+ }
+
+ CDOChangeSet targetChanges = createChangeSet(ids, ancestorInfo, targetInfo);
+ CDOChangeSet sourceChanges = createChangeSet(ids, baseInfo, sourceInfo);
+
+ CDOChangeSetData result = merger.merge(targetChanges, sourceChanges);
+ if (result == null)
+ {
+ return null;
+ }
+
+ return applyChangeSet(result, ancestorInfo, targetInfo, source, false).getChangeSetData();
+ }
+
+ private CDOChangeSet createChangeSet(Set<CDOID> ids, CDORevisionAvailabilityInfo startInfo,
+ CDORevisionAvailabilityInfo endInfo)
+ {
+ CDOChangeSetData data = CDORevisionUtil.createChangeSetData(ids, startInfo, endInfo);
+ return CDORevisionUtil.createChangeSet(startInfo.getBranchPoint(), endInfo.getBranchPoint(), data);
+ }
+
+ @Deprecated
+ public Pair<CDOChangeSetData, Pair<Map<CDOID, CDOID>, List<CDOID>>> applyChangeSetData(
+ CDOChangeSetData changeSetData, CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider,
+ CDOBranchPoint source)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public synchronized ApplyChangeSetResult applyChangeSet(CDOChangeSetData changeSetData,
+ CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, CDOBranchPoint source,
+ boolean keepVersions) throws ChangeSetOutdatedException
+ {
+ ApplyChangeSetResult result = new ApplyChangeSetResult();
+
+ // Merges from local offline branches may require additional ID mappings: localID -> tempID
+ if (source != null && source.getBranch().isLocal())
+ {
+ applyLocalIDMapping(changeSetData, result);
+ }
+
+ // New objects
+ applyNewObjects(changeSetData.getNewObjects(), result.getChangeSetData().getNewObjects());
+
+ // Detached objects
+ Set<CDOObject> detachedSet = applyDetachedObjects(changeSetData.getDetachedObjects(), result.getChangeSetData()
+ .getDetachedObjects());
+
+ // Changed objects
+ Map<CDOID, InternalCDORevision> oldRevisions = applyChangedObjects(changeSetData.getChangedObjects(),
+ ancestorProvider, targetProvider, keepVersions, result.getChangeSetData().getChangedObjects());
+
+ // Delta notifications
+ Collection<CDORevisionDelta> notificationDeltas = lastSavepoint.getRevisionDeltas().values();
+ if (!notificationDeltas.isEmpty() || !detachedSet.isEmpty())
+ {
+ sendDeltaNotifications(notificationDeltas, detachedSet, oldRevisions);
+ }
+
+ return result;
+ }
+
+ private void applyLocalIDMapping(CDOChangeSetData changeSetData, ApplyChangeSetResult result)
+ {
+ Map<CDOID, CDOID> idMappings = result.getIDMappings();
+
+ // Collect needed ID mappings
+ for (CDOIDAndVersion key : changeSetData.getNewObjects())
+ {
+ InternalCDORevision revision = (InternalCDORevision)key;
+ if (revision.getBranch().isLocal())
+ {
+ CDOID oldID = revision.getID();
+ CDOID newID = createIDForNewObject(null);
+ idMappings.put(oldID, newID);
+
+ revision.setID(newID);
+ revision.setVersion(0);
+ }
+ }
+
+ if (!idMappings.isEmpty())
+ {
+ // Apply collected ID mappings
+ CDOIDMapper idMapper = new CDOIDMapper(idMappings);
+ idMapper.setAllowUnmappedTempIDs(true);
+
+ for (CDOIDAndVersion key : changeSetData.getNewObjects())
+ {
+ InternalCDORevision revision = (InternalCDORevision)key;
+ revision.adjustReferences(idMapper);
+ }
+
+ for (CDORevisionKey key : changeSetData.getChangedObjects())
+ {
+ InternalCDORevisionDelta revisionDelta = (InternalCDORevisionDelta)key;
+ if (revisionDelta.adjustReferences(idMapper))
+ {
+ result.getAdjustedObjects().add(revisionDelta.getID());
+ }
+ }
+ }
+ }
+
+ private void applyNewObjects(List<CDOIDAndVersion> newObjects, List<CDOIDAndVersion> result)
+ {
+ for (CDOIDAndVersion key : newObjects)
+ {
+ InternalCDORevision revision = (InternalCDORevision)key;
+ CDOID id = revision.getID();
+ if (getObjectIfExists(id) == null)
+ {
+ InternalCDOObject object = newInstance(revision.getEClass());
+ object.cdoInternalSetView(this);
+ object.cdoInternalSetRevision(revision);
+ object.cdoInternalSetID(id);
+ object.cdoInternalSetState(CDOState.NEW);
+ object.cdoInternalPostLoad();
+
+ registerObject(object);
+ registerAttached(object, true);
+ result.add(revision);
+ dirty = true;
+ }
+ }
+ }
+
+ private Set<CDOObject> applyDetachedObjects(List<CDOIDAndVersion> detachedObjects, List<CDOIDAndVersion> result)
+ {
+ Set<CDOObject> detachedSet = new HashSet<CDOObject>();
+ for (CDOIDAndVersion key : detachedObjects)
+ {
+ CDOID id = key.getID();
+ InternalCDOObject object = getObjectIfExists(id);
+ if (object != null)
+ {
+ result.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION));
+ CDOStateMachine.INSTANCE.detach(object);
+ detachedSet.add(object);
+ dirty = true;
+ }
+ }
+
+ return detachedSet;
+ }
+
+ private Map<CDOID, InternalCDORevision> applyChangedObjects(List<CDORevisionKey> changedObjects,
+ CDORevisionProvider ancestorProvider, CDORevisionProvider targetProvider, boolean keepVersions,
+ List<CDORevisionKey> result) throws ChangeSetOutdatedException
+ {
+ Map<CDOID, InternalCDORevision> oldRevisions = new HashMap<CDOID, InternalCDORevision>();
+
+ Map<CDOID, CDOObject> dirtyObjects = lastSavepoint.getDirtyObjects();
+ ConcurrentMap<CDOID, CDORevisionDelta> revisionDeltas = lastSavepoint.getRevisionDeltas();
+
+ for (CDORevisionKey key : changedObjects)
+ {
+ InternalCDORevisionDelta ancestorGoalDelta = (InternalCDORevisionDelta)key;
+ ancestorGoalDelta.setTarget(null);
+ CDOID id = ancestorGoalDelta.getID();
+ InternalCDORevision ancestorRevision = (InternalCDORevision)ancestorProvider.getRevision(id);
+
+ InternalCDOObject object = getObject(id);
+ boolean revisionChanged = false;
+
+ InternalCDORevision targetRevision = object.cdoRevision();
+ if (targetRevision == null)
+ {
+ targetRevision = (InternalCDORevision)targetProvider.getRevision(id);
+ object.cdoInternalSetRevision(targetRevision);
+ revisionChanged = true;
+ }
+
+ oldRevisions.put(id, targetRevision);
+
+ InternalCDORevision goalRevision = ancestorRevision.copy();
+ goalRevision.setBranchPoint(this);
+ if (!keepVersions)
+ {
+ goalRevision.setVersion(targetRevision.getVersion());
+ }
+
+ goalRevision.setRevised(CDOBranchPoint.UNSPECIFIED_DATE);
+ ancestorGoalDelta.apply(goalRevision);
+
+ InternalCDORevisionDelta targetGoalDelta = goalRevision.compare(targetRevision);
+ targetGoalDelta.setTarget(null);
+
+ if (!targetGoalDelta.isEmpty())
+ {
+ if (keepVersions && targetGoalDelta.getVersion() != ancestorRevision.getVersion())
+ {
+ throw new ChangeSetOutdatedException();
+ }
+
+ revisionDeltas.put(id, targetGoalDelta);
+ result.add(targetGoalDelta);
+
+ // handle reattached objects.
+ if (lastSavepoint.getDetachedObjects().containsKey(id))
+ {
+ CDOStateMachine.INSTANCE.attach(object, this);
+ }
+
+ object.cdoInternalSetState(CDOState.DIRTY);
+ object.cdoInternalSetRevision(goalRevision);
+ revisionChanged = true;
+
+ dirtyObjects.put(id, object);
+ dirty = true;
+ }
+
+ if (revisionChanged)
+ {
+ object.cdoInternalPostLoad();
+ }
+ }
+
+ return oldRevisions;
+ }
+
+ private InternalCDOObject getObjectIfExists(CDOID id)
+ {
+ try
+ {
+ return getObject(id);
+ }
+ catch (ObjectNotFoundException ex)
+ {
+ return null;
+ }
+ }
+
+ /*
+ * Synchronized through InvalidationRunnable.run()
+ */
+ @Override
+ protected synchronized void handleConflicts(Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts,
+ List<CDORevisionDelta> deltas)
+ {
+ CDOConflictResolver[] resolvers = options().getConflictResolvers();
+ if (resolvers.length == 0)
+ {
+ return;
+ }
+
+ // Remember original state to be able to restore it after an exception
+ List<CDOState> states = new ArrayList<CDOState>(conflicts.size());
+ List<CDORevision> revisions = new ArrayList<CDORevision>(conflicts.size());
+ for (CDOObject conflict : conflicts.keySet())
+ {
+ states.add(conflict.cdoState());
+ revisions.add(conflict.cdoRevision());
+ }
+
+ int resolved = 0;
+
+ try
+ {
+ Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> remaining = new HashMap<CDOObject, Pair<CDORevision, CDORevisionDelta>>(
+ conflicts);
+ for (CDOConflictResolver resolver : resolvers)
+ {
+ if (resolver instanceof CDOConflictResolver2)
+ {
+ ((CDOConflictResolver2)resolver).resolveConflicts(Collections.unmodifiableMap(remaining), deltas);
+ }
+ else
+ {
+ resolver.resolveConflicts(Collections.unmodifiableSet(remaining.keySet()));
+ }
+
+ for (Iterator<CDOObject> it = remaining.keySet().iterator(); it.hasNext();)
+ {
+ CDOObject object = it.next();
+ if (!object.cdoConflict())
+ {
+ ++resolved;
+ it.remove();
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ // Restore original state
+ Iterator<CDOState> state = states.iterator();
+ Iterator<CDORevision> revision = revisions.iterator();
+ for (CDOObject object : conflicts.keySet())
+ {
+ ((InternalCDOObject)object).cdoInternalSetState(state.next());
+ ((InternalCDOObject)object).cdoInternalSetRevision(revision.next());
+ }
+
+ throw WrappedException.wrap(ex);
+ }
+
+ conflict -= resolved;
+ }
+
+ /**
+ * @deprecated {@link #createIDForNewObject(EObject object)} is called since 4.1.
+ */
+ @Deprecated
+ public synchronized CDOIDTemp getNextTemporaryID()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public CDOID createIDForNewObject(EObject object)
+ {
+ return idGenerator.generateCDOID(object);
+ }
+
+ public synchronized CDOResourceFolder createResourceFolder(String path)
+ {
+ if (path.endsWith(CDOURIUtil.SEGMENT_SEPARATOR))
+ {
+ path = path.substring(0, path.length() - 1);
+ }
+
+ CDOResourceFolder folder = EresourceFactory.eINSTANCE.createCDOResourceFolder();
+ int pos = path.lastIndexOf(CDOURIUtil.SEGMENT_SEPARATOR_CHAR);
+ if (pos <= 0)
+ {
+ String name = path.substring(pos == 0 ? 1 : 0);
+ folder.setName(name);
+
+ getRootResource().getContents().add(folder);
+ }
+ else
+ {
+ String name = path.substring(pos + 1);
+ folder.setName(name);
+
+ path = path.substring(0, pos);
+ CDOResourceNode parent = null;
+
+ try
+ {
+ parent = getResourceNode(path);
+ }
+ catch (Exception ex)
+ {
+ parent = createResourceFolder(path);
+ }
+
+ if (parent instanceof CDOResourceFolder)
+ {
+ ((CDOResourceFolder)parent).getNodes().add(folder);
+ }
+ else
+ {
+ throw new CDOException("Parent is not a folder: " + parent);
+ }
+ }
+
+ return folder;
+ }
+
+ public synchronized CDOResource createResource(String path)
+ {
+ checkActive();
+ URI uri = CDOURIUtil.createResourceURI(this, path);
+ return (CDOResource)getResourceSet().createResource(uri);
+ }
+
+ public synchronized CDOResource getOrCreateResource(String path)
+ {
+ checkActive();
+
+ try
+ {
+ CDOID id = getResourceNodeID(path);
+ if (!CDOIDUtil.isNull(id))
+ {
+ return (CDOResource)getObject(id);
+ }
+ }
+ catch (Exception ignore)
+ {
+ // Just create the missing resource
+ }
+
+ return createResource(path);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public synchronized void attachResource(CDOResourceImpl resource)
+ {
+ if (resource.isExisting())
+ {
+ super.attachResource(resource);
+ }
+ else
+ {
+ // ResourceSet.createResource(uri) was called!!
+ attachNewResource(resource);
+ }
+ }
+
+ private void attachNewResource(CDOResourceImpl resource)
+ {
+ URI uri = resource.getURI();
+ List<String> names = CDOURIUtil.analyzePath(uri);
+ String resourceName = names.isEmpty() ? null : names.remove(names.size() - 1);
+
+ CDOResourceFolder folder = getOrCreateResourceFolder(names);
+ attachNewResourceNode(folder, resourceName, resource);
+ }
+
+ public synchronized CDOResourceFolder getOrCreateResourceFolder(String path)
+ {
+ checkActive();
+
+ try
+ {
+ CDOID id = getResourceNodeID(path);
+ if (!CDOIDUtil.isNull(id))
+ {
+ return (CDOResourceFolder)getObject(id);
+ }
+ }
+ catch (Exception ignore)
+ {
+ // Just create the missing folder
+ }
+
+ return createResourceFolder(path);
+ }
+
+ /**
+ * @return never <code>null</code>;
+ * @since 2.0
+ */
+ public synchronized CDOResourceFolder getOrCreateResourceFolder(List<String> names)
+ {
+ CDOResourceFolder folder = null;
+ for (String name : names)
+ {
+ CDOResourceNode node;
+
+ try
+ {
+ CDOID folderID = folder == null ? null : folder.cdoID();
+ node = getResourceNode(folderID, name);
+ }
+ catch (CDOException ex)
+ {
+ node = EresourceFactory.eINSTANCE.createCDOResourceFolder();
+ attachNewResourceNode(folder, name, node);
+ }
+
+ if (node instanceof CDOResourceFolder)
+ {
+ folder = (CDOResourceFolder)node;
+ }
+ else
+ {
+ throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.0"), node)); //$NON-NLS-1$
+ }
+ }
+
+ return folder;
+ }
+
+ private void attachNewResourceNode(CDOResourceFolder folder, String name, CDOResourceNode newNode)
+ {
+ CDOResourceNodeImpl node = (CDOResourceNodeImpl)newNode;
+ node.basicSetName(name, false);
+ if (folder == null)
+ {
+ if (node.isRoot())
+ {
+ CDOStateMachine.INSTANCE.attach(node, this);
+ }
+ else
+ {
+ getRootResource().getContents().add(node);
+ }
+ }
+ else
+ {
+ node.basicSetFolder(folder, false);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void detach(CDOResourceImpl cdoResource)
+ {
+ CDOStateMachine.INSTANCE.detach(cdoResource);
+ }
+
+ /**
+ * @since 4.1
+ */
+ public InternalCDOSavepoint getFirstSavepoint()
+ {
+ return firstSavepoint;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized InternalCDOSavepoint getLastSavepoint()
+ {
+ checkActive();
+ return lastSavepoint;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized CDOTransactionStrategy getTransactionStrategy()
+ {
+ if (transactionStrategy == null)
+ {
+ transactionStrategy = CDOTransactionStrategy.DEFAULT;
+ transactionStrategy.setTarget(this);
+ }
+
+ return transactionStrategy;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void setTransactionStrategy(CDOTransactionStrategy transactionStrategy)
+ {
+ if (this.transactionStrategy != null)
+ {
+ this.transactionStrategy.unsetTarget(this);
+ }
+
+ this.transactionStrategy = transactionStrategy;
+
+ if (this.transactionStrategy != null)
+ {
+ this.transactionStrategy.setTarget(this);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected synchronized CDOID getRootOrTopLevelResourceNodeID(String name)
+ {
+ if (dirty)
+ {
+ CDOResourceNode node = getRootResourceNode(name, getDirtyObjects().values());
+ if (node != null)
+ {
+ return node.cdoID();
+ }
+
+ node = getRootResourceNode(name, getNewObjects().values());
+ if (node != null)
+ {
+ return node.cdoID();
+ }
+ }
+
+ CDOID id = super.getRootOrTopLevelResourceNodeID(name);
+ if (getLastSavepoint().getAllDetachedObjects().containsKey(id) || getDirtyObjects().containsKey(id))
+ {
+ throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.1"), name)); //$NON-NLS-1$
+ }
+
+ return id;
+ }
+
+ private CDOResourceNode getRootResourceNode(String name, Collection<? extends CDOObject> objects)
+ {
+ for (CDOObject object : objects)
+ {
+ if (object instanceof CDOResourceNode)
+ {
+ CDOResourceNode node = (CDOResourceNode)object;
+ if (node.getFolder() == null && ObjectUtil.equals(name, node.getName()))
+ {
+ return node;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public synchronized InternalCDOObject getObject(CDOID id, boolean loadOnDemand)
+ {
+ checkActive();
+ if (CDOIDUtil.isNull(id))
+ {
+ return null;
+ }
+
+ if (isObjectNew(id) && isObjectDetached(id))
+ {
+ throw new ObjectNotFoundException(id, this);
+ }
+
+ return super.getObject(id, loadOnDemand);
+ }
+
+ @Override
+ public boolean isObjectNew(CDOID id)
+ {
+ return lastSavepoint.isNewObject(id);
+ }
+
+ private boolean isObjectDetached(CDOID id)
+ {
+ return lastSavepoint.getAllDetachedObjects().containsKey(id);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized InternalCDOCommitContext createCommitContext()
+ {
+ return new CDOCommitContextImpl(this);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized CDOCommitInfo commit(IProgressMonitor progressMonitor) throws CommitException
+ {
+ try
+ {
+ checkActive();
+ if (hasConflict())
+ {
+ throw new CommitException(Messages.getString("CDOTransactionImpl.2")); //$NON-NLS-1$
+ }
+
+ if (progressMonitor == null)
+ {
+ progressMonitor = new NullProgressMonitor();
+ }
+
+ CDOTransactionStrategy transactionStrategy = getTransactionStrategy();
+ CDOCommitInfo info = transactionStrategy.commit(this, progressMonitor);
+ if (info != null)
+ {
+ lastCommitTime = info.getTimeStamp();
+ }
+
+ return info;
+ }
+ catch (CommitException ex)
+ {
+ throw ex;
+ }
+ catch (Throwable t)
+ {
+ throw new CommitException(t);
+ }
+ }
+
+ public synchronized CDOCommitInfo commit() throws CommitException
+ {
+ return commit(null);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void rollback()
+ {
+ checkActive();
+ getTransactionStrategy().rollback(this, firstSavepoint);
+ cleanUp(null);
+ }
+
+ private void removeObject(CDOID id, final CDOObject object)
+ {
+ ((InternalCDOObject)object).cdoInternalSetState(CDOState.TRANSIENT);
+ removeObject(id);
+
+ if (object instanceof CDOResource)
+ {
+ getViewSet().executeWithoutNotificationHandling(new Callable<Boolean>()
+ {
+ public Boolean call() throws Exception
+ {
+ getResourceSet().getResources().remove(object);
+ return true;
+ }
+ });
+ }
+
+ ((InternalCDOObject)object).cdoInternalSetID(null);
+ ((InternalCDOObject)object).cdoInternalSetRevision(null);
+ ((InternalCDOObject)object).cdoInternalSetView(null);
+ }
+
+ private Set<CDOID> rollbackCompletely(CDOUserSavepoint savepoint)
+ {
+ Set<CDOID> idsOfNewObjectsWithDeltas = new HashSet<CDOID>();
+
+ // Start from the last savepoint and come back up to the active
+ for (InternalCDOSavepoint itrSavepoint = lastSavepoint; itrSavepoint != null; itrSavepoint = itrSavepoint
+ .getPreviousSavepoint())
+ {
+ // Rollback new objects attached after the save point
+ Map<CDOID, CDOObject> newObjectsMap = itrSavepoint.getNewObjects();
+ for (CDOID id : newObjectsMap.keySet())
+ {
+ CDOObject object = newObjectsMap.get(id);
+ removeObject(id, object);
+ }
+
+ // Rollback new objects re-attached after the save point
+ Map<CDOID, CDOObject> reattachedObjectsMap = itrSavepoint.getReattachedObjects();
+ Set<CDOID> detachedIDs = itrSavepoint.getDetachedObjects().keySet();
+ for (CDOObject reattachedObject : reattachedObjectsMap.values())
+ {
+ CDOID id = reattachedObject.cdoID();
+ if (!detachedIDs.contains(id))
+ {
+ removeObject(id, reattachedObject);
+ }
+ }
+
+ Map<CDOID, CDORevisionDelta> revisionDeltas = itrSavepoint.getRevisionDeltas();
+ if (!revisionDeltas.isEmpty())
+ {
+ for (CDORevisionDelta dirtyObject : revisionDeltas.values())
+ {
+ CDOID id = dirtyObject.getID();
+ if (isObjectNew(id))
+ {
+ idsOfNewObjectsWithDeltas.add(id);
+ }
+ }
+ }
+
+ // Rollback all detached objects
+ Map<CDOID, CDOObject> detachedObjectsMap = itrSavepoint.getDetachedObjects();
+ if (!detachedObjectsMap.isEmpty())
+ {
+ for (Entry<CDOID, CDOObject> detachedObjectEntry : detachedObjectsMap.entrySet())
+ {
+ CDOID id = detachedObjectEntry.getKey();
+ if (isObjectNew(id))
+ {
+ idsOfNewObjectsWithDeltas.add(id);
+ }
+ else
+ {
+ InternalCDOObject detachedObject = (InternalCDOObject)detachedObjectEntry.getValue();
+ InternalCDORevision cleanRev = cleanRevisions.get(detachedObject);
+ cleanObject(detachedObject, cleanRev);
+ }
+ }
+ }
+
+ for (Entry<CDOID, CDOObject> entryDirtyObject : itrSavepoint.getDirtyObjects().entrySet())
+ {
+ CDOID id = entryDirtyObject.getKey();
+ if (!isObjectNew(id))
+ {
+ InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirtyObject.getValue();
+
+ // Bug 283985 (Re-attachment): Skip objects that were reattached, because
+ // they were already reset to TRANSIENT earlier in this method
+ if (!reattachedObjectsMap.values().contains(internalDirtyObject))
+ {
+ CDOStateMachine.INSTANCE.rollback(internalDirtyObject);
+ }
+ }
+ }
+
+ if (savepoint == itrSavepoint)
+ {
+ break;
+ }
+ }
+
+ return idsOfNewObjectsWithDeltas;
+ }
+
+ private void loadSavepoint(CDOSavepoint savepoint, Set<CDOID> idsOfNewObjectWithDeltas)
+ {
+ Map<CDOID, CDOObject> dirtyObjects = getDirtyObjects();
+ Map<CDOID, CDOObject> newObjMaps = getNewObjects();
+ Map<CDOID, CDORevision> newBaseRevision = getBaseNewObjects();
+ Map<CDOID, CDOObject> detachedObjects = getDetachedObjects();
+
+ // Reload the objects (NEW) with their base.
+ for (CDOID id : idsOfNewObjectWithDeltas)
+ {
+ if (detachedObjects.containsKey(id))
+ {
+ continue;
+ }
+
+ InternalCDOObject object = (InternalCDOObject)newObjMaps.get(id);
+ CDORevision revision = newBaseRevision.get(id);
+ if (revision != null)
+ {
+ object.cdoInternalSetRevision(revision.copy());
+ object.cdoInternalSetView(this);
+ object.cdoInternalSetID(revision.getID());
+ object.cdoInternalSetState(CDOState.NEW);
+
+ // Load the object from revision to EObject
+ object.cdoInternalPostLoad();
+ if (super.getObject(object.cdoID(), false) == null)
+ {
+ registerObject(object);
+ }
+ }
+ }
+
+ // We need to register back new objects that are not removed anymore there.
+ for (Entry<CDOID, CDOObject> entryNewObject : newObjMaps.entrySet())
+ {
+ InternalCDOObject object = (InternalCDOObject)entryNewObject.getValue();
+
+ // Go back to the previous state
+ cleanObject(object, object.cdoRevision());
+ object.cdoInternalSetState(CDOState.NEW);
+ }
+
+ for (Entry<CDOID, CDOObject> entryDirtyObject : dirtyObjects.entrySet())
+ {
+ if (detachedObjects.containsKey(entryDirtyObject.getKey()))
+ {
+ continue;
+ }
+
+ // Rollback every persisted objects
+ InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirtyObject.getValue();
+ cleanObject(internalDirtyObject, getRevision(entryDirtyObject.getKey(), true));
+ }
+
+ CDOObjectMerger merger = new CDOObjectMerger();
+ for (InternalCDOSavepoint itrSavepoint = firstSavepoint; itrSavepoint != savepoint; itrSavepoint = itrSavepoint
+ .getNextSavepoint())
+ {
+ for (CDORevisionDelta delta : itrSavepoint.getRevisionDeltas().values())
+ {
+ CDOID id = delta.getID();
+ boolean isNew = isObjectNew(id);
+ if (isNew && !idsOfNewObjectWithDeltas.contains(id) || detachedObjects.containsKey(id))
+ {
+ continue;
+ }
+
+ Map<CDOID, CDOObject> map = isNew ? newObjMaps : dirtyObjects;
+ InternalCDOObject object = (InternalCDOObject)map.get(id);
+
+ // Change state of the objects
+ merger.merge(object, delta);
+
+ // Load the object from revision to EObject
+ object.cdoInternalPostLoad();
+ }
+ }
+
+ dirty = savepoint.wasDirty();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void detachObject(InternalCDOObject object)
+ {
+ CDOTransactionHandler1[] handlers = getTransactionHandlers1();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ CDOTransactionHandler1 handler = handlers[i];
+ handler.detachingObject(this, object);
+ }
+
+ // deregister object
+ CDOID id = object.cdoID();
+ if (object.cdoState() == CDOState.NEW)
+ {
+ Map<CDOID, CDOObject> map = getLastSavepoint().getNewObjects();
+
+ // Determine if we added object
+ if (map.containsKey(id))
+ {
+ map.remove(id);
+ }
+ else
+ {
+ getLastSavepoint().getDetachedObjects().put(id, object);
+ }
+
+ // deregister object
+ deregisterObject(object);
+ }
+ else
+ {
+ getLastSavepoint().getDetachedObjects().put(id, object);
+
+ if (!cleanRevisions.containsKey(object))
+ {
+ cleanRevisions.put(object, object.cdoRevision());
+ }
+
+ // Object may have been reattached previously, in which case it must
+ // here be removed from the collection of reattached objects
+ lastSavepoint.getReattachedObjects().remove(id);
+ }
+
+ if (!dirty)
+ {
+ dirty = true;
+ IListener[] listeners = getListeners();
+ if (listeners != null)
+ {
+ fireEvent(new StartedEvent(), listeners);
+ }
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized void handleRollback(InternalCDOSavepoint savepoint)
+ {
+ if (savepoint == null)
+ {
+ throw new IllegalArgumentException(Messages.getString("CDOTransactionImpl.3")); //$NON-NLS-1$
+ }
+
+ if (savepoint.getTransaction() != this)
+ {
+ throw new IllegalArgumentException(MessageFormat.format(Messages.getString("CDOTransactionImpl.4"), savepoint)); //$NON-NLS-1$
+ }
+
+ if (!savepoint.isValid())
+ {
+ throw new IllegalArgumentException(MessageFormat.format(Messages.getString("CDOTransactionImpl.6"), savepoint)); //$NON-NLS-1$
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("handleRollback()"); //$NON-NLS-1$
+ }
+
+ try
+ {
+ // Remember current revisions
+ Map<CDOObject, CDORevision> oldRevisions = new HashMap<CDOObject, CDORevision>();
+ for (CDOObject object : getDirtyObjects().values())
+ {
+ CDORevision oldRevision = object.cdoRevision();
+ if (oldRevision != null)
+ {
+ oldRevisions.put(object, oldRevision);
+ }
+ }
+
+ // Rollback objects
+ Set<CDOID> idsOfNewObjectWithDeltas = rollbackCompletely(savepoint);
+
+ lastSavepoint = savepoint;
+ lastSavepoint.setNextSavepoint(null);
+ lastSavepoint.clear();
+
+ // Load from first savepoint up to current savepoint
+ loadSavepoint(lastSavepoint, idsOfNewObjectWithDeltas);
+
+ if (lastSavepoint == firstSavepoint && options().isAutoReleaseLocksEnabled())
+ {
+ CDORepositoryInfo repositoryInfo = getSession().getRepositoryInfo();
+ if (isDurableView() && repositoryInfo.getState() == CDOCommonRepository.State.ONLINE
+ || repositoryInfo.getType() == CDOCommonRepository.Type.MASTER)
+ {
+ // Unlock all objects
+ unlockObjects(null, null);
+ }
+ }
+
+ // Send notifications
+ for (Entry<CDOObject, CDORevision> entry : oldRevisions.entrySet())
+ {
+ InternalCDOObject object = (InternalCDOObject)entry.getKey();
+ if (FSMUtil.isTransient(object))
+ {
+ continue;
+ }
+
+ InternalCDORevision oldRevision = (InternalCDORevision)entry.getValue();
+ InternalCDORevision newRevision = object.cdoRevision();
+ if (newRevision == null)
+ {
+ newRevision = getRevision(oldRevision.getID(), true);
+ object.cdoInternalSetRevision(newRevision);
+ object.cdoInternalSetState(CDOState.CLEAN);
+ }
+
+ if (newRevision != null)
+ {
+ InternalCDORevisionDelta delta = newRevision.compare(oldRevision);
+ if (!delta.isEmpty())
+ {
+ Set<CDOObject> detachedObjects = Collections.emptySet();
+
+ CDONotificationBuilder builder = new CDONotificationBuilder(this);
+ NotificationChain notification = builder.buildNotification(object, oldRevision, delta, detachedObjects);
+ if (notification != null)
+ {
+ notification.dispatch();
+ }
+ }
+ }
+ }
+
+ Map<CDOID, CDOID> idMappings = Collections.emptyMap();
+ IListener[] listeners = getListeners();
+ if (listeners != null)
+ {
+ fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.ROLLED_BACK, idMappings), listeners);
+ }
+
+ CDOTransactionHandler2[] handlers = getTransactionHandlers2();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ CDOTransactionHandler2 handler = handlers[i];
+
+ try
+ {
+ handler.rolledBackTransaction(this);
+ }
+ catch (RuntimeException ex)
+ {
+ OM.LOG.error(ex);
+ }
+ }
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized InternalCDOSavepoint handleSetSavepoint()
+ {
+ addToBase(lastSavepoint.getNewObjects());
+ lastSavepoint = createSavepoint(lastSavepoint);
+ return lastSavepoint;
+ }
+
+ private CDOSavepointImpl createSavepoint(InternalCDOSavepoint lastSavepoint)
+ {
+ return new CDOSavepointImpl(this, lastSavepoint);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized InternalCDOSavepoint setSavepoint()
+ {
+ checkActive();
+ return (InternalCDOSavepoint)getTransactionStrategy().setSavepoint(this);
+ }
+
+ private void addToBase(Map<CDOID, CDOObject> objects)
+ {
+ for (CDOObject object : objects.values())
+ {
+ // Load instance to revision
+ ((InternalCDOObject)object).cdoInternalPreCommit();
+ lastSavepoint.getBaseNewObjects().put(object.cdoID(), object.cdoRevision().copy());
+ }
+ }
+
+ @Override
+ protected String getClassName()
+ {
+ return "CDOTransaction"; //$NON-NLS-1$
+ }
+
+ public synchronized void registerAttached(InternalCDOObject object, boolean isNew)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Registering new object {0}", object); //$NON-NLS-1$
+ }
+
+ if (isNew)
+ {
+ registerNewPackage(object.eClass().getEPackage());
+ }
+
+ CDOTransactionHandler1[] handlers = getTransactionHandlers1();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ CDOTransactionHandler1 handler = handlers[i];
+ handler.attachingObject(this, object);
+ }
+
+ if (isNew)
+ {
+ registerNew(lastSavepoint.getNewObjects(), object);
+ }
+ }
+
+ private void registerNewPackage(EPackage ePackage)
+ {
+ CDOPackageRegistry packageRegistry = getSession().getPackageRegistry();
+ if (!packageRegistry.containsKey(ePackage.getNsURI()))
+ {
+ packageRegistry.putEPackage(ePackage);
+ }
+ }
+
+ /**
+ * Receives notification for new and dirty objects
+ */
+ public synchronized void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ CDOID id = object.cdoID();
+ boolean needToSaveFeatureDelta = true;
+
+ if (object.cdoState() == CDOState.NEW)
+ {
+ // Register Delta for new objects only if objectA doesn't belong to
+ // this savepoint
+ if (getLastSavepoint().getPreviousSavepoint() == null || featureDelta == null)
+ {
+ needToSaveFeatureDelta = false;
+ }
+ else
+ {
+ Map<CDOID, CDOObject> map = getLastSavepoint().getNewObjects();
+ needToSaveFeatureDelta = !map.containsKey(id);
+ }
+ }
+
+ if (needToSaveFeatureDelta)
+ {
+ CDORevisionDelta revisionDelta = lastSavepoint.getRevisionDeltas().get(id);
+ if (revisionDelta == null)
+ {
+ revisionDelta = CDORevisionUtil.createDelta(object.cdoRevision());
+ lastSavepoint.getRevisionDeltas().put(id, revisionDelta);
+ }
+
+ ((InternalCDORevisionDelta)revisionDelta).addFeatureDelta(featureDelta);
+ }
+
+ CDOTransactionHandler1[] handlers = getTransactionHandlers1();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ CDOTransactionHandler1 handler = handlers[i];
+ handler.modifyingObject(this, object, featureDelta);
+ }
+ }
+
+ public synchronized void registerRevisionDelta(CDORevisionDelta revisionDelta)
+ {
+ lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta);
+ }
+
+ public synchronized void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Registering dirty object {0}", object); //$NON-NLS-1$
+ }
+
+ if (featureDelta != null)
+ {
+ registerFeatureDelta(object, featureDelta);
+ }
+
+ registerNew(lastSavepoint.getDirtyObjects(), object);
+ }
+
+ /**
+ * TODO Simon: Should this method go to CDOSavePointImpl?
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private void registerNew(Map map, InternalCDOObject object)
+ {
+ Object old = map.put(object.cdoID(), object);
+ if (old != null)
+ {
+ throw new IllegalStateException(MessageFormat.format(Messages.getString("CDOTransactionImpl.10"), object)); //$NON-NLS-1$
+ }
+
+ if (!dirty)
+ {
+ dirty = true;
+ IListener[] listeners = getListeners();
+ if (listeners != null)
+ {
+ fireEvent(new StartedEvent(), listeners);
+ }
+ }
+ }
+
+ public synchronized List<CDOPackageUnit> analyzeNewPackages()
+ {
+ CDOPackageRegistry packageRegistry = getSession().getPackageRegistry();
+ Set<EPackage> usedPackages = new HashSet<EPackage>();
+ Set<EPackage> usedNewPackages = new HashSet<EPackage>();
+ for (CDOObject object : getNewObjects().values())
+ {
+ EPackage ePackage = object.eClass().getEPackage();
+ if (usedPackages.add(ePackage))
+ {
+ EPackage topLevelPackage = EMFUtil.getTopLevelPackage(ePackage);
+ if (ePackage == topLevelPackage || usedPackages.add(topLevelPackage))
+ {
+ // if (!CDOModelUtil.isSystemPackage(topLevelPackage))
+ {
+ CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(topLevelPackage);
+ if (packageUnit.getState() == CDOPackageUnit.State.NEW)
+ {
+ usedNewPackages.add(topLevelPackage);
+ }
+ }
+ }
+ }
+ }
+
+ if (usedNewPackages.size() > 0)
+ {
+ Set<CDOPackageUnit> result = new HashSet<CDOPackageUnit>();
+ for (EPackage usedNewPackage : analyzeNewPackages(usedNewPackages, packageRegistry))
+ {
+ CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(usedNewPackage);
+ result.add(packageUnit);
+ }
+
+ return new ArrayList<CDOPackageUnit>(result);
+ }
+
+ return Collections.emptyList();
+ }
+
+ private static List<EPackage> analyzeNewPackages(Collection<EPackage> usedTopLevelPackages,
+ CDOPackageRegistry packageRegistry)
+ {
+ // Determine which of the corresdonding EPackages are new
+ List<EPackage> newPackages = new ArrayList<EPackage>();
+
+ IPackageClosure closure = new CompletePackageClosure();
+ usedTopLevelPackages = closure.calculate(usedTopLevelPackages);
+
+ for (EPackage usedPackage : usedTopLevelPackages)
+ {
+ // if (!CDOModelUtil.isSystemPackage(usedPackage))
+ {
+ CDOPackageUnit packageUnit = packageRegistry.getPackageUnit(usedPackage);
+ if (packageUnit == null)
+ {
+ throw new CDOException(MessageFormat.format(Messages.getString("CDOTransactionImpl.11"), usedPackage)); //$NON-NLS-1$
+ }
+
+ if (packageUnit.getState() == CDOPackageUnit.State.NEW)
+ {
+ newPackages.add(usedPackage);
+ }
+ }
+ }
+
+ return newPackages;
+ }
+
+ private void cleanUp(CDOCommitContext commitContext)
+ {
+ if (commitContext == null || !commitContext.isPartialCommit())
+ {
+ lastSavepoint = firstSavepoint;
+ firstSavepoint.clear();
+ firstSavepoint.setNextSavepoint(null);
+
+ cleanRevisions.clear();
+ dirty = false;
+ conflict = 0;
+ idGenerator.reset();
+ }
+ else
+ {
+ collapseSavepoints(commitContext);
+
+ for (CDOObject object : commitContext.getDetachedObjects().values())
+ {
+ cleanRevisions.remove(object);
+ }
+
+ for (CDOObject object : commitContext.getDirtyObjects().values())
+ {
+ cleanRevisions.remove(object);
+ }
+ }
+
+ // Reset partial-commit filter
+ committables = null;
+ }
+
+ private void collapseSavepoints(CDOCommitContext commitContext)
+ {
+ InternalCDOSavepoint newSavepoint = createSavepoint(null);
+ copyUncommitted(lastSavepoint.getAllNewObjects(), commitContext.getNewObjects(), newSavepoint.getNewObjects());
+ copyUncommitted(lastSavepoint.getAllDirtyObjects(), commitContext.getDirtyObjects(), newSavepoint.getDirtyObjects());
+ copyUncommitted(lastSavepoint.getAllRevisionDeltas(), commitContext.getRevisionDeltas(),
+ newSavepoint.getRevisionDeltas());
+ copyUncommitted(lastSavepoint.getAllDetachedObjects(), commitContext.getDetachedObjects(),
+ newSavepoint.getDetachedObjects());
+ lastSavepoint = newSavepoint;
+ firstSavepoint = lastSavepoint;
+ }
+
+ private <T> void copyUncommitted(Map<CDOID, T> oldSavepointMap, Map<CDOID, T> commitContextMap,
+ Map<CDOID, T> newSavepointMap)
+ {
+ for (Entry<CDOID, T> entry : oldSavepointMap.entrySet())
+ {
+ if (!commitContextMap.containsKey(entry.getKey()))
+ {
+ newSavepointMap.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ public synchronized CDOSavepoint[] exportChanges(OutputStream stream) throws IOException
+ {
+ CDODataOutput out = new CDODataOutputImpl(new ExtendedDataOutputStream(stream))
+ {
+ @Override
+ public CDOIDProvider getIDProvider()
+ {
+ return CDOTransactionImpl.this;
+ }
+
+ @Override
+ public CDOPackageRegistry getPackageRegistry()
+ {
+ return getSession().getPackageRegistry();
+ }
+ };
+
+ List<CDOSavepoint> savepoints = new ArrayList<CDOSavepoint>();
+ int totalNewObjects = 0;
+
+ InternalCDOSavepoint savepoint = firstSavepoint;
+ while (savepoint != null)
+ {
+ Collection<CDOObject> newObjects = savepoint.getNewObjects().values();
+ totalNewObjects += newObjects.size();
+
+ savepoint = savepoint.getNextSavepoint();
+ }
+
+ out.writeInt(totalNewObjects);
+
+ savepoint = firstSavepoint;
+ while (savepoint != null)
+ {
+ Collection<CDOObject> newObjects = savepoint.getNewObjects().values();
+ Collection<CDORevisionDelta> revisionDeltas = savepoint.getRevisionDeltas().values();
+ if (newObjects.isEmpty() && revisionDeltas.isEmpty())
+ {
+ savepoint = savepoint.getNextSavepoint();
+ continue;
+ }
+
+ savepoints.add(savepoint);
+ out.writeBoolean(true);
+
+ out.writeInt(newObjects.size());
+ for (CDOObject newObject : newObjects)
+ {
+ out.writeCDORevision(newObject.cdoRevision(), CDORevision.UNCHUNKED);
+ }
+
+ out.writeInt(revisionDeltas.size());
+ for (CDORevisionDelta revisionDelta : revisionDeltas)
+ {
+ out.writeCDORevisionDelta(revisionDelta);
+ }
+
+ savepoint = savepoint.getNextSavepoint();
+ }
+
+ out.writeBoolean(false);
+ return savepoints.toArray(new CDOSavepoint[savepoints.size()]);
+ }
+
+ public synchronized CDOSavepoint[] importChanges(InputStream stream, boolean reconstructSavepoints)
+ throws IOException
+ {
+ List<CDOSavepoint> savepoints = new ArrayList<CDOSavepoint>();
+ if (stream.available() > 0)
+ {
+ CDODataInput in = new CDODataInputImpl(new ExtendedDataInputStream(stream))
+ {
+ @Override
+ protected CDOPackageRegistry getPackageRegistry()
+ {
+ return getSession().getPackageRegistry();
+ }
+
+ @Override
+ protected CDOBranchManager getBranchManager()
+ {
+ return getSession().getBranchManager();
+ }
+
+ @Override
+ protected CDOCommitInfoManager getCommitInfoManager()
+ {
+ return getSession().getCommitInfoManager();
+ }
+
+ @Override
+ protected CDORevisionFactory getRevisionFactory()
+ {
+ return getSession().getRevisionManager().getFactory();
+ }
+
+ @Override
+ protected CDOLobStore getLobStore()
+ {
+ return getSession().getLobStore();
+ }
+
+ @Override
+ protected CDOListFactory getListFactory()
+ {
+ return CDOListWithElementProxiesImpl.FACTORY;
+ }
+ };
+
+ // Increase the internal tempID counter to prevent ID collisions during mapping
+ int totalNewObjects = in.readInt();
+ for (int i = 0; i < totalNewObjects; i++)
+ {
+ createIDForNewObject(null);
+ }
+
+ Map<CDOID, CDOID> idMappings = new HashMap<CDOID, CDOID>();
+ while (in.readBoolean())
+ {
+ if (reconstructSavepoints)
+ {
+ InternalCDOSavepoint savepoint = setSavepoint();
+ savepoints.add(savepoint);
+ }
+
+ // Import revisions and deltas
+ List<InternalCDORevision> revisions = new ArrayList<InternalCDORevision>();
+ importNewRevisions(in, revisions, idMappings);
+ List<InternalCDORevisionDelta> revisionDeltas = importRevisionDeltas(in);
+
+ // Re-map temp IDs
+ CDOIDMapper idMapper = new CDOIDMapper(idMappings);
+ for (InternalCDORevision revision : revisions)
+ {
+ revision.adjustReferences(idMapper);
+ }
+
+ for (InternalCDORevisionDelta delta : revisionDeltas)
+ {
+ delta.adjustReferences(idMapper);
+ }
+
+ // Create new objects
+ List<InternalCDOObject> newObjects = new ArrayList<InternalCDOObject>();
+ for (InternalCDORevision revision : revisions)
+ {
+ InternalCDOObject object = newInstance(revision);
+ registerObject(object);
+ registerAttached(object, true);
+
+ newObjects.add(object);
+ }
+
+ // Post-load new objects (important for legacy objects!)
+ for (InternalCDOObject object : newObjects)
+ {
+ object.cdoInternalPostLoad();
+ }
+
+ // Apply deltas
+ CDOObjectMerger merger = new CDOObjectMerger();
+ for (InternalCDORevisionDelta delta : revisionDeltas)
+ {
+ InternalCDOObject object = getObject(delta.getID());
+ int oldVersion = object.cdoRevision().getVersion();
+
+ merger.merge(object, delta);
+ registerRevisionDelta(delta);
+ registerDirty(object, null);
+
+ if (delta.getVersion() < oldVersion)
+ {
+ setConflict(object);
+ }
+ }
+ }
+ }
+
+ return savepoints.toArray(new CDOSavepoint[savepoints.size()]);
+ }
+
+ private void importNewRevisions(CDODataInput in, List<InternalCDORevision> revisions, Map<CDOID, CDOID> idMappings)
+ throws IOException
+ {
+ int size = in.readInt();
+ for (int i = 0; i < size; i++)
+ {
+ InternalCDORevision revision = (InternalCDORevision)in.readCDORevision(false);
+
+ CDOID oldID = revision.getID();
+ if (oldID.isTemporary())
+ {
+ CDOID newID = createIDForNewObject(null);
+ idMappings.put(oldID, newID);
+ revision.setID(newID);
+ }
+
+ revisions.add(revision);
+ }
+ }
+
+ private List<InternalCDORevisionDelta> importRevisionDeltas(CDODataInput in) throws IOException
+ {
+ int size = in.readInt();
+ List<InternalCDORevisionDelta> deltas = new ArrayList<InternalCDORevisionDelta>(size);
+ for (int i = 0; i < size; i++)
+ {
+ InternalCDORevisionDelta delta = (InternalCDORevisionDelta)in.readCDORevisionDelta();
+ deltas.add(delta);
+ }
+
+ return deltas;
+ }
+
+ private InternalCDOObject newInstance(InternalCDORevision revision)
+ {
+ InternalCDOObject object = newInstance(revision.getEClass());
+ object.cdoInternalSetID(revision.getID());
+ object.cdoInternalSetRevision(revision);
+ object.cdoInternalSetState(CDOState.NEW);
+ object.cdoInternalSetView(this);
+ return object;
+ }
+
+ public synchronized Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllDirtyObjects();
+ }
+
+ public synchronized Map<CDOID, CDOObject> getNewObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllNewObjects();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized Map<CDOID, CDORevision> getBaseNewObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllBaseNewObjects();
+ }
+
+ public synchronized Map<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ checkActive();
+ return lastSavepoint.getAllRevisionDeltas();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public synchronized Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllDetachedObjects();
+ }
+
+ @Override
+ protected synchronized CDOID getXRefTargetID(CDOObject target)
+ {
+ CDORevisionKey key = cleanRevisions.get(target);
+ if (key != null)
+ {
+ return key.getID();
+ }
+
+ return super.getXRefTargetID(target);
+ }
+
+ @Override
+ protected synchronized CDOID getID(InternalCDOObject object, boolean onlyPersistedID)
+ {
+ CDOID id = super.getID(object, onlyPersistedID);
+
+ // If super returned a good result, return immediately
+ if (id != null)
+ {
+ return id;
+ }
+
+ // Don't perform the trickery that follows later in this method, if we are being called
+ // indirectly through provideCDOID. This occurs when deltas or revisions are
+ // being written out to a stream; in which case null must be returned (for transients) so that
+ // the caller will detect a dangling reference
+ if (providingCDOID.get())
+ {
+ return null;
+ }
+
+ // The super implementation will return null for a transient (unattached) object;
+ // but in a tx, an transient object may previously have been attached. So we consult
+ // the cleanRevisions if that's the case.
+ CDORevisionKey revKey = cleanRevisions.get(object);
+ if (revKey != null && getDetachedObjects().containsValue(object))
+ {
+ id = revKey.getID();
+ }
+
+ return id;
+ }
+
+ @Override
+ public synchronized CDOID provideCDOID(Object idOrObject)
+ {
+ try
+ {
+ providingCDOID.set(true);
+ return super.provideCDOID(idOrObject);
+ }
+ finally
+ {
+ providingCDOID.set(false);
+ }
+ }
+
+ @Override
+ public synchronized CDOQueryImpl createQuery(String language, String queryString, Object context)
+ {
+ return createQuery(language, queryString, context, false);
+ }
+
+ public synchronized CDOQueryImpl createQuery(String language, String queryString, boolean considerDirtyState)
+ {
+ return createQuery(language, queryString, null, considerDirtyState);
+ }
+
+ public synchronized CDOQueryImpl createQuery(String language, String queryString, Object context,
+ boolean considerDirtyState)
+ {
+ CDOQueryImpl query = super.createQuery(language, queryString, context);
+ if (considerDirtyState && isDirty())
+ {
+ query.setChangeSetData(getChangeSetData());
+ }
+
+ return query;
+ }
+
+ @Override
+ protected void doActivate() throws Exception
+ {
+ super.doActivate();
+
+ InternalCDOSession session = getSession();
+ if (session.getRepositoryInfo().getIDGenerationLocation() == IDGenerationLocation.STORE)
+ {
+ idGenerator = new TempIDGenerator();
+ }
+ else
+ {
+ idGenerator = session.getIDGenerator();
+ if (idGenerator == null)
+ {
+ idGenerator = CDOIDGenerator.UUID;
+ }
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ options().disposeConflictResolvers();
+ lastSavepoint = null;
+ firstSavepoint = null;
+ transactionStrategy = null;
+ idGenerator = null;
+ super.doDeactivate();
+ }
+
+ /**
+ * Bug 298561: This override removes references to remotely detached objects that are present in any DIRTY or NEW
+ * objects.
+ *
+ * @since 3.0
+ */
+ /*
+ * Synchronized through InvlidationRunner.run()
+ */
+ @Override
+ protected Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> invalidate(long lastUpdateTime,
+ List<CDORevisionKey> allChangedObjects, List<CDOIDAndVersion> allDetachedObjects, List<CDORevisionDelta> deltas,
+ Map<CDOObject, CDORevisionDelta> revisionDeltas, Set<CDOObject> detachedObjects)
+ {
+ if (!allDetachedObjects.isEmpty())
+ {
+ Set<CDOID> referencedOIDs = new HashSet<CDOID>();
+ for (CDOIDAndVersion key : allDetachedObjects)
+ {
+ referencedOIDs.add(key.getID());
+ }
+
+ Collection<CDOObject> cachedDirtyObjects = getDirtyObjects().values();
+ removeCrossReferences(cachedDirtyObjects, referencedOIDs);
+
+ Collection<CDOObject> cachedNewObjects = getNewObjects().values();
+ removeCrossReferences(cachedNewObjects, referencedOIDs);
+ }
+
+ // Bug 290032 - Sticky views
+ InternalCDOSession session = getSession();
+ if (session.isSticky())
+ {
+ session.clearCommittedSinceLastRefresh();
+ }
+
+ return super.invalidate(lastUpdateTime, allChangedObjects, allDetachedObjects, deltas, revisionDeltas,
+ detachedObjects);
+ }
+
+ private void removeCrossReferences(Collection<CDOObject> referencers, Set<CDOID> referencedOIDs)
+ {
+ List<Pair<Setting, EObject>> objectsToBeRemoved = new LinkedList<Pair<Setting, EObject>>();
+ for (CDOObject referencer : referencers)
+ {
+ FeatureIterator<EObject> it = getChangeableCrossReferences(referencer);
+ while (it.hasNext())
+ {
+ EObject referencedObject = it.next();
+ CDOID referencedOID = CDOUtil.getCDOObject(referencedObject).cdoID();
+
+ if (referencedOIDs.contains(referencedOID))
+ {
+ EReference reference = (EReference)it.feature();
+
+ // In the case of DIRTY, we must investigate further: Is the referencer dirty
+ // because a reference to the referencedObject was added? Only in this case
+ // should we remove it. If this is not the case (i.e. it is dirty in a different
+ // way), we skip it. (If the reference is not persistent, then this exception
+ // doesn't apply: it must be removed for sure.)
+ if (referencer.cdoState() == CDOState.DIRTY && EMFUtil.isPersistent(reference))
+ {
+ InternalCDORevision cleanRevision = cleanRevisions.get(referencer);
+
+ Object value = cleanRevision.get(reference, EStore.NO_INDEX);
+ if (value instanceof CDOObject && value == referencedObject || //
+ value instanceof CDOID && value.equals(referencedOID) || //
+ value instanceof CDOList && ((CDOList)value).contains(referencedOID))
+ {
+ continue;
+ }
+ }
+
+ Setting setting = ((InternalEObject)referencer).eSetting(reference);
+ objectsToBeRemoved.add(new Pair<Setting, EObject>(setting, referencedObject));
+ }
+ }
+ }
+
+ for (Pair<Setting, EObject> pair : objectsToBeRemoved)
+ {
+ EcoreUtil.remove(pair.getElement1(), pair.getElement2());
+ }
+ }
+
+ private FeatureIterator<EObject> getChangeableCrossReferences(EObject object)
+ {
+ FeatureSubsetSupplier features = (FeatureSubsetSupplier)object.eClass().getEAllStructuralFeatures();
+ EStructuralFeature[] crossReferences = features.crossReferences();
+ if (crossReferences != null)
+ {
+ List<EStructuralFeature> changeableReferences = new ArrayList<EStructuralFeature>();
+ for (int i = 0; i < crossReferences.length; i++)
+ {
+ EStructuralFeature reference = crossReferences[i];
+
+ // Filter out derived references
+ if (reference.isDerived())
+ {
+ continue;
+ }
+
+ // Filter out unchangeable references
+ if (!reference.isChangeable())
+ {
+ continue;
+ }
+
+ changeableReferences.add(reference);
+ }
+
+ if (!changeableReferences.isEmpty())
+ {
+ EStructuralFeature[] collectedStructuralFeatures = changeableReferences
+ .toArray(new EStructuralFeature[changeableReferences.size()]);
+ return (FeatureIterator<EObject>)new ECrossReferenceEListDerived(object, collectedStructuralFeatures)
+ .iterator();
+ }
+ }
+
+ return (FeatureIterator<EObject>)ECrossReferenceEList.<EObject> emptyContentsEList().iterator();
+ }
+
+ public synchronized long getLastCommitTime()
+ {
+ return lastCommitTime;
+ }
+
+ public synchronized String getCommitComment()
+ {
+ return commitComment;
+ }
+
+ public synchronized void setCommitComment(String comment)
+ {
+ commitComment = comment;
+ }
+
+ public synchronized void setCommittables(Set<? extends EObject> committables)
+ {
+ this.committables = committables;
+ }
+
+ public synchronized Set<? extends EObject> getCommittables()
+ {
+ return committables;
+ }
+
+ public synchronized Map<InternalCDOObject, InternalCDORevision> getCleanRevisions()
+ {
+ return cleanRevisions;
+ }
+
+ @Override
+ protected InternalCDORevision getViewedRevision(InternalCDOObject object)
+ {
+ InternalCDORevision rev = super.getViewedRevision(object);
+
+ // Bug 336590: If we have a clean revision for this object, return that instead
+ if (rev != null)
+ {
+ InternalCDORevision cleanRev = cleanRevisions.get(object);
+ if (cleanRev != null)
+ {
+ return cleanRev;
+ }
+ }
+
+ return rev;
+ }
+
+ @Override
+ protected InternalCDORevision getRevision(CDOObject object)
+ {
+ if (object.cdoState() == CDOState.TRANSIENT)
+ {
+ InternalCDORevision revision = cleanRevisions.get(object);
+ if (revision == null)
+ {
+ throw new IllegalStateException("No revision for transient object " + object);
+ }
+
+ return revision;
+ }
+
+ return super.getRevision(object);
+ }
+
+ @Override
+ protected InternalCDOLockState createUpdatedLockStateForNewObject(CDOObject object, LockType lockType, boolean on)
+ {
+ CheckUtil.checkState(FSMUtil.isNew(object), "Object is not in NEW state");
+ CheckUtil.checkArg(lockType, "lockType");
+
+ InternalCDOLockState lockState = (InternalCDOLockState)getLockState(object);
+ if (lockState == null)
+ {
+ CheckUtil.checkArg(on == true, "on != true");
+ Object lockTarget = getLockTarget(object);
+ lockState = (InternalCDOLockState)CDOLockUtil.createLockState(lockTarget);
+ }
+ else
+ {
+ lockState = (InternalCDOLockState)CDOLockUtil.copyLockState(lockState);
+ }
+
+ CDOLockOwner lockOwner = CDOLockUtil.createLockOwner(this);
+
+ if (on)
+ {
+ switch (lockType)
+ {
+ case READ:
+ lockState.addReadLockOwner(lockOwner);
+ break;
+ case WRITE:
+ lockState.setWriteLockOwner(lockOwner);
+ break;
+ case OPTION:
+ lockState.setWriteOptionOwner(lockOwner);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown lock type " + lockType);
+ }
+ }
+ else
+ {
+ switch (lockType)
+ {
+ case READ:
+ lockState.removeReadLockOwner(lockOwner);
+ break;
+ case WRITE:
+ lockState.setWriteLockOwner(null);
+ break;
+ case OPTION:
+ lockState.setWriteOptionOwner(null);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown lock type " + lockType);
+ }
+ }
+
+ return lockState;
+ }
+
+ @Override
+ protected List<CDOLockState> createUnlockedLockStatesForAllNewObjects()
+ {
+ List<CDOLockState> locksOnNewObjects = new LinkedList<CDOLockState>();
+ for (CDOObject object : getNewObjects().values())
+ {
+ Object lockTarget = getLockTarget(object);
+ CDOLockState lockState = CDOLockUtil.createLockState(lockTarget);
+ locksOnNewObjects.add(lockState);
+ }
+
+ return locksOnNewObjects;
+ }
+
+ private static Object getLockTarget(CDOObject object)
+ {
+ CDOView view = object.cdoView();
+ if (view == null)
+ {
+ return null;
+ }
+
+ CDOID id = object.cdoID();
+ boolean branching = view.getSession().getRepositoryInfo().isSupportingBranches();
+ if (branching)
+ {
+ return CDOIDUtil.createIDAndBranch(id, view.getBranch());
+ }
+
+ return id;
+ }
+
+ private final class ResolvingRevisionMap extends HashMap<InternalCDOObject, InternalCDORevision>
+ {
+ private static final long serialVersionUID = 1L;
+
+ public ResolvingRevisionMap()
+ {
+ }
+
+ @Override
+ public InternalCDORevision get(Object cdoObject)
+ {
+ InternalCDORevision revision = super.get(cdoObject);
+ if (revision != null)
+ {
+ getSession().resolveAllElementProxies(revision);
+ }
+
+ return revision;
+ }
+ }
+
+ /**
+ * Generates {@link CDOIDTemp temporary} ID values.
+ *
+ * @author Eike Stepper
+ */
+ private static final class TempIDGenerator implements CDOIDGenerator
+ {
+ private AtomicInteger lastTemporaryID = new AtomicInteger();
+
+ public TempIDGenerator()
+ {
+ }
+
+ public CDOID generateCDOID(EObject object)
+ {
+ return CDOIDUtil.createTempObject(lastTemporaryID.incrementAndGet());
+ }
+
+ public void reset()
+ {
+ lastTemporaryID.set(0);
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private final class CDOCommitContextImpl implements InternalCDOCommitContext
+ {
+ private InternalCDOTransaction transaction;
+
+ /**
+ * Tracks whether this commit is *actually* partial or not. (Having tx.committables != null does not in itself mean
+ * that the commit will be partial, because the committables could cover all dirty/new/detached objects. But this
+ * boolean gets set to reflect whether the commit will really commit less than all dirty/new/detached objects.)
+ */
+ private boolean isPartialCommit;
+
+ private CDOCommitData commitData;
+
+ private Collection<CDOLockState> locksOnNewObjects;
+
+ private Map<CDOID, CDOObject> newObjects;
+
+ private Map<CDOID, CDOObject> detachedObjects;
+
+ private Map<CDOID, CDORevisionDelta> revisionDeltas;
+
+ private Map<CDOID, CDOObject> dirtyObjects;
+
+ private Map<ByteArrayWrapper, CDOLob<?>> lobs = new HashMap<ByteArrayWrapper, CDOLob<?>>();
+
+ public CDOCommitContextImpl(InternalCDOTransaction transaction)
+ {
+ this.transaction = transaction;
+ calculateCommitData();
+ }
+
+ private void calculateCommitData()
+ {
+ List<CDOPackageUnit> newPackageUnits = analyzeNewPackages();
+ newObjects = filterCommittables(transaction.getNewObjects());
+ List<CDOIDAndVersion> revisions = new ArrayList<CDOIDAndVersion>(newObjects.size());
+ for (CDOObject newObject : newObjects.values())
+ {
+ revisions.add(newObject.cdoRevision());
+ }
+
+ revisionDeltas = filterCommittables(transaction.getRevisionDeltas());
+ List<CDORevisionKey> deltas = new ArrayList<CDORevisionKey>(revisionDeltas.size());
+ for (CDORevisionDelta delta : revisionDeltas.values())
+ {
+ deltas.add(delta);
+ }
+
+ detachedObjects = filterCommittables(transaction.getDetachedObjects());
+ List<CDOIDAndVersion> detached = new ArrayList<CDOIDAndVersion>(detachedObjects.size());
+ for (CDOID id : detachedObjects.keySet())
+ {
+ // Add "version-less" key.
+ // CDOSessionImpl.reviseRevisions() will call reviseLatest() accordingly.
+ detached.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION));
+ }
+
+ dirtyObjects = filterCommittables(transaction.getDirtyObjects());
+
+ CDOLockState[] locksOnNewObjectsArray = getLockStates(newObjects.keySet(), false);
+ locksOnNewObjects = Arrays.asList(locksOnNewObjectsArray);
+
+ commitData = new CDOCommitDataImpl(newPackageUnits, revisions, deltas, detached);
+ }
+
+ private <T> Map<CDOID, T> filterCommittables(Map<CDOID, T> map)
+ {
+ if (committables == null)
+ {
+ // No partial commit filter -- nothing to do
+ return map;
+ }
+
+ Map<CDOID, T> newMap = new HashMap<CDOID, T>();
+ for (Entry<CDOID, T> entry : map.entrySet())
+ {
+ CDOID id = entry.getKey();
+ CDOObject o = getObject(id);
+ if (committables.contains(o))
+ {
+ newMap.put(id, entry.getValue());
+ }
+ else
+ {
+ isPartialCommit = true;
+ }
+ }
+
+ return newMap;
+ }
+
+ public String getUserID()
+ {
+ return transaction.getSession().getUserID();
+ }
+
+ public int getViewID()
+ {
+ return transaction.getViewID();
+ }
+
+ public CDOBranch getBranch()
+ {
+ return transaction.getBranch();
+ }
+
+ public InternalCDOTransaction getTransaction()
+ {
+ return transaction;
+ }
+
+ public boolean isPartialCommit()
+ {
+ return isPartialCommit;
+ }
+
+ public boolean isAutoReleaseLocks()
+ {
+ return transaction.options().isAutoReleaseLocksEnabled();
+ }
+
+ public String getCommitComment()
+ {
+ return transaction.getCommitComment();
+ }
+
+ public CDOCommitData getCommitData()
+ {
+ return commitData;
+ }
+
+ public Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ return dirtyObjects;
+ }
+
+ public Map<CDOID, CDOObject> getNewObjects()
+ {
+ return newObjects;
+ }
+
+ public List<CDOPackageUnit> getNewPackageUnits()
+ {
+ return commitData.getNewPackageUnits();
+ }
+
+ public Collection<CDOLockState> getLocksOnNewObjects()
+ {
+ return locksOnNewObjects;
+ }
+
+ public Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ return detachedObjects;
+ }
+
+ public Map<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ return revisionDeltas;
+ }
+
+ public Collection<CDOLob<?>> getLobs()
+ {
+ return lobs.values();
+ }
+
+ public void preCommit()
+ {
+ if (isDirty())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("commit()"); //$NON-NLS-1$
+ }
+
+ CDOTransactionHandler2[] handlers = getTransactionHandlers2();
+ if (handlers.length != 0)
+ {
+ final boolean[] modifiedAgain = { false };
+ CDOTransactionHandler1 modifiedAgainHandler = new CDODefaultTransactionHandler1()
+ {
+ @Override
+ public void modifyingObject(CDOTransaction transaction, CDOObject object, CDOFeatureDelta featureChange)
+ {
+ modifiedAgain[0] = true;
+ }
+ };
+
+ addTransactionHandler(modifiedAgainHandler);
+
+ try
+ {
+ for (int i = 0; i < handlers.length; i++)
+ {
+ modifiedAgain[0] = false;
+ CDOTransactionHandler2 handler = handlers[i];
+ handler.committingTransaction(getTransaction(), this);
+ if (modifiedAgain[0])
+ {
+ calculateCommitData();
+ }
+ }
+ }
+ finally
+ {
+ removeTransactionHandler(modifiedAgainHandler);
+ }
+ }
+
+ try
+ {
+ // TODO (CD) It might be wise to always do the checks,
+ // instead of only for partial commits
+ if (isPartialCommit)
+ {
+ new CommitIntegrityCheck(this, CommitIntegrityCheck.Style.EXCEPTION_FAST).check();
+ }
+
+ preCommit(getNewObjects(), lobs);
+ preCommit(getDirtyObjects(), lobs);
+
+ if (!lobs.isEmpty())
+ {
+ CDOSessionProtocol sessionProtocol = getSession().getSessionProtocol();
+ List<byte[]> alreadyKnown = sessionProtocol.queryLobs(ByteArrayWrapper.toByteArray(lobs.keySet()));
+
+ for (byte[] id : alreadyKnown)
+ {
+ lobs.remove(new ByteArrayWrapper(id));
+ }
+ }
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+ }
+
+ public void postCommit(CommitTransactionResult result)
+ {
+ try
+ {
+ InternalCDOSession session = getSession();
+ long timeStamp = result.getTimeStamp();
+
+ if (result.getRollbackMessage() != null)
+ {
+ CDOCommitInfo commitInfo = new FailureCommitInfo(timeStamp, result.getPreviousTimeStamp());
+ session.invalidate(commitInfo, transaction);
+ return;
+ }
+
+ CDOBranch branch = result.getBranch();
+ boolean branchChanged = !ObjectUtil.equals(branch, getBranch());
+ if (branchChanged)
+ {
+ basicSetBranchPoint(branch.getHead());
+ }
+
+ for (CDOPackageUnit newPackageUnit : getNewPackageUnits())
+ {
+ ((InternalCDOPackageUnit)newPackageUnit).setState(CDOPackageUnit.State.LOADED);
+ }
+
+ postCommit(getNewObjects(), result);
+ postCommit(getDirtyObjects(), result);
+
+ for (CDORevisionDelta delta : getRevisionDeltas().values())
+ {
+ ((InternalCDORevisionDelta)delta).adjustReferences(result.getReferenceAdjuster());
+ }
+
+ for (CDOID id : getDetachedObjects().keySet())
+ {
+ removeObject(id);
+ }
+
+ CDOCommitInfo commitInfo = makeCommitInfo(timeStamp, result.getPreviousTimeStamp());
+ session.invalidate(commitInfo, transaction);
+
+ // Bug 290032 - Sticky views
+ if (session.isSticky())
+ {
+ CDOBranchPoint commitBranchPoint = CDOBranchUtil.copyBranchPoint(result);
+ for (CDOObject object : getNewObjects().values()) // Note: keyset() does not work because ID mappings are
+ // not applied there!
+ {
+ session.setCommittedSinceLastRefresh(object.cdoID(), commitBranchPoint);
+ }
+
+ for (CDOID id : getDirtyObjects().keySet())
+ {
+ session.setCommittedSinceLastRefresh(id, commitBranchPoint);
+ }
+
+ for (CDOID id : getDetachedObjects().keySet())
+ {
+ session.setCommittedSinceLastRefresh(id, commitBranchPoint);
+ }
+ }
+
+ CDOTransactionHandler2[] handlers = getTransactionHandlers2();
+ for (int i = 0; i < handlers.length; i++)
+ {
+ CDOTransactionHandler2 handler = handlers[i];
+ if (handler instanceof CDOTransactionHandler3)
+ {
+ CDOTransactionHandler3 handler3 = (CDOTransactionHandler3)handler;
+ handler3.committedTransaction(transaction, this, commitInfo);
+ }
+ else
+ {
+ handler.committedTransaction(transaction, this);
+ }
+ }
+
+ getChangeSubscriptionManager().committedTransaction(transaction, this);
+ getAdapterManager().committedTransaction(transaction, this);
+
+ cleanUp(this);
+ Map<CDOID, CDOID> idMappings = result.getIDMappings();
+ IListener[] listeners = getListeners();
+ if (listeners != null)
+ {
+ if (branchChanged)
+ {
+ fireViewTargetChangedEvent(listeners);
+ }
+
+ fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings), listeners);
+ }
+
+ CDOLockState[] newLockStates = result.getNewLockStates();
+ if (newLockStates != null)
+ {
+ updateAndNotifyLockStates(Operation.UNLOCK, null, result.getTimeStamp(), newLockStates);
+ }
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+
+ private CDOCommitInfo makeCommitInfo(long timeStamp, long previousTimeStamp)
+ {
+ InternalCDOSession session = getSession();
+ CDOBranch branch = getBranch();
+ String userID = session.getUserID();
+ String comment = getCommitComment();
+
+ InternalCDOCommitInfoManager commitInfoManager = session.getCommitInfoManager();
+ return commitInfoManager.createCommitInfo(branch, timeStamp, previousTimeStamp, userID, comment, commitData);
+ }
+
+ private void preCommit(Map<CDOID, CDOObject> objects, Map<ByteArrayWrapper, CDOLob<?>> lobs)
+ {
+ if (!objects.isEmpty())
+ {
+ boolean noLegacy = !isLegacyModeEnabled();
+ for (CDOObject object : objects.values())
+ {
+ if (noLegacy && object instanceof CDOObjectWrapper)
+ {
+ throw new LegacyModeNotEnabledException();
+ }
+
+ collectLobs((InternalCDORevision)object.cdoRevision(), lobs);
+ ((InternalCDOObject)object).cdoInternalPreCommit();
+ }
+ }
+ }
+
+ private void collectLobs(InternalCDORevision revision, Map<ByteArrayWrapper, CDOLob<?>> lobs)
+ {
+ EStructuralFeature[] features = revision.getClassInfo().getAllPersistentFeatures();
+ for (int i = 0; i < features.length; i++)
+ {
+ EStructuralFeature feature = features[i];
+ if (CDOModelUtil.isLob(feature.getEType()))
+ {
+ CDOLob<?> lob = (CDOLob<?>)revision.getValue(feature);
+ if (lob != null)
+ {
+ lobs.put(new ByteArrayWrapper(lob.getID()), lob);
+ }
+ }
+ }
+ }
+
+ private void postCommit(Map<CDOID, CDOObject> objects, CommitTransactionResult result)
+ {
+ if (!objects.isEmpty())
+ {
+ for (CDOObject object : objects.values())
+ {
+ CDOStateMachine.INSTANCE.commit((InternalCDOObject)object, result);
+ }
+ }
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class StartedEvent extends Event implements CDOTransactionStartedEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private StartedEvent()
+ {
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOTransactionStartedEvent[source={0}]", getSource()); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class FinishedEvent extends Event implements CDOTransactionFinishedEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private Type type;
+
+ private Map<CDOID, CDOID> idMappings;
+
+ private FinishedEvent(Type type, Map<CDOID, CDOID> idMappings)
+ {
+ this.type = type;
+ this.idMappings = idMappings;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public Map<CDOID, CDOID> getIDMappings()
+ {
+ return idMappings;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOTransactionFinishedEvent[source={0}, type={1}, idMappings={2}]", getSource(), //$NON-NLS-1$
+ getType(), idMappings == null ? 0 : idMappings.size());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class ConflictEvent extends Event implements CDOTransactionConflictEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private InternalCDOObject conflictingObject;
+
+ private boolean firstConflict;
+
+ public ConflictEvent(InternalCDOObject conflictingObject, boolean firstConflict)
+ {
+ this.conflictingObject = conflictingObject;
+ this.firstConflict = firstConflict;
+ }
+
+ public InternalCDOObject getConflictingObject()
+ {
+ return conflictingObject;
+ }
+
+ public boolean isFirstConflict()
+ {
+ return firstConflict;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOTransactionConflictEvent[source={0}, conflictingObject={1}, firstConflict={2}]", //$NON-NLS-1$
+ getSource(), getConflictingObject(), isFirstConflict());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 2.0
+ */
+ protected final class OptionsImpl extends CDOViewImpl.OptionsImpl implements CDOTransaction.Options
+ {
+ private List<CDOConflictResolver> conflictResolvers = new ArrayList<CDOConflictResolver>();
+
+ private boolean autoReleaseLocksEnabled = true;
+
+ public OptionsImpl()
+ {
+ }
+
+ @Override
+ public CDOTransactionImpl getContainer()
+ {
+ return (CDOTransactionImpl)super.getContainer();
+ }
+
+ public CDOConflictResolver[] getConflictResolvers()
+ {
+ synchronized (CDOTransactionImpl.this)
+ {
+ return conflictResolvers.toArray(new CDOConflictResolver[conflictResolvers.size()]);
+ }
+ }
+
+ public void setConflictResolvers(CDOConflictResolver[] resolvers)
+ {
+ synchronized (CDOTransactionImpl.this)
+ {
+ for (CDOConflictResolver resolver : conflictResolvers)
+ {
+ resolver.setTransaction(null);
+ }
+
+ conflictResolvers.clear();
+
+ for (CDOConflictResolver resolver : resolvers)
+ {
+ validateResolver(resolver);
+ conflictResolvers.add(resolver);
+ }
+ }
+
+ fireEvent(new ConflictResolversEventImpl());
+ }
+
+ public void addConflictResolver(CDOConflictResolver resolver)
+ {
+ IEvent event = null;
+ synchronized (CDOTransactionImpl.this)
+ {
+ validateResolver(resolver);
+ conflictResolvers.add(resolver);
+ event = new ConflictResolversEventImpl();
+ }
+
+ fireEvent(event);
+ }
+
+ public void removeConflictResolver(CDOConflictResolver resolver)
+ {
+ IEvent event = null;
+ synchronized (CDOTransactionImpl.this)
+ {
+ if (conflictResolvers.remove(resolver))
+ {
+ resolver.setTransaction(null);
+ event = new ConflictResolversEventImpl();
+ }
+ }
+
+ fireEvent(event);
+ }
+
+ public void disposeConflictResolvers()
+ {
+ try
+ {
+ // Do not call getConflictResolvers() because that method may block!
+ CDOConflictResolver[] array = conflictResolvers.toArray(new CDOConflictResolver[conflictResolvers.size()]);
+ for (CDOConflictResolver resolver : array)
+ {
+ try
+ {
+ resolver.setTransaction(null);
+ }
+ catch (Exception ignore)
+ {
+ }
+ }
+ }
+ catch (Exception ignore)
+ {
+ }
+ }
+
+ private void validateResolver(CDOConflictResolver resolver)
+ {
+ if (resolver.getTransaction() != null)
+ {
+ throw new IllegalArgumentException(Messages.getString("CDOTransactionImpl.17")); //$NON-NLS-1$
+ }
+
+ resolver.setTransaction(CDOTransactionImpl.this);
+ }
+
+ public boolean isAutoReleaseLocksEnabled()
+ {
+ return autoReleaseLocksEnabled;
+ }
+
+ public void setAutoReleaseLocksEnabled(boolean on)
+ {
+ IEvent event = null;
+ synchronized (CDOTransactionImpl.this)
+ {
+ if (autoReleaseLocksEnabled != on)
+ {
+ autoReleaseLocksEnabled = on;
+ event = new AutoReleaseLocksEventImpl();
+ }
+ }
+
+ fireEvent(event);
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class ConflictResolversEventImpl extends OptionsEvent implements ConflictResolversEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ public ConflictResolversEventImpl()
+ {
+ super(OptionsImpl.this);
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class AutoReleaseLocksEventImpl extends OptionsEvent implements AutoReleaseLocksEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ public AutoReleaseLocksEventImpl()
+ {
+ super(OptionsImpl.this);
+ }
+ }
+ }
+
+ public static class ECrossReferenceEListDerived extends ECrossReferenceEList<EObject>
+ {
+
+ public ECrossReferenceEListDerived(EObject eObject)
+ {
+ super(eObject);
+ }
+
+ public ECrossReferenceEListDerived(EObject eObject, EStructuralFeature[] eStructuralFeatures)
+ {
+ super(eObject, eStructuralFeatures);
+ }
+ }
+
+}

Back to the top