blob: 79577884aa48d4117e093b94aa286eba8bdb910e [file] [log] [blame]
/*
* Copyright (c) 2010-2012, 2016 Eike Stepper (Loehne, 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:
* Victor Roldan Betancort - initial API and implementation
*/
package org.eclipse.emf.cdo.server.internal.db4o;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDExternal;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.model.CDOClassInfo;
import org.eclipse.emf.cdo.common.revision.CDOList;
import org.eclipse.emf.cdo.common.revision.CDOListFactory;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionData;
import org.eclipse.emf.cdo.common.revision.CDORevisionFactory;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.server.IRepository;
import org.eclipse.emf.cdo.server.IStore;
import org.eclipse.emf.cdo.spi.common.revision.CDOFeatureMapEntry;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDOList;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.util.FeatureMap;
import java.util.ArrayList;
import java.util.List;
/**
* @author Victor Roldan Betancort
*/
public class DB4ORevision
{
public static final String ATTRIBUTE_CLASS_NAME = "className";
public static final String ATTRIBUTE_PACKAGE_NS_URI = "packageNsURI";
private String packageNsURI;
private String className;
private long id;
private int version;
private long timeStamp;
private long resourceID;
/**
* Can be an external ID!
*/
private Object containerID;
private int containingFeatureID;
private List<Object> values;
// TODO enum RevisionType { NORMAL, ROOT_RESOURCE, RESOURCE, RESOURCE_FOLDER }??
private boolean isResource;
private boolean isResourceFolder;
public DB4ORevision(String packageURI, String className, long id, int version, long resourceID, Object containerID, int containingFeatureID,
List<Object> values, long timestamp, boolean isResource, boolean isResourceFolder)
{
setPackageURI(packageURI);
setClassName(className);
setID(id);
setVersion(version);
setResourceID(resourceID);
setContainerID(containerID);
setContainingFeatureID(containingFeatureID);
setValues(values);
setTimeStamp(timestamp);
setResource(isResource);
setResourceFolder(isResourceFolder);
}
public void setPackageURI(String packageURI)
{
packageNsURI = packageURI;
}
public String getPackageURI()
{
return packageNsURI;
}
public void setClassName(String className)
{
this.className = className;
}
public String getClassName()
{
return className;
}
public void setID(long id)
{
this.id = id;
}
public long getID()
{
return id;
}
public int getBranchID()
{
return CDOBranch.MAIN_BRANCH_ID;
}
public void setVersion(int version)
{
this.version = version;
}
public int getVersion()
{
return version;
}
public long getRevised()
{
return CDORevision.UNSPECIFIED_DATE;
}
public void setResourceID(long resourceID)
{
this.resourceID = resourceID;
}
public long getResourceID()
{
return resourceID;
}
public void setContainerID(Object containerID)
{
this.containerID = containerID;
}
public Object getContainerID()
{
return containerID;
}
public void setContainingFeatureID(int containingFeatureID)
{
this.containingFeatureID = containingFeatureID;
}
public int getContainingFeatureID()
{
return containingFeatureID;
}
public void setValues(List<Object> values)
{
this.values = values;
}
public List<Object> getValues()
{
return values;
}
public void setTimeStamp(long timeStamp)
{
this.timeStamp = timeStamp;
}
public long getTimeStamp()
{
return timeStamp;
}
public void setResource(boolean isResource)
{
this.isResource = isResource;
}
public boolean isResource()
{
return isResource;
}
public void setResourceFolder(boolean isResourceFolder)
{
this.isResourceFolder = isResourceFolder;
}
public boolean isResourceFolder()
{
return isResourceFolder;
}
public boolean isResourceNode()
{
return isResource || isResourceFolder;
}
public static DB4ORevision getDB4ORevision(InternalCDORevision revision)
{
CDOClassInfo classInfo = revision.getClassInfo();
EClass eClass = classInfo.getEClass();
String packageURI = eClass.getEPackage().getNsURI();
String className = eClass.getName();
CDOID revisionID = revision.getID();
if (revisionID.isTemporary())
{
throw new IllegalArgumentException("TEMPORARY CDOID: " + revisionID);
}
boolean isResource = revision.isResource();
boolean isResourceFolder = revision.isResourceFolder();
long id = CDOIDUtil.getLong(revisionID);
int version = revision.getVersion();
long timeStamp = revision.getTimeStamp();
long resourceID = CDOIDUtil.getLong(revision.getResourceID());
Object containerID = getDB4OID((CDOID)revision.getContainerID());
int containingFeatureID = revision.getContainingFeatureID();
EStructuralFeature[] features = classInfo.getAllPersistentFeatures();
List<Object> values = new ArrayList<Object>(features.length);
if (features.length > 0)
{
for (int i = 0; i < features.length; i++)
{
EStructuralFeature feature = features[i];
Object obj = revision.getValue(feature);
// We will process CDOList for EReferences to get rid of CDOIDs (we want to get only primitive types,
// otherwise the database will persist unwanted objects coming from Object-level relationships
// Multi-valued EAttributes (also kept in CDOList) will be saved as is
if (obj instanceof InternalCDOList && feature instanceof EReference)
{
InternalCDOList cdoList = (InternalCDOList)obj;
List<Object> list = new ArrayList<Object>();
for (Object listElement : cdoList)
{
if (!(listElement instanceof CDOID))
{
throw new IllegalStateException("CDOList should contain only CDOID instances but received " + listElement.getClass().getName() + " instead");
}
list.add(getDB4OID((CDOID)listElement));
}
values.add(i, list);
}
else if (listContainsInstancesOfClass(obj, CDOFeatureMapEntry.class)) // FeatureMap
{
values.add(i, DB4OFeatureMapEntry.getPrimitiveFeatureMapEntryList(obj));
}
else
{
// Prevent the explicit null-ref "NIL" from being serialized!
if (obj == CDORevisionData.NIL)
{
obj = new ExplicitNull();
}
values.add(i, obj);
}
}
}
return new DB4ORevision(packageURI, className, id, version, resourceID, containerID, containingFeatureID, values, timeStamp, isResource, isResourceFolder);
}
public static InternalCDORevision getCDORevision(IStore store, DB4ORevision primitiveRevision)
{
IRepository repository = store.getRepository();
CDORevisionFactory factory = ((InternalCDORevisionManager)repository.getRevisionManager()).getFactory();
CDOBranch branch = repository.getBranchManager().getMainBranch();
String nsURI = primitiveRevision.getPackageURI();
String className = primitiveRevision.getClassName();
EPackage ePackage = repository.getPackageRegistry().getEPackage(nsURI);
EClass eClass = (EClass)ePackage.getEClassifier(className);
InternalCDORevision revision = (InternalCDORevision)factory.createRevision(eClass);
revision.setID(getCDOID(primitiveRevision.getID()));
revision.setVersion(primitiveRevision.getVersion());
revision.setBranchPoint(branch.getPoint(primitiveRevision.getTimeStamp()));
revision.setRevised(primitiveRevision.getRevised());
revision.setResourceID(getCDOID(primitiveRevision.getResourceID()));
revision.setContainerID(getCDOID(primitiveRevision.getContainerID()));
revision.setContainingFeatureID(primitiveRevision.getContainingFeatureID());
EStructuralFeature[] features = revision.getClassInfo().getAllPersistentFeatures();
int i = 0;
for (Object value : primitiveRevision.getValues())
{
EStructuralFeature feature = features[i++];
if (feature instanceof EReference && value instanceof List<?>)
{
List<?> sourceList = (List<?>)value;
CDOList list = CDOListFactory.DEFAULT.createList(sourceList.size(), sourceList.size(), CDORevision.UNCHUNKED);
for (int j = 0; j < sourceList.size(); j++)
{
list.set(j, getCDOID(sourceList.get(j)));
}
value = list;
}
else if (listContainsInstancesOfClass(value, DB4OFeatureMapEntry.class))
{
value = DB4OFeatureMapEntry.getCDOFeatureMapEntryList(eClass, value);
}
// Convert 'null' into the explicit null-ref "NIL" if appropriate
if (value instanceof ExplicitNull)
{
value = CDORevisionData.NIL;
}
revision.setValue(feature, value);
}
return revision;
}
public static Object getDB4OID(CDOID id)
{
if (id.isExternal())
{
return new String(((CDOIDExternal)id).getURI());
}
return CDOIDUtil.getLong(id);
}
public static CDOID getCDOID(Object id)
{
if (id == null)
{
return CDOID.NULL;
}
if (id instanceof String)
{
return CDOIDUtil.createExternal((String)id);
}
if (id instanceof CDOID)
{
return (CDOID)id;
}
return CDOIDUtil.createLong((Long)id);
}
public static boolean listContainsInstancesOfClass(Object obj, Class<?> clazz)
{
if (obj instanceof List)
{
List<?> list = (List<?>)obj;
for (Object potentialFeatureMap : list)
{
if (!clazz.isAssignableFrom(potentialFeatureMap.getClass()))
{
return false;
}
}
return true;
}
return false;
}
private static final class DB4OFeatureMapEntry
{
private int featureID;
private Object valueID;
public DB4OFeatureMapEntry(int featureID, Object valueID)
{
setFeatureID(featureID);
setValueID(valueID);
}
private void setFeatureID(int featureID)
{
this.featureID = featureID;
}
public int getFeatureID()
{
return featureID;
}
private void setValueID(Object valueID)
{
this.valueID = valueID;
}
public Object getValueID()
{
return valueID;
}
public static List<DB4OFeatureMapEntry> getPrimitiveFeatureMapEntryList(Object obj)
{
InternalCDOList cdoList = (InternalCDOList)obj;
List<DB4OFeatureMapEntry> list = new ArrayList<DB4OFeatureMapEntry>();
for (Object listElement : cdoList)
{
if (listElement instanceof FeatureMap.Entry)
{
FeatureMap.Entry entry = (FeatureMap.Entry)listElement;
EStructuralFeature entryFeature = entry.getEStructuralFeature();
CDOID entryValue = (CDOID)entry.getValue();
DB4OFeatureMapEntry db4oEntry = new DB4OFeatureMapEntry(entryFeature.getFeatureID(), getDB4OID(entryValue));
list.add(db4oEntry);
}
}
return list;
}
public static CDOList getCDOFeatureMapEntryList(EClass eClass, Object value)
{
List<?> sourceList = (List<?>)value;
CDOList list = CDOListFactory.DEFAULT.createList(sourceList.size(), sourceList.size(), CDORevision.UNCHUNKED);
for (int j = 0; j < sourceList.size(); j++)
{
DB4OFeatureMapEntry mapEntry = (DB4OFeatureMapEntry)sourceList.get(j);
EStructuralFeature entryFeature = eClass.getEStructuralFeature(mapEntry.getFeatureID());
CDOID valueID = getCDOID(mapEntry.getValueID());
list.set(j, CDORevisionUtil.createFeatureMapEntry(entryFeature, valueID));
}
return list;
}
}
/**
* @author Caspar De Groot
*/
private static final class ExplicitNull
{
}
}