| /* |
| * 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); |
| } |
| } |
| } |