Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessorBase.java')
-rw-r--r--org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessorBase.java508
1 files changed, 508 insertions, 0 deletions
diff --git a/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessorBase.java b/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessorBase.java
new file mode 100644
index 0000000000..7be7a2a3a8
--- /dev/null
+++ b/org.eclipse.emf.cdo.server/src/org/eclipse/emf/cdo/spi/server/StoreAccessorBase.java
@@ -0,0 +1,508 @@
+/**
+ * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ * Simon McDuff - bug 201266
+ * Simon McDuff - bug 213402
+ */
+package org.eclipse.emf.cdo.spi.server;
+
+import org.eclipse.emf.cdo.common.branch.CDOBranch;
+import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
+import org.eclipse.emf.cdo.common.branch.CDOBranchVersion;
+import org.eclipse.emf.cdo.common.commit.CDOCommitData;
+import org.eclipse.emf.cdo.common.id.CDOID;
+import org.eclipse.emf.cdo.common.id.CDOIDTemp;
+import org.eclipse.emf.cdo.common.id.CDOIDUtil;
+import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
+import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
+import org.eclipse.emf.cdo.common.revision.CDOList;
+import org.eclipse.emf.cdo.common.revision.CDORevision;
+import org.eclipse.emf.cdo.common.revision.CDORevisionHandler;
+import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
+import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
+import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
+import org.eclipse.emf.cdo.common.util.CDOCommonUtil;
+import org.eclipse.emf.cdo.internal.common.commit.CDOCommitDataImpl;
+import org.eclipse.emf.cdo.internal.server.bundle.OM;
+import org.eclipse.emf.cdo.server.ISession;
+import org.eclipse.emf.cdo.server.IStoreAccessor;
+import org.eclipse.emf.cdo.server.ITransaction;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry;
+import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
+import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureDeltaVisitorImpl;
+import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
+import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
+
+import org.eclipse.net4j.util.lifecycle.Lifecycle;
+import org.eclipse.net4j.util.om.monitor.OMMonitor;
+import org.eclipse.net4j.util.om.trace.ContextTracer;
+
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @author Eike Stepper
+ * @since 4.0
+ */
+public abstract class StoreAccessorBase extends Lifecycle implements IStoreAccessor
+{
+ private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, StoreAccessorBase.class);
+
+ private Store store;
+
+ private Object context;
+
+ private boolean reader;
+
+ private List<CommitContext> commitContexts = new ArrayList<CommitContext>();
+
+ private StoreAccessorBase(Store store, Object context, boolean reader)
+ {
+ this.store = store;
+ this.context = context;
+ this.reader = reader;
+ }
+
+ protected StoreAccessorBase(Store store, ISession session)
+ {
+ this(store, session, true);
+ }
+
+ protected StoreAccessorBase(Store store, ITransaction transaction)
+ {
+ this(store, transaction, false);
+ }
+
+ void setContext(Object context)
+ {
+ this.context = context;
+ }
+
+ public Store getStore()
+ {
+ return store;
+ }
+
+ public boolean isReader()
+ {
+ return reader;
+ }
+
+ /**
+ * @since 3.0
+ */
+ public InternalSession getSession()
+ {
+ if (context instanceof ITransaction)
+ {
+ return (InternalSession)((ITransaction)context).getSession();
+ }
+
+ return (InternalSession)context;
+ }
+
+ public ITransaction getTransaction()
+ {
+ if (context instanceof ITransaction)
+ {
+ return (ITransaction)context;
+ }
+
+ return null;
+ }
+
+ public void release()
+ {
+ store.releaseAccessor(this);
+ commitContexts.clear();
+ }
+
+ /**
+ * @since 3.0
+ */
+ public final void write(InternalCommitContext context, OMMonitor monitor)
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Writing transaction: {0}", getTransaction()); //$NON-NLS-1$
+ }
+
+ commitContexts.add(context);
+ doWrite(context, monitor);
+ }
+
+ protected abstract void doWrite(InternalCommitContext context, OMMonitor monitor);
+
+ /**
+ * @since 3.0
+ */
+ public final void commit(OMMonitor monitor)
+ {
+ doCommit(monitor);
+
+ long latest = CDORevision.UNSPECIFIED_DATE;
+ long latestNonLocal = CDORevision.UNSPECIFIED_DATE;
+ for (CommitContext commitContext : commitContexts)
+ {
+ CDOBranchPoint branchPoint = commitContext.getBranchPoint();
+ long timeStamp = branchPoint.getTimeStamp();
+ if (timeStamp > latest)
+ {
+ latest = timeStamp;
+ }
+
+ CDOBranch branch = branchPoint.getBranch();
+ if (!branch.isLocal())
+ {
+ if (timeStamp > latestNonLocal)
+ {
+ latestNonLocal = timeStamp;
+ }
+ }
+ }
+
+ getStore().setLastCommitTime(latest);
+ getStore().setLastNonLocalCommitTime(latestNonLocal);
+ }
+
+ /**
+ * @since 3.0
+ */
+ protected abstract void doCommit(OMMonitor monitor);
+
+ public final void rollback()
+ {
+ if (TRACER.isEnabled())
+ {
+ TRACER.format("Rolling back transaction: {0}", getTransaction()); //$NON-NLS-1$
+ }
+
+ for (CommitContext commitContext : commitContexts)
+ {
+ doRollback(commitContext);
+ }
+ }
+
+ protected abstract void doRollback(CommitContext commitContext);
+
+ /**
+ * @since 3.0
+ */
+ public CDOID readResourceID(CDOID folderID, String name, CDOBranchPoint branchPoint)
+ {
+ QueryResourcesContext.ExactMatch context = Store.createExactMatchContext(folderID, name, branchPoint);
+ queryResources(context);
+ return context.getResourceID();
+ }
+
+ /**
+ * @since 3.0
+ */
+ public CDOCommitData loadCommitData(long timeStamp)
+ {
+ CommitDataRevisionHandler handler = new CommitDataRevisionHandler(this, timeStamp);
+ return handler.getCommitData();
+ }
+
+ /**
+ * Add ID mappings for all new objects of a transaction to the commit context. The implementor must, for each new
+ * object of the commit context, determine a permanent CDOID and make it known to the context by calling
+ * {@link InternalCommitContext#addIDMapping(CDOID, CDOID)}.
+ *
+ * @since 3.0
+ */
+ public void addIDMappings(InternalCommitContext commitContext, OMMonitor monitor)
+ {
+ try
+ {
+ CDORevision[] newObjects = commitContext.getNewObjects();
+ monitor.begin(newObjects.length);
+ for (CDORevision revision : newObjects)
+ {
+ CDOID id = revision.getID();
+ if (id instanceof CDOIDTemp)
+ {
+ CDOIDTemp oldID = (CDOIDTemp)id;
+ CDOID newID = getNextCDOID(revision);
+ if (CDOIDUtil.isNull(newID) || newID.isTemporary())
+ {
+ throw new IllegalStateException("newID=" + newID); //$NON-NLS-1$
+ }
+
+ commitContext.addIDMapping(oldID, newID);
+ }
+
+ monitor.worked();
+ }
+ }
+ finally
+ {
+ monitor.done();
+ }
+ }
+
+ protected abstract CDOID getNextCDOID(CDORevision revision);
+
+ protected void doPassivate() throws Exception
+ {
+ }
+
+ protected void doUnpassivate() throws Exception
+ {
+ }
+
+ /**
+ * @author Eike Stepper
+ * @since 3.0
+ */
+ public static class CommitDataRevisionHandler implements CDORevisionHandler
+ {
+ private IStoreAccessor storeAccessor;
+
+ private long timeStamp;
+
+ private InternalCDORevisionManager revisionManager;
+
+ private List<CDOPackageUnit> newPackageUnits = new ArrayList<CDOPackageUnit>();
+
+ private List<CDOIDAndVersion> newObjects = new ArrayList<CDOIDAndVersion>();
+
+ private List<CDORevisionKey> changedObjects = new ArrayList<CDORevisionKey>();
+
+ private DetachCounter detachCounter = new DetachCounter();
+
+ public CommitDataRevisionHandler(IStoreAccessor storeAccessor, long timeStamp)
+ {
+ this.storeAccessor = storeAccessor;
+ this.timeStamp = timeStamp;
+
+ InternalStore store = (InternalStore)storeAccessor.getStore();
+ InternalRepository repository = store.getRepository();
+ revisionManager = repository.getRevisionManager();
+
+ InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false);
+ InternalCDOPackageUnit[] packageUnits = packageRegistry.getPackageUnits(timeStamp, timeStamp);
+ for (InternalCDOPackageUnit packageUnit : packageUnits)
+ {
+ if (!packageUnit.isSystem())
+ {
+ newPackageUnits.add(packageUnit);
+ }
+ }
+ }
+
+ public CDOCommitData getCommitData()
+ {
+ storeAccessor.handleRevisions(null, null, timeStamp, true, new CDORevisionHandler.Filtered.Undetached(this));
+
+ List<CDOIDAndVersion> detachedObjects = detachCounter.getDetachedObjects();
+ return new CDOCommitDataImpl(newPackageUnits, newObjects, changedObjects, detachedObjects);
+ }
+
+ /**
+ * @since 4.0
+ */
+ public boolean handleRevision(CDORevision rev)
+ {
+ if (rev.getTimeStamp() != timeStamp)
+ {
+ throw new IllegalArgumentException("Invalid revision time stamp: "
+ + CDOCommonUtil.formatTimeStamp(rev.getTimeStamp()));
+ }
+
+ if (rev instanceof DetachedCDORevision)
+ {
+ // Do nothing. Detached objects are handled by detachCounter.
+ }
+ else
+ {
+ InternalCDORevision revision = (InternalCDORevision)rev;
+ CDOID id = revision.getID();
+ CDOBranch branch = revision.getBranch();
+ int version = revision.getVersion();
+ if (version > CDOBranchVersion.FIRST_VERSION)
+ {
+ CDOBranchVersion oldVersion = branch.getVersion(version - 1);
+ InternalCDORevision oldRevision = revisionManager.getRevisionByVersion(id, oldVersion, CDORevision.UNCHUNKED,
+ true);
+ InternalCDORevisionDelta delta = revision.compare(oldRevision);
+ changedObjects.add(delta);
+
+ detachCounter.update(oldRevision, delta);
+ }
+ else
+ {
+ InternalCDORevision oldRevision = getRevisionFromBase(id, branch);
+ if (oldRevision != null)
+ {
+ InternalCDORevisionDelta delta = revision.compare(oldRevision);
+ changedObjects.add(delta);
+ }
+ else
+ {
+ InternalCDORevision newRevision = revision.copy();
+ newRevision.setRevised(CDOBranchPoint.UNSPECIFIED_DATE);
+ newObjects.add(newRevision);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private InternalCDORevision getRevisionFromBase(CDOID id, CDOBranch branch)
+ {
+ if (branch.isMainBranch())
+ {
+ return null;
+ }
+
+ CDOBranchPoint base = branch.getBase();
+ InternalCDORevision revision = revisionManager.getRevision(id, base, CDORevision.UNCHUNKED,
+ CDORevision.DEPTH_NONE, true);
+ if (revision == null)
+ {
+ revision = getRevisionFromBase(id, base.getBranch());
+ }
+
+ return revision;
+ }
+
+ /**
+ * @author Eike Stepper
+ */
+ private static final class DetachCounter extends CDOFeatureDeltaVisitorImpl
+ {
+ private Map<CDOID, AtomicInteger> counters = new HashMap<CDOID, AtomicInteger>();
+
+ private InternalCDORevision oldRevision;
+
+ public DetachCounter()
+ {
+ }
+
+ public void update(InternalCDORevision oldRevision, InternalCDORevisionDelta delta)
+ {
+ try
+ {
+ this.oldRevision = oldRevision;
+ delta.accept(this);
+ }
+ finally
+ {
+ this.oldRevision = null;
+ }
+ }
+
+ public List<CDOIDAndVersion> getDetachedObjects()
+ {
+ List<CDOIDAndVersion> result = new ArrayList<CDOIDAndVersion>();
+ for (Entry<CDOID, AtomicInteger> entry : counters.entrySet())
+ {
+ int value = entry.getValue().get();
+ if (value == -1)
+ {
+ CDOID id = entry.getKey();
+ result.add(CDOIDUtil.createIDAndVersion(id, CDOBranchVersion.UNSPECIFIED_VERSION));
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void visit(CDOAddFeatureDelta delta)
+ {
+ if (isContainment(delta.getFeature()))
+ {
+ handleContainment(delta.getValue(), 1);
+ }
+ }
+
+ @Override
+ public void visit(CDORemoveFeatureDelta delta)
+ {
+ if (isContainment(delta.getFeature()))
+ {
+ handleContainment(delta.getValue(), -1);
+ }
+ }
+
+ @Override
+ public void visit(CDOSetFeatureDelta delta)
+ {
+ if (isContainment(delta.getFeature()))
+ {
+ handleContainment(delta.getValue(), 1);
+ }
+ }
+
+ @Override
+ public void visit(CDOUnsetFeatureDelta delta)
+ {
+ EStructuralFeature feature = delta.getFeature();
+ if (isContainment(feature))
+ {
+ Object value = oldRevision.getValue(feature);
+ handleContainment(value, -1);
+ }
+ }
+
+ @Override
+ public void visit(CDOClearFeatureDelta delta)
+ {
+ EStructuralFeature feature = delta.getFeature();
+ if (isContainment(feature))
+ {
+ CDOList list = oldRevision.getList(feature);
+ for (Object value : list)
+ {
+ handleContainment(value, -1);
+ }
+ }
+ }
+
+ private void handleContainment(Object value, int delta)
+ {
+ CDOID id = (CDOID)value;
+ AtomicInteger counter = counters.get(id);
+ if (counter == null)
+ {
+ counter = new AtomicInteger();
+ counters.put(id, counter);
+ }
+
+ counter.addAndGet(delta);
+ }
+
+ private static boolean isContainment(EStructuralFeature feature)
+ {
+ if (feature instanceof EReference)
+ {
+ EReference reference = (EReference)feature;
+ return reference.isContainment();
+ }
+
+ return false;
+ }
+ }
+ }
+}

Back to the top