Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorptessier2015-05-20 12:52:15 +0000
committerptessier2015-05-20 12:52:15 +0000
commitcf3536db70cc3aca49f447ad5f7b416a4ec948b7 (patch)
treea3d2a6ecddb30039593b52e12dde5ea9c0c95255 /extraplugins
parent573be2fe9ca598c3897c869b5ff7289da9ae33cf (diff)
downloadorg.eclipse.papyrus-cf3536db70cc3aca49f447ad5f7b416a4ec948b7.tar.gz
org.eclipse.papyrus-cf3536db70cc3aca49f447ad5f7b416a4ec948b7.tar.xz
org.eclipse.papyrus-cf3536db70cc3aca49f447ad5f7b416a4ec948b7.zip
447870: [Papyrus Req] Papyrus shall import or export reqIF file
https://bugs.eclipse.org/bugs/show_bug.cgi?id=447870 Finalize re-import Change-Id: I3b6b416bbc2c21063c78fee6059e1fb01bcb240c
Diffstat (limited to 'extraplugins')
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/BasicRequirementMerger.java425
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/I_RI.java34
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/ReqIFImporter.java8
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/BasicRequirementMerger.java391
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/CopierWithoutContainment.java473
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/EqualityHelperWithoutContainment.java341
-rw-r--r--extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/IRequirementMerger.java33
7 files changed, 1243 insertions, 462 deletions
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/BasicRequirementMerger.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/BasicRequirementMerger.java
deleted file mode 100644
index 03648923a96..00000000000
--- a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/BasicRequirementMerger.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/*****************************************************************************
- * Copyright (c) 2015 CEA LIST.
- *
- *
- * 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:
- * Mauricio Alferez (CEA LIST) mauricio.alferez@cea.fr - Initial API and implementation
- * Patrick Tessier (CEA LIST) patrick.tesseir@cea.fr- modification
- *
- *****************************************************************************/
-package org.eclipse.papyrus.req.reqif.transformation;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-import org.eclipse.emf.ecore.EObject;
-import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.jface.dialogs.MessageDialog;
-import org.eclipse.swt.widgets.Shell;
-import org.eclipse.uml2.uml.Class;
-import org.eclipse.uml2.uml.Classifier;
-import org.eclipse.uml2.uml.Comment;
-import org.eclipse.uml2.uml.Element;
-import org.eclipse.uml2.uml.NamedElement;
-import org.eclipse.uml2.uml.Package;
-import org.eclipse.uml2.uml.PackageableElement;
-import org.eclipse.uml2.uml.Property;
-import org.eclipse.uml2.uml.Stereotype;
-import org.eclipse.uml2.uml.UMLFactory;
-/**
- * This is a basic merger in order to add requirement from right to left
- * could be improved by using hashmap
- * This algorithm is n2
- *
- */
-public class BasicRequirementMerger {
-
- protected Package leftPackage=null;
- protected Package rightPackage=null;
- protected String matchProperty=null;
- protected String changeableProperty=null;
- protected HashMap<String, Element> leftIndex= new HashMap<>();
- protected HashMap<String, Element> rightIndex= new HashMap<>();
-
- /**
- * Merge information from version2 into version1
- *
- * @param leftPackage
- * is the package where we will do the modifications
- * @param rightPackage
- * is the package that we will analyze
- * @param matchProperty
- * is the stereotype's property name used to determine if one
- * element in basePk is the same than other element in extPk. For
- * example, "id" is a good matchProperty when comparing SysML
- * Requirements
- * @param changeableProperty
- * is the property that we will change if the value of
- * copyAllPropertyValues is false. For example "text".
- * **/
- public BasicRequirementMerger(Package leftPackage, Package rightPackage, String matchProperty, String changeableProperty) {
- this.leftPackage=leftPackage;
- this.rightPackage=rightPackage;
- this.matchProperty=matchProperty;
- this.changeableProperty=changeableProperty;
- }
-
- /**
- *
- *@param checkPackageName
- * is an option. true means that the matched packaged elements
- * must be in packages with the same name.
- * @param copyAllPropertyValues
- * is an option. true means that the user wants to copy the name
- * and all the stereotype values. This option disables the
- * changeableProperty parameter.
- * @param deleteFromBase
- * is an option. True means that element that not match with right will be removed
- * @return true merge finishes successfully
- */
- public boolean merge(boolean checkPackageName, boolean copyAllPropertyValues, boolean deleteFromBase) {
- boolean merged = false;
- merged = updateAndAddFromRight(leftPackage, rightPackage, matchProperty, changeableProperty, checkPackageName, copyAllPropertyValues);
- if (merged && deleteFromBase == I_RI.DELETE_FROM_BASE) {
- deleteInsideLeft( matchProperty, checkPackageName, leftPackage,rightPackage);
- }
- return true;
- }
-
- private boolean deleteInsideLeft(String matchProperty, boolean checkPackageName, Package basePk, Package extPk) {
- List<PackageableElement> delList = new ArrayList<PackageableElement>();
- delList = (getElementsToBeDeleted(basePk, extPk, matchProperty,
- checkPackageName, delList));
- return delList.isEmpty() ? false : confirmDelete( basePk,
- delList, matchProperty);
- }
-
- /**
- * Prepare a list of Packageable Elements to be deleted from basePk
- *
- * @param version1
- * is the package where we will try to find elements to be
- * deleted because they are not anymore in the extPk (which is a
- * version of basePk that evolved separately).
- * @param version2
- * is the package where we will try to find elements that are not
- * in the basePk.
- * @param matchProperty
- * is the stereotype's property name used to determine if one
- * element in basePk is the same than other element in extPk. For
- * example, "id" is a good matchProperty when comparing SysML
- * Requirements
- * @param delList
- * empty list that will store the packageableElements to be
- * deleted.
- * @return list of packageableElements to be deleted.
- */
- private List<PackageableElement> getElementsToBeDeleted(
- org.eclipse.uml2.uml.Package version1,
- org.eclipse.uml2.uml.Package version2, String matchProperty,
- boolean checkPackageName, List<PackageableElement> delList) {
-
-// for (PackageableElement peInBasePk : version1.getPackagedElements()) {
-// if (peInBasePk instanceof org.eclipse.uml2.uml.Class
-// && peInBasePk.getAppliedStereotypes().size() > 0) {
-// Stereotype stOfPeInBasePk = peInBasePk.getAppliedStereotypes()
-// .get(0);
-// boolean foundMatch = false;
-// foundMatch = matchStereotypedPackagedElements(version2,
-// peInBasePk, stOfPeInBasePk, matchProperty, null,
-// checkPackageName, !I_RI.PERFORM_CHANGES,
-// !I_RI.COPY_All_PROPERTY_VALUES);
-// if (!foundMatch) {
-// delList.add(peInBasePk);
-// }
-// } else if (peInBasePk instanceof Package) {
-// return getElementsToBeDeleted((Package) peInBasePk, version2,
-// matchProperty, checkPackageName, delList);
-// }
-// }
- return delList;
- }
-
- /**
- * Confirm to delete or not a list of packageable elements
- *
- * @param window IWorkbenchWindow to receive the confirmation to delete the elements
- * @param baseModel package or model where the elements in delList will be deleted
- * @param delList list of elements to be deleted
- * @param matchProperty
- * is the stereotype's property name used to determine if one
- * element in basePk is the same than other element in
- * externalPk. For example "id" when comparing SysML
- * Requirements.
- * @return true if deletion finishes successfully
- */
- private boolean confirmDelete(Package baseModel,
- List<PackageableElement> delList, String matchProperty) {
- StringBuffer humanReadableList = new StringBuffer();
-
- for (PackageableElement pe : delList) {
- humanReadableList.append("\n"
- + matchProperty
- + I_RI.TOOL_PROPERTY_SEPARATOR
- + pe.getValue(pe.getAppliedStereotypes().get(0),
- matchProperty) + "\t"
- + I_RI.PACKAGED_ELEMENT_NAME_ATT
- + I_RI.TOOL_PROPERTY_SEPARATOR + pe.getName());
- }
- if (MessageDialog.openQuestion(new Shell(), I_RI.TOOL_TITLE,
- I_RI.TOOL_DEL_CONFIRM + humanReadableList)) {
- return deletePackagedElements(delList, baseModel, matchProperty);
- }
- return false;
- }
-
- /**
- * Delete a list of packageable elements without any confirmation from the user
- *
- * @param delList list of elements to be deleted
- * @param basePk
- * @param matchProperty
- * @return
- */
- private boolean deletePackagedElements(List<PackageableElement> delList,
- Package basePk, String matchProperty) {
- for (Iterator<PackageableElement> elementsToDelete = delList.iterator(); elementsToDelete
- .hasNext();) {
- PackageableElement del = elementsToDelete.next();
- Stereotype stOfDel = del.getAppliedStereotypes().get(0);
- String matchInDel = (String) del.getValue(stOfDel, matchProperty);
-
- for (Iterator<PackageableElement> elementsInBasePk = basePk
- .getPackagedElements().iterator(); elementsInBasePk
- .hasNext();) {
- PackageableElement peInBasePk = elementsInBasePk.next();
- if (peInBasePk instanceof org.eclipse.uml2.uml.Class
- && peInBasePk.getAppliedStereotypes().size() > 0) {
- Stereotype stOfmatchInBasePk = peInBasePk
- .getAppliedStereotypes().get(0);
- String matchInBasePk = (String) peInBasePk.getValue(
- stOfmatchInBasePk, matchProperty);
- if (matchInDel.trim().contentEquals(matchInBasePk.trim())) {
- peInBasePk.destroy();
- break;
- }
- } else if (peInBasePk instanceof Package) {
- return deletePackagedElements(delList,
- (Package) peInBasePk, matchProperty);
- }
- }
- }
- return true;
- }
-
-
- /**
- * Merge information from version2 into version1
- *
- * @param leftContainer
- * is the package where we will do the modifications
- * @param rightContainer
- * is the package that we will analyze
- * @param matchProperty
- * is the stereotype's property name used to determine if one
- * element in basePk is the same than other element in extPk. For
- * example, "id" is a good matchProperty when comparing SysML
- * Requirements
- * @param changeableProperty
- * is the property that we will change if the value of
- * copyAllPropertyValues is false. For example "text".
- * @param chkPkNameOption
- * is an option. true means that the matched packaged elements
- * must be in packages with the same name.
- * @param copyOption
- * is an option. true means that the user wants to copy the name
- * and all the stereotype values. This option disables the
- * changeableProperty parameter.
- * @return true merge finishes successfully
- */
- private boolean updateAndAddFromRight(org.eclipse.uml2.uml.Element leftContainer, org.eclipse.uml2.uml.Element rightContainer, String matchProperty,
- String changeableProperty, boolean chkPkNameOption, boolean copyOption) {
- for (Element subElementFromRight : rightContainer.getOwnedElements()) {
- Element foundLeftElement = null;
- if (subElementFromRight.getAppliedStereotypes().size() > 0) {
- Stereotype appliedStereotypeFromRight= subElementFromRight.getAppliedStereotypes().get(0);
-
- foundLeftElement = matchStereotypedPackagedElements(leftContainer,subElementFromRight, appliedStereotypeFromRight, matchProperty,
- changeableProperty);
- if(foundLeftElement!=null){
- copyConfig(subElementFromRight, appliedStereotypeFromRight, changeableProperty,foundLeftElement, appliedStereotypeFromRight, copyOption);
-
- }
- else {
- foundLeftElement = addElementInsideLeft(leftContainer, subElementFromRight, appliedStereotypeFromRight);
- }
- }
- if (subElementFromRight.getOwnedElements().size()>0) {
- return updateAndAddFromRight(foundLeftElement, subElementFromRight, matchProperty, changeableProperty, chkPkNameOption, copyOption);
- }
- }
- return true;
- }
-
- /**
- * Add a packageable element from right to left
- *
- * @param leftContainer
- * is the package where we will add new elements from rightPackage.
- * @param elementFromRight
- * Packageable element in Right package.
- * @param appliedSterotypeRight
- * stereotype of peInExtPk.
- * @return createdElement
- */
- private Element addElementInsideLeft(Element leftContainer,Element elementFromRight, Stereotype appliedSterotypeRight) {
- Element result= null;
- EObject stApplication_right = elementFromRight.getStereotypeApplication(appliedSterotypeRight);
- ArrayList<EObject> subsetToCopy=new ArrayList<EObject>();
- subsetToCopy.add(elementFromRight);
- subsetToCopy.add(elementFromRight.getStereotypeApplication(appliedSterotypeRight));
- Collection<EObject> copy=EcoreUtil.copyAll(subsetToCopy);
- for (EObject eObject : copy) {
- if( eObject instanceof Element){
- if( eObject instanceof Comment){
- (leftContainer).getOwnedComments().add((Comment) eObject);}
- else if( leftContainer instanceof Package && eObject instanceof PackageableElement ){
- ((Package)leftContainer).getPackagedElements().add((PackageableElement) eObject);}
- else if( leftContainer instanceof Classifier && eObject instanceof Classifier){
- ((Class)leftContainer).getNestedClassifiers().add((Classifier) eObject);}
- else{
- System.err.println("Impossible to add "+ eObject+ " inside"+ leftContainer);
- }
- result=(Element) eObject;
- }
- else{
- leftContainer.eResource().getContents().add(eObject);
- }
- }
- return result;
- }
-
- /**
- * Copy all not derived stereotype property values without changing the base
- * class
- *
- * @param peInExtPk
- * Packageable element in external package.
- * @param stOfExtPe
- * stereotype of peInExtPk.
- * @param peInBasePk
- * Packageable element in base package that will receive the new
- * values from peInExtPk.
- */
- private void copyAllStereotypePropertyValues(Element peInExtPk,
- Stereotype stOfExtPe, Element peInBasePk) {
- for (Property stProperty : stOfExtPe.getAllAttributes()) {
- if (!stProperty.isReadOnly() && !stProperty.isDerived()
- && !stProperty.getName().startsWith("base_")) {
- peInBasePk.setValue(stOfExtPe, stProperty.getName(),
- peInExtPk.getValue(stOfExtPe, stProperty.getName()));
- }
- }
- }
-
- /**
- * Matches two stereotyped packageable elements based on a matchProperty at the current level
- *
- * @param containerLeft
- * is the container where we look for elementRight
- * @param elementRight
- * is the stereotyped PackagedElement to be matched. For example,
- * the packaged element of type "org.eclipse.uml2.uml.Class"
- * stereotyped with "ReqType5".
- * @param appliedStereotypeRight
- * is the Stereotype that defines the matchProperty. For example,
- * the stereotype "ReqType5" defines the matchProperty "id".
- * @param matchProperty
- * is the stereotype's property name used to determine if one
- * element in basePk matches other element in extPk. For example,
- * the stereotype "Requirement" in the profile SysML Requirements
- * defines the property "id" that is used frequently as a
- * matchProperty.
- * @param changeableProperty
- * is the property whose value will be changed. For example the
- * property "text" in the stereotype "Requirement".
- * @param checkPackageName
- * is an option. true means that the matched packaged elements
- * must be in packages with the same name.
- * @param performChanges
- * is an option. true means that the user wants to actually
- * change the value of changeableProperty. false will disable the
- * copyAllPropertyValues option.
-
- * @return the element that matches
- */
- private Element matchStereotypedPackagedElements(Element containerLeft, Element elementRight,
- Stereotype appliedStereotypeRight, String matchProperty,String changeableProperty) {
- String matchPropertyValueRight = (String) elementRight.getValue(appliedStereotypeRight, matchProperty);
- if(matchPropertyValueRight!=null){
- for (Element subElementLeft : containerLeft.getOwnedElements()) {
- if (subElementLeft.getAppliedStereotypes().size() > 0) {
- Stereotype appliedStereotypeLeft = subElementLeft.getAppliedStereotypes().get(0);
- if (appliedStereotypeLeft.getName().equals(appliedStereotypeRight.getName())) {
- String matchPropertyValueLeft = (String) subElementLeft.getValue(appliedStereotypeLeft, matchProperty);
- if(matchPropertyValueLeft!=null){
- if (matchPropertyValueRight.trim().equals(matchPropertyValueLeft.trim())) {
- return subElementLeft;
- }
- }
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Copy the name of an element and either one or all stereotype property
- * values depending on the parameter copyOption
- *
- * @param rightElement
- * is the packageable element in external package
- * @param AppliedStereotypeRight
- * is the stereotype of peInExtPk
- * @param changeableProperty
- * is the property to copy when the value of copyOption is false
- * @param leftElement
- * is the stereotyped packageable element whose value(s) will be
- * modified.
- * @param stOfPeInBasePk
- * is the stereotype of peInBasePk
- * @param copyOption
- * is the copy option. true means to copy all the stereotype
- * property values. false means to copy only the property in the
- * parameter changeableProperty.
- */
- private void copyConfig(Element rightElement, Stereotype AppliedStereotypeRight,
- String changeableProperty, Element leftElement,
- Stereotype appliedStereotype, boolean copyOption) {
- if (copyOption == I_RI.COPY_All_PROPERTY_VALUES) {
- if( leftElement instanceof NamedElement){
- ((NamedElement)leftElement).setName(((NamedElement)rightElement).getName());
- }
- for (Stereotype st : leftElement.getAppliedStereotypes()) {
- copyAllStereotypePropertyValues(rightElement, st, leftElement);
- }
- } else if (copyOption != I_RI.COPY_All_PROPERTY_VALUES) {
- leftElement.setValue(appliedStereotype, changeableProperty,
- rightElement.getValue(AppliedStereotypeRight, changeableProperty));
- }
- }
-
-}
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/I_RI.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/I_RI.java
deleted file mode 100644
index 495a4d35d1b..00000000000
--- a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/I_RI.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.eclipse.papyrus.req.reqif.transformation;
-
-public interface I_RI {
- /** name of the stereotype "Requirement" */
- public static final String REQ = "Requirement";
- /** name of property "text" of the stereotype "Requirement" */
- public static final String REQ_TEXT_ATT = "text";
- /** name of property "id" of the stereotype "Requirement" */
- public static final String REQ_ID_ATT = "id";
- /** name of property "name" of PackagedElement */
- public static final String PACKAGED_ELEMENT_NAME_ATT = "name";
- /** Qualified name of stereotype Requirement */
- public static final String REQ_STEREOTYPE = "SysML::Requirements::Requirement";
- /** Delete from the base model the requirements that are not in the external model*/
- public static final boolean DELETE_FROM_BASE = true;
- /** Copy all contents without references to the original object during a merge process. If it is true, it will overwrite the "changeable parameter" parameter */
- public static final boolean COPY_All_PROPERTY_VALUES = true;
- /** Change values in properties when the matchStereotypedPackagedElements method finds a match */
- public static final boolean PERFORM_CHANGES = true;
- /** Check package name during matching*/
- public static final boolean CHECK_PACKAGE_NAME = true;
- /** name to show in at the beginning of user messages */
- public static final String TOOL_TITLE = "Papyrus SysML REQ Reimport";
- /** Confirmation message to make sure that the user really wants to delete requirements in base model*/
- public static final String TOOL_DEL_CONFIRM = "Do you really want to delete: ";
- /** Papyrus REQ reimport message when the tool finished without problems */
- public static final String TOOL_SUCCESS = "Successfull re-import";
- /** Papyrus REQ reimport message when the tool finished with problems */
- public static final String TOOL_FAIL = "UnSuccessfull re-import";
- /** Constant message when a File cannot be read*/
- public static final String TOOL_ERR_FILE_READ ="Not Readable files";
- /** Constant property value separator*/
- public static final String TOOL_PROPERTY_SEPARATOR =": ";
-}
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/ReqIFImporter.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/ReqIFImporter.java
index c682503e91c..7cf3b6da8c3 100644
--- a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/ReqIFImporter.java
+++ b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/transformation/ReqIFImporter.java
@@ -43,6 +43,8 @@ import org.eclipse.papyrus.req.reqif.assistant.CreateOrSelectProfilDialog;
import org.eclipse.papyrus.req.reqif.assistant.SelectProfilDialog;
import org.eclipse.papyrus.req.reqif.integration.assistant.ChooseAttributeEnumerationDialog;
import org.eclipse.papyrus.req.reqif.preference.ReqIFPreferenceConstants;
+import org.eclipse.papyrus.req.reqif.util.BasicRequirementMerger;
+import org.eclipse.papyrus.req.reqif.util.IRequirementMerger;
import org.eclipse.papyrus.uml.extensionpoints.profile.IRegisteredProfile;
import org.eclipse.papyrus.uml.extensionpoints.profile.RegisteredProfile;
import org.eclipse.papyrus.uml.extensionpoints.utils.Util;
@@ -316,9 +318,9 @@ public abstract class ReqIFImporter extends ReqIFBaseTransformation {
}
targetUMLModel=reImportModel;
boolean importResult= importReqIFModel ( interactive);
- BasicRequirementMerger merger= new BasicRequirementMerger(firstVersion, targetUMLModel, I_RI.REQ_ID_ATT,null);
- merger.merge( !I_RI.CHECK_PACKAGE_NAME, I_RI.COPY_All_PROPERTY_VALUES, I_RI.DELETE_FROM_BASE);
-
+ IRequirementMerger merger= new BasicRequirementMerger(firstVersion, targetUMLModel, I_SysMLStereotype.REQUIREMENT_ID_ATT, true, domain);
+ merger.merge();
+ firstVersion.eResource().getContents().remove(targetUMLModel);
return importResult;
}
/**
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/BasicRequirementMerger.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/BasicRequirementMerger.java
new file mode 100644
index 00000000000..02f1e354811
--- /dev/null
+++ b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/BasicRequirementMerger.java
@@ -0,0 +1,391 @@
+/*****************************************************************************
+ * Copyright (c) 2015 CEA LIST.
+ *
+ *
+ * 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:
+ * Mauricio Alferez (CEA LIST) mauricio.alferez@cea.fr - Initial API and implementation
+ * Patrick Tessier (CEA LIST) patrick.tesseir@cea.fr- modification
+ *
+ *****************************************************************************/
+package org.eclipse.papyrus.req.reqif.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.transaction.TransactionalEditingDomain;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.emf.type.core.requests.DestroyElementRequest;
+import org.eclipse.papyrus.infra.services.edit.service.ElementEditServiceUtils;
+import org.eclipse.papyrus.infra.services.edit.service.IElementEditService;
+import org.eclipse.uml2.uml.Class;
+import org.eclipse.uml2.uml.Classifier;
+import org.eclipse.uml2.uml.Comment;
+import org.eclipse.uml2.uml.Element;
+import org.eclipse.uml2.uml.NamedElement;
+import org.eclipse.uml2.uml.Package;
+import org.eclipse.uml2.uml.PackageableElement;
+import org.eclipse.uml2.uml.Property;
+import org.eclipse.uml2.uml.Stereotype;
+/**
+ * This is a basic merger in order to add requirement from right to left
+ * could be improved by using hashmap
+ * This algorithm is n2
+ *
+ */
+public class BasicRequirementMerger implements IRequirementMerger {
+
+ protected Package leftPackage=null;
+ protected Package rightPackage=null;
+ protected String matchProperty=null;
+ protected String changeableProperty=null;
+ protected EqualityHelperWithoutContainment equalityHelper= new EqualityHelperWithoutContainment();
+ protected CopierWithoutContainment copier= new CopierWithoutContainment();
+ protected TransactionalEditingDomain domain;
+ protected ArrayList<Element> elementToDelete= new ArrayList<Element>();
+ protected ArrayList<Element> addedElements= new ArrayList<Element>();
+ protected boolean deleteElements=true;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.papyrus.req.reqif.transformation.IRequirementMerger#getElementToDelete()
+ */
+ @Override
+ public ArrayList<Element> getElementToDelete() {
+ return elementToDelete;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.papyrus.req.reqif.transformation.IRequirementMerger#getAddedElements()
+ */
+ @Override
+ public ArrayList<Element> getAddedElements() {
+ return addedElements;
+ }
+
+
+ /**
+ * Merge information from version2 into version1
+ *
+ * @param leftPackage
+ * is the package where we will do the modifications
+ * @param rightPackage
+ * is the package that we will analyze
+ * @param matchProperty
+ * is the stereotype's property name used to determine if one
+ * element in basePk is the same than other element in extPk. For
+ * example, "id" is a good matchProperty when comparing SysML
+ * Requirements
+ * @param changeableProperty
+ * is the property that we will change if the value of
+ * copyAllPropertyValues is false. For example "text".
+ * **/
+ public BasicRequirementMerger(Package leftPackage, Package rightPackage, String matchProperty, boolean deleteElements, TransactionalEditingDomain domain) {
+ this.leftPackage=leftPackage;
+ this.rightPackage=rightPackage;
+ this.matchProperty=matchProperty;
+ this.domain=domain;
+ this.deleteElements=deleteElements;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.papyrus.req.reqif.transformation.IRequirementMerger#merge()
+ */
+ @Override
+ public boolean merge() {
+ boolean merged = false;
+ equalityHelper=new EqualityHelperWithoutContainment();
+ merged = updateAndAddFromRight(leftPackage, rightPackage, matchProperty);
+ equalityHelper=new EqualityHelperWithoutContainment();
+ if (merged ) {
+ deleteInsideLeft( matchProperty, leftPackage,rightPackage);
+ }
+ return true;
+ }
+
+ /**
+ *
+ * @param matchProperty the property if stereotype used to delete element
+ * @param checkPackageName
+ * @param leftPackage the package where element will be removed
+ * @param rightPackage the package that will be compared
+ */
+ protected void deleteInsideLeft(String matchProperty, Package leftPackage, Package rightPackage) {
+ elementToDelete = getElementsToBeDeleted(leftPackage, rightPackage, matchProperty, elementToDelete);
+ filterReq( matchProperty);
+ if(deleteElements){
+ deleteElements(elementToDelete, leftPackage);
+ }
+ }
+
+ /**
+ * filter elements that has an ID property
+ * @param matchProperty
+ */
+ protected void filterReq(String matchProperty) {
+ ArrayList<Element> result= new ArrayList<Element>();
+ for (Element elementToDelete : elementToDelete) {
+ if( elementToDelete.getAppliedStereotypes().size()>0){
+ Stereotype appliedStereotype=elementToDelete.getAppliedStereotypes().get(0);
+ if((elementToDelete.getStereotypeApplication(appliedStereotype)).eClass().getEStructuralFeature(matchProperty)!=null){
+ String idValue= (String) elementToDelete.getValue(appliedStereotype, matchProperty);
+ if( idValue!=null){
+ result.add(elementToDelete);
+ }
+ }
+ }
+ }
+ elementToDelete=result;
+
+ }
+
+ /**
+ * Prepare a list of Packageable Elements to be deleted from basePk
+ *
+ * @param version1
+ * is the package where we will try to find elements to be
+ * deleted because they are not anymore in the extPk (which is a
+ * version of basePk that evolved separately).
+ * @param version2
+ * is the package where we will try to find elements that are not
+ * in the basePk.
+ * @param matchProperty
+ * is the stereotype's property name used to determine if one
+ * element in basePk is the same than other element in extPk. For
+ * example, "id" is a good matchProperty when comparing SysML
+ * Requirements
+ * @param delList
+ * empty list that will store the packageableElements to be
+ * deleted.
+ * @return list of packageableElements to be deleted.
+ */
+ protected ArrayList<Element> getElementsToBeDeleted(
+ Element containerLeft, Element containerRight,
+ String matchProperty,ArrayList<Element> delList) {
+
+ for (Element elementLeft : containerLeft.getOwnedElements()) {
+ Element foundRightElement = null;
+ foundRightElement = lookforEquivalent(containerRight,elementLeft, matchProperty);
+ if(foundRightElement==null){
+ delList.add(elementLeft);
+ }
+ if (elementLeft.getOwnedElements().size()>0&&foundRightElement!=null) {
+ getElementsToBeDeleted(elementLeft, foundRightElement, matchProperty, delList);
+ }
+ }
+ return delList;
+ }
+
+
+ /**
+ * Delete a list of packageable elements without any confirmation from the user
+ *
+ * @param delList list of elements to be deleted
+ * @param basePk the container of all element it can be indirect.
+ * @param matchProperty
+ * @return true if no problems
+ */
+ protected boolean deleteElements(List<Element> delList, Package basePk) {
+ IElementEditService provider = ElementEditServiceUtils.getCommandProvider(basePk);
+ if(provider == null) {
+ return false;
+ }
+
+ for (Element elementToDelete : delList) {
+ if( elementToDelete!=null){
+ ICommand createGMFCommand = provider.getEditCommand(new DestroyElementRequest(domain, elementToDelete, false));
+
+ if(createGMFCommand != null) {
+ Command emfCommand = new org.eclipse.papyrus.commands.wrappers.GMFtoEMFCommandWrapper(createGMFCommand);
+ domain.getCommandStack().execute(emfCommand);
+ }
+ }
+ }
+ return true;
+ }
+
+
+ /**
+ * Merge information from right into left
+ *
+ * @param leftContainer
+ * is the package where we will do the modifications
+ * @param rightContainer
+ * is the package that we will analyze
+ * @param matchProperty
+ * is the stereotype's property name used to determine if one
+ * element in basePk is the same than other element in extPk. For
+ * example, "id" is a good matchProperty when comparing SysML
+ * Requirements
+ * @param changeableProperty
+ * is the property that we will change if the value of
+ * copyAllPropertyValues is false. For example "text".
+ * @param copyOption
+ * is an option. true means that the user wants to copy the name
+ * and all the stereotype values. This option disables the
+ * changeableProperty parameter.
+ * @return true merge finishes successfully
+ */
+ protected boolean updateAndAddFromRight(org.eclipse.uml2.uml.Element leftContainer, org.eclipse.uml2.uml.Element rightContainer, String matchProperty) {
+ for (Element subElementFromRight : rightContainer.getOwnedElements()) {
+ Element foundLeftElement = null;
+ foundLeftElement = lookforEquivalent(leftContainer,subElementFromRight, matchProperty);
+ if(foundLeftElement!=null){
+ copyConfig(subElementFromRight, foundLeftElement);
+
+ }
+ else {
+ foundLeftElement = addElementInsideLeft(leftContainer, subElementFromRight);
+ }
+
+ if (subElementFromRight.getOwnedElements().size()>0) {
+ updateAndAddFromRight(foundLeftElement, subElementFromRight, matchProperty);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Add an element from right to left
+ *
+ * @param leftContainer
+ * is the package where we will add new elements from rightPackage.
+ * @param elementFromRight
+ * element in Right package.
+ * @param appliedSterotypeRight
+ * stereotype of peInExtPk.
+ * @return createdElement
+ */
+ protected Element addElementInsideLeft(Element leftContainer,Element elementFromRight) {
+ Element result= null;
+ ArrayList<EObject> subsetToCopy=new ArrayList<EObject>();
+ subsetToCopy.add(elementFromRight);
+ for (EObject stereoAppli : elementFromRight.getStereotypeApplications()) {
+ subsetToCopy.add(stereoAppli);
+ }
+
+
+ Collection<EObject> copy=copier.copyAll(subsetToCopy);
+ copier.copyReferences();
+ for (EObject eObject : copy) {
+ if( eObject instanceof Element){
+ addedElements.add((Element)eObject);
+ if( eObject instanceof Comment){
+ (leftContainer).getOwnedComments().add((Comment) eObject);}
+ else if( leftContainer instanceof Package && eObject instanceof PackageableElement ){
+ ((Package)leftContainer).getPackagedElements().add((PackageableElement) eObject);}
+ else if( leftContainer instanceof Classifier && eObject instanceof Classifier){
+ ((Class)leftContainer).getNestedClassifiers().add((Classifier) eObject);}
+ else{
+ System.err.println("Impossible to add "+ eObject+ " inside"+ leftContainer);
+ }
+ result=(Element) eObject;
+ }
+ else{
+ leftContainer.eResource().getContents().add(eObject);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Copy all not derived stereotype property values without changing the base
+ * class
+ *
+ * @param peInExtPk
+ * Packageable element in external package.
+ * @param stOfExtPe
+ * stereotype of peInExtPk.
+ * @param peInBasePk
+ * Packageable element in base package that will receive the new
+ * values from peInExtPk.
+ */
+ protected void copyAllStereotypePropertyValues(Element peInExtPk,
+ Stereotype stOfExtPe, Element peInBasePk) {
+ for (Property stProperty : stOfExtPe.getAllAttributes()) {
+ if (!stProperty.isReadOnly() && !stProperty.isDerived() && !stProperty.getName().startsWith("base_")) {
+ peInBasePk.setValue(stOfExtPe, stProperty.getName(),peInExtPk.getValue(stOfExtPe, stProperty.getName()));
+ }
+ }
+ }
+
+ /**
+ * Matches two stereotyped packageable elements based on a matchProperty at the current level
+ *
+ * @param researchSpace
+ * is the container where we look for elementRight
+ * @param wantedElement
+ * is the stereotyped PackagedElement to be matched. For example,
+ * the packaged element of type "org.eclipse.uml2.uml.Class"
+ * stereotyped with "ReqType5".
+ * @param matchProperty
+ * is the stereotype's property name used to determine if one
+ * element in basePk matches other element in extPk. For example,
+ * the stereotype "Requirement" in the profile SysML Requirements
+ * defines the property "id" that is used frequently as a
+ * matchProperty.
+
+ * @return the element that matches
+ */
+ protected Element lookforEquivalent(Element researchSpace, Element wantedElement, String matchProperty) {
+
+ for (Element potentialElement : researchSpace.getOwnedElements()) {
+ if(equalityHelper.equals(potentialElement, wantedElement)){
+
+ if(wantedElement.getAppliedStereotypes().size()==0){
+ return potentialElement;
+ }
+ //they have a stereotype
+ Stereotype wantedAppliedStereotype=wantedElement.getAppliedStereotypes().get(0);
+ //have they the same applied stereotype?
+ if(!potentialElement.isStereotypeApplied(wantedAppliedStereotype)){
+ return null;
+ }
+ String wantedPropertyValue = null;
+ String potentialPropertyValueLeft=null;
+ if((wantedElement.getStereotypeApplication(wantedAppliedStereotype)).eClass().getEStructuralFeature(matchProperty)!=null){
+ wantedPropertyValue = (String) wantedElement.getValue(wantedAppliedStereotype, matchProperty);
+ }
+ if((potentialElement.getStereotypeApplication(wantedAppliedStereotype)).eClass().getEStructuralFeature(matchProperty)!=null){
+ potentialPropertyValueLeft = (String) potentialElement.getValue(wantedAppliedStereotype, matchProperty);
+ }
+ if(potentialPropertyValueLeft==null && wantedPropertyValue==null){
+ return potentialElement;
+ }
+ if(potentialPropertyValueLeft!=null&&wantedPropertyValue!=null){
+ if (wantedPropertyValue.trim().equals(potentialPropertyValueLeft.trim())) {
+ return potentialElement;
+ }
+ }
+ }
+
+ }
+ return null;
+ }
+
+ /**
+ * Copy the name of an element and either one or all stereotype property
+ * values depending on the parameter copyOption
+ *
+ * @param rightElement
+ * is the packageable element in external package
+ * @param leftElement
+ * is the stereotyped packageable element whose value(s) will be
+ * modified.
+ */
+ protected void copyConfig(Element rightElement, Element leftElement) {
+ if( leftElement instanceof NamedElement){
+ ((NamedElement)leftElement).setName(((NamedElement)rightElement).getName());
+ }
+ for (Stereotype st : leftElement.getAppliedStereotypes()) {
+ copyAllStereotypePropertyValues(rightElement, st, leftElement);
+ }
+ }
+}
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/CopierWithoutContainment.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/CopierWithoutContainment.java
new file mode 100644
index 00000000000..b937a390e3d
--- /dev/null
+++ b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/CopierWithoutContainment.java
@@ -0,0 +1,473 @@
+package org.eclipse.papyrus.req.reqif.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.ecore.util.FeatureMapUtil;
+import org.eclipse.emf.ecore.util.InternalEList;
+
+/**
+ * A mapping building traverser of a collection of {@link EObject#eAllContents content trees};
+ * the map is from {@link EObject} to <code>EObject</code>, i.e., from original to copy;
+ * use {@link EcoreUtil#copy EcoreUtil.copy} or {@link EcoreUtil#copyAll EcoreUtil.copyAll} to do routine copies.
+ * Since this implementation extends a Map implementation, it acts as the result of the over all copy.
+ * The client can call {@link #copy copy} and {@link #copyAll copyAll} repeatedly.
+ * When all the objects have been copied,
+ * the client should call {@link #copyReferences copyReferences}
+ * to copy the {@link #copyReference appropriate} {@link EObject#eCrossReferences cross references}.
+ *<pre>
+ * Copier copier = new Copier();
+ * EObject result = copier.copy(eObject);
+ * Collection results = copier.copyAll(eObjects);
+ * copier.copyReferences();
+ *</pre>
+ * The copier delegates to {@link #copyContainment copyContainment}, {@link #copyAttribute copyAttribute} during the copy phase
+ * and to {@link #copyReference copyReference}, during the cross reference phase.
+ * This allows tailored handling through derivation.
+ */
+public class CopierWithoutContainment extends LinkedHashMap<EObject, EObject>
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Whether proxies should be resolved during copying.
+ */
+ protected boolean resolveProxies = true;
+
+ /**
+ * Whether non-copied references should be used during copying.
+ */
+ protected boolean useOriginalReferences = true;
+
+ /**
+ * Creates an instance.
+ */
+ public CopierWithoutContainment()
+ {
+ super();
+ }
+
+ /**
+ * Creates an instance that resolves proxies or not as specified.
+ * @param resolveProxies whether proxies should be resolved while copying.
+ */
+ public CopierWithoutContainment(boolean resolveProxies)
+ {
+ this.resolveProxies = resolveProxies;
+ }
+
+ /**
+ * Creates an instance that resolves proxies or not and uses non-copied references or not as specified.
+ * @param resolveProxies whether proxies should be resolved while copying.
+ * @param useOriginalReferences whether non-copied references should be used while copying.
+ */
+ public CopierWithoutContainment(boolean resolveProxies, boolean useOriginalReferences)
+ {
+ this.resolveProxies = resolveProxies;
+ this.useOriginalReferences = useOriginalReferences;
+ }
+
+ /**
+ * Returns a collection containing a copy of each EObject in the given collection.
+ * @param eObjects the collection of objects to copy.
+ * @return the collection of copies.
+ */
+ public <T> Collection<T> copyAll(Collection<? extends T> eObjects)
+ {
+ Collection<T> result = new ArrayList<T>(eObjects.size());
+ for (Object object : eObjects)
+ {
+ @SuppressWarnings("unchecked") T t = (T)copy((EObject)object);
+ if (t != null)
+ {
+ result.add(t);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns a copy of the given eObject.
+ * @param eObject the object to copy.
+ * @return the copy.
+ */
+ public EObject copy(EObject eObject)
+ {
+ if (eObject == null)
+ {
+ return null;
+ }
+ else
+ {
+ EObject copyEObject = createCopy(eObject);
+ if (copyEObject != null)
+ {
+ put(eObject, copyEObject);
+ EClass eClass = eObject.eClass();
+ for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
+ {
+ EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(i);
+ if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
+ {
+ if (eStructuralFeature instanceof EAttribute)
+ {
+ copyAttribute((EAttribute)eStructuralFeature, eObject, copyEObject);
+ }
+ else
+ {
+ EReference eReference = (EReference)eStructuralFeature;
+ if (eReference.isContainment())
+ {
+ //copyContainment(eReference, eObject, copyEObject);
+ }
+ }
+ }
+ }
+
+ copyProxyURI(eObject, copyEObject);
+ }
+
+ return copyEObject;
+ }
+ }
+
+ /**
+ * Copies the proxy URI from the original to the copy, if present.
+ * @param eObject the object being copied.
+ * @param copyEObject the copy being initialized.
+ */
+ protected void copyProxyURI(EObject eObject, EObject copyEObject)
+ {
+ if (eObject.eIsProxy())
+ {
+ ((InternalEObject)copyEObject).eSetProxyURI(((InternalEObject)eObject).eProxyURI());
+ }
+ }
+
+ /**
+ * Returns a new instance of the object's target class.
+ * @param eObject the object to copy.
+ * @return a new instance of the target class.
+ * @see #getTarget(EObject)
+ * @see EcoreUtil#create(EClass)
+ */
+ protected EObject createCopy(EObject eObject)
+ {
+ EClass eClass = getTarget(eObject);
+ return eClass == null ? null : EcoreUtil.create(eClass);
+ }
+
+ /**
+ * Returns the target class used to create a copy instance for the given instance object.
+ * @param eObject the object to be copied.
+ * @return the target class used to create a copy instance.
+ * @since 2.10
+ */
+ protected EClass getTarget(EObject eObject)
+ {
+ return getTarget(eObject.eClass());
+ }
+
+ /**
+ * Returns the target class used to create a copy instance for objects of the given source class.
+ * @param eClass the source class.
+ * @return the target class used to create a copy instance.
+ * @see #getTarget(EStructuralFeature, EObject, EObject)
+ */
+ protected EClass getTarget(EClass eClass)
+ {
+ return eClass;
+ }
+
+ /**
+ * Returns a setting for the feature and copy instance to be populated with the original object's source feature's value.
+ * @param eStructuralFeature the source feature.
+ * @return the target feature used to populate a copy instance.
+ * @see #getTarget(EStructuralFeature)
+ * @see #getTarget(EObject)
+ * @since 2.10
+ */
+ protected EStructuralFeature.Setting getTarget(EStructuralFeature eStructuralFeature, EObject eObject, EObject copyEObject)
+ {
+ EStructuralFeature targetEStructuralFeature = getTarget(eStructuralFeature);
+ return targetEStructuralFeature == null ? null : ((InternalEObject)copyEObject).eSetting(targetEStructuralFeature);
+ }
+
+ /**
+ * Returns the target feature used to populate a copy instance from the given source feature.
+ * @param eStructuralFeature the source feature.
+ * @return the target feature used to populate a copy instance.
+ * @see #getTarget(EClass)
+ */
+ protected EStructuralFeature getTarget(EStructuralFeature eStructuralFeature)
+ {
+ return eStructuralFeature;
+ }
+
+ /**
+ * Called to handle the copying of a containment feature;
+ * this adds a list of copies or sets a single copy as appropriate for the multiplicity.
+ * @param eReference the feature to copy.
+ * @param eObject the object from which to copy.
+ * @param copyEObject the object to copy to.
+ */
+ protected void copyContainment(EReference eReference, EObject eObject, EObject copyEObject)
+ {
+ if (eObject.eIsSet(eReference))
+ {
+ EStructuralFeature.Setting setting = getTarget(eReference, eObject, copyEObject);
+ if (setting != null)
+ {
+ Object value = eObject.eGet(eReference);
+ if (eReference.isMany())
+ {
+ @SuppressWarnings("unchecked")
+ List<EObject> target = (List<EObject>)value;
+ setting.set(copyAll(target));
+ }
+ else
+ {
+ setting.set(copy((EObject)value));
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to handle the copying of an attribute;
+ * this adds a list of values or sets a single value as appropriate for the multiplicity.
+ * @param eAttribute the attribute to copy.
+ * @param eObject the object from which to copy.
+ * @param copyEObject the object to copy to.
+ */
+ protected void copyAttribute(EAttribute eAttribute, EObject eObject, EObject copyEObject)
+ {
+ if (eObject.eIsSet(eAttribute))
+ {
+ if (FeatureMapUtil.isFeatureMap(eAttribute))
+ {
+ FeatureMap featureMap = (FeatureMap)eObject.eGet(eAttribute);
+ copyFeatureMap(featureMap);
+ }
+ else
+ {
+ EStructuralFeature.Setting setting = getTarget(eAttribute, eObject, copyEObject);
+ if (setting != null)
+ {
+ copyAttributeValue(eAttribute, eObject, eObject.eGet(eAttribute), setting);
+ }
+ }
+ }
+ }
+
+ /**
+ * Call to handle copying the contained objects within a feature map.
+ * @param featureMap the feature map the copy.
+ * @since 2.10
+ */
+ protected void copyFeatureMap(FeatureMap featureMap)
+ {
+ for (int i = 0, size = featureMap.size(); i < size; ++i)
+ {
+ EStructuralFeature feature = featureMap.getEStructuralFeature(i);
+ if (feature instanceof EReference && ((EReference)feature).isContainment())
+ {
+ Object value = featureMap.getValue(i);
+ if (value != null)
+ {
+ // The containment references are hooked up later during copyReferences.
+ //
+ copy((EObject)value);
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to handle copying of an attribute's value to the target setting.
+ * @param eAttribute the attribute of the source object corresponding to the value.
+ * @param eObject the object being copied.
+ * @param value the value to be copied.
+ * @param setting the feature-value pair that is the target of of the copy.
+ * @since 2.10
+ */
+ protected void copyAttributeValue(EAttribute eAttribute, EObject eObject, Object value, EStructuralFeature.Setting setting)
+ {
+ setting.set(value);
+ }
+
+ /**
+ * Hooks up cross references; it delegates to {@link #copyReference copyReference}.
+ */
+ public void copyReferences()
+ {
+ for (Map.Entry<EObject, EObject> entry : entrySet())
+ {
+ EObject eObject = entry.getKey();
+ EObject copyEObject = entry.getValue();
+ EClass eClass = eObject.eClass();
+ for (int j = 0, size = eClass.getFeatureCount(); j < size; ++j)
+ {
+ EStructuralFeature eStructuralFeature = eClass.getEStructuralFeature(j);
+ if (eStructuralFeature.isChangeable() && !eStructuralFeature.isDerived())
+ {
+ if (eStructuralFeature instanceof EReference)
+ {
+ EReference eReference = (EReference)eStructuralFeature;
+ if (!eReference.isContainment() && !eReference.isContainer())
+ {
+ copyReference(eReference, eObject, copyEObject);
+ }
+ }
+ else if (FeatureMapUtil.isFeatureMap(eStructuralFeature))
+ {
+ FeatureMap copyFeatureMap = (FeatureMap)getTarget(eStructuralFeature, eObject, copyEObject);
+ if (copyFeatureMap != null)
+ {
+ FeatureMap featureMap = (FeatureMap)eObject.eGet(eStructuralFeature);
+ int copyFeatureMapSize = copyFeatureMap.size();
+ for (int k = 0, featureMapSize = featureMap.size(); k < featureMapSize; ++k)
+ {
+ EStructuralFeature feature = featureMap.getEStructuralFeature(k);
+ if (feature instanceof EReference)
+ {
+ Object referencedEObject = featureMap.getValue(k);
+ Object copyReferencedEObject = get(referencedEObject);
+ if (copyReferencedEObject == null && referencedEObject != null)
+ {
+ EReference reference = (EReference)feature;
+ if (!useOriginalReferences || reference.isContainment() || reference.getEOpposite() != null)
+ {
+ continue;
+ }
+ copyReferencedEObject = referencedEObject;
+ }
+
+ // If we can't add it, it must already be in the list so find it and move it to the end.
+ //
+ if (!copyFeatureMap.add(feature, copyReferencedEObject))
+ {
+ for (int l = 0; l < copyFeatureMapSize; ++l)
+ {
+ if (copyFeatureMap.getEStructuralFeature(l) == feature && copyFeatureMap.getValue(l) == copyReferencedEObject)
+ {
+ copyFeatureMap.move(copyFeatureMap.size() - 1, l);
+ --copyFeatureMapSize;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ copyFeatureMap.add(getTarget(featureMap.getEStructuralFeature(k)), featureMap.getValue(k));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Called to handle the copying of a cross reference;
+ * this adds values or sets a single value as appropriate for the multiplicity
+ * while omitting any bidirectional reference that isn't in the copy map.
+ * @param eReference the reference to copy.
+ * @param eObject the object from which to copy.
+ * @param copyEObject the object to copy to.
+ */
+ protected void copyReference(EReference eReference, EObject eObject, EObject copyEObject)
+ {
+ if (eObject.eIsSet(eReference))
+ {
+ EStructuralFeature.Setting setting = getTarget(eReference, eObject, copyEObject);
+ if (setting != null)
+ {
+ Object value = eObject.eGet(eReference, resolveProxies);
+ if (eReference.isMany())
+ {
+ @SuppressWarnings("unchecked") InternalEList<EObject> source = (InternalEList<EObject>)value;
+ @SuppressWarnings("unchecked") InternalEList<EObject> target = (InternalEList<EObject>)setting;
+ if (source.isEmpty())
+ {
+ target.clear();
+ }
+ else
+ {
+ boolean isBidirectional = eReference.getEOpposite() != null;
+ int index = 0;
+ for (Iterator<EObject> k = resolveProxies ? source.iterator() : source.basicIterator(); k.hasNext();)
+ {
+ EObject referencedEObject = k.next();
+ EObject copyReferencedEObject = get(referencedEObject);
+ if (copyReferencedEObject == null)
+ {
+ if (useOriginalReferences && !isBidirectional)
+ {
+ target.addUnique(index, referencedEObject);
+ ++index;
+ }
+ }
+ else
+ {
+ if (isBidirectional)
+ {
+ int position = target.indexOf(copyReferencedEObject);
+ if (position == -1)
+ {
+ target.addUnique(index, copyReferencedEObject);
+ }
+ else if (index != position)
+ {
+ target.move(index, copyReferencedEObject);
+ }
+ }
+ else
+ {
+ target.addUnique(index, copyReferencedEObject);
+ }
+ ++index;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (value == null)
+ {
+ setting.set(null);
+ }
+ else
+ {
+ Object copyReferencedEObject = get(value);
+ if (copyReferencedEObject == null)
+ {
+ if (useOriginalReferences && eReference.getEOpposite() == null)
+ {
+ setting.set(value);
+ }
+ }
+ else
+ {
+ setting.set(copyReferencedEObject);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/EqualityHelperWithoutContainment.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/EqualityHelperWithoutContainment.java
new file mode 100644
index 00000000000..40837da1678
--- /dev/null
+++ b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/EqualityHelperWithoutContainment.java
@@ -0,0 +1,341 @@
+package org.eclipse.papyrus.req.reqif.util;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.eclipse.emf.ecore.EAttribute;
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EReference;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.InternalEObject;
+import org.eclipse.emf.ecore.util.FeatureMap;
+import org.eclipse.emf.ecore.util.FeatureMapUtil;
+
+public class EqualityHelperWithoutContainment extends HashMap<EObject, EObject>
+{
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Returns whether <code>eObject1</code> and <code>eObject2</code> are {@link EqualityHelper equal}
+ * in the context of this helper instance.
+ * @return whether <code>eObject1</code> and <code>eObject2</code> are equal.
+ * @since 2.1.0
+ */
+ public boolean equals(EObject eObject1, EObject eObject2)
+ {
+ // If the first object is null, the second object must be null.
+ //
+ if (eObject1 == null)
+ {
+ return eObject2 == null;
+ }
+
+ // We know the first object isn't null, so if the second one is, it can't be equal.
+ //
+ if (eObject2 == null)
+ {
+ return false;
+ }
+
+ // Both eObject1 and eObject2 are not null.
+ // If eObject1 has been compared already...
+ //
+ Object eObject1MappedValue = get(eObject1);
+ if (eObject1MappedValue != null)
+ {
+ // Then eObject2 must be that previous match.
+ //
+ return eObject1MappedValue == eObject2;
+ }
+
+ // If eObject2 has been compared already...
+ //
+ Object eObject2MappedValue = get(eObject2);
+ if (eObject2MappedValue != null)
+ {
+ // Then eObject1 must be that match.
+ //
+ return eObject2MappedValue == eObject1;
+ }
+
+ // Neither eObject1 nor eObject2 have been compared yet.
+
+ // If eObject1 and eObject2 are the same instance...
+ //
+ if (eObject1 == eObject2)
+ {
+ // Match them and return true.
+ //
+ put(eObject1, eObject2);
+ put(eObject2, eObject1);
+ return true;
+ }
+
+ // If eObject1 is a proxy...
+ //
+ if (eObject1.eIsProxy())
+ {
+ // Then the other object must be a proxy with the same URI.
+ //
+ if (((InternalEObject)eObject1).eProxyURI().equals(((InternalEObject)eObject2).eProxyURI()))
+ {
+ put(eObject1, eObject2);
+ put(eObject2, eObject1);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ // If eObject1 isn't a proxy but eObject2 is, they can't be equal.
+ //
+ else if (eObject2.eIsProxy())
+ {
+ return false;
+ }
+
+ // If they don't have the same class, they can't be equal.
+ //
+ EClass eClass = eObject1.eClass();
+ if (eClass != eObject2.eClass())
+ {
+ return false;
+ }
+
+ // Assume from now on that they match.
+ //
+ put(eObject1, eObject2);
+ put(eObject2, eObject1);
+
+ // Check all the values.
+ //
+ for (int i = 0, size = eClass.getFeatureCount(); i < size; ++i)
+ {
+ // Ignore derived features.
+ //
+ EStructuralFeature feature = eClass.getEStructuralFeature(i);
+ if (!feature.isDerived())
+ {
+ if( feature instanceof EReference){
+ if(! ((EReference)feature).isContainment()){
+ if (!haveEqualFeature(eObject1, eObject2, feature))
+ {
+ remove(eObject1);
+ remove(eObject2);
+ return false;
+ }
+ }
+ }
+ else{
+
+ if (!haveEqualFeature(eObject1, eObject2, feature))
+ {
+ remove(eObject1);
+ remove(eObject2);
+ return false;
+ }
+ }
+ }
+ }
+
+ // There's no reason they aren't equal, so they are.
+ //
+ return true;
+ }
+
+ /**
+ * Returns whether <code>list1</code> and <code>list2</code> contain
+ * {@link #equals(EObject, EObject) equal} {@link EObject}s at the same index.
+ * It is assumed that list1 and list2 only contain EObjects.
+ * @return whether <code>list1</code> and <code>list2</code> contain equal objects.
+ * @since 2.1.0
+ */
+ public boolean equals(List<EObject> list1, List<EObject> list2)
+ {
+ int size = list1.size();
+ if (size != list2.size())
+ {
+ return false;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ EObject eObject1 = list1.get(i);
+ EObject eObject2 = list2.get(i);
+ if (!equals(eObject1, eObject2))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns whether the two objects have {@link EqualityHelper equal}
+ * {@link EObject#eIsSet(EStructuralFeature) isSet} states and {@link EObject#eGet(EStructuralFeature) value}s for the feature.
+ * @return whether the two objects have equal isSet states and values for the feature.
+ * @since 2.2.0
+ * @see #equals(EObject, EObject)
+ * @see #equals(List, List)
+ */
+ protected boolean haveEqualFeature(EObject eObject1, EObject eObject2, EStructuralFeature feature)
+ {
+ // If the set states are the same, and the values of the feature are the structurally equal, they are equal.
+ //
+ final boolean isSet1 = eObject1.eIsSet(feature);
+ final boolean isSet2 = eObject2.eIsSet(feature);
+ if (isSet1 && isSet2)
+ {
+ return
+ feature instanceof EReference ?
+ haveEqualReference(eObject1, eObject2, (EReference)feature) :
+ haveEqualAttribute(eObject1, eObject2, (EAttribute)feature);
+ }
+ else
+ {
+ return isSet1 == isSet2;
+ }
+ }
+
+ /**
+ * Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the reference.
+ * @return whether the two objects have equal values for the reference.
+ * @since 2.1.0
+ * @see #equals(EObject, EObject)
+ * @see #equals(List, List)
+ */
+ @SuppressWarnings("unchecked")
+ protected boolean haveEqualReference(EObject eObject1, EObject eObject2, EReference reference)
+ {
+ Object value1 = eObject1.eGet(reference);
+ Object value2 = eObject2.eGet(reference);
+
+ return
+ reference.isMany() ?
+ equals((List<EObject>)value1, (List<EObject>)value2) :
+ equals((EObject)value1, (EObject)value2);
+ }
+
+
+ /**
+ * Returns whether the two objects have {@link EqualityHelper equal} {@link EObject#eGet(EStructuralFeature) value}s for the attribute.
+ * @return whether the two objects have equal values for the attribute.
+ * @since 2.1.0
+ * @see #equalFeatureMaps(FeatureMap, FeatureMap)
+ */
+ protected boolean haveEqualAttribute(EObject eObject1, EObject eObject2, EAttribute attribute)
+ {
+ Object value1 = eObject1.eGet(attribute);
+ Object value2 = eObject2.eGet(attribute);
+
+ // If the first value is null, the second value must be null.
+ //
+ if (value1 == null)
+ {
+ return value2 == null;
+ }
+
+ // Since the first value isn't null, if the second one is, they aren't equal.
+ //
+ if (value2 == null)
+ {
+ return false;
+ }
+
+ // If this is a feature map...
+ //
+ if (FeatureMapUtil.isFeatureMap(attribute))
+ {
+ // The feature maps must be equal.
+ //
+ FeatureMap featureMap1 = (FeatureMap)value1;
+ FeatureMap featureMap2 = (FeatureMap)value2;
+ return equalFeatureMaps(featureMap1, featureMap2);
+ }
+ else
+ {
+ // The values must be Java equal.
+ //
+ return equalValues(value1, value2);
+ }
+ }
+
+ /**
+ * Returns whether value1 and value2 are structurally equal.
+ * The default implementation only checks for Java equality.
+ * @param value1 the first non-null value.
+ * @param value2 the second potentially null value.
+ * @return whether value1 and value2 are structurally equal.
+ * @since 2.10
+ */
+ protected boolean equalValues(Object value1, Object value2)
+ {
+ return value1.equals(value2);
+ }
+
+ /**
+ * Returns whether the two feature maps are {@link EqualityHelper equal}.
+ * @return whether the two feature maps are equal.
+ * @since 2.1.0
+ */
+ protected boolean equalFeatureMaps(FeatureMap featureMap1, FeatureMap featureMap2)
+ {
+ // If they don't have the same size, the feature maps aren't equal.
+ //
+ int size = featureMap1.size();
+ if (size != featureMap2.size())
+ {
+ return false;
+ }
+
+ // Compare entries in order.
+ //
+ for (int i = 0; i < size; i++)
+ {
+ // If entries don't have the same feature, the feature maps aren't equal.
+ //
+ EStructuralFeature feature = featureMap1.getEStructuralFeature(i);
+ if (feature != featureMap2.getEStructuralFeature(i))
+ {
+ return false;
+ }
+
+ Object value1 = featureMap1.getValue(i);
+ Object value2 = featureMap2.getValue(i);
+
+ if (!equalFeatureMapValues(value1, value2, feature))
+ {
+ return false;
+ }
+ }
+
+ // There is no reason they aren't equals.
+ //
+ return true;
+ }
+
+ /**
+ * Returns whether the two values of a feature map are {@link EqualityHelper equal}.
+ * @return whether the two values of a feature map are equal.
+ * @since 2.2.0
+ */
+ protected boolean equalFeatureMapValues(Object value1, Object value2, EStructuralFeature feature)
+ {
+ if (feature instanceof EReference)
+ {
+ // If the referenced EObjects aren't equal, the feature maps aren't equal.
+ //
+ return equals((EObject)value1, (EObject)value2);
+ }
+ else
+ {
+ // If the values aren't Java equal, the feature maps aren't equal.
+ //
+ return value1 == null ? value2 == null : equalValues(value1, value2);
+ }
+ }
+
+} // EqualityHelper \ No newline at end of file
diff --git a/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/IRequirementMerger.java b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/IRequirementMerger.java
new file mode 100644
index 00000000000..1594fd14e9c
--- /dev/null
+++ b/extraplugins/req/org.eclipse.papyrus.req.reqif/src/org/eclipse/papyrus/req/reqif/util/IRequirementMerger.java
@@ -0,0 +1,33 @@
+package org.eclipse.papyrus.req.reqif.util;
+
+import java.util.ArrayList;
+
+import org.eclipse.uml2.uml.Element;
+
+public interface IRequirementMerger {
+
+ /**
+ *
+ * @return the list that must be deleted during merge
+ */
+ ArrayList<Element> getElementToDelete();
+
+ /**
+ *
+ * @return the list of added element during merge
+ */
+ ArrayList<Element> getAddedElements();
+
+ /**
+ *
+ * @param copyAllPropertyValues
+ * is an option. true means that the user wants to copy the name
+ * and all the stereotype values. This option disables the
+ * changeableProperty parameter.
+ * @param deleteFromBase
+ * is an option. True means that element that not match with right will be removed
+ * @return true merge finishes successfully
+ */
+ boolean merge();
+
+} \ No newline at end of file

Back to the top