Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilip Langer2014-11-13 16:00:50 +0000
committerAxel RICHARD2014-12-07 15:17:23 +0000
commit01ae0763a8e0156dabc6bcdd1bcef170f1782099 (patch)
tree2f6a268534f4f781b88b300ba9d8d0035112b570
parent4ae5ea7b3b5c828d6a88421fd396ad042a01967f (diff)
downloadorg.eclipse.emf.compare-01ae0763a8e0156dabc6bcdd1bcef170f1782099.tar.gz
org.eclipse.emf.compare-01ae0763a8e0156dabc6bcdd1bcef170f1782099.tar.xz
org.eclipse.emf.compare-01ae0763a8e0156dabc6bcdd1bcef170f1782099.zip
[451365] Adds specific handling of opaque action, behavior & expression
Opaque actions, behaviors, and expressions all have a multi-valued language and multi-valued body attribute. Their indices have to be kept in sync, because the language value at the index n denotes the language of the body value at the index n. Moreover, if concurrent changes to the same body value are applied, they should be merged using a line-based three-way merge algorithm. If they are not mergeable with such an algorithm, a specific conflict should be raised. This commit contributes support for the aforementioned requirements by introducing a new UML-specific change type, specific conflict detection, and a specific merger. Bug: 451365 Change-Id: I6bf5c786e72a10c56eff7f0faaedd67b77528b4b Signed-off-by: Philip Langer <planger@eclipsesource.com>
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/icons/full/obj16/OpaqueElementBodyChange.gifbin0 -> 129 bytes
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/plugin.properties4
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/OpaqueElementBodyChangeItemProvider.java131
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/UMLCompareItemProviderAdapterFactory.java23
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/OpaqueElementBodyChangeCustomItemProvider.java121
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/UMLCompareCustomItemProviderAdapterFactory.java13
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java9
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeDiffTest.java215
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java660
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/OpaqueInputData.java204
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/left.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/origin.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/left.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/right.uml22
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/left.uml10
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/origin.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/right.uml16
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/left.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/origin.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/right.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/left.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/origin.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/right.uml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/useCases82
-rw-r--r--plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/suite/AllTests.java8
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/model/uml2compare.ecore3
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/plugin.xml14
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/OpaqueElementBodyChange.java56
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLCompareFactory.java9
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLComparePackage.java205
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/OpaqueElementBodyChangeImpl.java172
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLCompareFactoryImpl.java12
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLComparePackageImpl.java34
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareAdapterFactory.java18
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareSwitch.java24
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java435
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/OpaqueElementBodyChangePostProcessor.java316
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLExtensionFactoryRegistry.java1
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLOpaqueElementBodyChangeFactory.java538
-rw-r--r--plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/util/UMLCompareUtil.java72
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java18
-rw-r--r--plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java18
74 files changed, 4231 insertions, 6 deletions
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/icons/full/obj16/OpaqueElementBodyChange.gif b/plugins/org.eclipse.emf.compare.uml2.edit/icons/full/obj16/OpaqueElementBodyChange.gif
new file mode 100644
index 000000000..904159880
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/icons/full/obj16/OpaqueElementBodyChange.gif
Binary files differ
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/plugin.properties b/plugins/org.eclipse.emf.compare.uml2.edit/plugin.properties
index 0347d0c70..80fc1f524 100644
--- a/plugins/org.eclipse.emf.compare.uml2.edit/plugin.properties
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/plugin.properties
@@ -1,5 +1,5 @@
################################################################################
-# Copyright (c) 2011, 2012 Obeo.
+# Copyright (c) 2011, 2014 Obeo.
# 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
@@ -164,6 +164,8 @@ _UI_DirectedRelationshipChange_type = Directed Relationship Change
_UI_StereotypeAttributeChange_type = Stereotype Attribute Change
_UI_StereotypedElementChange_type = Stereotyped Element Change
_UI_StereotypedElementChange_stereotypeApplications_feature = Stereotype Applications
+_UI_OpaqueElementBodyChange_type = Opaque Element Body Change
+_UI_OpaqueElementBodyChange_language_feature = Language
#Error messaged
Unable_To_Retreive_Icon_Error_Message = "Unable to retrieve the icon at location {0}
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/OpaqueElementBodyChangeItemProvider.java b/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/OpaqueElementBodyChangeItemProvider.java
new file mode 100644
index 000000000..07d0d305f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/OpaqueElementBodyChangeItemProvider.java
@@ -0,0 +1,131 @@
+/**
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.uml2.internal.provider;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.UMLComparePackage;
+import org.eclipse.emf.edit.provider.ComposeableAdapterFactory;
+import org.eclipse.emf.edit.provider.IItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ItemPropertyDescriptor;
+import org.eclipse.emf.edit.provider.ViewerNotification;
+
+/**
+ * This is the item provider adapter for a
+ * {@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange} object. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ */
+public class OpaqueElementBodyChangeItemProvider extends UMLDiffItemProvider {
+ /**
+ * This constructs an instance from a factory and a notifier. <!-- begin-user-doc --> <!-- end-user-doc
+ * -->
+ *
+ * @generated
+ */
+ public OpaqueElementBodyChangeItemProvider(AdapterFactory adapterFactory) {
+ super(adapterFactory);
+ }
+
+ /**
+ * This returns the property descriptors for the adapted class. <!-- begin-user-doc --> <!-- end-user-doc
+ * -->
+ *
+ * @generated
+ */
+ @Override
+ public List<IItemPropertyDescriptor> getPropertyDescriptors(Object object) {
+ if (itemPropertyDescriptors == null) {
+ super.getPropertyDescriptors(object);
+
+ addLanguagePropertyDescriptor(object);
+ }
+ return itemPropertyDescriptors;
+ }
+
+ /**
+ * This adds a property descriptor for the Language feature. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ protected void addLanguagePropertyDescriptor(Object object) {
+ itemPropertyDescriptors
+ .add(createItemPropertyDescriptor(
+ ((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
+ getResourceLocator(),
+ getString("_UI_OpaqueElementBodyChange_language_feature"), //$NON-NLS-1$
+ getString(
+ "_UI_PropertyDescriptor_description", "_UI_OpaqueElementBodyChange_language_feature", "_UI_OpaqueElementBodyChange_type"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ UMLComparePackage.Literals.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE, true, false, false,
+ ItemPropertyDescriptor.GENERIC_VALUE_IMAGE, null, null));
+ }
+
+ /**
+ * This returns OpaqueElementBodyChange.gif. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public Object getImage(Object object) {
+ return overlayImage(object, getResourceLocator().getImage("full/obj16/OpaqueElementBodyChange")); //$NON-NLS-1$
+ }
+
+ /**
+ * This returns the label text for the adapted class. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public String getText(Object object) {
+ DifferenceKind labelValue = ((OpaqueElementBodyChange)object).getKind();
+ String label = labelValue == null ? null : labelValue.toString();
+ return label == null || label.length() == 0 ? getString("_UI_OpaqueElementBodyChange_type") : //$NON-NLS-1$
+ getString("_UI_OpaqueElementBodyChange_type") + " " + label; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * This handles model notifications by calling {@link #updateChildren} to update any cached children and
+ * by creating a viewer notification, which it passes to {@link #fireNotifyChanged}. <!-- begin-user-doc
+ * --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ public void notifyChanged(Notification notification) {
+ updateChildren(notification);
+
+ switch (notification.getFeatureID(OpaqueElementBodyChange.class)) {
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE:
+ fireNotifyChanged(new ViewerNotification(notification, notification.getNotifier(), false,
+ true));
+ return;
+ }
+ super.notifyChanged(notification);
+ }
+
+ /**
+ * This adds {@link org.eclipse.emf.edit.command.CommandParameter}s describing the children that can be
+ * created under this object. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ @Override
+ protected void collectNewChildDescriptors(Collection<Object> newChildDescriptors, Object object) {
+ super.collectNewChildDescriptors(newChildDescriptors, object);
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/UMLCompareItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/UMLCompareItemProviderAdapterFactory.java
index ef7a27e9d..387d2bf8e 100644
--- a/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/UMLCompareItemProviderAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/src-gen/org/eclipse/emf/compare/uml2/internal/provider/UMLCompareItemProviderAdapterFactory.java
@@ -215,6 +215,29 @@ public class UMLCompareItemProviderAdapterFactory extends UMLCompareAdapterFacto
}
/**
+ * This keeps track of the one adapter used for all {@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange} instances.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ protected OpaqueElementBodyChangeItemProvider opaqueElementBodyChangeItemProvider;
+
+ /**
+ * This creates an adapter for a {@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange}.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public Adapter createOpaqueElementBodyChangeAdapter() {
+ if (opaqueElementBodyChangeItemProvider == null) {
+ opaqueElementBodyChangeItemProvider = new OpaqueElementBodyChangeItemProvider(this);
+ }
+
+ return opaqueElementBodyChangeItemProvider;
+ }
+
+ /**
* This returns the root adapter factory that contains this factory.
* <!-- begin-user-doc --> <!--
* end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/OpaqueElementBodyChangeCustomItemProvider.java b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/OpaqueElementBodyChangeCustomItemProvider.java
new file mode 100644
index 000000000..7d8ca833c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/OpaqueElementBodyChangeCustomItemProvider.java
@@ -0,0 +1,121 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.internal.provider.custom;
+
+import org.eclipse.emf.common.notify.AdapterFactory;
+import org.eclipse.emf.compare.provider.ExtendedAdapterFactoryItemDelegator;
+import org.eclipse.emf.compare.provider.utils.ComposedStyledString;
+import org.eclipse.emf.compare.provider.utils.IStyledString;
+import org.eclipse.emf.compare.provider.utils.IStyledString.Style;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.eclipse.uml2.uml.OpaqueBehavior;
+import org.eclipse.uml2.uml.OpaqueExpression;
+
+/**
+ * A custom {@link org.eclipse.emf.compare.uml2.internal.provider.OpaqueElementBodyChangeItemProvider} that
+ * handles {@link org.eclipse.emf.compare.provider.IItemStyledLabelProvider} and
+ * {@link org.eclipse.emf.compare.provider.IItemDescriptionProvider}.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class OpaqueElementBodyChangeCustomItemProvider extends UMLDiffCustomItemProvider {
+
+ /** The item delegator to reuse root adapter factory (if any). */
+ private final ExtendedAdapterFactoryItemDelegator itemDelegator;
+
+ /**
+ * This constructs an instance from a factory and a notifier.
+ *
+ * @param adapterFactory
+ * the adapter factory to use.
+ */
+ public OpaqueElementBodyChangeCustomItemProvider(AdapterFactory adapterFactory) {
+ super(adapterFactory);
+ itemDelegator = new ExtendedAdapterFactoryItemDelegator(getRootAdapterFactory());
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see org.eclipse.emf.compare.provider.IItemStyledLabelProvider#getStyledText(java.lang.Object)
+ */
+ @Override
+ public IStyledString.IComposedStyledString getStyledText(Object object) {
+ final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)object;
+ final EObject discriminant = bodyChange.getDiscriminant();
+
+ final ComposedStyledString text = new ComposedStyledString();
+ text.append(bodyChange.getLanguage());
+ text.append(" body of ");
+ text.append(itemDelegator.getText(discriminant));
+ text.append(" ");
+ text.append(getChangeKindLabel(bodyChange));
+
+ final String opaqueElementType = getOpaqueElementTypeLabel(discriminant);
+ return text.append(" [" + opaqueElementType + " body change]", Style.DECORATIONS_STYLER);
+ }
+
+ /**
+ * Returns a label text for the change kind of the given {@code bodyChange}.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to get the change kind label for.
+ * @return The text for the label of the change kind of {@code bodyChange}.
+ */
+ private String getChangeKindLabel(OpaqueElementBodyChange bodyChange) {
+ final String changeKindLabel;
+ switch (bodyChange.getKind()) {
+ case ADD:
+ changeKindLabel = "added";
+ break;
+ case DELETE:
+ changeKindLabel = "deleted";
+ break;
+ case MOVE:
+ changeKindLabel = "moved";
+ break;
+ case CHANGE: //$FALL-THROUGH$
+ default:
+ changeKindLabel = "changed";
+ break;
+ }
+ return changeKindLabel;
+ }
+
+ /**
+ * Returns the label text for the opaque element type of the given {@code element}.
+ * <p>
+ * If {@code element} is not an {@link OpaqueAction}, an {@link OpaqueBehavior}, or an
+ * {@link OpaqueExpression}, something went wrong before hand. So this method will return an empty string
+ * in this case.
+ * </p>
+ *
+ * @param element
+ * The element to get the type label for.
+ * @return The label for the opaque element type.
+ */
+ private String getOpaqueElementTypeLabel(EObject element) {
+ final String opaqueElementTypeLabel;
+ if (element instanceof OpaqueAction) {
+ opaqueElementTypeLabel = "opaque action";
+ } else if (element instanceof OpaqueBehavior) {
+ opaqueElementTypeLabel = "opaque behavior";
+ } else if (element instanceof OpaqueExpression) {
+ opaqueElementTypeLabel = "opaque expression";
+ } else {
+ opaqueElementTypeLabel = "";
+ }
+ return opaqueElementTypeLabel;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/UMLCompareCustomItemProviderAdapterFactory.java b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/UMLCompareCustomItemProviderAdapterFactory.java
index f838ec359..a3181186b 100644
--- a/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/UMLCompareCustomItemProviderAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2.edit/src/org/eclipse/emf/compare/uml2/internal/provider/custom/UMLCompareCustomItemProviderAdapterFactory.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2012, 2014 Obeo.
+ * Copyright (c) 2012, 2014 Obeo 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - added OpaqueElementBodyChange adapter
*/
package org.eclipse.emf.compare.uml2.internal.provider.custom;
@@ -108,6 +109,16 @@ public class UMLCompareCustomItemProviderAdapterFactory extends UMLCompareAdapte
/**
* {@inheritDoc}
*
+ * @see UMLCompareAdapterFactory#createOpaqueElementBodyChangeAdapter()
+ */
+ @Override
+ public Adapter createOpaqueElementBodyChangeAdapter() {
+ return new OpaqueElementBodyChangeCustomItemProvider(this);
+ }
+
+ /**
+ * {@inheritDoc}
+ *
* @see org.eclipse.emf.edit.provider.ComposeableAdapterFactory#getRootAdapterFactory()
*/
public ComposeableAdapterFactory getRootAdapterFactory() {
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
index f125fffa0..ef7edc245 100644
--- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/AbstractUMLTest.java
@@ -47,8 +47,10 @@ import org.eclipse.emf.compare.scope.IComparisonScope;
import org.eclipse.emf.compare.tests.postprocess.data.TestPostProcessor;
import org.eclipse.emf.compare.uml2.internal.StereotypedElementChange;
import org.eclipse.emf.compare.uml2.internal.UMLDiff;
+import org.eclipse.emf.compare.uml2.internal.merge.OpaqueElementBodyChangeMerger;
import org.eclipse.emf.compare.uml2.internal.merge.UMLMerger;
import org.eclipse.emf.compare.uml2.internal.merge.UMLReferenceChangeMerger;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.OpaqueElementBodyChangePostProcessor;
import org.eclipse.emf.compare.uml2.internal.postprocessor.UMLPostProcessor;
import org.eclipse.emf.compare.uml2.profile.test.uml2comparetestprofile.UML2CompareTestProfilePackage;
import org.eclipse.emf.compare.utils.ReferenceUtil;
@@ -113,10 +115,13 @@ public abstract class AbstractUMLTest {
mergerRegistry = IMerger.RegistryImpl.createStandaloneInstance();
final IMerger umlMerger = new UMLMerger();
final IMerger umlReferenceChangeMerger = new UMLReferenceChangeMerger();
+ final IMerger opaqueElementBodyChangeMerger = new OpaqueElementBodyChangeMerger();
umlMerger.setRanking(11);
umlReferenceChangeMerger.setRanking(25);
+ opaqueElementBodyChangeMerger.setRanking(25);
mergerRegistry.add(umlMerger);
mergerRegistry.add(umlReferenceChangeMerger);
+ mergerRegistry.add(opaqueElementBodyChangeMerger);
emfCompare = builder.build();
}
@@ -131,6 +136,10 @@ public abstract class AbstractUMLTest {
new TestPostProcessor.TestPostProcessorDescriptor(Pattern
.compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null,
new UMLPostProcessor(), 20));
+ postProcessorRegistry.put(OpaqueElementBodyChangePostProcessor.class.getName(),
+ new TestPostProcessor.TestPostProcessorDescriptor(Pattern
+ .compile("http://www.eclipse.org/uml2/\\d\\.0\\.0/UML"), null,
+ new OpaqueElementBodyChangePostProcessor(), 25));
}
@After
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeDiffTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeDiffTest.java
new file mode 100644
index 000000000..b27fdf260
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeDiffTest.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.tests.opaque;
+
+import static com.google.common.base.Predicates.and;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.size;
+import static org.eclipse.emf.compare.DifferenceKind.ADD;
+import static org.eclipse.emf.compare.DifferenceKind.CHANGE;
+import static org.eclipse.emf.compare.DifferenceKind.DELETE;
+import static org.eclipse.emf.compare.DifferenceKind.MOVE;
+import static org.eclipse.emf.compare.DifferenceSource.LEFT;
+import static org.eclipse.emf.compare.DifferenceSource.RIGHT;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.fromSide;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.base.Predicate;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.tests.AbstractUMLInputData;
+import org.eclipse.emf.compare.uml2.tests.AbstractUMLTest;
+import org.eclipse.emf.compare.uml2.tests.opaque.data.OpaqueInputData;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.junit.Test;
+
+/**
+ * Tests the detection of {@link OpaqueElementBodyChange opaque element body changes}.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+@SuppressWarnings("nls")
+public class OpaqueElementBodyChangeDiffTest extends AbstractUMLTest {
+
+ private static final Predicate<Diff> IS_OPAQUE_ELEMENT_CHANGE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return diff instanceof OpaqueElementBodyChange;
+ }
+ };
+
+ private static final String OPAQUE_ACTION1_ID = "_opaqueAction1";
+
+ private OpaqueInputData input = new OpaqueInputData();
+
+ @Test
+ public void testA1UseCaseLeft() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+
+ Comparison comparison = compare(left, origin, null);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> opaqueChanges = filter(diffs, IS_OPAQUE_ELEMENT_CHANGE);
+ assertEquals(1, size(opaqueChanges));
+
+ Diff firstDiff = opaqueChanges.iterator().next();
+ OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)firstDiff;
+
+ assertEquals(DifferenceKind.CHANGE, bodyChange.getKind());
+ assertEquals(DifferenceSource.LEFT, bodyChange.getSource());
+ assertEquals(2, bodyChange.getRefinedBy().size());
+ assertEquals(1, size(filter(bodyChange.getRefinedBy(), ofKind(ADD))));
+ assertEquals(1, size(filter(bodyChange.getRefinedBy(), ofKind(DELETE))));
+ assertEquals(2, size(filter(bodyChange.getRefinedBy(), fromSide(LEFT))));
+ }
+
+ @Test
+ public void testA1UseCase() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+ Resource right = input.getA1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> leftOpaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(LEFT)));
+ assertEquals(1, size(leftOpaqueChanges));
+
+ Diff firstLeftDiff = leftOpaqueChanges.iterator().next();
+ OpaqueElementBodyChange leftBodyChange = (OpaqueElementBodyChange)firstLeftDiff;
+
+ assertEquals(DifferenceKind.CHANGE, leftBodyChange.getKind());
+ assertEquals(DifferenceSource.LEFT, leftBodyChange.getSource());
+ assertEquals(2, leftBodyChange.getRefinedBy().size());
+ assertEquals(0, size(filter(leftBodyChange.getRefinedBy(), fromSide(RIGHT))));
+ assertEquals(2, size(filter(leftBodyChange.getRefinedBy(), fromSide(LEFT))));
+ assertEquals(1, size(filter(leftBodyChange.getRefinedBy(), ofKind(ADD))));
+ assertEquals(1, size(filter(leftBodyChange.getRefinedBy(), ofKind(DELETE))));
+
+ Iterable<Diff> rightOpaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(RIGHT)));
+ assertEquals(1, size(rightOpaqueChanges));
+
+ Diff firstRightDiff = rightOpaqueChanges.iterator().next();
+ OpaqueElementBodyChange rightBodyChange = (OpaqueElementBodyChange)firstRightDiff;
+
+ assertEquals(DifferenceKind.CHANGE, rightBodyChange.getKind());
+ assertEquals(DifferenceSource.RIGHT, rightBodyChange.getSource());
+ assertEquals(2, rightBodyChange.getRefinedBy().size());
+ assertEquals(2, size(filter(rightBodyChange.getRefinedBy(), fromSide(RIGHT))));
+ assertEquals(0, size(filter(rightBodyChange.getRefinedBy(), fromSide(LEFT))));
+ assertEquals(1, size(filter(rightBodyChange.getRefinedBy(), ofKind(ADD))));
+ assertEquals(1, size(filter(rightBodyChange.getRefinedBy(), ofKind(DELETE))));
+ }
+
+ @Test
+ public void testA5UseCaseLeft() throws IOException {
+ Resource origin = input.getA5Origin();
+ Resource left = input.getA5Left();
+
+ Comparison comparison = compare(left, origin, null);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> opaqueChanges = filter(diffs, IS_OPAQUE_ELEMENT_CHANGE);
+ assertEquals(1, size(opaqueChanges));
+
+ Diff firstDiff = opaqueChanges.iterator().next();
+ OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)firstDiff;
+
+ assertEquals(DifferenceKind.ADD, bodyChange.getKind());
+ assertEquals(DifferenceSource.LEFT, bodyChange.getSource());
+ assertEquals(2, bodyChange.getRefinedBy().size());
+ assertEquals(2, size(filter(bodyChange.getRefinedBy(), ofKind(ADD))));
+ assertEquals(2, size(filter(bodyChange.getRefinedBy(), fromSide(LEFT))));
+ }
+
+ @Test
+ public void testA5UseCase() throws IOException {
+ Resource origin = input.getA5Origin();
+ Resource left = input.getA5Left();
+ Resource right = input.getA5Right();
+
+ Comparison comparison = compare(left, right, origin);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> leftOpaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(LEFT)));
+ assertEquals(1, size(leftOpaqueChanges));
+
+ Diff firstLeftDiff = leftOpaqueChanges.iterator().next();
+ OpaqueElementBodyChange leftBodyChange = (OpaqueElementBodyChange)firstLeftDiff;
+
+ assertEquals(DifferenceKind.ADD, leftBodyChange.getKind());
+ assertEquals(DifferenceSource.LEFT, leftBodyChange.getSource());
+ assertEquals(2, leftBodyChange.getRefinedBy().size());
+ assertEquals(0, size(filter(leftBodyChange.getRefinedBy(), fromSide(RIGHT))));
+ assertEquals(2, size(filter(leftBodyChange.getRefinedBy(), fromSide(LEFT))));
+ assertEquals(2, size(filter(leftBodyChange.getRefinedBy(), ofKind(ADD))));
+
+ Iterable<Diff> rightOpaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(RIGHT)));
+ assertEquals(1, size(rightOpaqueChanges));
+
+ Diff firstRightDiff = rightOpaqueChanges.iterator().next();
+ OpaqueElementBodyChange rightBodyChange = (OpaqueElementBodyChange)firstRightDiff;
+
+ assertEquals(DifferenceKind.ADD, rightBodyChange.getKind());
+ assertEquals(DifferenceSource.RIGHT, rightBodyChange.getSource());
+ assertEquals(2, rightBodyChange.getRefinedBy().size());
+ assertEquals(2, size(filter(rightBodyChange.getRefinedBy(), fromSide(RIGHT))));
+ assertEquals(0, size(filter(rightBodyChange.getRefinedBy(), fromSide(LEFT))));
+ assertEquals(2, size(filter(rightBodyChange.getRefinedBy(), ofKind(ADD))));
+ }
+
+ @Test
+ public void testA7UseCaseRight_MoveAndChange() throws IOException {
+ Resource origin = input.getA7Origin();
+ Resource right = input.getA7Right();
+
+ Comparison comparison = compare(right, origin, null);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> opaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(LEFT)));
+ assertEquals(2, size(opaqueChanges));
+ assertEquals(1, size(filter(opaqueChanges, ofKind(MOVE))));
+ assertEquals(1, size(filter(opaqueChanges, ofKind(CHANGE))));
+ }
+
+ @Test
+ public void testA7UseCaseRight_Move() throws IOException {
+ Resource origin = input.getA7Origin();
+ Resource right = input.getA7Right();
+
+ // Make sure JAVA body is unchanged
+ OpaqueAction rightAction = (OpaqueAction)right.getEObject(OPAQUE_ACTION1_ID);
+ OpaqueAction originAction = (OpaqueAction)origin.getEObject(OPAQUE_ACTION1_ID);
+ String bodyJava = originAction.getBodies().get(0);
+ rightAction.getBodies().set(1, bodyJava);
+
+ Comparison comparison = compare(right, origin, null);
+ EList<Diff> diffs = comparison.getDifferences();
+ Iterable<Diff> opaqueChanges = filter(diffs, and(IS_OPAQUE_ELEMENT_CHANGE, fromSide(LEFT)));
+ assertEquals(1, size(opaqueChanges));
+ assertEquals(1, size(filter(opaqueChanges, ofKind(MOVE))));
+
+ Diff opaqueChangeDiff = opaqueChanges.iterator().next();
+ OpaqueElementBodyChange opaqueChange = (OpaqueElementBodyChange)opaqueChangeDiff;
+ assertEquals(2, opaqueChange.getRefinedBy().size());
+ assertEquals(2, size(filter(opaqueChange.getRefinedBy(), ofKind(MOVE))));
+ }
+
+ @Override
+ protected AbstractUMLInputData getInput() {
+ return input;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java
new file mode 100644
index 000000000..3f86f6fc7
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/OpaqueElementBodyChangeMergeTest.java
@@ -0,0 +1,660 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.tests.opaque;
+
+import static com.google.common.base.Predicates.and;
+import static com.google.common.collect.Iterables.filter;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Predicate;
+
+import java.io.IOException;
+
+import org.eclipse.emf.common.util.BasicMonitor;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.ConflictKind;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.merge.IMerger;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.tests.AbstractUMLInputData;
+import org.eclipse.emf.compare.uml2.tests.AbstractUMLTest;
+import org.eclipse.emf.compare.uml2.tests.opaque.data.OpaqueInputData;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.eclipse.uml2.uml.OpaqueBehavior;
+import org.eclipse.uml2.uml.OpaqueExpression;
+import org.junit.Test;
+
+/**
+ * Tests merging of the body attribute of {@link OpaqueBehavior opaque behaviors}, {@link OpaqueAction opaque
+ * actions}, and {@link OpaqueExpression opaque expressions} containing multi-line contents also with respect
+ * to their respective language attribute.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+@SuppressWarnings("nls")
+public class OpaqueElementBodyChangeMergeTest extends AbstractUMLTest {
+
+ private static final String NL = "\r\n";
+
+ private static final String OPAQUE_ACTION1_ID = "_opaqueAction1";
+
+ private static final String OPAQUE_BEHAVIOR1_ID = "_opaqueBehavior1";
+
+ private static final String OPAQUE_EXPRESSION1_ID = "_opaqueExpression1";
+
+ private static final String OCL = "OCL";
+
+ private static final String JAVA = "JAVA";
+
+ private static final String EXPECTED_MERGE = "This is a" + NL //
+ + "test with multi-line (changed)" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes (changed)" + NL //
+ + "of them.";
+
+ private static final String EXPECTED_MERGE_JAVA = "This is a JAVA" + NL//
+ + "test with multi-line" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes (changed)" + NL //
+ + "of them.";
+
+ private static final String EXPECTED_MERGE_OCL = "This is an OCL" + NL//
+ + "test with multi-line (changed)" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes (changed)" + NL //
+ + "of them.";
+
+ private static final String EXPECTED_JAVA = "This is a JAVA" + NL//
+ + "test with multi-line" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes" + NL //
+ + "of them.";
+
+ private static final String EXPECTED_OCL = "This is an OCL" + NL//
+ + "test with multi-line" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes" + NL //
+ + "of them.";
+
+ private static final String EXPECTED_C = "This is a C" + NL//
+ + "test with multi-line" + NL //
+ + "String attribute" + NL //
+ + "and concurrent changes" + NL //
+ + "of them.";
+
+ private static final Predicate<Diff> IS_OPAQUE_ELEMENT_CHANGE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return diff instanceof OpaqueElementBodyChange;
+ }
+ };
+
+ private static final Predicate<Diff> IS_RIGHT_SOURCE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return DifferenceSource.RIGHT.equals(diff.getSource());
+ }
+ };
+
+ private static final Predicate<Diff> IS_LEFT_SOURCE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return DifferenceSource.LEFT.equals(diff.getSource());
+ }
+ };
+
+ private OpaqueInputData input = new OpaqueInputData();
+
+ @Test
+ public void testA1UseCaseRtoL() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+ Resource right = input.getA1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertA1UseCaseMergeResult(left.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ @Test
+ public void testA1UseCaseLtoR() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+ Resource right = input.getA1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertA1UseCaseMergeResult(right.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ private void assertA1UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueAction);
+
+ OpaqueAction action = (OpaqueAction)eObject;
+ assertEquals(1, action.getLanguages().size());
+ assertEquals(1, action.getBodies().size());
+
+ assertEquals(JAVA, action.getLanguages().get(0));
+ assertEquals(EXPECTED_MERGE, action.getBodies().get(0));
+ }
+
+ @Test
+ public void testA1UseCase_RevertChangeLeftTwoWay() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+
+ OpaqueAction originAction = (OpaqueAction)origin.getEObject(OPAQUE_ACTION1_ID);
+ String originBody = originAction.getBodies().get(0);
+
+ Comparison comparison = compare(left, origin, null);
+ revertLeftOpaqueElementBodyChanges(comparison);
+ assertOneBodyWithContents(left, originBody);
+ }
+
+ @Test
+ public void testA1UseCase_RevertChangeRightThreeWay() throws IOException {
+ Resource origin = input.getA1Origin();
+ Resource left = input.getA1Left();
+ Resource right = input.getA1Right();
+
+ OpaqueAction originAction = (OpaqueAction)origin.getEObject(OPAQUE_ACTION1_ID);
+ String originBody = originAction.getBodies().get(0);
+
+ Comparison comparison = compare(left, right, origin);
+ revertRightOpaqueElementBodyChanges(comparison);
+ assertOneBodyWithContents(right, originBody);
+ }
+
+ @Test
+ public void testA2UseCase() throws IOException {
+ Resource origin = input.getA2Origin();
+ Resource left = input.getA2Left();
+ Resource right = input.getA2Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA3UseCase() throws IOException {
+ Resource origin = input.getA3Origin();
+ Resource left = input.getA3Left();
+ Resource right = input.getA3Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA4UseCaseLtoR() throws IOException {
+ Resource origin = input.getA4Origin();
+ Resource left = input.getA4Left();
+ Resource right = input.getA4Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertA4UseCaseMergeResult(right.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ @Test
+ public void testA4UseCaseRtoL() throws IOException {
+ Resource origin = input.getA4Origin();
+ Resource left = input.getA4Left();
+ Resource right = input.getA4Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertA4UseCaseMergeResult(left.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ private void assertA4UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueAction);
+
+ OpaqueAction action = (OpaqueAction)eObject;
+ assertEquals(2, action.getLanguages().size());
+ assertEquals(2, action.getBodies().size());
+
+ assertEquals(JAVA, action.getLanguages().get(0));
+ assertEquals(OCL, action.getLanguages().get(1));
+
+ assertEquals(EXPECTED_MERGE_JAVA, action.getBodies().get(0));
+ assertEquals(EXPECTED_OCL, action.getBodies().get(1));
+ }
+
+ @Test
+ public void testA4UseCase_RevertAdditionLeftTwoWay() throws IOException {
+ Resource origin = input.getA4Origin();
+ Resource left = input.getA4Left();
+
+ OpaqueAction originAction = (OpaqueAction)origin.getEObject(OPAQUE_ACTION1_ID);
+ String originBody = originAction.getBodies().get(0);
+
+ Comparison comparison = compare(left, origin, null);
+ revertLeftOpaqueElementBodyChanges(comparison);
+ assertOneBodyWithContents(left, originBody);
+ }
+
+ @Test
+ public void testA4UseCase_RevertDeletionLeftTwoWay() throws IOException {
+ Resource left = input.getA4Left();
+ Resource origin = input.getA4Origin();
+
+ // swapped left and origin to create deletion
+ Comparison comparison = compare(origin, left, null);
+ revertLeftOpaqueElementBodyChanges(comparison);
+
+ EObject eObject = origin.getEObject(OPAQUE_ACTION1_ID);
+ OpaqueAction action = (OpaqueAction)eObject;
+ assertEquals(2, action.getLanguages().size());
+ assertEquals(2, action.getBodies().size());
+ }
+
+ @Test
+ public void testA5UseCaseLtoR() throws IOException {
+ Resource origin = input.getA5Origin();
+ Resource left = input.getA5Left();
+ Resource right = input.getA5Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertA5UseCaseMergeResult(right.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ @Test
+ public void testA5UseCaseRtoL() throws IOException {
+ Resource origin = input.getA5Origin();
+ Resource left = input.getA5Left();
+ Resource right = input.getA5Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertA5UseCaseMergeResult(left.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ private void assertA5UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueAction);
+
+ OpaqueAction action = (OpaqueAction)eObject;
+ assertEquals(3, action.getLanguages().size());
+ assertEquals(3, action.getBodies().size());
+
+ assertTrue(action.getLanguages().contains("JAVA"));
+ assertTrue(action.getLanguages().contains("OCL"));
+ assertTrue(action.getLanguages().contains("C"));
+
+ int indexJava = action.getLanguages().indexOf("JAVA");
+ int indexOcl = action.getLanguages().indexOf("OCL");
+ int indexC = action.getLanguages().indexOf("C");
+
+ assertEquals(EXPECTED_JAVA, action.getBodies().get(indexJava));
+ assertEquals(EXPECTED_OCL, action.getBodies().get(indexOcl));
+ assertEquals(EXPECTED_C, action.getBodies().get(indexC));
+ }
+
+ @Test
+ public void testA6UseCaseLtoR() throws IOException {
+ Resource origin = input.getA6Origin();
+ Resource left = input.getA6Left();
+ Resource right = input.getA6Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertA6UseCaseMergeResult(right.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ @Test
+ public void testA6UseCaseRtoL() throws IOException {
+ Resource origin = input.getA6Origin();
+ Resource left = input.getA6Left();
+ Resource right = input.getA6Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertA6UseCaseMergeResult(left.getEObject(OPAQUE_ACTION1_ID));
+ }
+
+ private void assertA6UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueAction);
+
+ OpaqueAction action = (OpaqueAction)eObject;
+ assertEquals(2, action.getLanguages().size());
+ assertEquals(2, action.getBodies().size());
+
+ assertTrue(action.getLanguages().contains("JAVA"));
+ assertTrue(action.getLanguages().contains("OCL"));
+
+ int indexJava = action.getLanguages().indexOf("JAVA");
+ int indexOcl = action.getLanguages().indexOf("OCL");
+
+ assertEquals(EXPECTED_JAVA, action.getBodies().get(indexJava));
+ assertEquals(EXPECTED_MERGE_OCL, action.getBodies().get(indexOcl));
+
+ assertEquals(indexOcl, 0);
+ assertEquals(indexJava, 1);
+ }
+
+ @Test
+ public void testA6UseCase_RevertReorderRightTwoWay() throws IOException {
+ Resource origin = input.getA6Origin();
+ // we take right as left, because we want to test reverting the reordering
+ Resource left = input.getA6Right();
+
+ Comparison comparison = compare(left, origin, null);
+ revertLeftOpaqueElementBodyChanges(comparison);
+
+ OpaqueAction action = (OpaqueAction)left.getEObject(OPAQUE_ACTION1_ID);
+
+ assertEquals(2, action.getLanguages().size());
+ assertEquals(2, action.getBodies().size());
+
+ int indexJava = action.getLanguages().indexOf("JAVA");
+ int indexOcl = action.getLanguages().indexOf("OCL");
+
+ // assert that the order of languages and bodies is reverted
+ assertEquals(indexJava, 0);
+ assertEquals(indexOcl, 1);
+ assertEquals(EXPECTED_JAVA, action.getBodies().get(indexJava));
+ assertEquals(EXPECTED_OCL, action.getBodies().get(indexOcl));
+ }
+
+ @Test
+ public void testA7UseCase() throws IOException {
+ Resource origin = input.getA7Origin();
+ Resource left = input.getA7Left();
+ Resource right = input.getA7Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA8UseCase() throws IOException {
+ Resource origin = input.getA8Origin();
+ Resource left = input.getA8Left();
+ Resource right = input.getA8Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA9UseCaseLtoR() throws IOException {
+ Resource origin = input.getA9Origin();
+ Resource left = input.getA9Left();
+ Resource right = input.getA9Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+
+ assertA9UseCaseMergeResult(right);
+ }
+
+ @Test
+ public void testA9UseCaseRtoL() throws IOException {
+ Resource origin = input.getA9Origin();
+ Resource left = input.getA9Left();
+ Resource right = input.getA9Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+
+ assertA9UseCaseMergeResult(left);
+ }
+
+ private void assertA9UseCaseMergeResult(Resource resource) {
+ EObject eObject = resource.getEObject(OPAQUE_ACTION1_ID);
+ assertTrue(eObject instanceof OpaqueAction);
+ OpaqueAction opaqueAction = (OpaqueAction)eObject;
+ assertEquals(0, opaqueAction.getBodies().size());
+ assertEquals(0, opaqueAction.getLanguages().size());
+ }
+
+ @Test
+ public void testA10UseCaseRtoL() throws IOException {
+ Resource origin = input.getA10Origin();
+ Resource left = input.getA10Left();
+ Resource right = input.getA10Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+
+ assertOneBodyWithContents(left, EXPECTED_MERGE_OCL);
+ }
+
+ @Test
+ public void testA10UseCaseLtoR() throws IOException {
+ Resource origin = input.getA10Origin();
+ Resource left = input.getA10Left();
+ Resource right = input.getA10Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+
+ assertOneBodyWithContents(right, EXPECTED_MERGE_OCL);
+ }
+
+ @Test
+ public void testA11UseCase() throws IOException {
+ Resource origin = input.getA11Origin();
+ Resource left = input.getA11Left();
+ Resource right = input.getA11Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA12UseCase() throws IOException {
+ Resource origin = input.getA12Origin();
+ Resource left = input.getA12Left();
+ Resource right = input.getA12Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertOneRealConflict(comparison);
+ }
+
+ @Test
+ public void testA13UseCase() throws IOException {
+ Resource origin = input.getA13Origin();
+ Resource left = input.getA13Left();
+ Resource right = input.getA13Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+
+ EObject leftEObject = left.getEObject(OPAQUE_ACTION1_ID);
+ OpaqueAction leftOpaqueAction = (OpaqueAction)leftEObject;
+ String bodyLeft = leftOpaqueAction.getBodies().get(0);
+
+ assertOneBodyWithContents(right, bodyLeft);
+ }
+
+ @Test
+ public void testB1UseCaseRtoL() throws IOException {
+ Resource origin = input.getB1Origin();
+ Resource left = input.getB1Left();
+ Resource right = input.getB1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertB1UseCaseMergeResult(left.getEObject(OPAQUE_BEHAVIOR1_ID));
+ }
+
+ @Test
+ public void testB1UseCaseLtoR() throws IOException {
+ Resource origin = input.getB1Origin();
+ Resource left = input.getB1Left();
+ Resource right = input.getB1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertB1UseCaseMergeResult(right.getEObject(OPAQUE_BEHAVIOR1_ID));
+ }
+
+ private void assertB1UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueBehavior);
+
+ OpaqueBehavior action = (OpaqueBehavior)eObject;
+ assertEquals(1, action.getLanguages().size());
+ assertEquals(1, action.getBodies().size());
+
+ assertEquals(JAVA, action.getLanguages().get(0));
+ assertEquals(EXPECTED_MERGE, action.getBodies().get(0));
+ }
+
+ @Test
+ public void testE1UseCaseRtoL() throws IOException {
+ Resource origin = input.getE1Origin();
+ Resource left = input.getE1Left();
+ Resource right = input.getE1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyRightOpaqueElementBodyChangesToLeft(comparison);
+ assertE1UseCaseMergeResult(left.getEObject(OPAQUE_EXPRESSION1_ID));
+ }
+
+ @Test
+ public void testE1UseCaseLtoR() throws IOException {
+ Resource origin = input.getE1Origin();
+ Resource left = input.getE1Left();
+ Resource right = input.getE1Right();
+
+ Comparison comparison = compare(left, right, origin);
+ assertNoRealConflict(comparison);
+
+ applyLeftOpaqueElementBodyChangesToRight(comparison);
+ assertE1UseCaseMergeResult(right.getEObject(OPAQUE_EXPRESSION1_ID));
+ }
+
+ private void assertE1UseCaseMergeResult(EObject eObject) {
+ assertTrue(eObject instanceof OpaqueExpression);
+
+ OpaqueExpression action = (OpaqueExpression)eObject;
+ assertEquals(1, action.getLanguages().size());
+ assertEquals(1, action.getBodies().size());
+
+ assertEquals(JAVA, action.getLanguages().get(0));
+ assertEquals(EXPECTED_MERGE, action.getBodies().get(0));
+ }
+
+ private void assertOneBodyWithContents(Resource resource, String contents) {
+ EObject eObject = resource.getEObject(OPAQUE_ACTION1_ID);
+ assertTrue(eObject instanceof OpaqueAction);
+ OpaqueAction opaqueAction = (OpaqueAction)eObject;
+ assertEquals(1, opaqueAction.getBodies().size());
+ assertEquals(1, opaqueAction.getLanguages().size());
+
+ String body = opaqueAction.getBodies().get(0);
+ assertEquals(contents, body);
+ }
+
+ private void applyRightOpaqueElementBodyChangesToLeft(Comparison comparison) {
+ final EList<Diff> allDifferences = comparison.getDifferences();
+ final Iterable<Diff> rightOpaqueElementBodyChanges = filter(allDifferences, and(
+ IS_OPAQUE_ELEMENT_CHANGE, IS_RIGHT_SOURCE));
+ for (Diff diff : rightOpaqueElementBodyChanges) {
+ IMerger merger = getMergerRegistry().getHighestRankingMerger(diff);
+ merger.copyRightToLeft(diff, new BasicMonitor());
+ }
+ }
+
+ private void revertLeftOpaqueElementBodyChanges(Comparison comparison) {
+ final EList<Diff> allDifferences = comparison.getDifferences();
+ final Iterable<Diff> leftOpaqueElementBodyChanges = filter(allDifferences, and(
+ IS_OPAQUE_ELEMENT_CHANGE, IS_LEFT_SOURCE));
+ for (Diff diff : leftOpaqueElementBodyChanges) {
+ IMerger merger = getMergerRegistry().getHighestRankingMerger(diff);
+ merger.copyRightToLeft(diff, new BasicMonitor());
+ }
+ }
+
+ private void revertRightOpaqueElementBodyChanges(Comparison comparison) {
+ final EList<Diff> allDifferences = comparison.getDifferences();
+ final Iterable<Diff> rightOpaqueElementBodyChanges = filter(allDifferences, and(
+ IS_OPAQUE_ELEMENT_CHANGE, IS_RIGHT_SOURCE));
+ for (Diff diff : rightOpaqueElementBodyChanges) {
+ IMerger merger = getMergerRegistry().getHighestRankingMerger(diff);
+ merger.copyLeftToRight(diff, new BasicMonitor());
+ }
+ }
+
+ private void applyLeftOpaqueElementBodyChangesToRight(Comparison comparison) {
+ final EList<Diff> allDifferences = comparison.getDifferences();
+ final Iterable<Diff> leftOpaqueElementBodyChanges = filter(allDifferences, and(
+ IS_OPAQUE_ELEMENT_CHANGE, IS_LEFT_SOURCE));
+ for (Diff diff : leftOpaqueElementBodyChanges) {
+ IMerger merger = getMergerRegistry().getHighestRankingMerger(diff);
+ merger.copyLeftToRight(diff, new BasicMonitor());
+ }
+ }
+
+ private void assertNoRealConflict(Comparison comparison) {
+ for (Conflict conflict : comparison.getConflicts()) {
+ assertFalse(isRealConflict(conflict));
+ }
+ }
+
+ private void assertOneRealConflict(Comparison comparison) {
+ int numberOfRealConflicts = 0;
+ for (Conflict conflict : comparison.getConflicts()) {
+ if (isRealConflict(conflict)) {
+ numberOfRealConflicts++;
+ }
+ }
+ assertEquals(1, numberOfRealConflicts);
+ }
+
+ private boolean isRealConflict(Conflict conflict) {
+ return ConflictKind.REAL.equals(conflict.getKind());
+ }
+
+ @Override
+ protected AbstractUMLInputData getInput() {
+ return input;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/OpaqueInputData.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/OpaqueInputData.java
new file mode 100644
index 000000000..7607d808b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/OpaqueInputData.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.tests.opaque.data;
+
+import java.io.IOException;
+
+import org.eclipse.emf.compare.uml2.tests.AbstractUMLInputData;
+import org.eclipse.emf.compare.uml2.tests.opaque.OpaqueElementBodyChangeMergeTest;
+import org.eclipse.emf.ecore.resource.Resource;
+
+/**
+ * Provides test data for the {@link OpaqueElementBodyChangeMergeTest}.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class OpaqueInputData extends AbstractUMLInputData {
+ public Resource getA1Origin() throws IOException {
+ return loadFromClassLoader("a1/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA1Left() throws IOException {
+ return loadFromClassLoader("a1/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA1Right() throws IOException {
+ return loadFromClassLoader("a1/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA2Origin() throws IOException {
+ return loadFromClassLoader("a2/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA2Left() throws IOException {
+ return loadFromClassLoader("a2/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA2Right() throws IOException {
+ return loadFromClassLoader("a2/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA3Origin() throws IOException {
+ return loadFromClassLoader("a3/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA3Left() throws IOException {
+ return loadFromClassLoader("a3/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA3Right() throws IOException {
+ return loadFromClassLoader("a3/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA4Origin() throws IOException {
+ return loadFromClassLoader("a4/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA4Left() throws IOException {
+ return loadFromClassLoader("a4/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA4Right() throws IOException {
+ return loadFromClassLoader("a4/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA5Origin() throws IOException {
+ return loadFromClassLoader("a5/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA5Left() throws IOException {
+ return loadFromClassLoader("a5/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA5Right() throws IOException {
+ return loadFromClassLoader("a5/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA6Origin() throws IOException {
+ return loadFromClassLoader("a6/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA6Left() throws IOException {
+ return loadFromClassLoader("a6/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA6Right() throws IOException {
+ return loadFromClassLoader("a6/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA7Origin() throws IOException {
+ return loadFromClassLoader("a7/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA7Left() throws IOException {
+ return loadFromClassLoader("a7/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA7Right() throws IOException {
+ return loadFromClassLoader("a7/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA8Origin() throws IOException {
+ return loadFromClassLoader("a8/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA8Left() throws IOException {
+ return loadFromClassLoader("a8/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA8Right() throws IOException {
+ return loadFromClassLoader("a8/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA9Origin() throws IOException {
+ return loadFromClassLoader("a9/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA9Left() throws IOException {
+ return loadFromClassLoader("a9/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA9Right() throws IOException {
+ return loadFromClassLoader("a9/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA10Origin() throws IOException {
+ return loadFromClassLoader("a10/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA10Left() throws IOException {
+ return loadFromClassLoader("a10/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA10Right() throws IOException {
+ return loadFromClassLoader("a10/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA11Origin() throws IOException {
+ return loadFromClassLoader("a11/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA11Left() throws IOException {
+ return loadFromClassLoader("a11/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA11Right() throws IOException {
+ return loadFromClassLoader("a11/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA12Origin() throws IOException {
+ return loadFromClassLoader("a12/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA12Left() throws IOException {
+ return loadFromClassLoader("a12/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA12Right() throws IOException {
+ return loadFromClassLoader("a12/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA13Origin() throws IOException {
+ return loadFromClassLoader("a13/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA13Left() throws IOException {
+ return loadFromClassLoader("a13/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getA13Right() throws IOException {
+ return loadFromClassLoader("a13/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getB1Origin() throws IOException {
+ return loadFromClassLoader("b1/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getB1Left() throws IOException {
+ return loadFromClassLoader("b1/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getB1Right() throws IOException {
+ return loadFromClassLoader("b1/right.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getE1Origin() throws IOException {
+ return loadFromClassLoader("e1/origin.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getE1Left() throws IOException {
+ return loadFromClassLoader("e1/left.uml"); //$NON-NLS-1$
+ }
+
+ public Resource getE1Right() throws IOException {
+ return loadFromClassLoader("e1/right.uml"); //$NON-NLS-1$
+ }
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/left.uml
new file mode 100644
index 000000000..fed93990b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/origin.uml
new file mode 100644
index 000000000..be0cecdbe
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/right.uml
new file mode 100644
index 000000000..8e3947afd
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a1/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/left.uml
new file mode 100644
index 000000000..1e03af1cf
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <body>This is an OCL&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/right.uml
new file mode 100644
index 000000000..3d7f829f6
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a10/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/left.uml
new file mode 100644
index 000000000..1e03af1cf
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <body>This is an OCL&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/right.uml
new file mode 100644
index 000000000..d4bf4879a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a11/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+(changed) test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/left.uml
new file mode 100644
index 000000000..1e03af1cf
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <body>This is an OCL&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/right.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a12/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/left.uml
new file mode 100644
index 000000000..1e03af1cf
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <body>This is an OCL&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/right.uml
new file mode 100644
index 000000000..21b3809ec
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a13/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/left.uml
new file mode 100644
index 000000000..fed93990b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/left.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/origin.uml
new file mode 100644
index 000000000..be0cecdbe
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/right.uml
new file mode 100644
index 000000000..f6c56c59b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a2/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+(changed)test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/left.uml
new file mode 100644
index 000000000..436d09076
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/right.uml
new file mode 100644
index 000000000..f6a67250b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a3/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/left.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/origin.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/right.uml
new file mode 100644
index 000000000..d31d218e1
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a4/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/left.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/origin.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/right.uml
new file mode 100644
index 000000000..d2bd1ac3b
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a5/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>C</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is a C&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/left.uml
new file mode 100644
index 000000000..56fb7da8c
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/right.uml
new file mode 100644
index 000000000..e85db3ee3
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a6/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <language>JAVA</language>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/left.uml
new file mode 100644
index 000000000..75afe65ae
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/origin.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/origin.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/right.uml
new file mode 100644
index 000000000..a0a7fd9a4
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a7/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>OCL</language>
+ <language>JAVA</language>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is a JAVA&#xD;
+(changed) test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/left.uml
new file mode 100644
index 000000000..d1c6a7222
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/left.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is an OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/origin.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/right.uml
new file mode 100644
index 000000000..d57b727bb
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a8/right.uml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <language>OCL</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ <body>This is a different OCL&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/left.uml
new file mode 100644
index 000000000..f7c718aa6
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/left.uml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/origin.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/origin.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/right.uml
new file mode 100644
index 000000000..e3ad24c8f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/a9/right.uml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:Activity" xmi:id="_mlTEQGQIEeS_8IneN_JFUg" name="Activity1" node="_opaqueAction1">
+ <node xmi:type="uml:OpaqueAction" xmi:id="_opaqueAction1" name="OpaqueAction1">
+ <language>JAVA</language>
+ <body>This is a JAVA&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </node>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/left.uml
new file mode 100644
index 000000000..be677b7ce
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/left.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueBehavior" xmi:id="_opaqueBehavior1" name="OpaqueBehavior1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/origin.uml
new file mode 100644
index 000000000..c6dda644a
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/origin.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueBehavior" xmi:id="_opaqueBehavior1" name="OpaqueBehavior1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/right.uml
new file mode 100644
index 000000000..52819b935
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/b1/right.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueBehavior" xmi:id="_opaqueBehavior1" name="OpaqueBehavior1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/left.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/left.uml
new file mode 100644
index 000000000..774e3819f
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/left.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueExpression" xmi:id="_opaqueExpression1" name="OpaqueExpression1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line (changed)&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/origin.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/origin.uml
new file mode 100644
index 000000000..2834b4cb8
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/origin.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueExpression" xmi:id="_opaqueExpression1" name="OpaqueExpression1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/right.uml b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/right.uml
new file mode 100644
index 000000000..adc07dbb0
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/e1/right.uml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_mhydQGQIEeS_8IneN_JFUg" name="Model">
+ <packageImport xmi:id="_mhydQWQIEeS_8IneN_JFUg">
+ <importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml#_0"/>
+ </packageImport>
+ <packagedElement xmi:type="uml:OpaqueExpression" xmi:id="_opaqueExpression1" name="OpaqueExpression1">
+ <language>JAVA</language>
+ <body>This is a&#xD;
+test with multi-line&#xD;
+String attribute&#xD;
+and concurrent changes (changed)&#xD;
+of them.</body>
+ </packagedElement>
+</uml:Model>
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/useCases b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/useCases
new file mode 100644
index 000000000..ec5fcfeb2
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/opaque/data/useCases
@@ -0,0 +1,82 @@
+Use Cases for merging bodies of OpaqueBehaviors
+===============================================
+
+A1
+--
+Opaque action with one body attribute value that is concurrently modified in a
+mergeable way (i.e., at different lines).
+
+A2
+--
+Opaque action with one body attribute value that is concurrently modified in a
+non-mergeable way (i.e., conflict).
+
+A3
+--
+Opaque action with two body attribute values, whereas the second is concurrently
+modified in a non-mergeable way (i.e., conflict) and the first one is changed in
+a mergeable way (i.e., no conflict).
+
+A4
+--
+Opaque action with one body attribute value that is changed on the right-hand side
+and on the left-hand side a new language and body has been added (i.e., mergeable).
+
+A5
+--
+Opaque action with one body attribute value that is unchanged, but both sides add
+different new languages and bodies (i.e., mergeable).
+
+A6
+--
+Opaque action with two body attribute values, whereas one is changed on the both
+sides but on different lines (i.e., mergeable) and on the right-hand side the order
+of the language/body values is changed (i.e., mergeable).
+
+A7
+--
+Opaque action with two body attribute values, whereas one is changed on the both
+sides on the same line (i.e., conflict) and additionally on the right-hand side
+the order of the language/body values is changed.
+
+A8
+--
+Opaque action with one body attribute value that is unchanged, but both sides add
+same new language value with different body (i.e., conflict).
+
+A9
+--
+Opaque action with one body attribute value that is deleted on the left-hand side
+and left unchanged on the right-hand side.
+
+A10
+---
+Opaque action with two body attribute values, whereas one is deleted and the other one
+is changed left-hand side and on the right-hand side the one that has been changed on the
+left-hand side is also changed in a mergeable way.
+
+A11
+---
+Opaque action with two body attribute values, whereas one is deleted and the other one
+is changed left-hand side and on the right-hand side the one that has been changed on the
+left-hand side is also changed in a non-mergeable way (conflict).
+
+A12
+---
+Opaque action with two body attribute values, whereas one is deleted and the other one
+is changed left-hand side and on the right-hand side the one that has been changed on the
+left-hand side is deleted (delete-update conflict).
+
+A13
+---
+Opaque action with two body attribute values, whereas one is deleted and the other one
+is changed left-hand side and on the right-hand side the one that has been deleted on
+the left-hand side is deleted too (delete-delete -> no conflict).
+
+B1
+--
+Same as A1 but with OpaqueBehaviors.
+
+E1
+--
+Same as A1 but with OpaqueExpressions. \ No newline at end of file
diff --git a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/suite/AllTests.java b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/suite/AllTests.java
index 1cda2f7fe..0dc9c70b2 100644
--- a/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/suite/AllTests.java
+++ b/plugins/org.eclipse.emf.compare.uml2.tests/src/org/eclipse/emf/compare/uml2/tests/suite/AllTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2012, 2014 Obeo.
+ * Copyright (c) 2012, 2014 Obeo 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
@@ -7,6 +7,7 @@
*
* Contributors:
* Obeo - initial API and implementation
+ * Philip Langer - addition of OpaqueTest
*******************************************************************************/
package org.eclipse.emf.compare.uml2.tests.suite;
@@ -38,6 +39,8 @@ import org.eclipse.emf.compare.uml2.tests.implications.ImplicationsTransitionTes
import org.eclipse.emf.compare.uml2.tests.include.AddIncludeTest;
import org.eclipse.emf.compare.uml2.tests.merge.ExtensionMergeTest;
import org.eclipse.emf.compare.uml2.tests.message.AddMessageTest;
+import org.eclipse.emf.compare.uml2.tests.opaque.OpaqueElementBodyChangeDiffTest;
+import org.eclipse.emf.compare.uml2.tests.opaque.OpaqueElementBodyChangeMergeTest;
import org.eclipse.emf.compare.uml2.tests.profiles.DynamicProfileTest;
import org.eclipse.emf.compare.uml2.tests.profiles.StaticProfileTest;
import org.eclipse.emf.compare.uml2.tests.stereotypes.DynamicStereotypeTest;
@@ -65,7 +68,8 @@ import org.junit.runners.Suite.SuiteClasses;
StaticStereotypeTest.class, StaticStereotypedElementChangeTests.class, DynamicStereotypeTest.class,
DynamicStereotypedElementChangeTests.class, ImplicationsAssociationTest.class,
ImplicationsTransitionTest.class, ImplicationsInterfaceRealizationTest.class,
- StaticStereotypedElementItemProviderTest.class, DynamicStereotypedElementItemProviderTest.class })
+ StaticStereotypedElementItemProviderTest.class, DynamicStereotypedElementItemProviderTest.class,
+ OpaqueElementBodyChangeDiffTest.class, OpaqueElementBodyChangeMergeTest.class })
public class AllTests {
/**
diff --git a/plugins/org.eclipse.emf.compare.uml2/model/uml2compare.ecore b/plugins/org.eclipse.emf.compare.uml2/model/uml2compare.ecore
index 07c952d06..c8c820c2e 100644
--- a/plugins/org.eclipse.emf.compare.uml2/model/uml2compare.ecore
+++ b/plugins/org.eclipse.emf.compare.uml2/model/uml2compare.ecore
@@ -21,4 +21,7 @@
<eStructuralFeatures xsi:type="ecore:EReference" name="eReference" eType="ecore:EClass platform:/plugin/org.eclipse.emf.ecore/model/Ecore.ecore#//EReference"/>
</eClassifiers>
<eClassifiers xsi:type="ecore:EClass" name="StereotypedElementChange" eSuperTypes="#//UMLDiff"/>
+ <eClassifiers xsi:type="ecore:EClass" name="OpaqueElementBodyChange" eSuperTypes="#//UMLDiff">
+ <eStructuralFeatures xsi:type="ecore:EAttribute" name="language" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+ </eClassifiers>
</ecore:EPackage>
diff --git a/plugins/org.eclipse.emf.compare.uml2/plugin.xml b/plugins/org.eclipse.emf.compare.uml2/plugin.xml
index c9f90ebea..47cc9638c 100644
--- a/plugins/org.eclipse.emf.compare.uml2/plugin.xml
+++ b/plugins/org.eclipse.emf.compare.uml2/plugin.xml
@@ -10,6 +10,7 @@ http://www.eclipse.org/legal/epl-v10.html
Contributors:
Obeo - initial API and implementation
+ Philip Langer - post processor and merger for opaque element body changes
-->
<plugin>
@@ -31,6 +32,15 @@ Contributors:
value="http://www.eclipse.org/uml2/\d.0.0/UML">
</nsURI>
</processor>
+ <processor
+ class="org.eclipse.emf.compare.uml2.internal.postprocessor.OpaqueElementBodyChangePostProcessor"
+ description="Post Processor for detecting conflicts specific to opaque element body changes."
+ label="Opaque Element Change Processor"
+ ordinal="25">
+ <nsURI
+ value="http://www.eclipse.org/uml2/\d.0.0/UML">
+ </nsURI>
+ </processor>
<processor
class="org.eclipse.emf.compare.uml2.internal.postprocessor.StereotypedElementChangePostProcessor"
description="This post processor creates macro differences for stereotyped uml elements."
@@ -51,6 +61,10 @@ Contributors:
class="org.eclipse.emf.compare.uml2.internal.merge.UMLReferenceChangeMerger"
ranking="25">
</merger>
+ <merger
+ class="org.eclipse.emf.compare.uml2.internal.merge.OpaqueElementBodyChangeMerger"
+ ranking="25">
+ </merger>
</extension>
</plugin>
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/OpaqueElementBodyChange.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/OpaqueElementBodyChange.java
new file mode 100644
index 000000000..d466c6308
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/OpaqueElementBodyChange.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.uml2.internal;
+
+/**
+ * <!-- begin-user-doc -->
+ * A representation of the model object '<em><b>Opaque Element Body Change</b></em>'.
+ * <!-- end-user-doc -->
+ *
+ * <p>
+ * The following features are supported:
+ * <ul>
+ * <li>{@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange#getLanguage <em>Language</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @see org.eclipse.emf.compare.uml2.internal.UMLComparePackage#getOpaqueElementBodyChange()
+ * @model
+ * @generated
+ */
+public interface OpaqueElementBodyChange extends UMLDiff {
+ /**
+ * Returns the value of the '<em><b>Language</b></em>' attribute.
+ * <!-- begin-user-doc -->
+ * <p>
+ * If the meaning of the '<em>Language</em>' attribute isn't clear,
+ * there really should be more of a description here...
+ * </p>
+ * <!-- end-user-doc -->
+ * @return the value of the '<em>Language</em>' attribute.
+ * @see #setLanguage(String)
+ * @see org.eclipse.emf.compare.uml2.internal.UMLComparePackage#getOpaqueElementBodyChange_Language()
+ * @model
+ * @generated
+ */
+ String getLanguage();
+
+ /**
+ * Sets the value of the '{@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange#getLanguage <em>Language</em>}' attribute.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @param value the new value of the '<em>Language</em>' attribute.
+ * @see #getLanguage()
+ * @generated
+ */
+ void setLanguage(String value);
+
+} // OpaqueElementBodyChange
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLCompareFactory.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLCompareFactory.java
index 57d81803a..283c9154a 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLCompareFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLCompareFactory.java
@@ -134,6 +134,15 @@ public interface UMLCompareFactory extends EFactory {
StereotypedElementChange createStereotypedElementChange();
/**
+ * Returns a new object of class '<em>Opaque Element Body Change</em>'. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @return a new object of class '<em>Opaque Element Body Change</em>'.
+ * @generated
+ */
+ OpaqueElementBodyChange createOpaqueElementBodyChange();
+
+ /**
* Returns the package supported by this factory. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @return the package supported by this factory.
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLComparePackage.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLComparePackage.java
index a8e1ca3ec..cd5103727 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLComparePackage.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/UMLComparePackage.java
@@ -11,6 +11,7 @@
package org.eclipse.emf.compare.uml2.internal;
import org.eclipse.emf.compare.ComparePackage;
+import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
@@ -2063,6 +2064,168 @@ public interface UMLComparePackage extends EPackage {
int STEREOTYPED_ELEMENT_CHANGE_FEATURE_COUNT = UML_DIFF_FEATURE_COUNT + 0;
/**
+ * The meta object id for the '
+ * {@link org.eclipse.emf.compare.uml2.internal.impl.OpaqueElementBodyChangeImpl
+ * <em>Opaque Element Body Change</em>}' class. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @see org.eclipse.emf.compare.uml2.internal.impl.OpaqueElementBodyChangeImpl
+ * @see org.eclipse.emf.compare.uml2.internal.impl.UMLComparePackageImpl#getOpaqueElementBodyChange()
+ * @generated
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE = 13;
+
+ /**
+ * The feature id for the '<em><b>Match</b></em>' container reference. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__MATCH = UML_DIFF__MATCH;
+
+ /**
+ * The feature id for the '<em><b>Requires</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__REQUIRES = UML_DIFF__REQUIRES;
+
+ /**
+ * The feature id for the '<em><b>Required By</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__REQUIRED_BY = UML_DIFF__REQUIRED_BY;
+
+ /**
+ * The feature id for the '<em><b>Implies</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__IMPLIES = UML_DIFF__IMPLIES;
+
+ /**
+ * The feature id for the '<em><b>Implied By</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__IMPLIED_BY = UML_DIFF__IMPLIED_BY;
+
+ /**
+ * The feature id for the '<em><b>Refines</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__REFINES = UML_DIFF__REFINES;
+
+ /**
+ * The feature id for the '<em><b>Refined By</b></em>' reference list. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__REFINED_BY = UML_DIFF__REFINED_BY;
+
+ /**
+ * The feature id for the '<em><b>Prime Refining</b></em>' reference. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__PRIME_REFINING = UML_DIFF__PRIME_REFINING;
+
+ /**
+ * The feature id for the '<em><b>Kind</b></em>' attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__KIND = UML_DIFF__KIND;
+
+ /**
+ * The feature id for the '<em><b>Source</b></em>' attribute. <!-- begin-user-doc --> <!-- end-user-doc
+ * -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__SOURCE = UML_DIFF__SOURCE;
+
+ /**
+ * The feature id for the '<em><b>State</b></em>' attribute. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__STATE = UML_DIFF__STATE;
+
+ /**
+ * The feature id for the '<em><b>Equivalence</b></em>' reference. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__EQUIVALENCE = UML_DIFF__EQUIVALENCE;
+
+ /**
+ * The feature id for the '<em><b>Conflict</b></em>' reference. <!-- begin-user-doc --> <!-- end-user-doc
+ * -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__CONFLICT = UML_DIFF__CONFLICT;
+
+ /**
+ * The feature id for the '<em><b>Discriminant</b></em>' reference. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__DISCRIMINANT = UML_DIFF__DISCRIMINANT;
+
+ /**
+ * The feature id for the '<em><b>EReference</b></em>' reference. <!-- begin-user-doc --> <!--
+ * end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__EREFERENCE = UML_DIFF__EREFERENCE;
+
+ /**
+ * The feature id for the '<em><b>Language</b></em>' attribute. <!-- begin-user-doc --> <!-- end-user-doc
+ * -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE = UML_DIFF_FEATURE_COUNT + 0;
+
+ /**
+ * The number of structural features of the '<em>Opaque Element Body Change</em>' class. <!--
+ * begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @generated
+ * @ordered
+ */
+ int OPAQUE_ELEMENT_BODY_CHANGE_FEATURE_COUNT = UML_DIFF_FEATURE_COUNT + 1;
+
+ /**
* Returns the meta object for class '{@link org.eclipse.emf.compare.uml2.internal.AssociationChange
* <em>Association Change</em>}'. <!-- begin-user-doc --> <!-- end-user-doc -->
*
@@ -2250,6 +2413,29 @@ public interface UMLComparePackage extends EPackage {
EClass getStereotypedElementChange();
/**
+ * Returns the meta object for class '
+ * {@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange
+ * <em>Opaque Element Body Change</em>}'. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @return the meta object for class '<em>Opaque Element Body Change</em>'.
+ * @see org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange
+ * @generated
+ */
+ EClass getOpaqueElementBodyChange();
+
+ /**
+ * Returns the meta object for the attribute '
+ * {@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange#getLanguage <em>Language</em>}'.
+ * <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @return the meta object for the attribute '<em>Language</em>'.
+ * @see org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange#getLanguage()
+ * @see #getOpaqueElementBodyChange()
+ * @generated
+ */
+ EAttribute getOpaqueElementBodyChange_Language();
+
+ /**
* Returns the factory that creates the instances of the model. <!-- begin-user-doc --> <!-- end-user-doc
* -->
*
@@ -2448,6 +2634,25 @@ public interface UMLComparePackage extends EPackage {
*/
EClass STEREOTYPED_ELEMENT_CHANGE = eINSTANCE.getStereotypedElementChange();
+ /**
+ * The meta object literal for the '
+ * {@link org.eclipse.emf.compare.uml2.internal.impl.OpaqueElementBodyChangeImpl
+ * <em>Opaque Element Body Change</em>}' class. <!-- begin-user-doc --> <!-- end-user-doc -->
+ *
+ * @see org.eclipse.emf.compare.uml2.internal.impl.OpaqueElementBodyChangeImpl
+ * @see org.eclipse.emf.compare.uml2.internal.impl.UMLComparePackageImpl#getOpaqueElementBodyChange()
+ * @generated
+ */
+ EClass OPAQUE_ELEMENT_BODY_CHANGE = eINSTANCE.getOpaqueElementBodyChange();
+
+ /**
+ * The meta object literal for the '<em><b>Language</b></em>' attribute feature. <!-- begin-user-doc
+ * --> <!-- end-user-doc -->
+ *
+ * @generated
+ */
+ EAttribute OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE = eINSTANCE.getOpaqueElementBodyChange_Language();
+
}
} // UMLComparePackage
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/OpaqueElementBodyChangeImpl.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/OpaqueElementBodyChangeImpl.java
new file mode 100644
index 000000000..6ce9cafc0
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/OpaqueElementBodyChangeImpl.java
@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2012 Obeo.
+ * 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:
+ * Obeo - initial API and implementation
+ */
+package org.eclipse.emf.compare.uml2.internal.impl;
+
+import org.eclipse.emf.common.notify.Notification;
+
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.UMLComparePackage;
+
+import org.eclipse.emf.ecore.EClass;
+
+import org.eclipse.emf.ecore.impl.ENotificationImpl;
+
+/**
+ * <!-- begin-user-doc -->
+ * An implementation of the model object '<em><b>Opaque Element Body Change</b></em>'.
+ * <!-- end-user-doc -->
+ * <p>
+ * The following features are implemented:
+ * <ul>
+ * <li>{@link org.eclipse.emf.compare.uml2.internal.impl.OpaqueElementBodyChangeImpl#getLanguage <em>Language</em>}</li>
+ * </ul>
+ * </p>
+ *
+ * @generated
+ */
+public class OpaqueElementBodyChangeImpl extends UMLDiffImpl implements OpaqueElementBodyChange {
+ /**
+ * The default value of the '{@link #getLanguage() <em>Language</em>}' attribute.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @see #getLanguage()
+ * @generated
+ * @ordered
+ */
+ protected static final String LANGUAGE_EDEFAULT = null;
+
+ /**
+ * The cached value of the '{@link #getLanguage() <em>Language</em>}' attribute.
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @see #getLanguage()
+ * @generated
+ * @ordered
+ */
+ protected String language = LANGUAGE_EDEFAULT;
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ protected OpaqueElementBodyChangeImpl() {
+ super();
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ protected EClass eStaticClass() {
+ return UMLComparePackage.Literals.OPAQUE_ELEMENT_BODY_CHANGE;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public void setLanguage(String newLanguage) {
+ String oldLanguage = language;
+ language = newLanguage;
+ if (eNotificationRequired())
+ eNotify(new ENotificationImpl(this, Notification.SET,
+ UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE, oldLanguage, language));
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public Object eGet(int featureID, boolean resolve, boolean coreType) {
+ switch (featureID) {
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE:
+ return getLanguage();
+ }
+ return super.eGet(featureID, resolve, coreType);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public void eSet(int featureID, Object newValue) {
+ switch (featureID) {
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE:
+ setLanguage((String)newValue);
+ return;
+ }
+ super.eSet(featureID, newValue);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public void eUnset(int featureID) {
+ switch (featureID) {
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE:
+ setLanguage(LANGUAGE_EDEFAULT);
+ return;
+ }
+ super.eUnset(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public boolean eIsSet(int featureID) {
+ switch (featureID) {
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE:
+ return LANGUAGE_EDEFAULT == null ? language != null : !LANGUAGE_EDEFAULT.equals(language);
+ }
+ return super.eIsSet(featureID);
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ @Override
+ public String toString() {
+ if (eIsProxy())
+ return super.toString();
+
+ StringBuffer result = new StringBuffer(super.toString());
+ result.append(" (language: "); //$NON-NLS-1$
+ result.append(language);
+ result.append(')');
+ return result.toString();
+ }
+
+} //OpaqueElementBodyChangeImpl
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLCompareFactoryImpl.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLCompareFactoryImpl.java
index 24848ea0f..8f40a3ecc 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLCompareFactoryImpl.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLCompareFactoryImpl.java
@@ -17,6 +17,7 @@ import org.eclipse.emf.compare.uml2.internal.ExtendChange;
import org.eclipse.emf.compare.uml2.internal.GeneralizationSetChange;
import org.eclipse.emf.compare.uml2.internal.IntervalConstraintChange;
import org.eclipse.emf.compare.uml2.internal.MessageChange;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
import org.eclipse.emf.compare.uml2.internal.ProfileApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeAttributeChange;
@@ -81,6 +82,7 @@ public class UMLCompareFactoryImpl extends EFactoryImpl implements UMLCompareFac
case UMLComparePackage.PROFILE_APPLICATION_CHANGE: return createProfileApplicationChange();
case UMLComparePackage.DIRECTED_RELATIONSHIP_CHANGE: return createDirectedRelationshipChange();
case UMLComparePackage.STEREOTYPED_ELEMENT_CHANGE: return createStereotypedElementChange();
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE: return createOpaqueElementBodyChange();
default:
throw new IllegalArgumentException("The class '" + eClass.getName() + "' is not a valid classifier"); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -193,6 +195,16 @@ public class UMLCompareFactoryImpl extends EFactoryImpl implements UMLCompareFac
StereotypedElementChangeImpl stereotypedElementChange = new StereotypedElementChangeImpl();
return stereotypedElementChange;
}
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public OpaqueElementBodyChange createOpaqueElementBodyChange() {
+ OpaqueElementBodyChangeImpl opaqueElementBodyChange = new OpaqueElementBodyChangeImpl();
+ return opaqueElementBodyChange;
+ }
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLComparePackageImpl.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLComparePackageImpl.java
index 3b9e9fb02..686af35e9 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLComparePackageImpl.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/impl/UMLComparePackageImpl.java
@@ -18,6 +18,7 @@ import org.eclipse.emf.compare.uml2.internal.ExtendChange;
import org.eclipse.emf.compare.uml2.internal.GeneralizationSetChange;
import org.eclipse.emf.compare.uml2.internal.IntervalConstraintChange;
import org.eclipse.emf.compare.uml2.internal.MessageChange;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
import org.eclipse.emf.compare.uml2.internal.ProfileApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeAttributeChange;
@@ -26,6 +27,7 @@ import org.eclipse.emf.compare.uml2.internal.StereotypedElementChange;
import org.eclipse.emf.compare.uml2.internal.UMLCompareFactory;
import org.eclipse.emf.compare.uml2.internal.UMLComparePackage;
import org.eclipse.emf.compare.uml2.internal.UMLDiff;
+import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
@@ -117,6 +119,13 @@ public class UMLComparePackageImpl extends EPackageImpl implements UMLComparePac
* @generated
*/
private EClass stereotypedElementChangeEClass = null;
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ private EClass opaqueElementBodyChangeEClass = null;
/**
* Creates an instance of the model <b>Package</b>, registered with
@@ -317,6 +326,24 @@ public class UMLComparePackageImpl extends EPackageImpl implements UMLComparePac
public EClass getStereotypedElementChange() {
return stereotypedElementChangeEClass;
}
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public EClass getOpaqueElementBodyChange() {
+ return opaqueElementBodyChangeEClass;
+ }
+
+ /**
+ * <!-- begin-user-doc -->
+ * <!-- end-user-doc -->
+ * @generated
+ */
+ public EAttribute getOpaqueElementBodyChange_Language() {
+ return (EAttribute)opaqueElementBodyChangeEClass.getEStructuralFeatures().get(0);
+ }
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
@@ -372,6 +399,9 @@ public class UMLComparePackageImpl extends EPackageImpl implements UMLComparePac
createEReference(umlDiffEClass, UML_DIFF__EREFERENCE);
stereotypedElementChangeEClass = createEClass(STEREOTYPED_ELEMENT_CHANGE);
+
+ opaqueElementBodyChangeEClass = createEClass(OPAQUE_ELEMENT_BODY_CHANGE);
+ createEAttribute(opaqueElementBodyChangeEClass, OPAQUE_ELEMENT_BODY_CHANGE__LANGUAGE);
}
/**
@@ -418,6 +448,7 @@ public class UMLComparePackageImpl extends EPackageImpl implements UMLComparePac
directedRelationshipChangeEClass.getESuperTypes().add(this.getUMLDiff());
umlDiffEClass.getESuperTypes().add(theComparePackage.getDiff());
stereotypedElementChangeEClass.getESuperTypes().add(this.getUMLDiff());
+ opaqueElementBodyChangeEClass.getESuperTypes().add(this.getUMLDiff());
// Initialize classes and features; add operations and parameters
initEClass(associationChangeEClass, AssociationChange.class, "AssociationChange", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
@@ -449,6 +480,9 @@ public class UMLComparePackageImpl extends EPackageImpl implements UMLComparePac
initEReference(getUMLDiff_EReference(), theEcorePackage.getEReference(), null, "eReference", null, 0, 1, UMLDiff.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_COMPOSITE, IS_RESOLVE_PROXIES, !IS_UNSETTABLE, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
initEClass(stereotypedElementChangeEClass, StereotypedElementChange.class, "StereotypedElementChange", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
+
+ initEClass(opaqueElementBodyChangeEClass, OpaqueElementBodyChange.class, "OpaqueElementBodyChange", !IS_ABSTRACT, !IS_INTERFACE, IS_GENERATED_INSTANCE_CLASS); //$NON-NLS-1$
+ initEAttribute(getOpaqueElementBodyChange_Language(), ecorePackage.getEString(), "language", null, 0, 1, OpaqueElementBodyChange.class, !IS_TRANSIENT, !IS_VOLATILE, IS_CHANGEABLE, !IS_UNSETTABLE, !IS_ID, IS_UNIQUE, !IS_DERIVED, IS_ORDERED); //$NON-NLS-1$
// Create resource
createResource(eNS_URI);
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareAdapterFactory.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareAdapterFactory.java
index 2f0d15bfa..f98429e1d 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareAdapterFactory.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareAdapterFactory.java
@@ -121,6 +121,10 @@ public class UMLCompareAdapterFactory extends AdapterFactoryImpl {
return createStereotypedElementChangeAdapter();
}
@Override
+ public Adapter caseOpaqueElementBodyChange(OpaqueElementBodyChange object) {
+ return createOpaqueElementBodyChangeAdapter();
+ }
+ @Override
public Adapter caseDiff(Diff object) {
return createDiffAdapter();
}
@@ -313,6 +317,20 @@ public class UMLCompareAdapterFactory extends AdapterFactoryImpl {
public Adapter createStereotypedElementChangeAdapter() {
return null;
}
+
+ /**
+ * Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange <em>Opaque Element Body Change</em>}'.
+ * <!-- begin-user-doc -->
+ * This default implementation returns null so that we can easily ignore cases;
+ * it's useful to ignore a case when inheritance will catch all the cases anyway.
+ * <!-- end-user-doc -->
+ * @return the new adapter.
+ * @see org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange
+ * @generated
+ */
+ public Adapter createOpaqueElementBodyChangeAdapter() {
+ return null;
+ }
/**
* Creates a new adapter for an object of class '{@link org.eclipse.emf.compare.Diff <em>Diff</em>}'. <!--
diff --git a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareSwitch.java b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareSwitch.java
index 2398e4910..496d3097d 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareSwitch.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src-gen/org/eclipse/emf/compare/uml2/internal/util/UMLCompareSwitch.java
@@ -20,6 +20,7 @@ import org.eclipse.emf.compare.uml2.internal.ExtendChange;
import org.eclipse.emf.compare.uml2.internal.GeneralizationSetChange;
import org.eclipse.emf.compare.uml2.internal.IntervalConstraintChange;
import org.eclipse.emf.compare.uml2.internal.MessageChange;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
import org.eclipse.emf.compare.uml2.internal.ProfileApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeApplicationChange;
import org.eclipse.emf.compare.uml2.internal.StereotypeAttributeChange;
@@ -197,6 +198,14 @@ public class UMLCompareSwitch<T> {
if (result == null) result = defaultCase(theEObject);
return result;
}
+ case UMLComparePackage.OPAQUE_ELEMENT_BODY_CHANGE: {
+ OpaqueElementBodyChange opaqueElementBodyChange = (OpaqueElementBodyChange)theEObject;
+ T result = caseOpaqueElementBodyChange(opaqueElementBodyChange);
+ if (result == null) result = caseUMLDiff(opaqueElementBodyChange);
+ if (result == null) result = caseDiff(opaqueElementBodyChange);
+ if (result == null) result = defaultCase(theEObject);
+ return result;
+ }
default: return defaultCase(theEObject);
}
}
@@ -381,6 +390,21 @@ public class UMLCompareSwitch<T> {
public T caseStereotypedElementChange(StereotypedElementChange object) {
return null;
}
+
+ /**
+ * Returns the result of interpreting the object as an instance of '<em>Opaque Element Body Change</em>'.
+ * <!-- begin-user-doc -->
+ * This implementation returns null;
+ * returning a non-null result will terminate the switch.
+ * <!-- end-user-doc -->
+ * @param object the target of the switch.
+ * @return the result of interpreting the object as an instance of '<em>Opaque Element Body Change</em>'.
+ * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject)
+ * @generated
+ */
+ public T caseOpaqueElementBodyChange(OpaqueElementBodyChange object) {
+ return null;
+ }
/**
* Returns the result of interpreting the object as an instance of '<em>Diff</em>'.
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java
new file mode 100644
index 000000000..c53ba5045
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/merge/OpaqueElementBodyChangeMerger.java
@@ -0,0 +1,435 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.internal.merge;
+
+import com.google.common.base.Optional;
+
+import java.util.List;
+
+import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.DifferenceState;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.internal.utils.DiffUtil;
+import org.eclipse.emf.compare.merge.AttributeChangeMerger;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * Merger for {@link OpaqueElementBodyChange body changes} of OpaqueActions, OpaqueBehaviors and
+ * OpaqueExpressions.
+ * <p>
+ * This merger handles all {@link Diff differences} that are either {@link OpaqueElementBodyChange opaque
+ * element body changes} itself or that are AttributeChanges refining {@link OpaqueElementBodyChange opaque
+ * element body changes}. Note that this merger forces the merging of the entire
+ * {@link OpaqueElementBodyChange}, also if it is only invoked for one {@link AttributeChange} that refines a
+ * {@link OpaqueElementBodyChange}.
+ * </p>
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class OpaqueElementBodyChangeMerger extends AttributeChangeMerger {
+
+ @Override
+ public boolean isMergerFor(Diff target) {
+ return isOrRefinesOpaqueElementBodyChange(target);
+ }
+
+ /**
+ * Specifies whether the given {@code target} either is an {@link OpaqueElementBodyChange} or refines an
+ * {@link OpaqueElementBodyChange}.
+ *
+ * @param target
+ * The difference to check.
+ * @return <code>true</code> if it is or refines an {@link OpaqueElementBodyChange}, <code>false</code>
+ * otherwise.
+ */
+ private boolean isOrRefinesOpaqueElementBodyChange(Diff target) {
+ return getOpaqueElementBodyChange(target).isPresent();
+ }
+
+ /**
+ * Returns an the {@code Optional optional} {@link OpaqueElementBodyChange} for the given {@code diff}.
+ * <p>
+ * This is either the {@code diff} itself or the difference that is refined by the given {@code diff}. If
+ * neither {@code diff} itself nor the differences it refines is an {@link OpaqueElementBodyChange}, this
+ * method returns {@code Optional#absent()}.
+ * </p>
+ *
+ * @param diff
+ * The difference to get the {@link OpaqueElementBodyChange} for.
+ * @return The {@link OpaqueElementBodyChange} or {@code Optional#absent()} if not available.
+ */
+ private Optional<OpaqueElementBodyChange> getOpaqueElementBodyChange(Diff diff) {
+ final Optional<OpaqueElementBodyChange> bodyChange;
+ if (diff instanceof OpaqueElementBodyChange) {
+ bodyChange = Optional.of((OpaqueElementBodyChange)diff);
+ } else if (!diff.getRefines().isEmpty()) {
+ bodyChange = getRefinedOpaqueElementBodyChange(diff);
+ } else {
+ bodyChange = Optional.absent();
+ }
+ return bodyChange;
+ }
+
+ /**
+ * Returns the {@link Optional optional} {@link OpaqueElementBodyChange} that is refined by the given
+ * {@code diff} if available.
+ *
+ * @param diff
+ * The difference to get the refined {@link OpaqueElementBodyChange} for.
+ * @return The refined {@link OpaqueElementBodyChange} or {@code Optional#absent()} if not available.
+ */
+ private Optional<OpaqueElementBodyChange> getRefinedOpaqueElementBodyChange(Diff diff) {
+ for (Diff refinedDiff : diff.getRefines()) {
+ if (refinedDiff instanceof OpaqueElementBodyChange) {
+ return Optional.of((OpaqueElementBodyChange)refinedDiff);
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ protected void accept(Diff diff, boolean rightToLeft) {
+ final Optional<OpaqueElementBodyChange> possibleBodyChange = getOpaqueElementBodyChange(diff);
+ if (possibleBodyChange.isPresent()) {
+ final OpaqueElementBodyChange bodyChange = getOpaqueElementBodyChange(diff).get();
+ switch (bodyChange.getKind()) {
+ case ADD:
+ delegateAccept(diff, rightToLeft);
+ break;
+ case DELETE:
+ delegateAccept(diff, rightToLeft);
+ break;
+ case CHANGE:
+ changeElement(bodyChange, rightToLeft);
+ break;
+ case MOVE:
+ moveElement(bodyChange, rightToLeft);
+ break;
+ default:
+ break;
+
+ }
+ }
+ }
+
+ @Override
+ protected void reject(Diff diff, boolean rightToLeft) {
+ final Optional<OpaqueElementBodyChange> possibleBodyChange = getOpaqueElementBodyChange(diff);
+ if (possibleBodyChange.isPresent()) {
+ final OpaqueElementBodyChange bodyChange = possibleBodyChange.get();
+ switch (bodyChange.getKind()) {
+ case ADD:
+ delegateReject(diff, rightToLeft);
+ break;
+ case DELETE:
+ delegateReject(diff, rightToLeft);
+ break;
+ case CHANGE:
+ changeElement(bodyChange, rightToLeft);
+ break;
+ case MOVE:
+ moveElement(bodyChange, rightToLeft);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Delegates the accept of {@code diff} to the super class ({@link AttributeChangeMerger}).
+ * <p>
+ * If this method is called with an {@link OpaqueElementBodyChange}, its refining differences will be
+ * delegated. For any other kind of differences, they are be delegated directly.
+ * </p>
+ *
+ * @param diff
+ * The difference to be delegated.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void delegateAccept(Diff diff, boolean rightToLeft) {
+ if (diff instanceof OpaqueElementBodyChange) {
+ OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
+ acceptRefiningDiffs(bodyChange, rightToLeft);
+ } else {
+ super.accept(diff, rightToLeft);
+ }
+ }
+
+ /**
+ * Delegates the accept of the refining differences of the given {@code bodyChange} to the super class (
+ * {@link AttributeChangeMerger}).
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to be delegated.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void acceptRefiningDiffs(OpaqueElementBodyChange bodyChange, boolean rightToLeft) {
+ bodyChange.setState(DifferenceState.MERGED);
+ for (Diff refiningDiff : bodyChange.getRefinedBy()) {
+ super.accept(refiningDiff, rightToLeft);
+ }
+ }
+
+ /**
+ * Delegates the reject of {@code diff} to the super class ({@link AttributeChangeMerger}).
+ * <p>
+ * If this method is called with an {@link OpaqueElementBodyChange}, its refining differences will be
+ * delegated. For any other kind of differences, they are be delegated directly.
+ * </p>
+ *
+ * @param diff
+ * The difference to be delegated.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void delegateReject(Diff diff, boolean rightToLeft) {
+ if (diff instanceof OpaqueElementBodyChange) {
+ OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)diff;
+ rejectRefiningDiffs(bodyChange, rightToLeft);
+ } else {
+ super.reject(diff, rightToLeft);
+ }
+ }
+
+ /**
+ * Delegates the reject of the refining differences of the given {@code bodyChange} to the super class (
+ * {@link AttributeChangeMerger}).
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to be delegated.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void rejectRefiningDiffs(OpaqueElementBodyChange bodyChange, boolean rightToLeft) {
+ bodyChange.setState(DifferenceState.MERGED);
+ for (Diff refiningDiff : bodyChange.getRefinedBy()) {
+ super.reject(refiningDiff, rightToLeft);
+ }
+ }
+
+ /**
+ * Performs the change represented by the given {@code bodyChange}.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to be performed.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void changeElement(OpaqueElementBodyChange bodyChange, boolean rightToLeft) {
+ final Match match = bodyChange.getMatch();
+ final Comparison comparison = match.getComparison();
+ final String language = bodyChange.getLanguage();
+
+ final EObject leftContainer = match.getLeft();
+ final EObject rightContainer = match.getRight();
+
+ final String leftBody = UMLCompareUtil.getOpaqueElementBody(leftContainer, language);
+ final String rightBody = UMLCompareUtil.getOpaqueElementBody(rightContainer, language);
+
+ final String newBody;
+ if (comparison.isThreeWay()) {
+ final EObject originContainer = match.getOrigin();
+ final String originBody = UMLCompareUtil.getOpaqueElementBody(originContainer, language);
+ if (isAcceptingChange(bodyChange, rightToLeft)) {
+ newBody = performThreeWayTextMerge(leftBody, rightBody, originBody);
+ } else {
+ newBody = originBody;
+ }
+ } else if (rightToLeft) {
+ newBody = rightBody;
+ } else {
+ newBody = leftBody;
+ }
+
+ if (rightToLeft) {
+ setBody(leftContainer, newBody, language);
+ } else {
+ setBody(rightContainer, newBody, language);
+ }
+
+ // we merged the body change as a whole, so set all refining to merged too
+ setRefiningDiffsMerged(bodyChange);
+ }
+
+ /**
+ * Specifies whether the given {@code diff} is an accept in the context of the given direction of merging
+ * specified in {@code rightToLeft}.
+ *
+ * @param diff
+ * The difference to check.
+ * @param rightToLeft
+ * The direction of the merging.
+ * @return <code>true</code> if it is an accept, <code>false</code> otherwise.
+ */
+ private boolean isAcceptingChange(Diff diff, boolean rightToLeft) {
+ return (diff.getSource() == DifferenceSource.LEFT && !rightToLeft)
+ || (diff.getSource() == DifferenceSource.RIGHT && rightToLeft);
+ }
+
+ /**
+ * Sets {@code newBody} as the contents of the body for the given {@code language} in the given
+ * {@code container}.
+ *
+ * @param container
+ * The {@link EObject} to set the body.
+ * @param newBody
+ * The content of the body to set.
+ * @param language
+ * The language at which the body shall be set.
+ */
+ private void setBody(EObject container, String newBody, String language) {
+ final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(container);
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(container);
+ final int index = languages.indexOf(language);
+ bodies.set(index, newBody);
+ }
+
+ /**
+ * Performs the move represented by the given {@code bodyChange}.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to be performed.
+ * @param rightToLeft
+ * The direction of merging.
+ */
+ private void moveElement(OpaqueElementBodyChange bodyChange, boolean rightToLeft) {
+ final Match match = bodyChange.getMatch();
+ final Comparison comparison = match.getComparison();
+ final String language = bodyChange.getLanguage();
+
+ final Diff languageAttributeMove = getLanguageAttributeMove(bodyChange).get();
+ final EObject container = getTargetContainer(match, rightToLeft);
+ final int sourceIndex = getLanguageIndex(container, language);
+ final int targetIndex = DiffUtil.findInsertionIndex(comparison, languageAttributeMove, rightToLeft);
+
+ doMove(container, sourceIndex, targetIndex);
+
+ // we merged the body change as a whole, so set all refining to merged too
+ setRefiningDiffsMerged(bodyChange);
+ }
+
+ /**
+ * Returns the {@link Optional optional} refining {@link AttributeChange} representing the move of the
+ * language attribute value in the given {@code bodyChange}.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to get the move difference from.
+ * @return The {@link AttributeChange} representing the move of the language attribute value.
+ */
+ private Optional<Diff> getLanguageAttributeMove(OpaqueElementBodyChange bodyChange) {
+ for (Diff diff : bodyChange.getRefinedBy()) {
+ if (diff instanceof AttributeChange && DifferenceKind.MOVE.equals(diff.getKind())) {
+ return Optional.of(diff);
+ }
+ }
+ return Optional.absent();
+ }
+
+ /**
+ * Returns the target container of the given {@code match} in the context of the direction of the merging
+ * specified in {@code rightToLeft}.
+ *
+ * @param match
+ * The {@link Match} to get the target container from.
+ * @param rightToLeft
+ * The direction of merging.
+ * @return The target container, that is, the object to be changed.
+ */
+ private EObject getTargetContainer(final Match match, boolean rightToLeft) {
+ if (rightToLeft) {
+ return match.getLeft();
+ } else {
+ return match.getRight();
+ }
+ }
+
+ /**
+ * Returns the index of the given {@code language} in the language values of the given {@code container}.
+ *
+ * @param container
+ * The container to get the index of the language value for.
+ * @param language
+ * The language value.
+ * @return The index of {@code language} in the list of languages in {@code container}.
+ */
+ private int getLanguageIndex(EObject container, String language) {
+ return UMLCompareUtil.getOpaqueElementLanguages(container).indexOf(language);
+ }
+
+ /**
+ * Performs the move of the language and body value from the current {@code sourceIndex} to the given
+ * {@code targetIndex}.
+ *
+ * @param container
+ * The container to perform the move in.
+ * @param sourceIndex
+ * The source index specifying the values to be moved.
+ * @param targetIndex
+ * The target index of the move.
+ */
+ private void doMove(EObject container, int sourceIndex, int targetIndex) {
+ final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(container);
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(container);
+
+ final String bodyValueToMove = bodies.get(sourceIndex);
+ final String languageValueToMove = languages.get(sourceIndex);
+
+ int insertionIndex = targetIndex;
+ if (sourceIndex < targetIndex) {
+ insertionIndex--;
+ }
+
+ move(languages, languageValueToMove, insertionIndex);
+ move(bodies, bodyValueToMove, insertionIndex);
+
+ }
+
+ /**
+ * Performs the move of the {@code value} in the given {@code list} to the given {@targetIndex}.
+ *
+ * @param list
+ * The list in which the move is to be performed.
+ * @param value
+ * The value to be moved.
+ * @param targetIndex
+ * The target index of the move to be performed.
+ */
+ private void move(final List<String> list, final String value, int targetIndex) {
+ list.remove(value);
+ if (targetIndex < 0 || targetIndex > list.size()) {
+ list.add(value);
+ } else {
+ list.add(targetIndex, value);
+ }
+ }
+
+ /**
+ * Sets the {@link DifferenceState state} of all refining differences to merged.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to set its refining differences to merged.
+ */
+ private void setRefiningDiffsMerged(OpaqueElementBodyChange bodyChange) {
+ for (Diff refiningDiff : bodyChange.getRefinedBy()) {
+ refiningDiff.setState(DifferenceState.MERGED);
+ }
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/OpaqueElementBodyChangePostProcessor.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/OpaqueElementBodyChangePostProcessor.java
new file mode 100644
index 000000000..24e8216c5
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/OpaqueElementBodyChangePostProcessor.java
@@ -0,0 +1,316 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.internal.postprocessor;
+
+import static com.google.common.collect.Iterables.filter;
+
+import com.google.common.base.Predicate;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.common.util.Monitor;
+import org.eclipse.emf.compare.CompareFactory;
+import org.eclipse.emf.compare.Comparison;
+import org.eclipse.emf.compare.Conflict;
+import org.eclipse.emf.compare.ConflictKind;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.Match;
+import org.eclipse.emf.compare.conflict.DefaultConflictDetector;
+import org.eclipse.emf.compare.postprocessor.IPostProcessor;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil;
+import org.eclipse.emf.ecore.EObject;
+
+/**
+ * This post-processor or IConflictDetector adds conflicts specific to opaque element body changes.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class OpaqueElementBodyChangePostProcessor extends DefaultConflictDetector implements IPostProcessor {
+
+ /**
+ * A predicate for {@link Diff} that can be used to check whether the {@link Diff} is a
+ * {@link OpaqueElementBodyChange}.
+ */
+ private static final Predicate<Diff> IS_OPAQUE_ELEMENT_CHANGE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return diff instanceof OpaqueElementBodyChange;
+ }
+ };
+
+ /**
+ * A predicate for {@link Diff} that can be used to check whether the {@link Diff} is a
+ * {@link OpaqueElementBodyChange} and its {@link DifferenceSource} is LEFT.
+ */
+ private static final Predicate<Diff> IS_LEFT_OPAQUE_ELEMENT_CHANGE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return DifferenceSource.LEFT.equals(diff.getSource()) && IS_OPAQUE_ELEMENT_CHANGE.apply(diff);
+ }
+ };
+
+ /**
+ * A predicate for {@link Diff} that can be used to check whether the {@link Diff} is a
+ * {@link OpaqueElementBodyChange} and its {@link DifferenceSource} is RIGHT.
+ */
+ private static final Predicate<Diff> IS_RIGHT_OPAQUE_ELEMENT_CHANGE = new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return DifferenceSource.RIGHT.equals(diff.getSource()) && IS_OPAQUE_ELEMENT_CHANGE.apply(diff);
+ }
+ };
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postMatch(Comparison, Monitor)
+ */
+ public void postMatch(Comparison comparison, Monitor monitor) {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postDiff(Comparison, Monitor)
+ */
+ public void postDiff(Comparison comparison, Monitor monitor) {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postRequirements(Comparison, Monitor)
+ */
+ public void postRequirements(Comparison comparison, Monitor monitor) {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postEquivalences(Comparison, Monitor)
+ */
+ public void postEquivalences(Comparison comparison, Monitor monitor) {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postConflicts(Comparison, Monitor)
+ */
+ public void postConflicts(Comparison comparison, Monitor monitor) {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @see IPostProcessor#postComparison(Comparison, Monitor)
+ */
+ public void postComparison(Comparison comparison, Monitor monitor) {
+ detect(comparison, monitor);
+ }
+
+ /**
+ * Detects and adds conflicts related to changes of the language and bodies of opaque actions, behaviors,
+ * and expressions.
+ *
+ * @param comparison
+ * The comparison to check for conflicts.
+ * @param monitor
+ * The monitor to use for progress reporting.
+ */
+ @Override
+ public void detect(Comparison comparison, Monitor monitor) {
+ final EList<Diff> diffs = comparison.getDifferences();
+ final Iterable<Diff> leftBodyChanges = filter(diffs, IS_LEFT_OPAQUE_ELEMENT_CHANGE);
+ for (Diff leftDiff : leftBodyChanges) {
+ final OpaqueElementBodyChange leftBodyChange = (OpaqueElementBodyChange)leftDiff;
+ final EObject leftOpaqueElement = leftBodyChange.getDiscriminant();
+ final Match opaqueElementMatch = comparison.getMatch(leftOpaqueElement);
+ final EList<Diff> rightDiffs = comparison.getDifferences(opaqueElementMatch.getRight());
+ final Iterable<Diff> rightBodyChanges = filter(rightDiffs, IS_RIGHT_OPAQUE_ELEMENT_CHANGE);
+ for (Diff rightDiff : rightBodyChanges) {
+ OpaqueElementBodyChange rightBodyChange = (OpaqueElementBodyChange)rightDiff;
+ if (isConflicting(leftBodyChange, rightBodyChange)) {
+ final Conflict conflict = createRealConflict(leftBodyChange, rightBodyChange);
+ comparison.getConflicts().add(conflict);
+ }
+ }
+ }
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} is conflicting with the given {@code bodyChange2}. Note
+ * that the conflict relation among differences is symmetric, that means {@code bodyChange1} and
+ * {@code bodyChange2} can be switched and this method returns the same result.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} are conflicting,
+ * <code>false</code> otherwise.
+ */
+ private boolean isConflicting(OpaqueElementBodyChange bodyChange1, OpaqueElementBodyChange bodyChange2) {
+ boolean areConflicting = false;
+ if (concernSameLanguage(bodyChange1, bodyChange2)) {
+ if (areDifferenceKindChange(bodyChange1, bodyChange2)) {
+ areConflicting = isThreeWayTextConflict(bodyChange1);
+ } else if (areDifferenceKindChangeAndDelete(bodyChange1, bodyChange2)) {
+ areConflicting = true;
+ } else if (areDifferenceKindAdd(bodyChange1, bodyChange2)) {
+ areConflicting = true;
+ } else if (areDifferenceKindMove(bodyChange1, bodyChange2)) {
+ areConflicting = true;
+ }
+ }
+ return areConflicting;
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} and {@code bodyChange2} concern the same language
+ * value.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} concern the same language
+ * value, <code>false</code> otherwise.
+ */
+ private boolean concernSameLanguage(OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ return bodyChange1.getLanguage().equals(bodyChange2.getLanguage());
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} CHANGE.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} CHANGE, <code>false</code> otherwise.
+ */
+ private boolean areDifferenceKindChange(OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ return DifferenceKind.CHANGE.equals(bodyChange1.getKind())
+ && DifferenceKind.CHANGE.equals(bodyChange2.getKind());
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} ADD.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} ADD, <code>false</code> otherwise.
+ */
+ private boolean areDifferenceKindAdd(OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ return DifferenceKind.ADD.equals(bodyChange1.getKind())
+ && DifferenceKind.ADD.equals(bodyChange2.getKind());
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} is of {@link DifferenceKind} CHANGE and
+ * {@code bodyChange2} of {@link DifferenceKind} DELETE or vice versa.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} are of {@link DifferenceKind}
+ * CHANGE and {@link DifferenceKind} DELETE or vice versa.
+ */
+ private boolean areDifferenceKindChangeAndDelete(OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ return (DifferenceKind.CHANGE.equals(bodyChange1.getKind()) && DifferenceKind.DELETE
+ .equals(bodyChange2.getKind()))
+ || (DifferenceKind.DELETE.equals(bodyChange1.getKind()) && DifferenceKind.CHANGE
+ .equals(bodyChange2.getKind()));
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} MOVE.
+ *
+ * @param bodyChange1
+ * The one {@code OpaqueElementBodyChange} to check.
+ * @param bodyChange2
+ * The other {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if {@code bodyChange1} and {@code bodyChange2} both are of
+ * {@link DifferenceKind} MOVE, <code>false</code> otherwise.
+ */
+ private boolean areDifferenceKindMove(OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ return DifferenceKind.MOVE.equals(bodyChange1.getKind())
+ && DifferenceKind.MOVE.equals(bodyChange2.getKind());
+ }
+
+ /**
+ * Specifies whether the given {@code bodyChange} is a non-mergeable text change.
+ * <p>
+ * Changes are non-mergeable if they cannot be merged with opposite changes using a line-based three-way
+ * merge algorithm.
+ * </p>
+ *
+ * @param bodyChange
+ * The {@code OpaqueElementBodyChange} to check.
+ * @return <code>true</code> if the change is conflicting (i.e., non-mergeable), <code>false</code>
+ * otherwise.
+ */
+ private boolean isThreeWayTextConflict(OpaqueElementBodyChange bodyChange) {
+ if (bodyChange.getMatch().getOrigin() == null) {
+ return false;
+ }
+
+ final Match match = bodyChange.getMatch();
+ final EObject originContainer = match.getOrigin();
+ final EObject leftContainer = match.getLeft();
+ final EObject rightContainer = match.getRight();
+
+ final String language = bodyChange.getLanguage();
+ final String originBody = UMLCompareUtil.getOpaqueElementBody(originContainer, language);
+ final String leftBody = UMLCompareUtil.getOpaqueElementBody(leftContainer, language);
+ final String rightBody = UMLCompareUtil.getOpaqueElementBody(rightContainer, language);
+
+ return !isMergeableText(leftBody, rightBody, originBody);
+ }
+
+ /**
+ * Creates and returns a {@link Conflict} for the two given {@link OpaqueElementBodyChange changes},
+ * {@code bodyChange1} and {@code bodyChange2}.
+ *
+ * @param bodyChange1
+ * The one {@link OpaqueElementBodyChange} to create a conflict for.
+ * @param bodyChange2
+ * The other {@link OpaqueElementBodyChange} to create a conflict for.
+ * @return The created conflict.
+ */
+ private Conflict createRealConflict(final OpaqueElementBodyChange bodyChange1,
+ OpaqueElementBodyChange bodyChange2) {
+ Conflict conflict = CompareFactory.eINSTANCE.createConflict();
+ conflict.setKind(ConflictKind.REAL);
+ conflict.getDifferences().add(bodyChange1);
+ conflict.getDifferences().add(bodyChange2);
+ return conflict;
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLExtensionFactoryRegistry.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLExtensionFactoryRegistry.java
index 9f19a0d90..477259558 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLExtensionFactoryRegistry.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLExtensionFactoryRegistry.java
@@ -64,6 +64,7 @@ public final class UMLExtensionFactoryRegistry {
factories.add(new UMLStereotypeAttributeChangeFactory());
factories.add(new UMLStereotypeReferenceChangeFactory());
factories.add(new UMLStereotypeApplicationChangeFactory());
+ factories.add(new UMLOpaqueElementBodyChangeFactory());
for (IChangeFactory iDiffExtensionFactory : factories) {
dataset.put(iDiffExtensionFactory.getExtensionKind(), iDiffExtensionFactory);
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLOpaqueElementBodyChangeFactory.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLOpaqueElementBodyChangeFactory.java
new file mode 100644
index 000000000..c13d10a2e
--- /dev/null
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/extension/UMLOpaqueElementBodyChangeFactory.java
@@ -0,0 +1,538 @@
+/*******************************************************************************
+ * Copyright (c) 2014 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:
+ * Philip Langer - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.emf.compare.uml2.internal.postprocessor.extension;
+
+import static com.google.common.base.Predicates.instanceOf;
+import static com.google.common.base.Predicates.or;
+import static com.google.common.collect.Iterables.all;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.collect.Iterables.find;
+import static org.eclipse.emf.compare.DifferenceKind.ADD;
+import static org.eclipse.emf.compare.DifferenceKind.CHANGE;
+import static org.eclipse.emf.compare.DifferenceKind.DELETE;
+import static org.eclipse.emf.compare.DifferenceKind.MOVE;
+import static org.eclipse.emf.compare.utils.EMFComparePredicates.ofKind;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.compare.AttributeChange;
+import org.eclipse.emf.compare.Diff;
+import org.eclipse.emf.compare.DifferenceKind;
+import org.eclipse.emf.compare.DifferenceSource;
+import org.eclipse.emf.compare.uml2.internal.OpaqueElementBodyChange;
+import org.eclipse.emf.compare.uml2.internal.UMLCompareFactory;
+import org.eclipse.emf.compare.uml2.internal.UMLDiff;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.AbstractUMLChangeFactory;
+import org.eclipse.emf.compare.uml2.internal.postprocessor.util.UMLCompareUtil;
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.util.Switch;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.eclipse.uml2.uml.OpaqueBehavior;
+import org.eclipse.uml2.uml.OpaqueExpression;
+import org.eclipse.uml2.uml.UMLPackage;
+
+/**
+ * A change factory for creating {@link OpaqueElementBodyChange changes of bodies} of {@link OpaqueAction
+ * opaque actions}, {@link OpaqueBehavior opaque behaviors}, and {@link OpaqueExpression opaque expressions}.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+public class UMLOpaqueElementBodyChangeFactory extends AbstractUMLChangeFactory {
+
+ @Override
+ public boolean handles(Diff input) {
+ if (input instanceof AttributeChange && !refinesOpaqueElementBodyChange(input)) {
+ final AttributeChange attributeChange = (AttributeChange)input;
+ if (isChangeOfBodyAttributeWithLanguage(attributeChange)
+ || isMoveOfLanguageAttributeValue(attributeChange)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Specifies whether the given {@code diff} refines an {@link OpaqueElementBodyChange}.
+ *
+ * @param diff
+ * The difference to check.
+ * @return <code>true</code> if it refines an {@link OpaqueElementBodyChange}, <code>false</code>
+ * otherwise.
+ */
+ private boolean refinesOpaqueElementBodyChange(Diff diff) {
+ for (Diff refinedDiff : diff.getRefines()) {
+ if (refinedDiff instanceof OpaqueElementBodyChange) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Specifies whether the given {@code diff} is a change of a body attribute value of an
+ * {@link OpaqueAction}, {@link OpaqueBehavior}, or {@link OpaqueExpression} for which a corresponding
+ * language attribute value exists.
+ *
+ * @param diff
+ * The difference to check.
+ * @return <code>true</code> if it is a change of a body value that has a language attribute value,
+ * <code>false</code> otherwise.
+ */
+ private boolean isChangeOfBodyAttributeWithLanguage(AttributeChange diff) {
+ return isChangeOfBodyAttribute(diff) && affectsBodyWithLanguage(diff);
+ }
+
+ /**
+ * Specifies whether the given {@code diff} is a change of the body attribute of {@link OpaqueAction},
+ * {@link OpaqueBehavior}, or {@link OpaqueExpression}.
+ *
+ * @param diff
+ * The attribute change to check.
+ * @return <code>true</code> if it is a change of the body attribute, <code>false</code> otherwise.
+ */
+ private boolean isChangeOfBodyAttribute(AttributeChange diff) {
+ final EAttribute attribute = diff.getAttribute();
+ return UMLPackage.eINSTANCE.getOpaqueAction_Body().equals(attribute)
+ || UMLPackage.eINSTANCE.getOpaqueBehavior_Body().equals(attribute)
+ || UMLPackage.eINSTANCE.getOpaqueExpression_Body().equals(attribute);
+ }
+
+ /**
+ * Specifies whether the given {@code diff} is a change of the language attribute of {@link OpaqueAction},
+ * {@link OpaqueBehavior}, or {@link OpaqueExpression}.
+ *
+ * @param diff
+ * The attribute change to check.
+ * @return <code>true</code> if it is a change of the language attribute, <code>false</code> otherwise.
+ */
+ private boolean isChangeOfLanguageAttribute(AttributeChange diff) {
+ final EAttribute attribute = diff.getAttribute();
+ return UMLPackage.eINSTANCE.getOpaqueAction_Language().equals(attribute)
+ || UMLPackage.eINSTANCE.getOpaqueBehavior_Language().equals(attribute)
+ || UMLPackage.eINSTANCE.getOpaqueExpression_Language().equals(attribute);
+ }
+
+ /**
+ * Specifies whether the given {@code diff} affects a body value for which a language value exists or
+ * whether it affects a language value directly.
+ *
+ * @param diff
+ * The difference to check.
+ * @return <code>true</code> if it affects a body value with a language value, <code>false</code>
+ * otherwise.
+ */
+ private boolean affectsBodyWithLanguage(AttributeChange diff) {
+ return getAffectedLanguage(diff).isPresent();
+ }
+
+ /**
+ * Returns the language value of the body value that is changed by the given {@code diff} or, if
+ * {@code diff} represents a change of a language value directly, this method returns the changed language
+ * value.
+ *
+ * @param diff
+ * The difference to get the language value for.
+ * @return The language value.
+ */
+ private Optional<String> getAffectedLanguage(AttributeChange diff) {
+ Optional<String> language = Optional.absent();
+ if (isChangeOfBodyAttribute(diff)) {
+ final EObject changedObject = getObjectContainingTheChangedValue(diff);
+ final List<String> languages = UMLCompareUtil.getOpaqueElementLanguages(changedObject);
+ final List<String> bodies = UMLCompareUtil.getOpaqueElementBodies(changedObject);
+ final int changedIndex = bodies.indexOf(diff.getValue());
+ language = safeGet(languages, changedIndex);
+ } else if (isChangeOfLanguageAttribute(diff)) {
+ language = Optional.of((String)diff.getValue());
+ }
+ return language;
+ }
+
+ /**
+ * Returns the object that contains the value changed by the given {@code diff}.
+ * <p>
+ * If {@code diff} is a deletion, it will return the object that still contains the deleted value; that
+ * is, the object in the origin model or in the model of the opposite side of the deletion. Otherwise, it
+ * will return the object of the changed side.
+ * </p>
+ *
+ * @param diff
+ * The difference to get the object containing the changed value for.
+ * @return The object containing the changed value.
+ */
+ private EObject getObjectContainingTheChangedValue(AttributeChange diff) {
+ if (!DELETE.equals(diff.getKind())) {
+ return getDifferenceSourceEObject(diff);
+ } else {
+ return getOriginalSideEObject(diff);
+ }
+ }
+
+ /**
+ * Returns the object of the source side of the given {@code diff}.
+ * <p>
+ * This is the object of the side at which the given {@code diff} has been performed (e.g., where the
+ * added value has been added, the changed value has been set, etc.). Thus, in the returned object, the
+ * {@code diff} will already be effective.
+ * </p>
+ *
+ * @param diff
+ * The difference to get the source side for.
+ * @return The source-side object affected by the {@code diff}.
+ */
+ private EObject getDifferenceSourceEObject(AttributeChange diff) {
+ if (DifferenceSource.LEFT.equals(diff.getSource())) {
+ return diff.getMatch().getLeft();
+ } else {
+ return diff.getMatch().getRight();
+ }
+ }
+
+ /**
+ * Returns the object of the original side of the given {@code diff}.
+ * <p>
+ * This is the object affected by {@code diff} of the original side; that is, either the origin in a
+ * three-way scenario or the opposite of the difference source side in a two-way scenario.
+ * </p>
+ *
+ * @param diff
+ * The difference to get the original-side object for.
+ * @return The original-side object affected by the {@code diff}.
+ */
+ private EObject getOriginalSideEObject(AttributeChange diff) {
+ final EObject changedObject;
+ if (diff.getMatch().getComparison().isThreeWay()) {
+ changedObject = diff.getMatch().getOrigin();
+ } else {
+ if (DifferenceSource.RIGHT.equals(diff.getSource())) {
+ changedObject = diff.getMatch().getLeft();
+ } else {
+ changedObject = diff.getMatch().getRight();
+ }
+ }
+ return changedObject;
+ }
+
+ /**
+ * Returns the {@link Optional optional} value at {@code index} from the given {@code list}.
+ * <p>
+ * If the index is out of bounds or -1, this method will return {@link Optional#absent()}.
+ * </p>
+ *
+ * @param list
+ * The list to get the value from.
+ * @param index
+ * The index to get from the list.
+ * @return The value at index, or {@link Optional#absent()} if index is out of bounds or -1.
+ */
+ private Optional<String> safeGet(final List<String> list, final int index) {
+ final Optional<String> item;
+ if (index != -1 && list.size() > index) {
+ item = Optional.of(list.get(index));
+ } else {
+ item = Optional.absent();
+ }
+ return item;
+ }
+
+ /**
+ * Specifies whether the given {@code diff} represents a move of a value of a language attribute.
+ *
+ * @param diff
+ * The {@code diff} to check.
+ * @return <code>true</code> if it is a move of a value in a language attribute.
+ */
+ private boolean isMoveOfLanguageAttributeValue(AttributeChange diff) {
+ return MOVE.equals(diff.getKind()) && isChangeOfLanguageAttribute(diff);
+ }
+
+ @Override
+ public Diff create(Diff input) {
+ final OpaqueElementBodyChange extension = (OpaqueElementBodyChange)super.create(input);
+ // getAffectedLanguage must yield a value at this point, otherwise we wouldn't have
+ // returned true when handle was called
+ extension.setLanguage(getAffectedLanguage((AttributeChange)input).get());
+ extension.setKind(computeDifferenceKind(extension));
+ extension.setSource(input.getSource());
+ extension.getImplies().addAll(extension.getRefinedBy());
+ return extension;
+ }
+
+ /**
+ * Determines the difference kind of the given {@code bodyChange} based on its refining differences.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to get its difference kind.
+ * @return The difference kind of {@code bodyChange}.
+ */
+ private DifferenceKind computeDifferenceKind(OpaqueElementBodyChange bodyChange) {
+ final DifferenceKind differenceKind;
+ final List<Diff> refiningDiffs = bodyChange.getRefinedBy();
+ if (all(refiningDiffs, ofKind(ADD))) {
+ differenceKind = ADD;
+ } else if (all(refiningDiffs, ofKind(DELETE))) {
+ differenceKind = DELETE;
+ } else if (all(refiningDiffs, ofKind(MOVE))) {
+ differenceKind = MOVE;
+ } else {
+ differenceKind = CHANGE;
+ }
+ return differenceKind;
+ }
+
+ @Override
+ public void setRefiningChanges(Diff extension, DifferenceKind extensionKind, Diff refiningDiff) {
+ final OpaqueElementBodyChange bodyChange = (OpaqueElementBodyChange)extension;
+ bodyChange.getRefinedBy().add(refiningDiff);
+ collectAndAddOtherRefiningDiffs(bodyChange, refiningDiff);
+ }
+
+ /**
+ * Collects all {@link #isRefiningDiff(OpaqueElementBodyChange) refining differences} for the given
+ * {@code bodyChange} from all differences of the match of the {@code bodyChange} and adds it to the
+ * {@link Diff#getRefinedBy() refining differences} of {@code bodyChange}.
+ *
+ * @param bodyChange
+ * The {@link OpaqueElementBodyChange} to collect the refining changes for.
+ * @param refiningDiff
+ * The difference that is refining {@code bodyChange}.
+ */
+ private void collectAndAddOtherRefiningDiffs(final OpaqueElementBodyChange bodyChange, Diff refiningDiff) {
+ final RefinementCollector collector = new RefinementCollector((AttributeChange)refiningDiff);
+ Iterable<Diff> collectedRefiningDiffs = collector.collect();
+ for (Diff otherRefiningDiff : collectedRefiningDiffs) {
+ bodyChange.getRefinedBy().add(otherRefiningDiff);
+ }
+ }
+
+ /**
+ * A collector for obtaining the refining differences of an {@link OpaqueElementBodyChange} based on a
+ * reference differences.
+ *
+ * @author Philip Langer <planger@eclipsesource.com>
+ */
+ private class RefinementCollector {
+ /** The reference difference. */
+ private final AttributeChange referenceDiff;
+
+ /** The language of the reference difference. */
+ private String language;
+
+ /**
+ * Creates a new collector for the given {@code referenceDiff}.
+ *
+ * @param referenceDiff
+ * The reference difference that is used to collect the other refining differences.
+ */
+ public RefinementCollector(AttributeChange referenceDiff) {
+ this.referenceDiff = referenceDiff;
+ this.language = getLanguage(referenceDiff).get();
+ }
+
+ /**
+ * Collects all refining differences from all differences of the match of the reference difference.
+ *
+ * @return The refining differences that have been selected based on the given reference difference.
+ */
+ public Iterable<Diff> collect() {
+ final EList<Diff> differencesOfMatch = referenceDiff.getMatch().getDifferences();
+ return filter(differencesOfMatch, isRefiningDiff());
+ }
+
+ /**
+ * Returns a predicate determining whether a {@link Diff} is a difference that refines
+ * {@link #referenceDiff}.
+ *
+ * @return The predicate that can be used for checking whether a {@link Diff} refines
+ * {@link #referenceDiff}.
+ */
+ private Predicate<Diff> isRefiningDiff() {
+ return new Predicate<Diff>() {
+ public boolean apply(Diff diff) {
+ return diff instanceof AttributeChange
+ && isRefiningAttributeChange((AttributeChange)diff);
+ }
+ };
+ }
+
+ /**
+ * Specifies whether {@code attributeChange} is a refinement of an {@link OpaqueElementBodyChange}
+ * that is refined by the {@link #referenceDiff}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if {@code attributeChange} is a refinement with respect to
+ * {@link #referenceDiff}, <code>false</code> otherwise.
+ */
+ private boolean isRefiningAttributeChange(AttributeChange attributeChange) {
+ return isChangeOfBodyOrLanguageAttribute(attributeChange) //
+ && isOnSameSide(referenceDiff, attributeChange) //
+ && concernsSameObjectAndLanguage(attributeChange) //
+ && isCorrespondingChangeType(attributeChange);
+ }
+
+ /**
+ * Specifies whether two differences, {@code diff1} and {@code diff2} have the same difference source.
+ *
+ * @param diff1
+ * The first difference to check.
+ * @param diff2
+ * The second difference to check.
+ * @return <code>true</code> if they have the same difference source, <code>false</code> otherwise.
+ */
+ private boolean isOnSameSide(final Diff diff1, Diff diff2) {
+ return diff1.getSource().equals(diff2.getSource());
+ }
+
+ /**
+ * Specifies whether {@code attributeChange} affects the same object and the same language as
+ * {@link #referenceDiff}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if {@code attributeChange} concern the same object and language as
+ * {@link #referenceDiff} does, <code>false</code> otherwise.
+ */
+ private boolean concernsSameObjectAndLanguage(AttributeChange attributeChange) {
+ return concernsSameObject(attributeChange) && concernsSameLanguage(attributeChange);
+ }
+
+ /**
+ * Specifies whether {@code attributeChange} affects the same container object as
+ * {@link #referenceDiff}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if {@code attributeChange} concerns the same container object as
+ * {@link #referenceDiff}, <code>false</code> otherwise.
+ */
+ private boolean concernsSameObject(AttributeChange attributeChange) {
+ return referenceDiff.getMatch().equals(attributeChange.getMatch());
+ }
+
+ /**
+ * Specifies whether {@code attributeChange} concerns the same language as {@link #referenceDiff}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if {@code attributeChange} concern the same language, <code>false</code>
+ * otherwise.
+ */
+ private boolean concernsSameLanguage(AttributeChange attributeChange) {
+ return language.equals(getLanguage(attributeChange).get());
+ }
+
+ /**
+ * Returns the {@link Optional optional} language of the given {@code attributeChange}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to get the language for.
+ * @return The language of the {@code attributeChange} or {@link Optional#absent()} if not available.
+ */
+ private Optional<String> getLanguage(AttributeChange attributeChange) {
+ final Optional<String> languageOfAttributeChange;
+ if (isChangeOfBodyAttribute(attributeChange)) {
+ languageOfAttributeChange = getAffectedLanguage(attributeChange);
+ } else if (isChangeOfLanguageAttribute(attributeChange)) {
+ languageOfAttributeChange = Optional.of((String)attributeChange.getValue());
+ } else {
+ languageOfAttributeChange = Optional.absent();
+ }
+ return languageOfAttributeChange;
+ }
+
+ /**
+ * Specifies whether {@code attributeChange} has a change types (i.e., add, delete, move, change) that
+ * corresponds to the one of {@link #referenceDiff}. The change types correspond either if both are
+ * moves or if both are anything else except for moves.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if the change types correspond to each other, <code>false</code>
+ * otherwise.
+ */
+ private boolean isCorrespondingChangeType(AttributeChange attributeChange) {
+ final boolean isCorrespondingChangeType;
+ if (MOVE.equals(referenceDiff.getKind())) {
+ isCorrespondingChangeType = MOVE.equals(attributeChange.getKind());
+ } else {
+ isCorrespondingChangeType = !MOVE.equals(attributeChange.getKind());
+ }
+ return isCorrespondingChangeType;
+ }
+
+ /**
+ * Specifies whether the given {@code attributeChange} is either a change of the body attribute or a
+ * change of the language attribute of an {@link OpaqueAction}, {@link OpaqueBehavior}, or
+ * {@link OpaqueExpression}.
+ *
+ * @param attributeChange
+ * The {@link AttributeChange} to check.
+ * @return <code>true</code> if it is a body change or a language change, <code>false</code>
+ * otherwise.
+ */
+ private boolean isChangeOfBodyOrLanguageAttribute(AttributeChange attributeChange) {
+ return isChangeOfBodyAttribute(attributeChange) || isChangeOfLanguageAttribute(attributeChange);
+ }
+
+ }
+
+ @Override
+ public Class<? extends UMLDiff> getExtensionKind() {
+ return OpaqueElementBodyChange.class;
+ }
+
+ @Override
+ public UMLDiff createExtension() {
+ return UMLCompareFactory.eINSTANCE.createOpaqueElementBodyChange();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected EObject getDiscriminant(Diff input) {
+ return find(getDiscriminants(input), or(instanceOf(OpaqueAction.class),
+ instanceOf(OpaqueBehavior.class), instanceOf(OpaqueExpression.class)), null);
+ }
+
+ @Override
+ protected Switch<Set<EObject>> getDiscriminantsGetter() {
+ return new DiscriminantsGetter() {
+ @Override
+ public Set<EObject> caseOpaqueAction(OpaqueAction object) {
+ return getObjectAsSet(object);
+ }
+
+ @Override
+ public Set<EObject> caseOpaqueBehavior(OpaqueBehavior object) {
+ return getObjectAsSet(object);
+ }
+
+ @Override
+ public Set<EObject> caseOpaqueExpression(OpaqueExpression object) {
+ return getObjectAsSet(object);
+ }
+
+ private Set<EObject> getObjectAsSet(EObject object) {
+ Set<EObject> result = new HashSet<EObject>();
+ result.add(object);
+ return result;
+ }
+ };
+ }
+
+}
diff --git a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/util/UMLCompareUtil.java b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/util/UMLCompareUtil.java
index e90fe128b..e825471c3 100644
--- a/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/util/UMLCompareUtil.java
+++ b/plugins/org.eclipse.emf.compare.uml2/src/org/eclipse/emf/compare/uml2/internal/postprocessor/util/UMLCompareUtil.java
@@ -15,6 +15,7 @@ import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EObject;
@@ -22,6 +23,9 @@ import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Extension;
+import org.eclipse.uml2.uml.OpaqueAction;
+import org.eclipse.uml2.uml.OpaqueBehavior;
+import org.eclipse.uml2.uml.OpaqueExpression;
import org.eclipse.uml2.uml.util.UMLUtil;
/**
@@ -128,4 +132,72 @@ public final class UMLCompareUtil {
}
}
+ /**
+ * Returns the bodies of the given {@code eObject}, which must be either an OpaqueAction, OpaqueBehavior,
+ * or an OpaqueExpression.
+ *
+ * @throws IllegalArgumentException
+ * If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
+ * @param eObject
+ * The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the bodies of.
+ * @return The bodies of {@code eObject}.
+ */
+ public static List<String> getOpaqueElementBodies(EObject eObject) {
+ final List<String> bodies;
+ if (eObject instanceof OpaqueAction) {
+ bodies = ((OpaqueAction)eObject).getBodies();
+ } else if (eObject instanceof OpaqueBehavior) {
+ bodies = ((OpaqueBehavior)eObject).getBodies();
+ } else if (eObject instanceof OpaqueExpression) {
+ bodies = ((OpaqueExpression)eObject).getBodies();
+ } else {
+ throw new IllegalArgumentException(eObject.eClass().getName()
+ + " has no bodies. Only OpaqueAction, OpaqueBehavior, and OpaqueExpression do."); //$NON-NLS-1$
+ }
+ return bodies;
+ }
+
+ /**
+ * Returns the languages of the given {@code eObject}, which must be either an OpaqueAction,
+ * OpaqueBehavior, or an OpaqueExpression.
+ *
+ * @throws IllegalArgumentException
+ * If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
+ * @param eObject
+ * The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the languages of.
+ * @return The bodies of {@code eObject}.
+ */
+ public static List<String> getOpaqueElementLanguages(EObject eObject) {
+ final List<String> languages;
+ if (eObject instanceof OpaqueAction) {
+ languages = ((OpaqueAction)eObject).getLanguages();
+ } else if (eObject instanceof OpaqueBehavior) {
+ languages = ((OpaqueBehavior)eObject).getLanguages();
+ } else if (eObject instanceof OpaqueExpression) {
+ languages = ((OpaqueExpression)eObject).getLanguages();
+ } else {
+ throw new IllegalArgumentException(eObject.eClass().getName()
+ + " has no languages. Only OpaqueAction, OpaqueBehavior, and OpaqueExpression do."); //$NON-NLS-1$
+ }
+ return languages;
+ }
+
+ /**
+ * Returns the body for the given {@code language} of the given {@code eObject}, which must be either an
+ * OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
+ *
+ * @throws IllegalArgumentException
+ * If {@code eObject} is not a OpaqueAction, OpaqueBehavior, or an OpaqueExpression.
+ * @param eObject
+ * The OpaqueAction, OpaqueBehavior, or an OpaqueExpression to get the body of.
+ * @param language
+ * The language for which the body is requested.
+ * @return The body for the given {@code language} of the given {@code eObject}.
+ */
+ public static String getOpaqueElementBody(EObject eObject, String language) {
+ final List<String> languages = getOpaqueElementLanguages(eObject);
+ final List<String> bodies = getOpaqueElementBodies(eObject);
+ final int index = languages.indexOf(language);
+ return bodies.get(index);
+ }
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
index 6a92bb38d..779e17f90 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/conflict/DefaultConflictDetector.java
@@ -570,7 +570,23 @@ public class DefaultConflictDetector implements IConflictDetector {
final EObject originalContainer = diff1.getMatch().getOrigin();
final EAttribute changedAttribute = diff1.getAttribute();
final String originalValue = (String)originalContainer.eGet(changedAttribute);
- ThreeWayTextDiff textDiff = new ThreeWayTextDiff(originalValue, changedValue1, changedValue2);
+ return isMergeableText(changedValue1, changedValue2, originalValue);
+ }
+
+ /**
+ * Specifies whether the given three versions of a text {@code left}, {@code right}, and {@code origin}
+ * are mergeable with a line-based three-way merge.
+ *
+ * @param left
+ * The left version.
+ * @param right
+ * The right version.
+ * @param origin
+ * The original version.
+ * @return <code>true</code> if they are mergeable, false otherwise.
+ */
+ protected boolean isMergeableText(final String left, final String right, final String origin) {
+ ThreeWayTextDiff textDiff = new ThreeWayTextDiff(origin, left, right);
return !textDiff.isConflicting();
}
diff --git a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
index fefab1464..afc57ba5d 100644
--- a/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
+++ b/plugins/org.eclipse.emf.compare/src/org/eclipse/emf/compare/merge/AttributeChangeMerger.java
@@ -454,7 +454,23 @@ public class AttributeChangeMerger extends AbstractMerger {
final String leftValue = (String)safeEGet(match.getLeft(), attribute);
final String rightValue = (String)safeEGet(match.getRight(), attribute);
- ThreeWayTextDiff textDiff = new ThreeWayTextDiff(originValue, leftValue, rightValue);
+ return performThreeWayTextMerge(leftValue, rightValue, originValue);
+ }
+
+ /**
+ * Performs a three-way text merge for the given {@code origin}, {@code left}, and {@code right} text
+ * versions.
+ * @param left
+ * The left version of the String.
+ * @param right
+ * The right version of the String.
+ * @param origin
+ * The original version of the String.
+ *
+ * @return The merged version.
+ */
+ protected String performThreeWayTextMerge(final String left, final String right, final String origin) {
+ ThreeWayTextDiff textDiff = new ThreeWayTextDiff(origin, left, right);
return textDiff.getMerged();
}

Back to the top