blob: 3e34652b060cba49d69c6ba0f9d2febd48d595f1 [file] [log] [blame]
/*
* Copyright (c) 2010-2015 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
*/
package org.eclipse.emf.cdo.internal.common.commit;
import org.eclipse.emf.cdo.common.commit.CDOChangeKind;
import org.eclipse.emf.cdo.common.commit.CDOChangeSetData;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.common.id.CDOIDUtil;
import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.revision.CDORevision;
import org.eclipse.emf.cdo.common.revision.CDORevisionKey;
import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.spi.common.commit.CDOChangeKindCache;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta;
import org.eclipse.net4j.util.StringUtil;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author Eike Stepper
*/
public class CDOChangeSetDataImpl implements CDOChangeSetData
{
private List<CDOIDAndVersion> newObjects;
private List<CDORevisionKey> changedObjects;
private List<CDOIDAndVersion> detachedObjects;
private CDOChangeKindCache changeKindCache;
public CDOChangeSetDataImpl(List<CDOIDAndVersion> newObjects, List<CDORevisionKey> changedObjects,
List<CDOIDAndVersion> detachedObjects)
{
this.newObjects = newObjects;
this.changedObjects = changedObjects;
this.detachedObjects = detachedObjects;
}
public CDOChangeSetDataImpl()
{
this(new ArrayList<CDOIDAndVersion>(), new ArrayList<CDORevisionKey>(), new ArrayList<CDOIDAndVersion>());
}
public boolean isEmpty()
{
if (newObjects != null && !newObjects.isEmpty())
{
return false;
}
if (changedObjects != null && !changedObjects.isEmpty())
{
return false;
}
if (detachedObjects != null && !detachedObjects.isEmpty())
{
return false;
}
return true;
}
public CDOChangeSetData copy()
{
List<CDOIDAndVersion> newObjectsCopy = new ArrayList<CDOIDAndVersion>(newObjects.size());
for (CDOIDAndVersion key : newObjects)
{
if (key instanceof CDORevision)
{
CDORevision revision = (CDORevision)key;
newObjectsCopy.add(revision.copy());
}
else
{
newObjectsCopy.add(key);
}
}
List<CDORevisionKey> changedObjectsCopy = new ArrayList<CDORevisionKey>(changedObjects.size());
for (CDORevisionKey key : changedObjects)
{
if (key instanceof CDORevisionDelta)
{
CDORevisionDelta delta = (CDORevisionDelta)key;
changedObjectsCopy.add(delta.copy());
}
else
{
changedObjectsCopy.add(key);
}
}
List<CDOIDAndVersion> detachedObjectsCopy = new ArrayList<CDOIDAndVersion>(detachedObjects.size());
for (CDOIDAndVersion key : detachedObjects)
{
detachedObjectsCopy.add(key);
}
return new CDOChangeSetDataImpl(newObjectsCopy, changedObjectsCopy, detachedObjectsCopy);
}
public void merge(CDOChangeSetData changeSetData)
{
Map<CDOID, CDOIDAndVersion> newMap = CDOIDUtil.createMap();
fillMap(newMap, newObjects);
fillMap(newMap, changeSetData.getNewObjects());
Map<CDOID, CDORevisionKey> changedMap = CDOIDUtil.createMap();
fillMap(changedMap, changedObjects);
for (CDORevisionKey key : changeSetData.getChangedObjects())
{
mergeChangedObject(key, newMap, changedMap);
}
Map<CDOID, CDOIDAndVersion> detachedMap = CDOIDUtil.createMap();
fillMap(detachedMap, detachedObjects);
for (CDOIDAndVersion key : changeSetData.getDetachedObjects())
{
CDOID id = key.getID();
if (newMap.remove(id) == null)
{
detachedMap.put(id, key);
}
}
newObjects = new ArrayList<CDOIDAndVersion>(newMap.values());
changedObjects = new ArrayList<CDORevisionKey>(changedMap.values());
detachedObjects = new ArrayList<CDOIDAndVersion>(detachedMap.values());
}
private void mergeChangedObject(CDORevisionKey key, Map<CDOID, CDOIDAndVersion> newMap,
Map<CDOID, CDORevisionKey> changedMap)
{
CDOID id = key.getID();
if (key instanceof CDORevisionDelta)
{
CDORevisionDelta delta = (CDORevisionDelta)key;
// Try to add the delta to existing new revision
CDOIDAndVersion oldRevision = newMap.get(id);
if (oldRevision instanceof CDORevision)
{
CDORevision newRevision = (CDORevision)oldRevision;
delta.applyTo(newRevision);
return;
}
// Try to add the delta to existing delta
CDORevisionKey oldDelta = changedMap.get(id);
if (oldDelta instanceof CDORevisionDelta)
{
InternalCDORevisionDelta newDelta = (InternalCDORevisionDelta)oldDelta;
for (CDOFeatureDelta featureDelta : delta.getFeatureDeltas())
{
newDelta.addFeatureDelta(featureDelta, null);
}
return;
}
}
// Fall back
changedMap.put(id, key);
}
public List<CDOIDAndVersion> getNewObjects()
{
return newObjects;
}
public List<CDORevisionKey> getChangedObjects()
{
return changedObjects;
}
public List<CDOIDAndVersion> getDetachedObjects()
{
return detachedObjects;
}
public synchronized Map<CDOID, CDOChangeKind> getChangeKinds()
{
if (changeKindCache == null)
{
changeKindCache = new CDOChangeKindCache(this);
}
return changeKindCache;
}
public CDOChangeKind getChangeKind(CDOID id)
{
return getChangeKinds().get(id);
}
@Override
public String toString()
{
return MessageFormat.format("ChangeSetData[newObjects={0}, changedObjects={1}, detachedObjects={2}]", //$NON-NLS-1$
newObjects.size(), changedObjects.size(), detachedObjects.size());
}
public static String format(CDOChangeSetData changeSetData)
{
StringBuilder builder = new StringBuilder();
builder.append(changeSetData);
builder.append(StringUtil.NL);
format(builder, " New Objects:", changeSetData.getNewObjects());
format(builder, " Changed Objects:", changeSetData.getChangedObjects());
format(builder, " Detached Objects:", changeSetData.getDetachedObjects());
return builder.toString();
}
private static void format(StringBuilder builder, String label, List<?> objects)
{
builder.append(label);
builder.append(StringUtil.NL);
for (Object object : objects)
{
builder.append(" ");
builder.append(object);
builder.append(StringUtil.NL);
}
}
private static <T extends CDOIDAndVersion> void fillMap(Map<CDOID, T> map, Collection<T> c)
{
for (T key : c)
{
map.put(key.getID(), key);
}
}
}