Bug 500513 - Provide possibility to alter copy process during operation
recording

Change-Id: I3811ab38f645ff355fed0ca5aaaf472f275b0f86
diff --git a/bundles/org.eclipse.emf.emfstore.client/schema/changeRecordingOptions.exsd b/bundles/org.eclipse.emf.emfstore.client/schema/changeRecordingOptions.exsd
index 46cae92..4f7a59d 100644
--- a/bundles/org.eclipse.emf.emfstore.client/schema/changeRecordingOptions.exsd
+++ b/bundles/org.eclipse.emf.emfstore.client/schema/changeRecordingOptions.exsd
@@ -110,6 +110,16 @@
                </appInfo>
             </annotation>
          </attribute>
+         <attribute name="copier" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.emf.emfstore.client.util.ESCopier"/>
+               </appInfo>
+            </annotation>
+         </attribute>
       </complexType>
    </element>
 
diff --git a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/client/util/ESCopier.java b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/client/util/ESCopier.java
new file mode 100644
index 0000000..064eb92
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/client/util/ESCopier.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Edgar Mueller - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.client.util;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+
+/**
+ * An interface that enables to specify a different copy behavior
+ * than standard {@link EcoreUtil#copy(EObject)}.
+ * The copy of an {@link EObject} should be self-contained, if possible, i.e.
+ * there should be no references pointing outside the copied containment tree.
+ *
+ * @since 1.8
+ *
+ */
+public interface ESCopier {
+
+	/**
+	 * Whether this copier wants to copy the given {@link EObject}.
+	 * 
+	 * @param eObject the {@link EObject} to be copied
+	 * @return an integer that specifies how critical it is that the copier handles the given
+	 *         object. The copier that specifies the highest priority will be used to copy the object.
+	 */
+	int shouldHandle(EObject eObject);
+
+	/**
+	 * Copy the given {@link EObject}.
+	 *
+	 * @param eObject the {@link EObject} to be copied
+	 * @return the copied {@link EObject}
+	 */
+	EObject copy(EObject eObject);
+
+}
diff --git a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/configuration/Behavior.java b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/configuration/Behavior.java
index 1d84561..83e6bb4 100644
--- a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/configuration/Behavior.java
+++ b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/configuration/Behavior.java
@@ -15,10 +15,12 @@
 import java.util.List;
 
 import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.emfstore.client.ESServer;
 import org.eclipse.emf.emfstore.client.handler.ESChecksumErrorHandler;
 import org.eclipse.emf.emfstore.client.handler.ESOperationModifier;
 import org.eclipse.emf.emfstore.client.provider.ESClientConfigurationProvider;
+import org.eclipse.emf.emfstore.client.util.ESCopier;
 import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement;
 import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint;
 import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPointException;
@@ -26,6 +28,7 @@
 import org.eclipse.emf.emfstore.internal.client.model.ServerInfo;
 import org.eclipse.emf.emfstore.internal.client.model.Usersession;
 import org.eclipse.emf.emfstore.internal.client.model.connectionmanager.KeyStoreManager;
+import org.eclipse.emf.emfstore.internal.client.model.impl.api.DefaultCopier;
 import org.eclipse.emf.emfstore.internal.client.model.impl.api.ESServerImpl;
 import org.eclipse.emf.emfstore.internal.client.model.util.ChecksumErrorHandler;
 import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation;
@@ -91,6 +94,11 @@
 	 */
 	public static final String OPERATION_MODIFIER = "operationModifier"; //$NON-NLS-1$
 
+	/**
+	 * Copier option identifier.
+	 */
+	public static final String COPIER = "copier"; //$NON-NLS-1$
+
 	private static Boolean isAutoSaveActive;
 	private static Boolean isRerecordingActive;
 	private static Boolean isCutOffIncomingCrossReferencesActive;
@@ -99,6 +107,7 @@
 	private static Boolean isUseMemoryChangePackageActive;
 	private static Optional<Integer> changePackageFragmentSize;
 	private static ESOperationModifier operationModifier;
+	private static List<ESCopier> copierList;
 
 	private ESChecksumErrorHandler checksumErrorHandler;
 
