blob: d8c3d2aafca6cd852f2c3027ba2234be0563e3ca [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 - http://bugs.eclipse.org/201266
**************************************************************************/
package org.eclipse.emf.internal.cdo;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.model.CDOFeature;
import org.eclipse.emf.cdo.common.model.CDOType;
import org.eclipse.emf.cdo.common.revision.CDOReferenceProxy;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.eresource.CDOResource;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOAddFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOClearFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOContainerFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOMoveFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDORemoveFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOSetFeatureDeltaImpl;
import org.eclipse.emf.cdo.internal.common.revision.delta.CDOUnsetFeatureDeltaImpl;
import org.eclipse.emf.cdo.spi.common.InternalCDORevision;
import org.eclipse.emf.internal.cdo.bundle.OM;
import org.eclipse.emf.internal.cdo.util.FSMUtil;
import org.eclipse.emf.internal.cdo.util.GenUtil;
import org.eclipse.emf.internal.cdo.util.ModelUtil;
import org.eclipse.net4j.util.collection.MoveableList;
import org.eclipse.net4j.util.om.trace.ContextTracer;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.InternalEObject.EStore;
import org.eclipse.emf.ecore.util.EcoreUtil;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
/**
* @author Eike Stepper
*/
public final class CDOStore implements EStore
{
private final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOStore.class);
private CDOViewImpl view;
public CDOStore(CDOViewImpl view)
{
this.view = view;
}
public CDOViewImpl getView()
{
return view;
}
/**
* Expects eObject.cdoResource already set to the resource of the newContainer!
*
* @param newResource2
* @since 2.0
*/
public void setContainer(InternalEObject eObject, CDOResource newResource, InternalEObject newContainer,
int newContainerFeatureID)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
if (TRACER.isEnabled())
{
TRACER.format("setContainer({0}, {1}, {2}, {3})", cdoObject, newResource, newContainer, newContainerFeatureID);
}
CDOViewImpl newView = (CDOViewImpl)cdoObject.cdoView();
CDOID containerID = (CDOID)newView.convertObjectToID(newContainer);
CDOID resourceID = newResource == null ? null : newResource.cdoID();
CDOFeatureDelta delta = new CDOContainerFeatureDeltaImpl(containerID, newContainerFeatureID);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
revision.setResourceID(resourceID);
revision.setContainerID(containerID);
revision.setContainingFeatureID(newContainerFeatureID);
}
public InternalEObject getContainer(InternalEObject eObject)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
if (TRACER.isEnabled())
{
TRACER.format("getContainer({0})", cdoObject);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
CDOID id = revision.getContainerID();
return (InternalEObject)((CDOViewImpl)cdoObject.cdoView()).convertIDToObject(id);
}
public int getContainingFeatureID(InternalEObject eObject)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
if (TRACER.isEnabled())
{
TRACER.format("getContainingFeatureID({0})", cdoObject);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.getContainingFeatureID();
}
@Deprecated
public EStructuralFeature getContainingFeature(InternalEObject eObject)
{
throw new UnsupportedOperationException("Use getContainingFeatureID() instead");
}
public Object get(InternalEObject eObject, EStructuralFeature eFeature, int index)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("get({0}, {1}, {2})", cdoObject, cdoFeature, index);
}
view.getFeatureAnalyzer().preTraverseFeature(cdoObject, cdoFeature, index);
InternalCDORevision revision = getRevisionForReading(cdoObject);
Object value = get(revision, cdoFeature, index);
if (cdoFeature.isReference())
{
if (cdoFeature.isMany() && value instanceof CDOID)
{
CDOID id = (CDOID)value;
loadAhead(revision, cdoFeature, id, index);
}
value = view.convertIDToObject(value);
}
else if (cdoFeature.getType() == CDOType.CUSTOM)
{
value = EcoreUtil.createFromString((EDataType)eFeature.getEType(), (String)value);
}
view.getFeatureAnalyzer().postTraverseFeature(cdoObject, cdoFeature, index, value);
return value;
}
private void loadAhead(InternalCDORevision revision, CDOFeature cdoFeature, CDOID id, int index)
{
CDOSessionImpl session = view.getSession();
CDORevisionManagerImpl revisionManager = session.getRevisionManager();
int chunkSize = view.getLoadRevisionCollectionChunkSize();
if (chunkSize > 1 && !revisionManager.containsRevision(id))
{
MoveableList<Object> list = revision.getList(cdoFeature);
int fromIndex = index;
int toIndex = Math.min(index + chunkSize, list.size()) - 1;
Set<CDOID> notRegistered = new HashSet<CDOID>();
for (int i = fromIndex; i <= toIndex; i++)
{
Object element = list.get(i);
if (element instanceof CDOID)
{
CDOID idElement = (CDOID)element;
if (!idElement.isTemporary())
{
if (!revisionManager.containsRevision(idElement))
{
if (!notRegistered.contains(idElement))
{
notRegistered.add(idElement);
}
}
}
}
}
if (!notRegistered.isEmpty())
{
int referenceChunk = session.getReferenceChunkSize();
revisionManager.getRevisions(notRegistered, referenceChunk);
}
}
}
private Object get(InternalCDORevision revision, CDOFeature cdoFeature, int index)
{
Object result = revision.get(cdoFeature, index);
if (cdoFeature.isReference())
{
if (result instanceof CDOReferenceProxy)
{
result = ((CDOReferenceProxy)result).resolve();
}
}
return result;
}
public boolean isSet(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("isSet({0}, {1})", cdoObject, cdoFeature);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.isSet(cdoFeature);
}
public int size(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("size({0}, {1})", cdoObject, cdoFeature);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.size(cdoFeature);
}
public boolean isEmpty(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("isEmpty({0}, {1})", cdoObject, cdoFeature);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.isEmpty(cdoFeature);
}
public boolean contains(InternalEObject eObject, EStructuralFeature eFeature, Object value)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("contains({0}, {1}, {2})", cdoObject, cdoFeature, value);
}
if (cdoFeature.isReference())
{
value = ((CDOViewImpl)cdoObject.cdoView()).convertObjectToID(value);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.contains(cdoFeature, value);
}
public int indexOf(InternalEObject eObject, EStructuralFeature eFeature, Object value)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("indexOf({0}, {1}, {2})", cdoObject, cdoFeature, value);
}
if (cdoFeature.isReference())
{
value = ((CDOViewImpl)cdoObject.cdoView()).convertObjectToID(value);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.indexOf(cdoFeature, value);
}
public int lastIndexOf(InternalEObject eObject, EStructuralFeature eFeature, Object value)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("lastIndexOf({0}, {1}, {2})", cdoObject, cdoFeature, value);
}
if (cdoFeature.isReference())
{
value = ((CDOViewImpl)cdoObject.cdoView()).convertObjectToID(value);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.lastIndexOf(cdoFeature, value);
}
public int hashCode(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("hashCode({0}, {1})", cdoObject, cdoFeature);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
return revision.hashCode(cdoFeature);
}
public Object[] toArray(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("toArray({0}, {1})", cdoObject, cdoFeature);
}
InternalCDORevision revision = getRevisionForReading(cdoObject);
Object[] result = revision.toArray(cdoFeature);
if (cdoFeature.isReference())
{
for (int i = 0; i < result.length; i++)
{
if (result[i] instanceof CDOReferenceProxy)
{
result[i] = ((CDOReferenceProxy)result[i]).resolve();
}
result[i] = ((CDOViewImpl)cdoObject.cdoView()).convertIDToObject(result[i]);
}
}
return result;
}
@SuppressWarnings("unchecked")
public <T> T[] toArray(InternalEObject eObject, EStructuralFeature eFeature, T[] a)
{
Object[] array = toArray(eObject, eFeature);
int size = array.length;
if (a.length < size)
{
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
}
System.arraycopy(array, 0, a, 0, size);
if (a.length > size)
{
a[size] = null;
}
return a;
}
public Object set(InternalEObject eObject, EStructuralFeature eFeature, int index, Object value)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("set({0}, {1}, {2}, {3})", cdoObject, cdoFeature, index, value);
}
if (cdoFeature.getType() == CDOType.CUSTOM)
{
value = EcoreUtil.convertToString((EDataType)eFeature.getEType(), value);
}
else if (value == null && GenUtil.isPrimitiveType(eFeature.getEType()))
{
value = eFeature.getDefaultValue();
}
CDOFeatureDelta delta = new CDOSetFeatureDeltaImpl(cdoFeature, index, value);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
if (cdoFeature.isReference())
{
Object oldValue = revision.get(cdoFeature, index);
if (oldValue instanceof CDOReferenceProxy)
{
((CDOReferenceProxy)oldValue).resolve();
}
if (cdoFeature.isContainment() && value != null)
{
handleContainmentAdd(cdoObject, value);
}
}
Object result = revision.set(cdoFeature, index, value);
if (cdoFeature.isReference())
{
result = ((CDOViewImpl)cdoObject.cdoView()).convertIDToObject(result);
if (cdoFeature.isContainment() && result != null)
{
handleContainmentRemove(cdoObject, value);
}
}
return result;
}
public void unset(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("unset({0}, {1})", cdoObject, cdoFeature);
}
CDOFeatureDelta delta = new CDOUnsetFeatureDeltaImpl(cdoFeature);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
// TODO Handle containment remove!!!
revision.unset(cdoFeature);
}
public void add(InternalEObject eObject, EStructuralFeature eFeature, int index, Object value)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("add({0}, {1}, {2}, {3})", cdoObject, cdoFeature, index, value);
}
if (cdoFeature.isReference())
{
if (cdoFeature.isContainment() && value != null)
{
handleContainmentAdd(cdoObject, value);
}
value = ((CDOViewImpl)cdoObject.cdoView()).convertObjectToID(value);
}
CDOFeatureDelta delta = new CDOAddFeatureDeltaImpl(cdoFeature, index, value);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
revision.add(cdoFeature, index, value);
}
public Object remove(InternalEObject eObject, EStructuralFeature eFeature, int index)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("remove({0}, {1}, {2})", cdoObject, cdoFeature, index);
}
CDOFeatureDelta delta = new CDORemoveFeatureDeltaImpl(cdoFeature, index);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
Object result = revision.remove(cdoFeature, index);
if (cdoFeature.isReference())
{
if (result instanceof CDOReferenceProxy)
{
result = ((CDOReferenceProxy)result).resolve();
}
result = ((CDOViewImpl)cdoObject.cdoView()).convertIDToObject(result);
if (cdoFeature.isContainment() && result != null)
{
handleContainmentRemove(cdoObject, result);
}
}
return result;
}
public void clear(InternalEObject eObject, EStructuralFeature eFeature)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("clear({0}, {1})", cdoObject, cdoFeature);
}
CDOFeatureDelta delta = new CDOClearFeatureDeltaImpl(cdoFeature);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
// TODO Handle containment remove!!!
revision.clear(cdoFeature);
}
public Object move(InternalEObject eObject, EStructuralFeature eFeature, int target, int source)
{
InternalCDOObject cdoObject = getCDOObject(eObject);
CDOFeature cdoFeature = getCDOFeature(cdoObject, eFeature);
if (TRACER.isEnabled())
{
TRACER.format("move({0}, {1}, {2}, {3})", cdoObject, cdoFeature, target, source);
}
CDOFeatureDelta delta = new CDOMoveFeatureDeltaImpl(cdoFeature, target, source);
InternalCDORevision revision = getRevisionForWriting(cdoObject, delta);
Object result = revision.move(cdoFeature, target, source);
if (cdoFeature.isReference())
{
if (result instanceof CDOReferenceProxy)
{
result = ((CDOReferenceProxy)result).resolve();
}
result = ((CDOViewImpl)cdoObject.cdoView()).convertIDToObject(result);
}
return result;
}
public EObject create(EClass eClass)
{
throw new UnsupportedOperationException("Use the generated factory to create objects");
}
@Override
public String toString()
{
return MessageFormat.format("CDOStore[{0}]", view);
}
private InternalCDOObject getCDOObject(Object object)
{
return FSMUtil.adapt(object, view);
}
private CDOFeature getCDOFeature(InternalCDOObject cdoObject, EStructuralFeature eFeature)
{
CDOViewImpl view = (CDOViewImpl)cdoObject.cdoView();
if (view == null)
{
throw new IllegalStateException("view == null");
}
CDOSessionPackageManagerImpl packageManager = view.getSession().getPackageManager();
return ModelUtil.getCDOFeature(eFeature, packageManager);
}
private static InternalCDORevision getRevisionForReading(InternalCDOObject cdoObject)
{
CDOStateMachine.INSTANCE.read(cdoObject);
return getRevision(cdoObject);
}
private static InternalCDORevision getRevisionForWriting(InternalCDOObject cdoObject, CDOFeatureDelta delta)
{
CDOStateMachine.INSTANCE.write(cdoObject, delta);
return getRevision(cdoObject);
}
private static InternalCDORevision getRevision(InternalCDOObject cdoObject)
{
InternalCDORevision revision = (InternalCDORevision)cdoObject.cdoRevision();
if (revision == null)
{
throw new IllegalStateException("revision == null");
}
return revision;
}
private void handleContainmentAdd(InternalCDOObject container, Object value)
{
CDOViewImpl containerView = (CDOViewImpl)container.cdoView();
InternalCDOObject contained = getCDOObject(value);
FSMUtil.checkLegacySystemAvailability(containerView.getSession(), contained);
CDOViewImpl containedView = (CDOViewImpl)contained.cdoView();
if (containedView != containerView)
{
if (containedView != null)
{
CDOStateMachine.INSTANCE.detach(contained);
}
CDOStateMachine.INSTANCE.attach(contained, container.cdoResource(), containerView);
}
}
private void handleContainmentRemove(InternalCDOObject container, Object value)
{
// InternalCDOObject contained = getCDOObject(value);
// CDOStateMachine.INSTANCE.detach(contained);
}
}