Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction')
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOAbstractSavepoint.java87
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java356
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategy.java96
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTimeStampContextImpl.java64
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java1613
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXASavepoint.java41
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionCommitContext.java196
-rw-r--r--plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionImpl.java608
8 files changed, 3061 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOAbstractSavepoint.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOAbstractSavepoint.java
new file mode 100644
index 0000000000..da1bb7e5c3
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOAbstractSavepoint.java
@@ -0,0 +1,87 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.transaction.CDOSavepoint;
+import org.eclipse.emf.cdo.transaction.CDOUserTransaction;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public abstract class CDOAbstractSavepoint implements CDOSavepoint
+{
+ private CDOUserTransaction userTransaction;
+
+ private CDOAbstractSavepoint previousSavepoint;
+
+ private CDOAbstractSavepoint nextSavepoint;
+
+ public CDOAbstractSavepoint(CDOUserTransaction transaction, CDOAbstractSavepoint lastSavepoint)
+ {
+ userTransaction = transaction;
+ previousSavepoint = lastSavepoint;
+ if (previousSavepoint != null)
+ {
+ previousSavepoint.setNextSavepoint(this);
+ }
+ }
+
+ public void setPreviousSavepoint(CDOAbstractSavepoint previousSavepoint)
+ {
+ this.previousSavepoint = previousSavepoint;
+ }
+
+ public void setNextSavepoint(CDOAbstractSavepoint nextSavepoint)
+ {
+ this.nextSavepoint = nextSavepoint;
+ }
+
+ public CDOSavepoint getNextSavepoint()
+ {
+ return nextSavepoint;
+ }
+
+ public CDOSavepoint getPreviousSavepoint()
+ {
+ return previousSavepoint;
+ }
+
+ public CDOAbstractSavepoint getFirstSavePoint()
+ {
+ return previousSavepoint != null ? previousSavepoint.getFirstSavePoint() : this;
+ }
+
+ public CDOUserTransaction getUserTransaction()
+ {
+ return userTransaction;
+ }
+
+ public boolean isValid()
+ {
+ CDOSavepoint lastSavepoint = getUserTransaction().getLastSavepoint();
+ for (CDOSavepoint savepoint = lastSavepoint; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ if (savepoint == this)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void rollback()
+ {
+ getUserTransaction().rollback(this);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java
new file mode 100644
index 0000000000..f1edf03e9f
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSavepointImpl.java
@@ -0,0 +1,356 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ * Simon McDuff - http://bugs.eclipse.org/204890
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDeltaUtil;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.internal.common.revision.delta.CDORevisionDeltaImpl;
+import org.eclipse.emf.cdo.internal.common.revision.delta.InternalCDOFeatureDelta;
+
+import org.eclipse.net4j.util.collection.MultiMap;
+
+import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOSavepointImpl extends CDOAbstractSavepoint
+{
+ private Map<CDOID, CDOResource> newResources = new HashMap<CDOID, CDOResource>();
+
+ private Map<CDOID, CDOObject> newObjects = new HashMap<CDOID, CDOObject>();
+
+ private Map<CDOID, CDORevision> baseNewObjects = new HashMap<CDOID, CDORevision>();
+
+ private Map<CDOID, CDOObject> dirtyObjects = new HashMap<CDOID, CDOObject>();
+
+ private Map<CDOID, CDOObject> detachedObjects = new HashMap<CDOID, CDOObject>()
+ {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public CDOObject put(CDOID key, CDOObject object)
+ {
+ sharedDetachedObjects.add(key);
+ dirtyObjects.remove(key);
+ baseNewObjects.remove(key);
+ newObjects.remove(key);
+ newResources.remove(key);
+ revisionDeltas.remove(key);
+ return super.put(key, object);
+ }
+ };
+
+ private ConcurrentMap<CDOID, CDORevisionDelta> revisionDeltas = new ConcurrentHashMap<CDOID, CDORevisionDelta>();
+
+ /**
+ * Contains all persistent CDOIDs that were removed. The same instance is shared between all save points that belong
+ * to the same transaction.
+ */
+ private Set<CDOID> sharedDetachedObjects;
+
+ private boolean isDirty;
+
+ public CDOSavepointImpl(InternalCDOTransaction transaction, CDOSavepointImpl lastSavepoint)
+ {
+ super(transaction, lastSavepoint);
+ isDirty = transaction.isDirty();
+ if (getPreviousSavepoint() == null)
+ {
+ sharedDetachedObjects = new HashSet<CDOID>();
+ }
+ else
+ {
+ sharedDetachedObjects = lastSavepoint.getSharedDetachedObjects();
+ }
+ }
+
+ public void clear()
+ {
+ newResources.clear();
+ newObjects.clear();
+ dirtyObjects.clear();
+ revisionDeltas.clear();
+ baseNewObjects.clear();
+ detachedObjects.clear();
+ }
+
+ public boolean isDirty()
+ {
+ return isDirty;
+ }
+
+ public Map<CDOID, CDOResource> getNewResources()
+ {
+ return newResources;
+ }
+
+ public Map<CDOID, CDOObject> getNewObjects()
+ {
+ return newObjects;
+ }
+
+ public Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ return detachedObjects;
+ }
+
+ public Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ return dirtyObjects;
+ }
+
+ public Set<CDOID> getSharedDetachedObjects()
+ {
+ return sharedDetachedObjects;
+ }
+
+ public ConcurrentMap<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ return revisionDeltas;
+ }
+
+ public Map<CDOID, CDORevision> getBaseNewObjects()
+ {
+ return baseNewObjects;
+ }
+
+ /**
+ * Return the list of new objects from this point.
+ */
+ public Map<CDOID, CDOObject> getAllDirtyObjects()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return getDirtyObjects();
+ }
+
+ MultiMap.ListBased<CDOID, CDOObject> dirtyObjects = new MultiMap.ListBased<CDOID, CDOObject>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ dirtyObjects.getDelegates().add(savepoint.getDirtyObjects());
+ }
+
+ return dirtyObjects;
+ }
+
+ /**
+ * Return the list of new objects from this point without objects that are removed.
+ */
+ public Map<CDOID, CDOObject> getAllNewObjects()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return Collections.unmodifiableMap(getNewObjects());
+ }
+
+ if (getSharedDetachedObjects().size() == 0)
+ {
+ MultiMap.ListBased<CDOID, CDOObject> newObjects = new MultiMap.ListBased<CDOID, CDOObject>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ newObjects.getDelegates().add(savepoint.getNewObjects());
+ }
+
+ return newObjects;
+ }
+
+ Map<CDOID, CDOObject> newObjects = new HashMap<CDOID, CDOObject>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ for (Entry<CDOID, CDOObject> entry : savepoint.getNewObjects().entrySet())
+ {
+ if (!getSharedDetachedObjects().contains(entry.getKey()))
+ {
+ newObjects.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ return newObjects;
+ }
+
+ /**
+ * Return the list of new resources from this point without objects that are removed.
+ */
+ public Map<CDOID, CDOResource> getAllNewResources()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return Collections.unmodifiableMap(getNewResources());
+ }
+
+ if (getSharedDetachedObjects().size() == 0)
+ {
+ MultiMap.ListBased<CDOID, CDOResource> newResources = new MultiMap.ListBased<CDOID, CDOResource>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ newResources.getDelegates().add(savepoint.getNewResources());
+ }
+
+ return newResources;
+ }
+
+ Map<CDOID, CDOResource> newResources = new HashMap<CDOID, CDOResource>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ for (Entry<CDOID, CDOResource> entry : savepoint.getNewResources().entrySet())
+ {
+ if (!getSharedDetachedObjects().contains(entry.getKey()))
+ {
+ newResources.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ return newResources;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public Map<CDOID, CDORevision> getAllBaseNewObjects()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return Collections.unmodifiableMap(getBaseNewObjects());
+ }
+
+ MultiMap.ListBased<CDOID, CDORevision> newObjects = new MultiMap.ListBased<CDOID, CDORevision>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ newObjects.getDelegates().add(savepoint.getBaseNewObjects());
+ }
+
+ return newObjects;
+ }
+
+ /**
+ * Return the list of all deltas without objects that are removed.
+ */
+ public Map<CDOID, CDORevisionDelta> getAllRevisionDeltas()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return Collections.unmodifiableMap(getRevisionDeltas());
+ }
+
+ // We need to combined the result for all delta in different Savepoint
+ Map<CDOID, CDORevisionDelta> revisionDeltas = new HashMap<CDOID, CDORevisionDelta>();
+ for (CDOSavepointImpl savepoint = (CDOSavepointImpl)getFirstSavePoint(); savepoint != null; savepoint = savepoint
+ .getNextSavepoint())
+ {
+ for (Entry<CDOID, CDORevisionDelta> entry : savepoint.getRevisionDeltas().entrySet())
+ {
+ // Skipping temporary
+ if (entry.getKey().isTemporary() || getSharedDetachedObjects().contains(entry.getKey()))
+ {
+ continue;
+ }
+
+ CDORevisionDeltaImpl revisionDelta = (CDORevisionDeltaImpl)revisionDeltas.get(entry.getKey());
+ if (revisionDelta == null)
+ {
+ revisionDeltas.put(entry.getKey(), CDORevisionDeltaUtil.copy(entry.getValue()));
+ }
+ else
+ {
+
+ for (CDOFeatureDelta delta : entry.getValue().getFeatureDeltas())
+ {
+ revisionDelta.addFeatureDelta(((InternalCDOFeatureDelta)delta).copy());
+ }
+ }
+ }
+ }
+
+ return Collections.unmodifiableMap(revisionDeltas);
+ }
+
+ public Map<CDOID, CDOObject> getAllDetachedObjects()
+ {
+ if (getPreviousSavepoint() == null)
+ {
+ return Collections.unmodifiableMap(getDetachedObjects());
+ }
+
+ Map<CDOID, CDOObject> detachedObjects = new HashMap<CDOID, CDOObject>();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ for (Entry<CDOID, CDOObject> entry : savepoint.getDetachedObjects().entrySet())
+ {
+ if (!entry.getKey().isTemporary())
+ {
+ detachedObjects.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ return detachedObjects;
+ }
+
+ public void recalculateSharedDetachedObjects()
+ {
+ sharedDetachedObjects.clear();
+ for (CDOSavepointImpl savepoint = this; savepoint != null; savepoint = savepoint.getPreviousSavepoint())
+ {
+ for (CDOID id : savepoint.getDetachedObjects().keySet())
+ {
+ sharedDetachedObjects.add(id);
+ }
+ }
+ }
+
+ @Override
+ public CDOSavepointImpl getPreviousSavepoint()
+ {
+ return (CDOSavepointImpl)super.getPreviousSavepoint();
+ }
+
+ @Override
+ public CDOSavepointImpl getNextSavepoint()
+ {
+ return (CDOSavepointImpl)super.getNextSavepoint();
+ }
+
+ public void setPreviousSavepoint(CDOSavepointImpl previousSavepoint)
+ {
+ super.setPreviousSavepoint(previousSavepoint);
+ }
+
+ public void setNextSavepoint(CDOSavepointImpl nextSavepoint)
+ {
+ super.setNextSavepoint(nextSavepoint);
+ }
+
+ @Override
+ public void rollback()
+ {
+ getUserTransaction().rollback(this);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategy.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategy.java
new file mode 100644
index 0000000000..5f31a51ca1
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOSingleTransactionStrategy.java
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.transaction.CDOSavepoint;
+
+import org.eclipse.emf.internal.cdo.bundle.OM;
+import org.eclipse.emf.internal.cdo.protocol.CDOClientProtocol;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionRequest;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionResult;
+
+import org.eclipse.net4j.util.om.monitor.EclipseMonitor;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+import org.eclipse.net4j.util.transaction.TransactionException;
+
+import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
+import org.eclipse.emf.spi.cdo.InternalCDOCommitContext;
+import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOSingleTransactionStrategy implements CDOTransactionStrategy
+{
+ public static final CDOSingleTransactionStrategy INSTANCE = new CDOSingleTransactionStrategy();
+
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_TRANSCTION, CDOSingleTransactionStrategy.class);
+
+ public CDOSingleTransactionStrategy()
+ {
+ }
+
+ public void commit(InternalCDOTransaction transaction, IProgressMonitor progressMonitor) throws Exception
+ {
+ InternalCDOCommitContext commitContext = transaction.createCommitContext();
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("CDOCommitContext.preCommit");
+ }
+
+ commitContext.preCommit();
+ CommitTransactionResult result = null;
+ if (commitContext.getTransaction().isDirty())
+ {
+ CDOClientProtocol protocol = (CDOClientProtocol)transaction.getSession().getProtocol();
+ CommitTransactionRequest request = new CommitTransactionRequest(protocol, commitContext);
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Sending commit request");
+ }
+
+ result = request.send(new EclipseMonitor(progressMonitor));
+ String rollbackMessage = result.getRollbackMessage();
+ if (rollbackMessage != null)
+ {
+ throw new TransactionException(rollbackMessage);
+ }
+ }
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("CDOCommitContext.postCommit");
+ }
+ commitContext.postCommit(result);
+ }
+
+ public void rollback(InternalCDOTransaction transaction, CDOSavepoint savepoint)
+ {
+ transaction.handleRollback(savepoint);
+ }
+
+ public CDOSavepoint setSavepoint(InternalCDOTransaction transaction)
+ {
+ return transaction.handleSetSavepoint();
+ }
+
+ public void setTarget(InternalCDOTransaction transaction)
+ {
+ // Do nothing
+ }
+
+ public void unsetTarget(InternalCDOTransaction transaction)
+ {
+ // Do nothing
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTimeStampContextImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTimeStampContextImpl.java
new file mode 100644
index 0000000000..ee2568606e
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTimeStampContextImpl.java
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ * Eike Stepper - maintenance
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDAndVersion;
+import org.eclipse.emf.cdo.transaction.CDOTimeStampContext;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOTimeStampContextImpl implements CDOTimeStampContext
+{
+ private long timeStamp;
+
+ private Set<CDOIDAndVersion> dirtyObjects = new HashSet<CDOIDAndVersion>();
+
+ private Collection<CDOID> detachedObjects = new ArrayList<CDOID>();
+
+ public CDOTimeStampContextImpl(long timeStamp)
+ {
+ this.timeStamp = timeStamp;
+ }
+
+ public long getTimeStamp()
+ {
+ return timeStamp;
+ }
+
+ public Set<CDOIDAndVersion> getDirtyObjects()
+ {
+ return dirtyObjects;
+ }
+
+ public void setDirtyObjects(Set<CDOIDAndVersion> dirtyObjects)
+ {
+ this.dirtyObjects = dirtyObjects;
+ }
+
+ public Collection<CDOID> getDetachedObjects()
+ {
+ return detachedObjects;
+ }
+
+ public void setDetachedObjects(Collection<CDOID> detachedObjects)
+ {
+ this.detachedObjects = detachedObjects;
+ }
+}
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
new file mode 100644
index 0000000000..3ba95c7a30
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOTransactionImpl.java
@@ -0,0 +1,1613 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * 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
+ **************************************************************************/
+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.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDAndVersion;
+import org.eclipse.emf.cdo.common.id.CDOIDTemp;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.model.CDOPackage;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDeltaUtil;
+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.spi.common.model.InternalCDOPackage;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+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.CDOTransactionStartedEvent;
+import org.eclipse.emf.cdo.util.CDOURIUtil;
+import org.eclipse.emf.cdo.view.CDOConflictResolver;
+import org.eclipse.emf.cdo.view.CDOViewResourcesEvent;
+
+import org.eclipse.emf.internal.cdo.CDOObjectMerger;
+import org.eclipse.emf.internal.cdo.CDOStateMachine;
+import org.eclipse.emf.internal.cdo.bundle.OM;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionResult;
+import org.eclipse.emf.internal.cdo.session.CDOSessionPackageManagerImpl;
+import org.eclipse.emf.internal.cdo.util.CompletePackageClosure;
+import org.eclipse.emf.internal.cdo.util.FSMUtil;
+import org.eclipse.emf.internal.cdo.util.IPackageClosure;
+import org.eclipse.emf.internal.cdo.util.ModelUtil;
+import org.eclipse.emf.internal.cdo.view.CDOViewImpl;
+
+import org.eclipse.net4j.util.ImplementationError;
+import org.eclipse.net4j.util.ObjectUtil;
+import org.eclipse.net4j.util.WrappedException;
+import org.eclipse.net4j.util.event.Notifier;
+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.util.URI;
+import org.eclipse.emf.ecore.EPackage;
+import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
+import org.eclipse.emf.spi.cdo.InternalCDOCommitContext;
+import org.eclipse.emf.spi.cdo.InternalCDOObject;
+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.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * @author Eike Stepper
+ */
+public class CDOTransactionImpl extends CDOViewImpl implements InternalCDOTransaction
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_TRANSCTION, CDOTransactionImpl.class);
+
+ /**
+ * TODO Optimize by storing an array. See {@link Notifier}.
+ */
+ private List<CDOTransactionHandler> handlers = new ArrayList<CDOTransactionHandler>(0);
+
+ private CDOSavepointImpl lastSavepoint = new CDOSavepointImpl(this, null);
+
+ private CDOSavepointImpl firstSavepoint = lastSavepoint;
+
+ private boolean dirty;
+
+ private int conflict;
+
+ private long lastCommitTime = CDORevision.UNSPECIFIED_DATE;
+
+ private int lastTemporaryID;
+
+ private CDOTransactionStrategy transactionStrategy;
+
+ /**
+ * @since 2.0
+ */
+ public CDOTransactionImpl()
+ {
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ public OptionsImpl options()
+ {
+ return (OptionsImpl)super.options();
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected OptionsImpl initOptions()
+ {
+ return new OptionsImpl();
+ }
+
+ @Override
+ public Type getViewType()
+ {
+ return Type.TRANSACTION;
+ }
+
+ public void addHandler(CDOTransactionHandler handler)
+ {
+ synchronized (handlers)
+ {
+ if (!handlers.contains(handler))
+ {
+ handlers.add(handler);
+ }
+ }
+ }
+
+ public void removeHandler(CDOTransactionHandler handler)
+ {
+ synchronized (handlers)
+ {
+ handlers.remove(handler);
+ }
+ }
+
+ public CDOTransactionHandler[] getHandlers()
+ {
+ synchronized (handlers)
+ {
+ return handlers.toArray(new CDOTransactionHandler[handlers.size()]);
+ }
+ }
+
+ @Override
+ public boolean isDirty()
+ {
+ if (isClosed())
+ {
+ return false;
+ }
+
+ return dirty;
+ }
+
+ @Override
+ public boolean hasConflict()
+ {
+ checkActive();
+ return conflict != 0;
+ }
+
+ public void setConflict(InternalCDOObject object)
+ {
+ ConflictEvent event = new ConflictEvent(object, conflict == 0);
+ ++conflict;
+ fireEvent(event);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public 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;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void resolveConflicts(CDOConflictResolver... resolvers)
+ {
+ Set<CDOObject> conflicts = getConflicts();
+ handleConflicts(conflicts, resolvers);
+ }
+
+ public void handleConflicts(Set<CDOObject> conflicts)
+ {
+ handleConflicts(conflicts, options().getConflictResolvers());
+ }
+
+ private void handleConflicts(Set<CDOObject> conflicts, CDOConflictResolver[] resolvers)
+ {
+ 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)
+ {
+ states.add(conflict.cdoState());
+ revisions.add(conflict.cdoRevision());
+ }
+
+ int resolved = 0;
+
+ try
+ {
+ Set<CDOObject> remaining = new HashSet<CDOObject>(conflicts);
+ for (CDOConflictResolver resolver : resolvers)
+ {
+ resolver.resolveConflicts(Collections.unmodifiableSet(remaining));
+ for (Iterator<CDOObject> it = remaining.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)
+ {
+ ((InternalCDOObject)object).cdoInternalSetState(state.next());
+ ((InternalCDOObject)object).cdoInternalSetRevision(revision.next());
+ }
+
+ throw WrappedException.wrap(ex);
+ }
+
+ conflict -= resolved;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public long getLastCommitTime()
+ {
+ return lastCommitTime;
+ }
+
+ public CDOIDTemp getNextTemporaryID()
+ {
+ return CDOIDUtil.createTempObject(++lastTemporaryID);
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected CDOResourceImpl createRootResource()
+ {
+ return (CDOResourceImpl)getOrCreateResource(CDOResourceNode.ROOT_PATH);
+ }
+
+ public CDOResource createResource(String path)
+ {
+ checkActive();
+ URI uri = CDOURIUtil.createResourceURI(this, path);
+ return (CDOResource)getResourceSet().createResource(uri);
+ }
+
+ public CDOResource getOrCreateResource(String path)
+ {
+ checkActive();
+
+ try
+ {
+ CDOID id = getResourceID(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 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);
+ }
+
+ /**
+ * @return never <code>null</code>;
+ * @since 2.0
+ */
+ public 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("Not a ResourceFolder: " + node);
+ }
+ }
+
+ 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 void detach(CDOResourceImpl cdoResource)
+ {
+ CDOStateMachine.INSTANCE.detach(cdoResource);
+ fireEvent(new ResourcesEvent(cdoResource.getPath(), ResourcesEvent.Kind.REMOVED));
+ }
+
+ /**
+ * @since 2.0
+ */
+ public CDOSavepointImpl getLastSavepoint()
+ {
+ checkActive();
+ return lastSavepoint;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public CDOTransactionStrategy getTransactionStrategy()
+ {
+ if (transactionStrategy == null)
+ {
+ transactionStrategy = CDOTransactionStrategy.DEFAULT;
+ transactionStrategy.setTarget(this);
+ }
+
+ return transactionStrategy;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public 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 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();
+ }
+
+ node = getRootResourceNode(name, getNewResources().values());
+ if (node != null)
+ {
+ return node.cdoID();
+ }
+ }
+
+ CDOID id = super.getRootOrTopLevelResourceNodeID(name);
+ if (getLastSavepoint().getAllDetachedObjects().containsKey(id) || getDirtyObjects().containsKey(id))
+ {
+ throw new CDOException("Root resource node " + name + " doesn't exist");
+ }
+
+ 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 InternalCDOObject getObject(CDOID id, boolean loadOnDemand)
+ {
+ checkActive();
+ if (CDOIDUtil.isNull(id))
+ {
+ return null;
+ }
+
+ if (id.isTemporary() && isDetached(id))
+ {
+ FSMUtil.validate(id, null);
+ }
+
+ return super.getObject(id, loadOnDemand);
+ }
+
+ private boolean isDetached(CDOID id)
+ {
+ return lastSavepoint.getSharedDetachedObjects().contains(id);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public InternalCDOCommitContext createCommitContext()
+ {
+ return new CDOCommitContextImpl();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void commit(IProgressMonitor progressMonitor) throws TransactionException
+ {
+ checkActive();
+ if (hasConflict())
+ {
+ throw new TransactionException("This transaction has conflicts");
+ }
+
+ if (progressMonitor == null)
+ {
+ progressMonitor = new NullProgressMonitor();
+ }
+
+ try
+ {
+ getTransactionStrategy().commit(this, progressMonitor);
+ }
+ catch (TransactionException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+
+ public void commit() throws TransactionException
+ {
+ commit(null);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void rollback()
+ {
+ checkActive();
+ rollback(firstSavepoint);
+ cleanUp();
+ }
+
+ private void removeObjects(Collection<? extends CDOObject> objects)
+ {
+ if (!objects.isEmpty())
+ {
+ for (CDOObject object : objects)
+ {
+ ((InternalCDOObject)object).cdoInternalSetState(CDOState.TRANSIENT);
+ removeObject(object.cdoID());
+
+ if (object instanceof CDOResource)
+ {
+ getResourceSet().getResources().remove(object);
+ }
+
+ ((InternalCDOObject)object).cdoInternalSetID(null);
+ ((InternalCDOObject)object).cdoInternalSetRevision(null);
+ ((InternalCDOObject)object).cdoInternalSetView(null);
+ }
+ }
+ }
+
+ private Set<CDOID> rollbackCompletely(CDOSavepoint savepoint)
+ {
+ Set<CDOID> idsOfNewObjectWithDeltas = new HashSet<CDOID>();
+
+ // Start from the last savepoint and come back up to the active
+ for (CDOSavepointImpl itrSavepoint = lastSavepoint; itrSavepoint != null; itrSavepoint = itrSavepoint
+ .getPreviousSavepoint())
+ {
+ // Rollback new objects created after the save point
+ removeObjects(itrSavepoint.getNewResources().values());
+ removeObjects(itrSavepoint.getNewObjects().values());
+
+ Map<CDOID, CDORevisionDelta> revisionDeltas = itrSavepoint.getRevisionDeltas();
+ if (!revisionDeltas.isEmpty())
+ {
+ for (CDORevisionDelta dirtyObject : revisionDeltas.values())
+ {
+ if (dirtyObject.getID().isTemporary())
+ {
+ idsOfNewObjectWithDeltas.add(dirtyObject.getID());
+ }
+ }
+ }
+
+ // Rollback all persisted objects
+ Map<CDOID, CDOObject> detachedObjects = itrSavepoint.getDetachedObjects();
+ if (!detachedObjects.isEmpty())
+ {
+ for (Entry<CDOID, CDOObject> entryDirty : detachedObjects.entrySet())
+ {
+ if (entryDirty.getKey().isTemporary())
+ {
+ idsOfNewObjectWithDeltas.add(entryDirty.getKey());
+ }
+ else
+ {
+ InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirty.getValue();
+ cleanObject(internalDirtyObject, getRevision(entryDirty.getKey(), true));
+ }
+ }
+ }
+
+ for (Entry<CDOID, CDOObject> entryDirtyObject : itrSavepoint.getDirtyObjects().entrySet())
+ {
+ // Rollback all persisted objects
+ if (!entryDirtyObject.getKey().isTemporary())
+ {
+ InternalCDOObject internalDirtyObject = (InternalCDOObject)entryDirtyObject.getValue();
+ CDOStateMachine.INSTANCE.rollback(internalDirtyObject);
+ }
+ }
+
+ if (savepoint == itrSavepoint)
+ {
+ break;
+ }
+ }
+
+ return idsOfNewObjectWithDeltas;
+ }
+
+ private void loadSavepoint(CDOSavepoint savepoint, Set<CDOID> idsOfNewObjectWithDeltas)
+ {
+ lastSavepoint.recalculateSharedDetachedObjects();
+
+ Map<CDOID, CDOObject> dirtyObjects = getDirtyObjects();
+ Map<CDOID, CDOObject> newObjMaps = getNewObjects();
+ Map<CDOID, CDOResource> newResources = getNewResources();
+ 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);
+ if (object == null)
+ {
+ object = (InternalCDOObject)newResources.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();
+ }
+ }
+
+ // 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));
+ }
+
+ for (CDOSavepointImpl itrSavepoint = firstSavepoint; itrSavepoint != savepoint; itrSavepoint = itrSavepoint
+ .getNextSavepoint())
+ {
+ CDOObjectMerger merger = new CDOObjectMerger();
+ for (CDORevisionDelta delta : itrSavepoint.getRevisionDeltas().values())
+ {
+ if (delta.getID().isTemporary() && !idsOfNewObjectWithDeltas.contains(delta.getID())
+ || detachedObjects.containsKey(delta.getID()))
+ {
+ continue;
+ }
+
+ Map<CDOID, CDOObject> map = delta.getID().isTemporary() ? newObjMaps : dirtyObjects;
+ InternalCDOObject object = (InternalCDOObject)map.get(delta.getID());
+ if (object == null)
+ {
+ object = (InternalCDOObject)newResources.get(delta.getID());
+ }
+
+ // Change state of the objects
+ merger.merge(object, delta);
+
+ // Load the object from revision to EObject
+ object.cdoInternalPostLoad();
+ }
+ }
+
+ dirty = ((CDOSavepointImpl)savepoint).isDirty();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void detachObject(InternalCDOObject object)
+ {
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ handler.detachingObject(this, object);
+ }
+
+ // deregister object
+ if (object.cdoState() == CDOState.NEW)
+ {
+ Map<CDOID, ? extends CDOObject> map = object instanceof CDOResource ? getLastSavepoint().getNewResources()
+ : getLastSavepoint().getNewObjects();
+
+ // Determine if we added object
+ if (map.containsKey(object.cdoID()))
+ {
+ // deregister object
+ deregisterObject(object);
+ map.remove(object.cdoID());
+ }
+ else
+ {
+ getLastSavepoint().getDetachedObjects().put(object.cdoID(), object);
+ }
+ }
+ else
+ {
+ getLastSavepoint().getDetachedObjects().put(object.cdoID(), object);
+ }
+
+ if (!dirty)
+ {
+ dirty = true;
+ fireEvent(new StartedEvent());
+ }
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void rollback(CDOSavepoint savepoint)
+ {
+ checkActive();
+ getTransactionStrategy().rollback(this, savepoint);
+ }
+
+ /**
+ * @since 2.0
+ */
+ public void handleRollback(CDOSavepoint savepoint)
+ {
+ if (savepoint == null)
+ {
+ throw new IllegalArgumentException("Save point is null");
+ }
+
+ if (savepoint.getUserTransaction() != this)
+ {
+ throw new IllegalArgumentException("Save point to rollback doesn't belong to this transaction: " + savepoint);
+ }
+
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("handleRollback()");
+ }
+
+ try
+ {
+ if (!savepoint.isValid())
+ {
+ throw new IllegalArgumentException("Savepoint isn't valid : " + savepoint);
+ }
+
+ // Rollback objects
+ Set<CDOID> idsOfNewObjectWithDeltas = rollbackCompletely(savepoint);
+
+ lastSavepoint = (CDOSavepointImpl)savepoint;
+ // Make savepoint active. Erase savepoint that could have be after
+ lastSavepoint.setNextSavepoint(null);
+ lastSavepoint.clear();
+
+ // Load from first savepoint up to current savepoint
+ loadSavepoint(lastSavepoint, idsOfNewObjectWithDeltas);
+
+ if (lastSavepoint == firstSavepoint && options().isAutoReleaseLocksEnabled())
+ {
+ // Unlock all objects
+ unlockObjects(null, null);
+ }
+
+ Map<CDOIDTemp, CDOID> idMappings = Collections.emptyMap();
+ fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.ROLLED_BACK, idMappings));
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ 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 CDOSavepoint handleSetSavepoint()
+ {
+ // Take a copy of all new objects for the current save point
+ addToBase(lastSavepoint.getNewObjects());
+ addToBase(lastSavepoint.getNewResources());
+
+ lastSavepoint = new CDOSavepointImpl(this, lastSavepoint);
+ return lastSavepoint;
+ }
+
+ /**
+ * @since 2.0
+ */
+ public CDOSavepoint setSavepoint()
+ {
+ checkActive();
+ return getTransactionStrategy().setSavepoint(this);
+ }
+
+ private void addToBase(Map<CDOID, ? extends CDOObject> objects)
+ {
+ for (CDOObject object : objects.values())
+ {
+ // Load instance to revision
+ ((InternalCDOObject)object).cdoInternalPreCommit();
+ lastSavepoint.getBaseNewObjects().put(object.cdoID(), object.cdoRevision().copy());
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOTransaction({0})", getViewID());
+ }
+
+ public void registerNew(InternalCDOObject object)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Registering new object {0}", object);
+ }
+
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ handler.attachingObject(this, object);
+ }
+
+ if (object instanceof CDOResourceImpl)
+ {
+ registerNew(lastSavepoint.getNewResources(), object);
+ }
+ else
+ {
+ registerNew(lastSavepoint.getNewObjects(), object);
+ }
+ }
+
+ /**
+ * Receives notification for new and dirty objects
+ */
+ public void registerFeatureDelta(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ 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, ? extends CDOObject> map = object instanceof CDOResource ? getLastSavepoint().getNewResources()
+ : getLastSavepoint().getNewObjects();
+ needToSaveFeatureDelta = !map.containsKey(object.cdoID());
+ }
+ }
+
+ if (needToSaveFeatureDelta)
+ {
+ CDORevisionDelta revisionDelta = lastSavepoint.getRevisionDeltas().get(object.cdoID());
+ if (revisionDelta == null)
+ {
+ revisionDelta = CDORevisionDeltaUtil.create(object.cdoRevision());
+ lastSavepoint.getRevisionDeltas().put(object.cdoID(), revisionDelta);
+ }
+
+ ((InternalCDORevisionDelta)revisionDelta).addFeatureDelta(featureDelta);
+ }
+
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ handler.modifyingObject(this, object, featureDelta);
+ }
+ }
+
+ public void registerRevisionDelta(CDORevisionDelta revisionDelta)
+ {
+ lastSavepoint.getRevisionDeltas().putIfAbsent(revisionDelta.getID(), revisionDelta);
+ }
+
+ public void registerDirty(InternalCDOObject object, CDOFeatureDelta featureDelta)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Registering dirty object {0}", object);
+ }
+
+ if (featureDelta != null)
+ {
+ registerFeatureDelta(object, featureDelta);
+ }
+
+ registerNew(lastSavepoint.getDirtyObjects(), object);
+ }
+
+ /**
+ * TODO Simon: Should this method go to CDOSavePointImpl?
+ */
+ @SuppressWarnings("unchecked")
+ private void registerNew(Map map, InternalCDOObject object)
+ {
+ Object old = map.put(object.cdoID(), object);
+ if (old != null)
+ {
+ throw new ImplementationError("Duplicate ID: " + object);
+ }
+
+ if (!dirty)
+ {
+ dirty = true;
+ fireEvent(new StartedEvent());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private List<CDOPackage> analyzeNewPackages()
+ {
+ CDOSessionPackageManagerImpl packageManager = (CDOSessionPackageManagerImpl)getSession().getPackageManager();
+ 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 = ModelUtil.getTopLevelPackage(ePackage);
+ if (ePackage == topLevelPackage || usedPackages.add(topLevelPackage))
+ {
+ CDOPackage cdoPackage = ModelUtil.getCDOPackage(topLevelPackage, packageManager);
+ if (!cdoPackage.isPersistent() && !cdoPackage.isSystem())
+ {
+ usedNewPackages.add(topLevelPackage);
+ }
+ }
+ }
+ }
+
+ if (usedNewPackages.size() > 0)
+ {
+ return analyzeNewPackages(usedNewPackages, packageManager);
+ }
+
+ return Collections.EMPTY_LIST;
+ }
+
+ private static List<CDOPackage> analyzeNewPackages(Collection<EPackage> usedTopLevelPackages,
+ CDOSessionPackageManagerImpl packageManager)
+ {
+ // Determine which of the corresdonding CDOPackages are new
+ List<CDOPackage> newPackages = new ArrayList<CDOPackage>();
+
+ IPackageClosure closure = new CompletePackageClosure();
+ usedTopLevelPackages = closure.calculate(usedTopLevelPackages);
+
+ for (EPackage usedPackage : usedTopLevelPackages)
+ {
+ CDOPackage cdoPackage = ModelUtil.getCDOPackage(usedPackage, packageManager);
+ if (cdoPackage == null)
+ {
+ throw new IllegalStateException("Missing CDO package: " + usedPackage.getNsURI());
+ }
+
+ if (!(cdoPackage.isPersistent() || cdoPackage.isSystem()))
+ {
+ newPackages.add(cdoPackage);
+ }
+ }
+
+ return newPackages;
+ }
+
+ private void cleanUp()
+ {
+ lastSavepoint = firstSavepoint;
+ firstSavepoint.clear();
+ firstSavepoint.setNextSavepoint(null);
+ firstSavepoint.getSharedDetachedObjects().clear();
+ dirty = false;
+ conflict = 0;
+ lastTemporaryID = 0;
+ }
+
+ public Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllDirtyObjects();
+ }
+
+ public Map<CDOID, CDOObject> getNewObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllNewObjects();
+ }
+
+ public Map<CDOID, CDOResource> getNewResources()
+ {
+ checkActive();
+ return lastSavepoint.getAllNewResources();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public Map<CDOID, CDORevision> getBaseNewObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllBaseNewObjects();
+ }
+
+ public Map<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ checkActive();
+ return lastSavepoint.getAllRevisionDeltas();
+ }
+
+ /**
+ * @since 2.0
+ */
+ public Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ checkActive();
+ return lastSavepoint.getAllDetachedObjects();
+ }
+
+ /**
+ * @since 2.0
+ */
+ @Override
+ protected void doDeactivate() throws Exception
+ {
+ options().disposeConflictResolvers();
+ lastSavepoint = null;
+ firstSavepoint = null;
+ transactionStrategy = null;
+ super.doDeactivate();
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private class CDOCommitContextImpl implements InternalCDOCommitContext
+ {
+ private Map<CDOID, CDOResource> newResources;
+
+ private Map<CDOID, CDOObject> newObjects;
+
+ private Map<CDOID, CDOObject> dirtyObjects;
+
+ private Map<CDOID, CDORevisionDelta> revisionDeltas;
+
+ private Map<CDOID, CDOObject> detachedObjects;
+
+ private List<CDOPackage> newPackages;
+
+ public CDOCommitContextImpl()
+ {
+ CDOTransactionImpl transaction = getTransaction();
+ newResources = transaction.getNewResources();
+ newObjects = transaction.getNewObjects();
+ dirtyObjects = transaction.getDirtyObjects();
+ detachedObjects = transaction.getDetachedObjects();
+ revisionDeltas = transaction.getRevisionDeltas();
+ newPackages = transaction.analyzeNewPackages();
+ }
+
+ public CDOTransactionImpl getTransaction()
+ {
+ return CDOTransactionImpl.this;
+ }
+
+ public Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ return dirtyObjects;
+ }
+
+ public Map<CDOID, CDOObject> getNewObjects()
+ {
+ return newObjects;
+ }
+
+ public List<CDOPackage> getNewPackages()
+ {
+ return newPackages;
+ }
+
+ public Map<CDOID, CDOResource> getNewResources()
+ {
+ return newResources;
+ }
+
+ public Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ return detachedObjects;
+ }
+
+ public Map<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ return revisionDeltas;
+ }
+
+ public void preCommit()
+ {
+ if (isDirty())
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.trace("commit()");
+ }
+
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ handler.committingTransaction(getTransaction(), this);
+ }
+
+ try
+ {
+ preCommit(getNewResources());
+ preCommit(getNewObjects());
+ preCommit(getDirtyObjects());
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+ }
+
+ public void postCommit(CommitTransactionResult result)
+ {
+ if (isDirty())
+ {
+ try
+ {
+ Collection<CDORevisionDelta> deltas = getRevisionDeltas().values();
+
+ postCommit(getNewResources(), result);
+ postCommit(getNewObjects(), result);
+ postCommit(getDirtyObjects(), result);
+ for (Entry<CDOID, CDOObject> entry : getDetachedObjects().entrySet())
+ {
+ removeObject(entry.getKey());
+ }
+
+ InternalCDOSession session = getSession();
+ for (CDOPackage newPackage : newPackages)
+ {
+ ((InternalCDOPackage)newPackage).setPersistent(true);
+ }
+
+ long timeStamp = result.getTimeStamp();
+
+ Map<CDOID, CDOObject> dirtyObjects = getDirtyObjects();
+ Set<CDOIDAndVersion> dirtyIDs = new HashSet<CDOIDAndVersion>();
+ for (CDOObject dirtyObject : dirtyObjects.values())
+ {
+ CDORevision revision = dirtyObject.cdoRevision();
+ CDOIDAndVersion dirtyID = CDOIDUtil.createIDAndVersion(revision.getID(), revision.getVersion() - 1);
+ dirtyIDs.add(dirtyID);
+ }
+
+ if (!dirtyIDs.isEmpty() || !getDetachedObjects().isEmpty())
+ {
+ Set<CDOID> detachedIDs = new HashSet<CDOID>(getDetachedObjects().keySet());
+ Collection<CDORevisionDelta> deltasCopy = new ArrayList<CDORevisionDelta>(deltas);
+
+ // Adjust references in the deltas. Could be used in ChangeSubscription from others CDOView
+ for (CDORevisionDelta dirtyObjectDelta : deltasCopy)
+ {
+ ((InternalCDORevisionDelta)dirtyObjectDelta).adjustReferences(result.getReferenceAdjuster());
+ }
+
+ session.handleCommitNotification(timeStamp, dirtyIDs, detachedIDs, deltasCopy, getTransaction());
+ }
+
+ lastCommitTime = timeStamp;
+ for (CDOTransactionHandler handler : getHandlers())
+ {
+ handler.committedTransaction(getTransaction(), this);
+ }
+
+ getChangeSubscriptionManager().committedTransaction(getTransaction(), this);
+ getAdapterManager().committedTransaction(getTransaction(), this);
+
+ cleanUp();
+ Map<CDOIDTemp, CDOID> idMappings = result.getIDMappings();
+ fireEvent(new FinishedEvent(CDOTransactionFinishedEvent.Type.COMMITTED, idMappings));
+ }
+ catch (RuntimeException ex)
+ {
+ throw ex;
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionException(ex);
+ }
+ }
+ else
+ {
+ // Removes locks even if no one touch the transaction
+ if (options().isAutoReleaseLocksEnabled())
+ {
+ unlockObjects(null, null);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void preCommit(Map objects)
+ {
+ if (!objects.isEmpty())
+ {
+ for (Object object : objects.values())
+ {
+ ((InternalCDOObject)object).cdoInternalPreCommit();
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private void postCommit(Map objects, CommitTransactionResult result)
+ {
+ if (!objects.isEmpty())
+ {
+ for (Object 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());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class FinishedEvent extends Event implements CDOTransactionFinishedEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private Type type;
+
+ private Map<CDOIDTemp, CDOID> idMappings;
+
+ private FinishedEvent(Type type, Map<CDOIDTemp, CDOID> idMappings)
+ {
+ this.type = type;
+ this.idMappings = idMappings;
+ }
+
+ public Type getType()
+ {
+ return type;
+ }
+
+ public Map<CDOIDTemp, CDOID> getIDMappings()
+ {
+ return idMappings;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOTransactionFinishedEvent[source={0}, type={1}, idMappings={2}]", getSource(),
+ 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}]",
+ getSource(), getConflictingObject(), isFirstConflict());
+ }
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private final class ResourcesEvent extends Event implements CDOViewResourcesEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ private String resourcePath;
+
+ private Kind kind;
+
+ public ResourcesEvent(String resourcePath, Kind kind)
+ {
+ this.resourcePath = resourcePath;
+ this.kind = kind;
+ }
+
+ public String getResourcePath()
+ {
+ return resourcePath;
+ }
+
+ public Kind getKind()
+ {
+ return kind;
+ }
+
+ @Override
+ public String toString()
+ {
+ return MessageFormat.format("CDOViewResourcesEvent[source={0}, {1}={2}]", getSource(), resourcePath, kind);
+ }
+ }
+
+ /**
+ * @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()
+ {
+ }
+
+ public CDOConflictResolver[] getConflictResolvers()
+ {
+ synchronized (conflictResolvers)
+ {
+ return conflictResolvers.toArray(new CDOConflictResolver[conflictResolvers.size()]);
+ }
+ }
+
+ public void setConflictResolvers(CDOConflictResolver[] resolvers)
+ {
+ synchronized (conflictResolvers)
+ {
+ 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)
+ {
+ boolean changed = false;
+ synchronized (conflictResolvers)
+ {
+ if (!conflictResolvers.contains(resolver))
+ {
+ validateResolver(resolver);
+ conflictResolvers.add(resolver);
+ changed = true;
+ }
+ }
+
+ if (changed)
+ {
+ fireEvent(new ConflictResolversEventImpl());
+ }
+ }
+
+ public void removeConflictResolver(CDOConflictResolver resolver)
+ {
+ boolean changed = false;
+ synchronized (conflictResolvers)
+ {
+ changed = conflictResolvers.remove(resolver);
+ }
+
+ if (changed)
+ {
+ resolver.setTransaction(null);
+ fireEvent(new ConflictResolversEventImpl());
+ }
+ }
+
+ public void disposeConflictResolvers()
+ {
+ try
+ {
+ for (CDOConflictResolver resolver : options().getConflictResolvers())
+ {
+ try
+ {
+ resolver.setTransaction(null);
+ }
+ catch (Exception ignore)
+ {
+ }
+ }
+ }
+ catch (Exception ignore)
+ {
+ }
+ }
+
+ private void validateResolver(CDOConflictResolver resolver)
+ {
+ if (resolver.getTransaction() != null)
+ {
+ throw new IllegalArgumentException("New conflict resolver is already associated with a transaction");
+ }
+
+ resolver.setTransaction(CDOTransactionImpl.this);
+ }
+
+ public boolean isAutoReleaseLocksEnabled()
+ {
+ return autoReleaseLocksEnabled;
+ }
+
+ public void setAutoReleaseLocksEnabled(boolean on)
+ {
+ if (autoReleaseLocksEnabled != on)
+ {
+ autoReleaseLocksEnabled = on;
+ fireEvent(new AutoReleaseLockEventImpl());
+ }
+ }
+
+ /**
+ * @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 AutoReleaseLockEventImpl extends OptionsEvent implements AutoReleaseLockEvent
+ {
+ private static final long serialVersionUID = 1L;
+
+ public AutoReleaseLockEventImpl()
+ {
+ super(OptionsImpl.this);
+ }
+ }
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXASavepoint.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXASavepoint.java
new file mode 100644
index 0000000000..8d8d319ac3
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXASavepoint.java
@@ -0,0 +1,41 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.transaction.CDOSavepoint;
+import org.eclipse.emf.cdo.transaction.CDOUserTransaction;
+
+import java.util.List;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOXASavepoint extends CDOAbstractSavepoint
+{
+ private List<CDOSavepoint> savepoints;
+
+ public CDOXASavepoint(CDOUserTransaction transaction, CDOAbstractSavepoint lastSavepoint)
+ {
+ super(transaction, lastSavepoint);
+
+ }
+
+ public List<CDOSavepoint> getSavepoints()
+ {
+ return savepoints;
+ }
+
+ public void setSavepoints(List<CDOSavepoint> savepoints)
+ {
+ this.savepoints = savepoints;
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionCommitContext.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionCommitContext.java
new file mode 100644
index 0000000000..c397c4bb60
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionCommitContext.java
@@ -0,0 +1,196 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.CDOObject;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDProvider;
+import org.eclipse.emf.cdo.common.model.CDOPackage;
+import org.eclipse.emf.cdo.common.revision.CDOReferenceAdjuster;
+import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
+import org.eclipse.emf.cdo.eresource.CDOResource;
+import org.eclipse.emf.cdo.internal.common.id.CDOIDExternalTempImpl;
+import org.eclipse.emf.cdo.util.CDOUtil;
+
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionResult;
+import org.eclipse.emf.internal.cdo.transaction.CDOXATransactionImpl.CDOXAState;
+
+import org.eclipse.net4j.util.ImplementationError;
+
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.spi.cdo.InternalCDOCommitContext;
+import org.eclipse.emf.spi.cdo.InternalCDOObject;
+import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+/**
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOXATransactionCommitContext implements Callable<Object>, CDOIDProvider, InternalCDOCommitContext
+{
+ private CDOXATransactionImpl transactionManager;
+
+ private IProgressMonitor progressMonitor;
+
+ private CDOXAState state;
+
+ private CommitTransactionResult result;
+
+ private InternalCDOCommitContext delegateCommitContext;
+
+ private Map<CDOIDExternalTempImpl, InternalCDOTransaction> requestedIDs = new HashMap<CDOIDExternalTempImpl, InternalCDOTransaction>();
+
+ private Map<InternalCDOObject, CDOIDExternalTempImpl> objectToID = new HashMap<InternalCDOObject, CDOIDExternalTempImpl>();
+
+ public CDOXATransactionCommitContext(CDOXATransactionImpl manager, InternalCDOCommitContext commitContext)
+ {
+ transactionManager = manager;
+ delegateCommitContext = commitContext;
+ }
+
+ public CDOXATransactionImpl getTransactionManager()
+ {
+ return transactionManager;
+ }
+
+ public void setProgressMonitor(IProgressMonitor progressMonitor)
+ {
+ this.progressMonitor = progressMonitor;
+ }
+
+ public CDOXAState getState()
+ {
+ return state;
+ }
+
+ public void setState(CDOXAState state)
+ {
+ this.state = state;
+ }
+
+ public CommitTransactionResult getResult()
+ {
+ return result;
+ }
+
+ public void setResult(CommitTransactionResult result)
+ {
+ this.result = result;
+ }
+
+ public InternalCDOTransaction getTransaction()
+ {
+ return delegateCommitContext.getTransaction();
+ }
+
+ public Map<CDOIDExternalTempImpl, InternalCDOTransaction> getRequestedIDs()
+ {
+ return requestedIDs;
+ }
+
+ public Map<CDOID, CDOObject> getDirtyObjects()
+ {
+ return delegateCommitContext.getDirtyObjects();
+ }
+
+ public Map<CDOID, CDOObject> getNewObjects()
+ {
+ return delegateCommitContext.getNewObjects();
+ }
+
+ public List<CDOPackage> getNewPackages()
+ {
+ return delegateCommitContext.getNewPackages();
+ }
+
+ public Map<CDOID, CDOResource> getNewResources()
+ {
+ return delegateCommitContext.getNewResources();
+ }
+
+ public Map<CDOID, CDOObject> getDetachedObjects()
+ {
+ return delegateCommitContext.getDetachedObjects();
+ }
+
+ public Map<CDOID, CDORevisionDelta> getRevisionDeltas()
+ {
+ return delegateCommitContext.getRevisionDeltas();
+ }
+
+ public Object call() throws Exception
+ {
+ state.handle(this, progressMonitor);
+ return true;
+ }
+
+ public CDOID provideCDOID(Object idOrObject)
+ {
+ CDOID id = getTransaction().provideCDOID(idOrObject);
+
+ if (id instanceof CDOIDExternalTempImpl)
+ {
+ if (idOrObject instanceof InternalEObject)
+ {
+ CDOIDExternalTempImpl proxyTemp = (CDOIDExternalTempImpl)id;
+ if (!requestedIDs.containsKey(proxyTemp))
+ {
+ InternalCDOObject cdoObject = (InternalCDOObject)CDOUtil.getCDOObject((InternalEObject)idOrObject);
+ InternalCDOTransaction cdoTransaction = (InternalCDOTransaction)cdoObject.cdoView();
+ getTransactionManager().add(cdoTransaction, proxyTemp);
+ requestedIDs.put(proxyTemp, cdoTransaction);
+ objectToID.put(cdoObject, proxyTemp);
+ }
+ }
+ else
+ {
+ throw new ImplementationError("Object should be an EObject " + idOrObject);
+ }
+ }
+
+ return id;
+ }
+
+ public void preCommit()
+ {
+ delegateCommitContext.preCommit();
+ }
+
+ public void postCommit(CommitTransactionResult result)
+ {
+ if (result != null)
+ {
+ final CDOReferenceAdjuster defaultReferenceAdjuster = result.getReferenceAdjuster();
+ result.setReferenceAdjuster(new CDOReferenceAdjuster()
+ {
+ public Object adjustReference(Object id)
+ {
+ CDOIDExternalTempImpl externalID = objectToID.get(id);
+ if (externalID != null)
+ {
+ id = externalID;
+ }
+
+ return defaultReferenceAdjuster.adjustReference(id);
+ }
+ });
+ }
+
+ delegateCommitContext.postCommit(result);
+ }
+};
diff --git a/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionImpl.java b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionImpl.java
new file mode 100644
index 0000000000..c8fbb2e709
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo/src/org/eclipse/emf/internal/cdo/transaction/CDOXATransactionImpl.java
@@ -0,0 +1,608 @@
+/***************************************************************************
+ * Copyright (c) 2004 - 2008 Eike Stepper, Germany.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Simon McDuff - initial API and implementation
+ **************************************************************************/
+package org.eclipse.emf.internal.cdo.transaction;
+
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.transaction.CDOSavepoint;
+import org.eclipse.emf.cdo.transaction.CDOTransaction;
+import org.eclipse.emf.cdo.transaction.CDOXATransaction;
+import org.eclipse.emf.cdo.util.CDOUtil;
+import org.eclipse.emf.cdo.view.CDOView;
+import org.eclipse.emf.cdo.view.CDOViewSet;
+
+import org.eclipse.emf.internal.cdo.protocol.CDOClientProtocol;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionCancelRequest;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionPhase1Request;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionPhase2Request;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionPhase3Request;
+import org.eclipse.emf.internal.cdo.protocol.CommitTransactionResult;
+
+import org.eclipse.net4j.util.CheckUtil;
+import org.eclipse.net4j.util.om.monitor.EclipseMonitor;
+import org.eclipse.net4j.util.om.monitor.EclipseMonitor.SynchonizedSubProgressMonitor;
+import org.eclipse.net4j.util.transaction.TransactionException;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.spi.cdo.CDOTransactionStrategy;
+import org.eclipse.emf.spi.cdo.InternalCDOCommitContext;
+import org.eclipse.emf.spi.cdo.InternalCDOTransaction;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Three-phase commit.
+ * <p>
+ * Phase 1 does the following for each CDOTransaction:<br>
+ * - preCommit <br>
+ * - Accumulate external temporary ID.<br>
+ * - request the commit to the server.<br>
+ * - The server registers the commit context and returns the final ID for each temporary ID.
+ * <p>
+ * Phase 2 does the following for each CDOTransaction:<br>
+ * - Transfer to the server a list of mapping of temporary externalID and final external ID that we accumulate
+ * previously<br>
+ * - Returns to the client only when commit process is ready to flush to disk (commit). <br>
+ * <p>
+ * Phase 3 does the following for each CDOTransaction:<br>
+ * - Make modifications permanent.<br>
+ * - PostCommit.
+ * <p>
+ * If an exception occurred during phase 1 or phase 2, the commit will be cancelled for all {@link CDOTransaction}
+ * include in the XA transaction. If an exception occurred during phase 3, the commit will be cancelled only for the
+ * {@link CDOTransaction} where the error happened.
+ * <p>
+ * All {@link CDOTransaction} includes in the commit process need to have finish their phase before moving to the next
+ * phase. For one phase, every {@link CDOTransaction} could have their own thread. It depends of the ExecutorService.
+ * <p>
+ *
+ * @author Simon McDuff
+ * @since 2.0
+ */
+public class CDOXATransactionImpl implements CDOXATransaction
+{
+ private List<InternalCDOTransaction> transactions = new ArrayList<InternalCDOTransaction>();
+
+ private boolean allRequestEnabled = true;
+
+ private ExecutorService executorService = Executors.newFixedThreadPool(10);
+
+ private Map<InternalCDOTransaction, CDOXATransactionCommitContext> activeContext = new HashMap<InternalCDOTransaction, CDOXATransactionCommitContext>();
+
+ private Map<InternalCDOTransaction, Set<CDOID>> requestedCDOID = new HashMap<InternalCDOTransaction, Set<CDOID>>();
+
+ private CDOXASavepoint lastSavepoint = new CDOXASavepoint(this, null);
+
+ private CDOXASavepoint firstSavepoint = lastSavepoint;
+
+ private CDOTransactionStrategy transactionStrategy = new CDOXATransactionStrategyImpl();
+
+ private CDOXAInternalAdapter internalAdapter = new CDOXAInternalAdapter();
+
+ public CDOXATransactionImpl()
+ {
+ }
+
+ public boolean isAllowRequestFromTransactionEnabled()
+ {
+ return allRequestEnabled;
+ }
+
+ public void setAllowRequestFromTransactionEnabled(boolean allRequest)
+ {
+ allRequestEnabled = allRequest;
+ }
+
+ public void add(InternalCDOTransaction transaction)
+ {
+ transaction.setTransactionStrategy(transactionStrategy);
+ }
+
+ public void remove(InternalCDOTransaction transaction)
+ {
+ transaction.setTransactionStrategy(null);
+ }
+
+ public synchronized void add(CDOViewSet viewSet)
+ {
+ CDOXATransaction transSet = CDOUtil.getXATransaction(viewSet);
+ if (transSet != null)
+ {
+ throw new IllegalArgumentException("XATransaction is already attached to this viewSet");
+ }
+
+ viewSet.eAdapters().add(internalAdapter);
+
+ for (InternalCDOTransaction transaction : getTransactions(viewSet))
+ {
+ add(transaction);
+ }
+ }
+
+ public synchronized void remove(CDOViewSet viewSet)
+ {
+ CDOXATransaction transSet = CDOUtil.getXATransaction(viewSet);
+ if (transSet != this)
+ {
+ throw new IllegalArgumentException("ViewSet isn't attached to this XATransaction");
+ }
+
+ for (InternalCDOTransaction transaction : getTransactions(viewSet))
+ {
+ remove(transaction);
+ }
+
+ viewSet.eAdapters().remove(internalAdapter);
+ };
+
+ public void add(InternalCDOTransaction view, CDOID object)
+ {
+ synchronized (requestedCDOID)
+ {
+ Set<CDOID> ids = requestedCDOID.get(view);
+ if (ids == null)
+ {
+ ids = new HashSet<CDOID>();
+ requestedCDOID.put(view, ids);
+ }
+
+ ids.add(object);
+ }
+ }
+
+ public CDOID[] get(InternalCDOTransaction transaction)
+ {
+ Set<CDOID> ids = requestedCDOID.get(transaction);
+ return ids.toArray(new CDOID[ids.size()]);
+ }
+
+ public CDOXATransactionCommitContext getCommitContext(CDOTransaction transaction)
+ {
+ return activeContext.get(transaction);
+ }
+
+ private void send(Collection<CDOXATransactionCommitContext> xaContexts, final IProgressMonitor progressMonitor)
+ throws InterruptedException, ExecutionException
+ {
+ progressMonitor.beginTask("", xaContexts.size());
+
+ try
+ {
+ List<Future<Object>> futures = new ArrayList<Future<Object>>();
+ for (CDOXATransactionCommitContext xaContext : xaContexts)
+ {
+ xaContext.setProgressMonitor(new SynchonizedSubProgressMonitor(progressMonitor, 1));
+ futures.add(executorService.submit(xaContext));
+ }
+
+ int nbProcessDone;
+ do
+ {
+ nbProcessDone = 0;
+ for (Future<Object> future : futures)
+ {
+ try
+ {
+ future.get(1, TimeUnit.MILLISECONDS);
+ nbProcessDone++;
+ }
+ catch (TimeoutException ex)
+ {
+ }
+ }
+ } while (xaContexts.size() != nbProcessDone);
+ }
+ finally
+ {
+ progressMonitor.done();
+ for (CDOXATransactionCommitContext xaContext : xaContexts)
+ {
+ xaContext.setProgressMonitor(null);
+ }
+ }
+ }
+
+ private void cleanUp()
+ {
+ activeContext.clear();
+ requestedCDOID.clear();
+ }
+
+ private List<InternalCDOTransaction> getTransactions(CDOViewSet viewSet)
+ {
+ List<InternalCDOTransaction> transactions = new ArrayList<InternalCDOTransaction>();
+ for (CDOView view : viewSet.getViews())
+ {
+ if (view instanceof InternalCDOTransaction)
+ {
+ transactions.add((InternalCDOTransaction)view);
+ }
+ }
+
+ return transactions;
+ }
+
+ public void commit() throws TransactionException
+ {
+ commit(new NullProgressMonitor());
+ }
+
+ public void commit(IProgressMonitor progressMonitor) throws TransactionException
+ {
+ CheckUtil.checkArg(progressMonitor, "progressMonitor");
+ progressMonitor.beginTask("Committing XA transaction", 3);
+ int phase = 0;
+
+ for (InternalCDOTransaction transaction : transactions)
+ {
+ InternalCDOCommitContext context = transaction.createCommitContext();
+ CDOXATransactionCommitContext xaContext = new CDOXATransactionCommitContext(this, context);
+ xaContext.setState(CDOXAPhase1State.INSTANCE);
+ activeContext.put(transaction, xaContext);
+ }
+
+ try
+ {
+ // We need to complete 3 phases
+ while (phase < 3)
+ {
+ send(activeContext.values(), new SubProgressMonitor(progressMonitor, 1));
+ ++phase;
+ }
+ }
+ catch (Exception ex)
+ {
+ if (phase < 2)
+ {
+ // Phase 0 and 1 are the only two phases we can cancel.
+ for (CDOXATransactionCommitContext transaction : activeContext.values())
+ {
+ transaction.setState(CDOXACancel.INSTANCE);
+ }
+
+ try
+ {
+ send(activeContext.values(), new SubProgressMonitor(progressMonitor, 2 - phase));
+ }
+ catch (InterruptedException ignore)
+ {
+ }
+ catch (ExecutionException ignore)
+ {
+ }
+ }
+
+ throw new TransactionException(ex);
+ }
+ finally
+ {
+ cleanUp();
+ progressMonitor.done();
+ }
+ }
+
+ public CDOXASavepoint getLastSavepoint()
+ {
+ return lastSavepoint;
+ }
+
+ public void rollback()
+ {
+ rollback(firstSavepoint);
+ }
+
+ public void rollback(CDOSavepoint savepoint)
+ {
+ if (savepoint == null)
+ {
+ throw new IllegalArgumentException("Save point is null");
+ }
+
+ if (savepoint.getUserTransaction() != this)
+ {
+ throw new IllegalArgumentException("Save point to rollback doesn't belong to this transaction: " + savepoint);
+ }
+
+ if (!savepoint.isValid())
+ {
+ throw new IllegalArgumentException("Savepoint isn't valid : " + savepoint);
+ }
+
+ CDOXASavepoint savepointSet = (CDOXASavepoint)savepoint;
+ List<CDOSavepoint> savepoints = savepointSet.getSavepoints();
+ if (savepoints == null)
+ {
+ savepoints = getListSavepoints();
+ }
+
+ for (CDOSavepoint indexSavePoint : savepoints)
+ {
+ InternalCDOTransaction transaction = (InternalCDOTransaction)indexSavePoint.getUserTransaction();
+ CDOSingleTransactionStrategy.INSTANCE.rollback(transaction, indexSavePoint);
+ }
+
+ lastSavepoint = savepointSet;
+ lastSavepoint.setNextSavepoint(null);
+ lastSavepoint.setSavepoints(null);
+ }
+
+ public CDOSavepoint setSavepoint()
+ {
+ List<CDOSavepoint> savepoints = getListSavepoints();
+ for (CDOSavepoint savepoint : savepoints)
+ {
+ InternalCDOTransaction transaction = (InternalCDOTransaction)savepoint.getUserTransaction();
+ CDOSingleTransactionStrategy.INSTANCE.setSavepoint(transaction);
+ }
+
+ getLastSavepoint().setSavepoints(savepoints);
+ lastSavepoint = new CDOXASavepoint(this, getLastSavepoint());
+ return lastSavepoint;
+ }
+
+ private List<CDOSavepoint> getListSavepoints()
+ {
+ synchronized (transactions)
+ {
+ List<CDOSavepoint> savepoints = new ArrayList<CDOSavepoint>();
+ for (InternalCDOTransaction transaction : transactions)
+ {
+ savepoints.add(transaction.getLastSavepoint());
+ }
+
+ return savepoints;
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ private final class CDOXATransactionStrategyImpl implements CDOTransactionStrategy
+ {
+ public CDOXATransactionStrategyImpl()
+ {
+ }
+
+ public void setTarget(InternalCDOTransaction transaction)
+ {
+ synchronized (transactions)
+ {
+ transactions.add(transaction);
+ }
+ }
+
+ public void unsetTarget(InternalCDOTransaction transaction)
+ {
+ synchronized (transactions)
+ {
+ transactions.remove(transaction);
+ }
+ }
+
+ private void checkAccess()
+ {
+ if (!allRequestEnabled)
+ {
+ throw new IllegalStateException("Commit from CDOTransaction is not allowed.");
+ }
+ }
+
+ public void commit(InternalCDOTransaction transactionCommit, IProgressMonitor progressMonitor) throws Exception
+ {
+ checkAccess();
+ CDOXATransactionImpl.this.commit(progressMonitor);
+ }
+
+ public void rollback(InternalCDOTransaction transaction, CDOSavepoint savepoint)
+ {
+ checkAccess();
+ CDOXATransactionImpl.this.rollback(savepoint);
+ }
+
+ public CDOSavepoint setSavepoint(InternalCDOTransaction transaction)
+ {
+ checkAccess();
+ return CDOXATransactionImpl.this.setSavepoint();
+ }
+ }
+
+ /**
+ * @author Simon McDuff
+ */
+ public static abstract class CDOXAState
+ {
+ public static final CDOXAState DONE = new CDOXAState()
+ {
+ @Override
+ protected void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor) throws Exception
+ {
+ progressMonitor.done();
+ }
+ };
+
+ protected void check_result(CommitTransactionResult result)
+ {
+ if (result != null && result.getRollbackMessage() != null)
+ {
+ throw new TransactionException(result.getRollbackMessage());
+ }
+ }
+
+ protected abstract void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor)
+ throws Exception;
+ };
+
+ /**
+ * @author Simon McDuff
+ */
+ public static class CDOXAPhase1State extends CDOXAState
+ {
+ public static final CDOXAPhase1State INSTANCE = new CDOXAPhase1State();
+
+ @Override
+ protected void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor) throws Exception
+ {
+ xaContext.preCommit();
+ CommitTransactionResult result = null;
+ if (xaContext.getTransaction().isDirty())
+ {
+ // Phase 1
+ CDOClientProtocol protocol = (CDOClientProtocol)xaContext.getTransaction().getSession().getProtocol();
+ CommitTransactionPhase1Request request = new CommitTransactionPhase1Request(protocol, xaContext);
+ result = request.send(new EclipseMonitor(progressMonitor));
+ check_result(result);
+ }
+ xaContext.setResult(result);
+ xaContext.setState(CDOXAPhase2State.INSTANCE);
+ }
+ };
+
+ /**
+ * @author Simon McDuff
+ */
+ public static class CDOXAPhase2State extends CDOXAState
+ {
+ public static final CDOXAPhase2State INSTANCE = new CDOXAPhase2State();
+
+ public CDOXAPhase2State()
+ {
+ }
+
+ @Override
+ protected void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor) throws Exception
+ {
+ if (xaContext.getTransaction().isDirty())
+ {
+ // Phase 2
+ CDOClientProtocol protocol = (CDOClientProtocol)xaContext.getTransaction().getSession().getProtocol();
+ CommitTransactionPhase2Request request = new CommitTransactionPhase2Request(protocol, xaContext);
+ CommitTransactionResult result = request.send(new EclipseMonitor(progressMonitor));
+ check_result(result);
+ }
+ xaContext.setState(CDOXAPhase3State.INSTANCE);
+ }
+ };
+
+ /**
+ * @author Simon McDuff
+ */
+ public static class CDOXAPhase3State extends CDOXAState
+ {
+ public static final CDOXAPhase3State INSTANCE = new CDOXAPhase3State();
+
+ public CDOXAPhase3State()
+ {
+ }
+
+ @Override
+ protected void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor) throws Exception
+ {
+ // Phase 2
+ if (xaContext.getTransaction().isDirty())
+ {
+ CDOClientProtocol protocol = (CDOClientProtocol)xaContext.getTransaction().getSession().getProtocol();
+ CommitTransactionPhase3Request request = new CommitTransactionPhase3Request(protocol, xaContext);
+ CommitTransactionResult result = request.send(new EclipseMonitor(progressMonitor));
+ check_result(result);
+ }
+ xaContext.postCommit(xaContext.getResult());
+ xaContext.setState(null);
+ }
+ };
+
+ /**
+ * @author Simon McDuff
+ */
+ public static class CDOXACancel extends CDOXAState
+ {
+ public static final CDOXACancel INSTANCE = new CDOXACancel();
+
+ public CDOXACancel()
+ {
+ }
+
+ @Override
+ protected void handle(CDOXATransactionCommitContext xaContext, IProgressMonitor progressMonitor) throws Exception
+ {
+ // Phase 2
+ CDOClientProtocol protocol = (CDOClientProtocol)xaContext.getTransaction().getSession().getProtocol();
+ CommitTransactionCancelRequest request = new CommitTransactionCancelRequest(protocol, xaContext);
+ CommitTransactionResult result = request.send(new EclipseMonitor(progressMonitor));
+ check_result(result);
+ }
+ };
+
+ /**
+ * @author Simon McDuff
+ */
+ public class CDOXAInternalAdapter implements Adapter
+ {
+ public CDOXAInternalAdapter()
+ {
+ }
+
+ public CDOXATransactionImpl getCDOXA()
+ {
+ return CDOXATransactionImpl.this;
+ }
+
+ public Notifier getTarget()
+ {
+ return null;
+ }
+
+ public boolean isAdapterForType(Object type)
+ {
+ return false;
+ }
+
+ public void notifyChanged(Notification notification)
+ {
+ switch (notification.getEventType())
+ {
+ case Notification.ADD:
+ if (notification.getNewValue() instanceof InternalCDOTransaction)
+ {
+ CDOXATransactionImpl.this.add((InternalCDOTransaction)notification.getNewValue());
+ }
+ break;
+
+ case Notification.REMOVE:
+ if (notification.getOldValue() instanceof InternalCDOTransaction)
+ {
+ CDOXATransactionImpl.this.remove((InternalCDOTransaction)notification.getNewValue());
+ }
+ break;
+ }
+ }
+
+ public void setTarget(Notifier newTarget)
+ {
+ }
+ }
+}

Back to the top