@@ -306,6 +315,29 @@
 	}
 
 	/**
+	 * Returns the copier that is used to copy {@link EObject}s.
+	 *
+	 * @param eObject the {@link EObject} to be copied
+	 *
+	 * @return the copier
+	 */
+	public ESCopier getESCopierFor(EObject eObject) {
+		if (copierList == null) {
+			copierList = new ESExtensionPoint(RESOURCE_OPTIONS_EXTENSION_POINT_NAME).getClasses(COPIER, ESCopier.class);
+		}
+
+		ESCopier selectedCopier = new DefaultCopier();
+		final int maxPriority = -1;
+		for (final ESCopier copier : copierList) {
+			if (copier.shouldHandle(eObject) > maxPriority) {
+				selectedCopier = copier;
+			}
+		}
+
+		return selectedCopier;
+	}
+
+	/**
 	 * Sets the fragment size to be used when splitting change packages.
 	 *
 	 * @param fragmentSize
diff --git a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/OperationRecorder.java b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/OperationRecorder.java
index 0721b65..58507b9 100644
--- a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/OperationRecorder.java
+++ b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/OperationRecorder.java
@@ -35,14 +35,15 @@
 import org.eclipse.emf.ecore.EStructuralFeature.Setting;
 import org.eclipse.emf.ecore.InternalEObject;
 import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
 import org.eclipse.emf.emfstore.client.ESLocalProject;
 import org.eclipse.emf.emfstore.client.changetracking.ESCommandObserver;
 import org.eclipse.emf.emfstore.client.observer.ESCommitObserver;
 import org.eclipse.emf.emfstore.client.observer.ESPostCreationObserver;
 import org.eclipse.emf.emfstore.client.observer.ESShareObserver;
 import org.eclipse.emf.emfstore.client.observer.ESUpdateObserver;
+import org.eclipse.emf.emfstore.client.util.ESCopier;
 import org.eclipse.emf.emfstore.internal.client.model.CompositeOperationHandle;
+import org.eclipse.emf.emfstore.internal.client.model.Configuration;
 import org.eclipse.emf.emfstore.internal.client.model.ESWorkspaceProviderImpl;
 import org.eclipse.emf.emfstore.internal.client.model.ProjectSpace;
 import org.eclipse.emf.emfstore.internal.client.model.changeTracking.NotificationToOperationConverter;
@@ -402,9 +403,8 @@
 		final List<EObject> allContainedModelElements = ModelUtil.getAllContainedModelElementsAsList(element, false);
 		allContainedModelElements.add(element);
 
-		final Copier copier = new Copier(true, false);
+		final ESCopier copier = Configuration.getClientBehavior().getESCopierFor(element);
 		final EObject copiedElement = copier.copy(element);
-		copier.copyReferences();
 
 		final List<EObject> copiedAllContainedModelElements = ModelUtil.getAllContainedModelElementsAsList(
 			copiedElement,
@@ -426,8 +426,8 @@
 
 		createDeleteOperation.setModelElement(copiedElement);
 		createDeleteOperation.setModelElementId(collection.getModelElementId(modelElement));
-
 		createDeleteOperation.setClientDate(new Date());
+
 		return createDeleteOperation;
 	}
 
@@ -1078,7 +1078,7 @@
 		 * @param setting
 		 *            a setting consisting of an {@link EObject} and a non-many reference
 		 */
-		public SettingWithElementsToRemove(Setting setting) {
+		SettingWithElementsToRemove(Setting setting) {
 			this.setting = setting;
 		}
 
@@ -1090,7 +1090,7 @@
 		 * @param elementsToRemove
 		 *            the elemets to be removed from the many reference
 		 */
-		public SettingWithElementsToRemove(Setting setting, Set<EObject> elementsToRemove) {
+		SettingWithElementsToRemove(Setting setting, Set<EObject> elementsToRemove) {
 			this.setting = setting;
 			this.elementsToRemove.addAll(elementsToRemove);
 		}
diff --git a/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/api/DefaultCopier.java b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/api/DefaultCopier.java
new file mode 100644
index 0000000..69e2d7c
--- /dev/null
+++ b/bundles/org.eclipse.emf.emfstore.client/src/org/eclipse/emf/emfstore/internal/client/model/impl/api/DefaultCopier.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 2011-2016 EclipseSource Muenchen GmbH 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:
+ * Edgar Mueller - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.emf.emfstore.internal.client.model.impl.api;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
+import org.eclipse.emf.emfstore.client.util.ESCopier;
+
+/**
+ * The default {@link ESCopier} that does not copy by using
+ * original references.
+ *
+ */
+public class DefaultCopier implements ESCopier {
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.client.util.ESCopier#shouldHandle(org.eclipse.emf.ecore.EObject)
+	 */
+	public int shouldHandle(EObject eObject) {
+		return 0;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 *
+	 * @see org.eclipse.emf.emfstore.client.util.ESCopier#copy(org.eclipse.emf.ecore.EObject)
+	 */
+	public EObject copy(EObject eObject) {
+		final Copier copier = new Copier(true, false);
+		final EObject copiedElement = copier.copy(eObject);
+		copier.copyReferences();
+		return copiedElement;
+	}
+
+}