blob: 2f0387acb03984684e26c547c002d0f09718b360 [file] [log] [blame]
/***************************************************************************
* 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
**************************************************************************/
package org.eclipse.emf.internal.cdo;
import org.eclipse.emf.cdo.CDOState;
import org.eclipse.emf.cdo.CDOTransaction;
import org.eclipse.emf.cdo.CDOView;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDTemp;
import org.eclipse.emf.cdo.common.model.CDOClass;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.util.TransportException;
import org.eclipse.emf.cdo.spi.common.InternalCDORevision;
import org.eclipse.emf.cdo.util.InvalidObjectException;
import org.eclipse.emf.internal.cdo.bundle.OM;
import org.eclipse.emf.internal.cdo.protocol.CDOClientProtocol;
import org.eclipse.emf.internal.cdo.protocol.CommitTransactionResult;
import org.eclipse.emf.internal.cdo.protocol.VerifyRevisionRequest;
import org.eclipse.emf.internal.cdo.util.FSMUtil;
import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.fsm.FiniteStateMachine;
import org.eclipse.net4j.util.fsm.ITransition;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.EStoreEObjectImpl;
import org.eclipse.emf.ecore.resource.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @author Eike Stepper
*/
public final class CDOStateMachine extends FiniteStateMachine<CDOState, CDOEvent, InternalCDOObject>
{
// @Singleton
public static final CDOStateMachine INSTANCE = new CDOStateMachine();
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_STATEMACHINE, CDOStateMachine.class);
private InternalCDOObject lastTracedObject;
private CDOState lastTracedState;
private CDOEvent lastTracedEvent;
@SuppressWarnings("unchecked")
private CDOStateMachine()
{
super(CDOState.class, CDOEvent.class);
init(CDOState.TRANSIENT, CDOEvent.PREPARE, new PrepareTransition());
init(CDOState.TRANSIENT, CDOEvent.ATTACH, FAIL);
init(CDOState.TRANSIENT, CDOEvent.DETACH, IGNORE);
init(CDOState.TRANSIENT, CDOEvent.READ, IGNORE);
init(CDOState.TRANSIENT, CDOEvent.WRITE, IGNORE);
init(CDOState.TRANSIENT, CDOEvent.INVALIDATE, FAIL);
init(CDOState.TRANSIENT, CDOEvent.DETACH_REMOTE, FAIL);
init(CDOState.TRANSIENT, CDOEvent.RELOAD, IGNORE);
init(CDOState.TRANSIENT, CDOEvent.COMMIT, FAIL);
init(CDOState.TRANSIENT, CDOEvent.ROLLBACK, FAIL);
init(CDOState.PREPARED, CDOEvent.PREPARE, FAIL);
init(CDOState.PREPARED, CDOEvent.ATTACH, new AttachTransition());
init(CDOState.PREPARED, CDOEvent.DETACH, FAIL);
init(CDOState.PREPARED, CDOEvent.READ, IGNORE);
init(CDOState.PREPARED, CDOEvent.WRITE, FAIL);
init(CDOState.PREPARED, CDOEvent.INVALIDATE, FAIL);
init(CDOState.PREPARED, CDOEvent.DETACH_REMOTE, FAIL);
init(CDOState.PREPARED, CDOEvent.RELOAD, FAIL);
init(CDOState.PREPARED, CDOEvent.COMMIT, FAIL);
init(CDOState.PREPARED, CDOEvent.ROLLBACK, FAIL);
init(CDOState.NEW, CDOEvent.PREPARE, FAIL);
init(CDOState.NEW, CDOEvent.ATTACH, FAIL);
init(CDOState.NEW, CDOEvent.DETACH, new DetachTransition());
init(CDOState.NEW, CDOEvent.READ, IGNORE);
init(CDOState.NEW, CDOEvent.WRITE, new WriteNewTransition());
init(CDOState.NEW, CDOEvent.INVALIDATE, FAIL);
init(CDOState.NEW, CDOEvent.DETACH_REMOTE, FAIL);
init(CDOState.NEW, CDOEvent.RELOAD, FAIL);
init(CDOState.NEW, CDOEvent.COMMIT, new CommitTransition(false));
init(CDOState.NEW, CDOEvent.ROLLBACK, FAIL);
init(CDOState.CLEAN, CDOEvent.PREPARE, FAIL);
init(CDOState.CLEAN, CDOEvent.ATTACH, FAIL);
init(CDOState.CLEAN, CDOEvent.DETACH, new DetachTransition());
init(CDOState.CLEAN, CDOEvent.READ, IGNORE);
init(CDOState.CLEAN, CDOEvent.WRITE, new WriteTransition());
init(CDOState.CLEAN, CDOEvent.INVALIDATE, new InvalidateTransition());
init(CDOState.CLEAN, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
init(CDOState.CLEAN, CDOEvent.RELOAD, new ReloadTransition());
init(CDOState.CLEAN, CDOEvent.COMMIT, FAIL);
init(CDOState.CLEAN, CDOEvent.ROLLBACK, FAIL);
init(CDOState.DIRTY, CDOEvent.PREPARE, FAIL);
init(CDOState.DIRTY, CDOEvent.ATTACH, FAIL);
init(CDOState.DIRTY, CDOEvent.DETACH, new DetachTransition());
init(CDOState.DIRTY, CDOEvent.READ, IGNORE);
init(CDOState.DIRTY, CDOEvent.WRITE, new RewriteTransition());
init(CDOState.DIRTY, CDOEvent.INVALIDATE, new ConflictTransition());
init(CDOState.DIRTY, CDOEvent.DETACH_REMOTE, new InvalidConflictTransition());
init(CDOState.DIRTY, CDOEvent.RELOAD, new ReloadTransition());
init(CDOState.DIRTY, CDOEvent.COMMIT, new CommitTransition(true));
init(CDOState.DIRTY, CDOEvent.ROLLBACK, new RollbackTransition());
init(CDOState.PROXY, CDOEvent.PREPARE, FAIL);
init(CDOState.PROXY, CDOEvent.ATTACH, FAIL);
init(CDOState.PROXY, CDOEvent.DETACH, new DetachTransition());
init(CDOState.PROXY, CDOEvent.READ, new LoadTransition(false));
init(CDOState.PROXY, CDOEvent.WRITE, new LoadTransition(true));
init(CDOState.PROXY, CDOEvent.INVALIDATE, IGNORE);
init(CDOState.PROXY, CDOEvent.DETACH_REMOTE, DetachRemoteTransition.INSTANCE);
init(CDOState.PROXY, CDOEvent.RELOAD, new ReloadTransition());
init(CDOState.PROXY, CDOEvent.COMMIT, FAIL);
init(CDOState.PROXY, CDOEvent.ROLLBACK, FAIL);
init(CDOState.CONFLICT, CDOEvent.PREPARE, FAIL);
init(CDOState.CONFLICT, CDOEvent.ATTACH, IGNORE);
init(CDOState.CONFLICT, CDOEvent.DETACH, new DetachTransition());
init(CDOState.CONFLICT, CDOEvent.READ, IGNORE);
init(CDOState.CONFLICT, CDOEvent.WRITE, IGNORE);
init(CDOState.CONFLICT, CDOEvent.INVALIDATE, IGNORE);
init(CDOState.CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
init(CDOState.CONFLICT, CDOEvent.RELOAD, FAIL);
init(CDOState.CONFLICT, CDOEvent.COMMIT, IGNORE);
init(CDOState.CONFLICT, CDOEvent.ROLLBACK, new RollbackTransition());
init(CDOState.INVALID, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.DETACH, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.READ, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.WRITE, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.INVALIDATE, IGNORE);
init(CDOState.INVALID, CDOEvent.DETACH_REMOTE, IGNORE);
init(CDOState.INVALID, CDOEvent.RELOAD, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
init(CDOState.INVALID, CDOEvent.ROLLBACK, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.PREPARE, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.ATTACH, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.READ, IGNORE);
init(CDOState.INVALID_CONFLICT, CDOEvent.WRITE, IGNORE);
init(CDOState.INVALID_CONFLICT, CDOEvent.INVALIDATE, IGNORE);
init(CDOState.INVALID_CONFLICT, CDOEvent.DETACH_REMOTE, IGNORE);
init(CDOState.INVALID_CONFLICT, CDOEvent.RELOAD, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.COMMIT, InvalidTransition.INSTANCE);
init(CDOState.INVALID_CONFLICT, CDOEvent.ROLLBACK, DetachRemoteTransition.INSTANCE);
}
/**
* object is already attached in EMF world. It contains all the information needed to know where it will be connected.
* We used a mapOfContents only for performance reason.
*
* @since 2.0
*/
public void attach(InternalCDOObject object, InternalCDOTransaction transaction)
{
List<InternalCDOObject> contents = new ArrayList<InternalCDOObject>();
attach1(object, new Pair<InternalCDOTransaction, List<InternalCDOObject>>(transaction, contents));
attach2(object);
for (InternalCDOObject content : contents)
{
attach2(content);
}
}
/**
* Phase 1: TRANSIENT --> PREPARED
*/
private void attach1(InternalCDOObject object,
Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndMapOfContents)
{
if (TRACER.isEnabled())
{
TRACER.format("PREPARE: {0} --> {1}", object, transactionAndMapOfContents.getElement1());
}
process(object, CDOEvent.PREPARE, transactionAndMapOfContents);
}
/**
* Phase 2: PREPARED --> NEW
*/
private void attach2(InternalCDOObject object)
{
if (TRACER.isEnabled())
{
TRACER.format("ATTACH: {0}", object);
}
process(object, CDOEvent.ATTACH, null);
}
public void detach(InternalCDOObject object)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.DETACH);
}
List<InternalCDOObject> objectsToDetach = new ArrayList<InternalCDOObject>();
InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
// Accumulate objects that needs to be detached
// If we have an error, we will keep the graph exactly like it was before.
process(object, CDOEvent.DETACH, objectsToDetach);
// postDetach requires the object to be TRANSIENT
for (InternalCDOObject content : objectsToDetach)
{
CDOState oldState = content.cdoInternalSetState(CDOState.TRANSIENT);
content.cdoInternalPostDetach();
content.cdoInternalSetState(oldState);
}
// detachObject needs to know the state before we change the object to TRANSIENT
for (InternalCDOObject content : objectsToDetach)
{
transaction.detachObject(content);
content.cdoInternalSetState(CDOState.TRANSIENT);
content.cdoInternalSetView(null);
content.cdoInternalSetID(null);
content.cdoInternalSetRevision(null);
}
}
public void read(InternalCDOObject object)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.READ);
}
process(object, CDOEvent.READ, null);
}
public void write(InternalCDOObject object)
{
write(object, null);
}
public void write(InternalCDOObject object, CDOFeatureDelta featureDelta)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.WRITE);
}
process(object, CDOEvent.WRITE, featureDelta);
}
public void reload(InternalCDOObject... objects)
{
CDOView view = null;
Map<CDOID, InternalCDOObject> ids = new HashMap<CDOID, InternalCDOObject>();
List<InternalCDORevision> revisions = new ArrayList<InternalCDORevision>();
List<InternalCDORevision> revised = new ArrayList<InternalCDORevision>();
for (InternalCDOObject object : objects)
{
CDOState state = object.cdoState();
if (state != CDOState.TRANSIENT && state != CDOState.PREPARED && state != CDOState.NEW
&& state != CDOState.CONFLICT && state != CDOState.INVALID_CONFLICT && state != CDOState.INVALID)
{
if (view == null)
{
view = object.cdoView();
}
InternalCDORevision revision = object.cdoRevision();
if (revision.isCurrent())
{
revisions.add(revision);
}
else
{
revised.add(revision);
}
ids.put(object.cdoID(), object);
}
}
if (view != null)
{
try
{
CDOClientProtocol protocol = (CDOClientProtocol)view.getSession().getProtocol();
revisions = new VerifyRevisionRequest(protocol, revisions).send();
}
catch (Exception ex)
{
throw new TransportException(ex);
}
revisions.addAll(revised);
for (InternalCDORevision revision : revisions)
{
InternalCDOObject object = ids.get(revision.getID());
if (TRACER.isEnabled())
{
trace(object, CDOEvent.RELOAD);
}
process(object, CDOEvent.RELOAD, null);
}
}
}
/**
* @since 2.0
*/
public void invalidate(InternalCDOObject object, int version)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.INVALIDATE);
}
process(object, CDOEvent.INVALIDATE, version);
}
/**
* @since 2.0
*/
public void detachRemote(InternalCDOObject object)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.DETACH_REMOTE);
}
process(object, CDOEvent.DETACH_REMOTE, CDORevision.UNSPECIFIED_VERSION);
}
public void commit(InternalCDOObject object, CommitTransactionResult result)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.COMMIT);
}
process(object, CDOEvent.COMMIT, result);
}
/**
* @since 2.0
*/
public void rollback(InternalCDOObject object)
{
if (TRACER.isEnabled())
{
trace(object, CDOEvent.ROLLBACK);
}
process(object, CDOEvent.ROLLBACK, null);
}
@Override
protected CDOState getState(InternalCDOObject object)
{
return object.cdoState();
}
@Override
protected void setState(InternalCDOObject object, CDOState state)
{
object.cdoInternalSetState(state);
}
/**
* Removes clutter from the trace log
*/
private void trace(InternalCDOObject object, CDOEvent event)
{
CDOState state = object.cdoState();
if (lastTracedObject != object || lastTracedState != state || lastTracedEvent != event)
{
TRACER.format("{0}: {1}", event, object.getClass().getName());
lastTracedObject = object;
lastTracedState = state;
lastTracedEvent = event;
}
}
@SuppressWarnings("unused")
private void testAttach(InternalCDOObject object)
{
process(object, CDOEvent.ATTACH, null);
}
@SuppressWarnings("unused")
private void testReload(InternalCDOObject object)
{
process(object, CDOEvent.RELOAD, null);
}
/**
* Prepares a tree of transient objects to be subsequently {@link AttachTransition attached} to a CDOView.
* <p>
* Execution is recursive and includes:
* <ol>
* <li>Assignment of a new {@link CDOIDTemp}
* <li>Assignment of a new {@link CDORevision}
* <li>Bidirectional association with the {@link CDOView}
* <li>Registration with the {@link CDOTransaction}
* <li>Changing state to {@link CDOState#PREPARED PREPARED}
* </ol>
*
* @see AttachTransition
* @author Eike Stepper
*/
private final class PrepareTransition implements
ITransition<CDOState, CDOEvent, InternalCDOObject, Pair<InternalCDOTransaction, List<InternalCDOObject>>>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
Pair<InternalCDOTransaction, List<InternalCDOObject>> transactionAndMapOfContents)
{
InternalCDOTransaction transaction = transactionAndMapOfContents.getElement1();
List<InternalCDOObject> contents = transactionAndMapOfContents.getElement2();
// Prepare object
CDOID id = transaction.getNextTemporaryID();
object.cdoInternalSetID(id);
object.cdoInternalSetView(transaction);
changeState(object, CDOState.PREPARED);
// Create new revision
CDOClass cdoClass = object.cdoClass();
CDORevisionFactory factory = transaction.getSession().options().getRevisionFactory();
InternalCDORevision revision = (InternalCDORevision)factory.createRevision(cdoClass, id);
revision.setVersion(-1);
object.cdoInternalSetRevision(revision);
// Register object
transaction.registerObject(object);
transaction.registerNew(object);
// Prepare content tree
for (Iterator<InternalCDOObject> it = FSMUtil.getProperContents(object); it.hasNext();)
{
InternalCDOObject content = it.next();
contents.add(content);
INSTANCE.process(content, CDOEvent.PREPARE, transactionAndMapOfContents);
}
}
}
/**
* Attaches a tree of {@link PrepareTransition prepared} objects to a CDOView.
* <p>
* Execution is recursive and includes:
* <ol>
* <li>Calling {@link InternalCDOObject#cdoInternalPostAttach()},<br>
* which includes for {@link CDOObjectImpl}:
* <ol>
* <li>Population of the CDORevision with the current values in
* {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
* <li>Unsetting {@link EStoreEObjectImpl#eSetting(org.eclipse.emf.ecore.EStructuralFeature) eSettings}
* </ol>
* <li>Changing state to {@link CDOState#NEW NEW}
* </ol>
*
* @see PrepareTransition
* @author Eike Stepper
*/
private final class AttachTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
{
object.cdoInternalPostAttach();
changeState(object, CDOState.NEW);
}
}
/**
* @author Eike Stepper
*/
private final class DetachTransition implements
ITransition<CDOState, CDOEvent, InternalCDOObject, List<InternalCDOObject>>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event,
List<InternalCDOObject> objectsToDetach)
{
InternalCDOTransaction transaction = (InternalCDOTransaction)object.cdoView();
objectsToDetach.add(object);
boolean isResource = object instanceof Resource;
// Prepare content tree
for (Iterator<EObject> it = object.eContents().iterator(); it.hasNext();)
{
InternalEObject eObject = (InternalEObject)it.next();
boolean isDirectlyConnected = isResource && eObject.eDirectResource() == object;
if (isDirectlyConnected || eObject.eDirectResource() == null)
{
InternalCDOObject content = FSMUtil.adapt(eObject, transaction);
if (content != null)
{
INSTANCE.process(content, CDOEvent.DETACH, objectsToDetach);
}
}
}
}
}
/**
* @author Eike Stepper
*/
final private class CommitTransition implements
ITransition<CDOState, CDOEvent, InternalCDOObject, CommitTransactionResult>
{
private boolean useDeltas = false;
public CommitTransition(boolean useDeltas)
{
this.useDeltas = useDeltas;
}
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, CommitTransactionResult data)
{
InternalCDOView view = object.cdoView();
InternalCDORevision revision = object.cdoRevision();
Map<CDOIDTemp, CDOID> idMappings = data.getIDMappings();
// Adjust object
CDOID id, oldID;
oldID = id = object.cdoID();
CDOID newID = idMappings.get(id);
if (newID != null)
{
object.cdoInternalSetID(newID);
view.remapObject(oldID);
id = newID;
}
// Adjust revision
revision.setID(id);
revision.setUntransactional();
revision.setCreated(data.getTimeStamp());
// if (useDeltas)
// {
// // Cannot use that yet, since we need to change adjust index for list.
// // TODO Simon Implement a way to adjust indexes as fast as possible.
// RevisionAdjuster revisionAdjuster = new RevisionAdjuster(data.getReferenceAdjuster());
// CDORevisionDelta delta = data.getCommitContext().getRevisionDeltas().get(oldID);
// revisionAdjuster.adjustRevision(revision, delta);
// }
// else
{
revision.adjustReferences(data.getReferenceAdjuster());
}
CDORevisionManagerImpl revisionManager = (CDORevisionManagerImpl)view.getSession().getRevisionManager();
revisionManager.addCachedRevision(revision);
changeState(object, CDOState.CLEAN);
}
}
/**
* @author Eike Stepper
*/
private final class RollbackTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
{
changeState(object, CDOState.PROXY);
}
}
/**
* @author Eike Stepper
*/
private final class WriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
{
// Copy revision
InternalCDORevision revision = (InternalCDORevision)object.cdoRevision().copy();
revision.setTransactional();
object.cdoInternalSetRevision(revision);
InternalCDOView view = object.cdoView();
InternalCDOTransaction transaction = view.toTransaction();
transaction.registerDirty(object, (CDOFeatureDelta)featureDelta);
changeState(object, CDOState.DIRTY);
}
}
/**
* @author Simon McDuff
*/
private final class WriteNewTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
{
InternalCDOView view = object.cdoView();
InternalCDOTransaction transaction = view.toTransaction();
transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
}
}
/**
* @author Simon McDuff
*/
private final class RewriteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object featureDelta)
{
InternalCDOView view = object.cdoView();
InternalCDOTransaction transaction = view.toTransaction();
transaction.registerFeatureDelta(object, (CDOFeatureDelta)featureDelta);
}
}
/**
* @author Eike Stepper
*/
private final class ReloadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
{
changeState(object, CDOState.PROXY);
}
}
/**
* @author Simon McDuff
*/
static private class DetachRemoteTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
static DetachRemoteTransition INSTANCE = new DetachRemoteTransition();
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
{
InternalCDOView view = object.cdoView();
view.deregisterObject(object);
object.cdoInternalSetState(CDOState.INVALID);
object.cdoInternalPostInvalid();
}
}
/**
* @author Eike Stepper
*/
private class InvalidateTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Integer>
{
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Integer version)
{
InternalCDORevision revision = object.cdoRevision();
if (version == CDORevision.UNSPECIFIED_VERSION || revision.getVersion() <= version)
{
changeState(object, CDOState.PROXY);
object.cdoInternalSetRevision(null);
}
}
}
/**
* @author Eike Stepper
* @since 2.0
*/
protected class ConflictTransition extends InvalidateTransition
{
@Override
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Integer version)
{
InternalCDORevision revision = object.cdoRevision();
if (version == 0 || revision.getVersion() <= version + 1)
{
InternalCDOView view = object.cdoView();
InternalCDOTransaction transaction = view.toTransaction();
transaction.setConflict(object);
changeState(object, CDOState.CONFLICT);
}
}
}
/**
* @author Simon McDuff
*/
private final class InvalidConflictTransition extends ConflictTransition
{
@Override
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Integer version)
{
InternalCDOView view = object.cdoView();
InternalCDOTransaction transaction = view.toTransaction();
transaction.setConflict(object);
changeState(object, CDOState.INVALID_CONFLICT);
}
}
/**
* @author Eike Stepper
*/
private final class LoadTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
private boolean forWrite;
public LoadTransition(boolean forWrite)
{
this.forWrite = forWrite;
}
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object delta)
{
CDOID id = object.cdoID();
InternalCDOView view = object.cdoView();
InternalCDORevision revision = view.getRevision(id, true);
FSMUtil.validate(object, revision);
object.cdoInternalSetRevision(revision);
changeState(object, CDOState.CLEAN);
object.cdoInternalPostLoad();
if (forWrite)
{
INSTANCE.write(object, (CDOFeatureDelta)delta);
}
}
}
/**
* @author Simon McDuff
*/
private static final class InvalidTransition implements ITransition<CDOState, CDOEvent, InternalCDOObject, Object>
{
public static final InvalidTransition INSTANCE = new InvalidTransition();
public void execute(InternalCDOObject object, CDOState state, CDOEvent event, Object NULL)
{
throw new InvalidObjectException(object.cdoID());
}
}
}
/**
* @author Eike Stepper
*/
enum CDOEvent
{
PREPARE, ATTACH, DETACH, READ, WRITE, INVALIDATE, DETACH_REMOTE, RELOAD, COMMIT, ROLLBACK
}