/*******************************************************************************
* Copyright (c) 2012 University of Mannheim: Chair for Software Engineering
* 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:
* Ralph Gerbig - initial API and implementation and initial documentation
*******************************************************************************/
package de.uni_mannheim.informatik.swt.mlm.emendation.service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Clabject;
import de.uni_mannheim.informatik.swt.models.plm.PLM.Feature;
import de.uni_mannheim.informatik.swt.models.plm.PLM.PLMPackage;
/**
* Analyzes the impact of changes to a model. All model elements that need to be
* fixed after a change are calculated by this service. This service is the foundation
* for the implementation of all emendation service commands.
*
* <b>
* The result of all search operations is not allowed to contain the origin of
* the impact calculation. This will break the emendation service otherwise.
* </b>
*
*/
public class ImpactAnalyzer{
/**
*
* Collects all model elements effected by a feature move operation. This is the union of
* remove feature at sourceChangeOrigin and add feature at targetChangeOrigin
*
* @param sourceChangeOrigin Clabject from which the feature is moved away
* @param targetChangeOrigin Clabject to which the feature is moved to
* @param movedFeature The feature which is moved
* @return The union of remove feature on source and add feature on target
*/
public Set<EObject> getEffectedModelElementsForMoveFeatureOperation(Clabject sourceChangeOrigin, Clabject targetChangeOrigin, Feature movedFeature){
Set<EObject> result = new HashSet<EObject>();
result.addAll(getEffectedModelElementsForDeleteFeatureOperation(movedFeature, sourceChangeOrigin));
result.addAll(getEffectedModelElementsForAddFeatureOperation(targetChangeOrigin, movedFeature));
return result;
}
/**
* Collects the impact of adding a feature to a clabject. This does not include clabjects which
* do already contain a feature with the name of the added feature.
*
* @param changeOrigin Clabject to which the feature is added to
* @param addedFeature Feature which is added
* @return The list of clabjects to which the feature needs to be added
*/
public Set<Clabject> getEffectedModelElementsForAddFeatureOperation(Clabject changeOrigin, Feature addedFeature){
return getEffectedModelElementsForAddFeatureOperation(changeOrigin, addedFeature, false);
}
/**
* Collects the impact of adding a feature to a clabject. The user can choose whether to include clabjects which
* do already contain a feature with the name of the added feature.
*
* @param changeOrigin changeOrigin Clabject to which the feature is added to
* @param addedFeature Feature which is added
* @param includeDuplicates Whether to include clabjects already containing a feature with the name of the added feature
* @return The list of clabjects to which the feature needs to be added. Depending on the user's choice this can contain
* clabjects which already contain a clabject with a feature that has the same name as the feature to be added
*/
public Set<Clabject> getEffectedModelElementsForAddFeatureOperation(Clabject changeOrigin, Feature addedFeature, boolean includeDuplicates){
return getEffectedModelElementsForAddFeatureOperation(changeOrigin, addedFeature, addedFeature.getName(), includeDuplicates);
}
/**
* Collects the impact of adding a feature to a clabject. The user can choose whether to include clabjects which
* do already contain a feature with the name of the added feature.
*
* @param changeOrigin changeOrigin Clabject to which the feature is added to
* @param addedFeature Feature which is added
* @param includeDuplicates Whether to include clabjects already containing a feature with the name of the added feature
* @param addedFeatureName The name of the added feature. In some cases this is null in the addedFeature parameter but known
* e.g. when called from EmendAddAttributCommand
* @return The list of clabjects to which the feature needs to be added. Depending on the user's choice this can contain
* clabjects which already contain a clabject with a feature that has the same name as the feature to be added
*/
public Set<Clabject> getEffectedModelElementsForAddFeatureOperation(Clabject changeOrigin, Feature addedFeature, String addedFeatureName, boolean includeDuplicates){
return getEffectedModelElementsForAddFeatureOperation(changeOrigin, addedFeature, addedFeature.getName(), includeDuplicates, false, true, true);
}
/**
* Collects the impact of adding a feature to a clabject. The user can choose whether to include clabjects which
* do already contain a feature with the name of the added feature. Can include the supertypes only. This is useful
* in cases where the new feature shall not be added to an subtype in an inheritance hierarchy but to the supertype
* of each inheritance hierarchy.
*
* @param changeOrigin changeOrigin Clabject to which the feature is added to
* @param addedFeature Feature which is added
* @param includeDuplicates Whether to include clabjects already containing a feature with the name of the added feature
* @param addedFeatureName The name of the added feature. In some cases this is null in the addedFeature parameter but known
* e.g. when called from EmendAddAttributCommand
* @param includeSuperTypesOnly returns only the supertypes of inheritance hierarchies.
* @return The list of clabjects to which the feature needs to be added. Depending on the user's choice this can contain
* clabjects which already contain a clabject with a feature that has the same name as the feature to be added
*/
public Set<Clabject> getEffectedModelElementsForAddFeatureOperation(Clabject changeOrigin, Feature addedFeature, String addedFeatureName,
boolean includeDuplicates, boolean includeSuperTypesOnly, boolean includeOntologicalTypes, boolean includeOntologicalInstances){
Set<Clabject> result = new HashSet<Clabject>();
Set<Clabject> currentLevel = new HashSet<Clabject>();
if (!includeSuperTypesOnly)
currentLevel.add(changeOrigin);
else
//Change origin is root of the inheritance hierarchy
if (changeOrigin.getSupertypes().size() == 0)
currentLevel.add(changeOrigin);
else
//Search the root of the inheritance hierarchy
for(Clabject c : changeOrigin.getSupertypes())
if (c.getSupertypes().size() == 0)
currentLevel.add(c);
if (includeOntologicalTypes)
result.addAll(searchLevelForAddFeatureTypeDirection(currentLevel, includeSuperTypesOnly));
result.addAll(currentLevel);
if (includeOntologicalInstances)
result.addAll(searchLevelForAddFeatureInstanceDirection(result, includeSuperTypesOnly));
result.remove(changeOrigin);
if(!includeDuplicates){
Set<Clabject> clabjectsAlreadyContainingFeature = new HashSet<Clabject>();
//Filter out all results that have already the added attribute
for (Clabject c : result)
for (Feature f : c.getFeature())
if (f.getName() != null && f.getName().equals(addedFeatureName))
clabjectsAlreadyContainingFeature.add(c);
result.removeAll(clabjectsAlreadyContainingFeature);
}
return result;
}
/**
* Recursive method to search for clabjects which need the new feature to be added starting
* from the list of clabjects contained in clabjects. Moves upwards in the classification
* hierarchy.
*
* @param clabjects List of clabjects to start recursion from
* @return clabjects that need the feature to be added
*/
private Set<Clabject> searchLevelForAddFeatureTypeDirection(Set<Clabject> clabjects, boolean includeSuperTypesOnly){
Set<Clabject> result = new HashSet<Clabject>();
Set<Clabject> directTypes = new HashSet<Clabject>();
for(Clabject c : clabjects){
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
directTypes.addAll(c.getDirectTypes());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : c.getSubtypes())
directTypes.addAll(subType.getDirectTypes());
result.addAll(directTypes);
result.addAll(searchLevelForAddFeatureTypeDirection(directTypes, includeSuperTypesOnly));
}
//We can take this result if we do not want to have the supertypes only
if (!includeSuperTypesOnly)
return result;
//if we only want to have the supertypes in the inheritance hierarchy,
//we need to search for clabjects with getModelSupertypes()->size = 0
Set<Clabject> inheritanceRootResult = new HashSet<Clabject>();
for (Clabject c : result)
if (c.getSupertypes().size() == 0)
inheritanceRootResult.add(c);
else
for (Clabject superType : c.getSupertypes())
if (superType.getSupertypes().size() == 0)
inheritanceRootResult.add(superType);
return inheritanceRootResult;
}
/**
* Recursive method to search for clabjects which need the new feature to be added starting
* from the list of clabjects contained in clabjects. Moves downwards in the classification
* hierarchy.
*
* @param clabjects List of clabjects to start recursion from
* @return clabjects that need the feature to be added
*/
Set<Clabject> searchLevelForAddFeatureInstanceDirection(Set<Clabject> clabjects, boolean includeSuperTypesOnly){
Set<Clabject> result = new HashSet<Clabject>();
Set<Clabject> directInstances = new HashSet<Clabject>();
for(Clabject c : clabjects){
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
directInstances.addAll(c.getDirectInstances());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : c.getSubtypes())
directInstances.addAll(subType.getDirectInstances());
result.addAll(directInstances);
result.addAll(searchLevelForAddFeatureInstanceDirection(directInstances, includeSuperTypesOnly));
}
//We can take this result if we do not want to have the supertypes only
if (!includeSuperTypesOnly)
return result;
//if we only want to have the supertypes in the inheritance hierarchy,
//we need to search for clabjects with getModelSupertypes()->size = 0
Set<Clabject> inheritanceRootResult = new HashSet<Clabject>();
for (Clabject c : result)
if (c.getSupertypes().size() == 0)
inheritanceRootResult.add(c);
else
for (Clabject superType : c.getSupertypes())
if (superType.getSupertypes().size() == 0)
inheritanceRootResult.add(superType);
return inheritanceRootResult;
}
/**
* Collects the impact of a remove feature operation. All features which need to be removed after
* the feature changeOrigin is deleted are collected.
*
* @param changeOrigin The feature that is about to be deleted from the model
* @param changeOriginContainingClabject The clabject which contains the feature that is about to be deleted
* @return All features that need to be deleted after changeOrigin is deleted
*/
public Set<Feature> getEffectedModelElementsForDeleteFeatureOperation(Feature changeOrigin, Clabject changeOriginContainingClabject){
Set<Feature> result = new HashSet<Feature>();
boolean overridden = false;
//containingClabject.getAllFeatures() works here because this clabject does not contain
//the feature at this point of time anymore
for (Feature f :changeOriginContainingClabject.getAllFeatures())
if(match(changeOrigin, changeOriginContainingClabject, f, PLMPackage.eINSTANCE.getElement_Name(), changeOrigin.getName())){
overridden = true;
break;
}
//If overridden then nothing needs to be done just delete the overriding
if (overridden)
return result;
Set<Feature> currentLevel = new HashSet<Feature>();
currentLevel.add(changeOrigin);
result.addAll(searchLevelForRemoveFeatureTypeDirection(currentLevel, changeOriginContainingClabject, changeOrigin));
result.addAll(currentLevel);
result.addAll(searchLevelForRemoveFeatureInstanceDirection(result, changeOriginContainingClabject, changeOrigin));
result.removeAll(currentLevel);
return result;
}
/**
* Searches for all features that need to be removed after removing the feature stored in changeOrigin.
* Searches the upwards in the classification hierarchy.
*
* @param features List of features to start recursion from
* @param changeOriginContaining Clabject which contains the impact analysis triggering feature
* @param changeOrigin The feature for which the impact analysis was initially triggered
* @return Returns a list with features that need to be deleted after deleting change origin
*/
Set<Feature> searchLevelForRemoveFeatureTypeDirection(Set<Feature> features, Clabject changeOriginContaining, Feature changeOrigin){
Set<Feature> result = new HashSet<Feature>();
Set<Clabject> allTypes = new HashSet<Clabject>();
Set<Feature> allTypesFeatures = new HashSet<Feature>();
for(Feature f : features){
Clabject thisFeatureContainingClabject = null;
if (
//This happens on move. Feature has move target as owner
(f == changeOrigin && f.getClabject() != changeOrigin)
//Happens for origin on delete
|| f.getClabject() == null)
thisFeatureContainingClabject = changeOriginContaining;
else
thisFeatureContainingClabject = f.getClabject();
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
allTypes.addAll(thisFeatureContainingClabject.getModelTypes());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : thisFeatureContainingClabject.getSubtypes())
allTypes.addAll(subType.getModelTypes());
//after collecting the clabjects we must search for the conforming features
for(Clabject c : allTypes)
for (Feature containedFeature : c.getFeature())
if (match(f, thisFeatureContainingClabject, containedFeature, PLMPackage.eINSTANCE.getElement_Name(), f.getName()))
allTypesFeatures.add(containedFeature);
result.addAll(allTypesFeatures);
result.addAll(searchLevelForRemoveFeatureTypeDirection(allTypesFeatures, changeOriginContaining, changeOrigin));
}
return result;
}
/**
* Searches for all features that need to be removed after removing the feature stored in changeOrigin.
* Searches the downwards in the classification hierarchy.
*
* @param features List of features to start recursion from
* @param changeOriginContaining Clabject which contains the impact analysis triggering feature
* @param changeOrigin The feature for which the impact analysis was initially triggered
* @return Returns a list with features that need to be deleted after deleting change origin
*/
Set<Feature> searchLevelForRemoveFeatureInstanceDirection(Set<Feature> features, Clabject changeOriginContaining, Feature changeOrigin){
Set<Feature> result = new HashSet<Feature>();
Set<Clabject> allInstances = new HashSet<Clabject>();
Set<Feature> allInstancesFeatures = new HashSet<Feature>();
for(Feature f : features){
Clabject thisFeatureContainingClabject = null;
if (
//This happens on move. Feature has move target as owner
(f == changeOrigin && f.getClabject() != changeOrigin)
//Happens for origin on delete
|| f.getClabject() == null)
thisFeatureContainingClabject = changeOriginContaining;
else
thisFeatureContainingClabject = f.getClabject();
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
allInstances.addAll(thisFeatureContainingClabject.getInstances());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : thisFeatureContainingClabject.getSubtypes())
allInstances.addAll(subType.getInstances());
//after collecting the clabjects we must search for the conforming features
for(Clabject c : allInstances)
for (Feature containedFeature : c.getFeature())
if (match(f, thisFeatureContainingClabject, containedFeature, PLMPackage.eINSTANCE.getElement_Name(), f.getName()))
allInstancesFeatures.add(containedFeature);
result.addAll(allInstancesFeatures);
result.addAll(searchLevelForRemoveFeatureInstanceDirection(allInstancesFeatures, changeOriginContaining, changeOrigin));
}
return result;
}
/**
* Calculates the impact of changes to traits of Features. All features which are effected by a
* change to the trait changeOrigin are calculated.
*
* @param changeOrigin The changed clabject
* @param oldValue The value before the change
* @param changedTrait The change trait.
*
* @return A list with all features that need to be changed after changing changeOrigin
*/
public Set<Feature> getEffectedModelElementsForChangeTraitFeatureOperation(Feature changeOrigin, String oldValue, EStructuralFeature changedTrait){
Set<Feature> result = new HashSet<Feature>();
boolean overridden = false;
Clabject changeOriginContainingClabject = changeOrigin.getClabject();
//containingClabject.getAllFeatures() works here because this clabject does not contain
//the feature at this point of time anymore
for (Feature f :changeOriginContainingClabject.getAllFeatures())
if(f != changeOrigin
&& match(changeOrigin, changeOriginContainingClabject, f, PLMPackage.eINSTANCE.getElement_Name(), changeOrigin.getName())){
overridden = true;
break;
}
//If overridden then nothing needs to be done just delete the overriding
if (overridden)
return result;
Set<Feature> currentLevel = new HashSet<Feature>();
currentLevel.add(changeOrigin);
result.addAll(searchLevelForChangeFeatureTraitFeatureTypeDirection(currentLevel, changeOrigin, changedTrait, oldValue));
result.addAll(currentLevel);
result.addAll(searchLevelForChangeFeatureTraitFeatureInstanceDirection(result, changeOrigin, changedTrait, oldValue));
result.removeAll(currentLevel);
return result;
}
/**
* Recursively searches for features to change after changing changeOrigin. The search direction is
* upwards in the classification hierarchy relative from features.
*
* @param features The features to start the recursion from
* @param changeOrigin The initially changed feature which triggered the impact analysis
* @param changedTrait The trait that has been changed
* @param oldValue The trait value before the change
* @return All features that need to be changed after applying a change to changeOrigin in type direction
*/
Set<Feature> searchLevelForChangeFeatureTraitFeatureTypeDirection(Set<Feature> features, Feature changeOrigin, EStructuralFeature changedTrait, String oldValue){
Set<Feature> result = new HashSet<Feature>();
Set<Clabject> allTypes = new HashSet<Clabject>();
Set<Feature> allTypesFeatures = new HashSet<Feature>();
for(Feature f : features){
Clabject thisFeatureContainingClabject = f.getClabject();
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
allTypes.addAll(thisFeatureContainingClabject.getModelTypes());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : thisFeatureContainingClabject.getSubtypes())
allTypes.addAll(subType.getModelTypes());
//after collecting the clabjects we must search for the conforming features
for(Clabject c : allTypes)
for (Feature containedFeature : c.getFeature())
if (match(changeOrigin, changeOrigin.getClabject(), containedFeature, changedTrait, oldValue))
allTypesFeatures.add(containedFeature);
result.addAll(allTypesFeatures);
result.addAll(searchLevelForChangeFeatureTraitFeatureTypeDirection(allTypesFeatures, changeOrigin, changedTrait, oldValue));
}
return result;
}
/**
* Recursively searches for features to change after changing changeOrigin. The search direction is
* downwards in the classification hierarchy relative from features.
*
* @param features The features to start the recursion from
* @param changeOrigin The initially changed feature which triggered the impact analysis
* @param changedTrait The trait that has been changed
* @param oldValue The trait value before the change
* @return All features that need to be changed after applying a change to changeOrigin in instance direction
*/
Set<Feature> searchLevelForChangeFeatureTraitFeatureInstanceDirection(Set<Feature> features, Feature changeOrigin, EStructuralFeature changedTrait, String oldValue){
Set<Feature> result = new HashSet<Feature>();
Set<Clabject> allInstances = new HashSet<Clabject>();
Set<Feature> allInstancesFeatures = new HashSet<Feature>();
for(Feature f : features){
Clabject thisFeatureContainingClabject = f.getClabject();
//If we add an attribute to an clabject only this attribute is effected on the same level
//all subtypes get inherited the attribute by this clabject
allInstances.addAll(thisFeatureContainingClabject.getInstances());
//On the next level only the direct instances of the change origin and
//its subtypes are relevant. The subtypes of these do automatically get
//inherited the attribute
for(Clabject subType : thisFeatureContainingClabject.getSubtypes())
allInstances.addAll(subType.getInstances());
//after collecting the clabjects we must search for the conforming features
for(Clabject c : allInstances)
for (Feature containedFeature : c.getFeature())
if (match(changeOrigin, changeOrigin.getClabject(), containedFeature, changedTrait, oldValue))
allInstancesFeatures.add(containedFeature);
result.addAll(allInstancesFeatures);
result.addAll(searchLevelForChangeFeatureTraitFeatureInstanceDirection(allInstancesFeatures, changeOrigin, changedTrait, oldValue));
}
return result;
}
/**
* Calculates the impact of a change to a clabject's trait.
*
* @param changeOrigin The modified clabject
* @param oldValue The value before modification
* @param changedTrait The trait which has been modified
* @param includeNonShallowInheritance Whether to change the potency for non shallow super-/subtypes
* @return All clabjects that need to be changed after modifying changeOrigin
*/
public Set<Clabject> getEffectedModelElementsForChangeTraitClabjectOperation(Clabject changeOrigin, String oldValue, EStructuralFeature changedTrait, boolean includeNonShallowInheritance){
Set<Clabject> result = new HashSet<Clabject>();
Set<Clabject> changeOrigins = new HashSet<Clabject>();
changeOrigins.add(changeOrigin);
Set<Clabject> effectedTypes = searchLevelForClabjectTraitChangesTypeDirectionForShallowPotencyChange(changeOrigins, includeNonShallowInheritance);
result.addAll(effectedTypes);
result.addAll(searchLevelForClabjectTraitChangesInstanceDirectionForShallowPotencyChange(effectedTypes, includeNonShallowInheritance));
//Clean up the result in case the change origin is in.
result.remove(changeOrigin);
return new HashSet<Clabject>(result);
}
/**
* Searches for the clabjects that need to be changed after changing a clabject. The search direction is upwards in the
* classification hierarchy relative from baseClabjects.
*
* @param baseClabjects Clabjects to start recursion from
* @return A list with all clabjects that need to be changed in type direction
*/
private Set<Clabject> searchLevelForClabjectTraitChangesTypeDirectionForShallowPotencyChange(Set<Clabject> baseClabjects, boolean includeNonShallowInheritance){
Set<Clabject> result = new HashSet<Clabject>();
for(Clabject changeOrigin : baseClabjects){
//At first we need to collect the whole inheritance hierarchy that is effected.
//All shallow subtypes need to be updated.
Set<Clabject> effectedClabjectsSameLevel = new HashSet<Clabject>();
effectedClabjectsSameLevel.addAll(includeNonShallowInheritance ? changeOrigin.getSupertypes() : changeOrigin.getHollowSupertypes());
effectedClabjectsSameLevel.add(changeOrigin);
Iterator<Clabject> iter = effectedClabjectsSameLevel.iterator();
Set<Clabject> effectedClabjectsSameLevelTmp = new HashSet<Clabject>();
while (iter.hasNext())
effectedClabjectsSameLevelTmp .addAll(includeNonShallowInheritance ? iter.next().getSubtypes() : iter.next().getHollowSubtypes());
effectedClabjectsSameLevel.addAll(effectedClabjectsSameLevelTmp);
result.addAll(effectedClabjectsSameLevel);
//Now we need all direct types of the model elements that are effected on one level
//Direct types are important as only these and their shallow supertypes are effected
//and not the none shallow ones
Set<Clabject> effectedDirectTypes = new HashSet<Clabject>();
for (Clabject effectedClabjectSameLevel : effectedClabjectsSameLevel)
effectedDirectTypes.addAll(effectedClabjectSameLevel.getDirectTypes());
result.addAll(effectedDirectTypes);
result.addAll(searchLevelForClabjectTraitChangesTypeDirectionForShallowPotencyChange(effectedDirectTypes, includeNonShallowInheritance));
}
return result;
}
/**
* Searches for the clabjects that need to be changed after changing a clabject. The search direction is downwards in the
* classification hierarchy relative from baseClabjects.
*
* @param baseClabjects Clabjects to start recursion from
* @return A list with all clabjects that need to be changed in instance direction
*/
private Set<Clabject> searchLevelForClabjectTraitChangesInstanceDirectionForShallowPotencyChange(Set<Clabject> baseClabjects, boolean includeNonShallowInheritance){
Set<Clabject> result = new HashSet<Clabject>();
for(Clabject changeOrigin : baseClabjects){
//At first we need to collect the whole inheritance hierarchy that is effected.
//All shallow subtypes need to be updated.
Set<Clabject> effectedClabjectsSameLevel = new HashSet<Clabject>();
effectedClabjectsSameLevel.addAll(includeNonShallowInheritance ? changeOrigin.getSupertypes() : changeOrigin.getHollowSupertypes());
effectedClabjectsSameLevel.add(changeOrigin);
Iterator<Clabject> iter = effectedClabjectsSameLevel.iterator();
Set<Clabject> effectedClabjectsSameLevelTmp = new HashSet<Clabject>();
while (iter.hasNext())
effectedClabjectsSameLevelTmp .addAll(includeNonShallowInheritance ? iter.next().getSubtypes() : iter.next().getHollowSubtypes());
effectedClabjectsSameLevel.addAll(effectedClabjectsSameLevelTmp);
result.addAll(effectedClabjectsSameLevel);
//Now we need all direct instances of the model elements that are effected on one level
//Direct instances are important as only these and their shallow supertypes are effected
//and not the none shallow ones
Set<Clabject> effectedDirectInstances = new HashSet<Clabject>();
for (Clabject effectedClabjectSameLevel : effectedClabjectsSameLevel)
effectedDirectInstances.addAll(effectedClabjectSameLevel.getDirectInstances());
result.addAll(effectedDirectInstances);
result.addAll(searchLevelForClabjectTraitChangesInstanceDirectionForShallowPotencyChange(effectedDirectInstances, includeNonShallowInheritance));
}
return result;
}
/**
*
* This checks whether two features are relevant for emendation.
* The conditions are:
*
* <ul>
* <li>Name must be equal</li>
* <li>
* Potency rules are not allowed to be violated
* <ul>
* <li>f1.potency = -1 && f2.potency = -1</li>
* <li>f1.potency = -1 && f1.level < f2.level => f2.potency > -2
* <li>f1.potency = -1 && f1.level > f2.level => f2.potency = -1
* <li>f1.potency > -1 && f1.level < f2.level => f2.potency = f1.potency - (f2.level - f1.level)</li>
* <li>f1.potency > -1 && f1.level > f2.level => f1.potency = f2.potency - (f1.level - f2.level)</li>
* </ul>
* </li>
* </ul>
*
* @param changeOrigin
* @param f2
* @param newValue can bee needed because if emendation request comes from UI it can be already changed in
* the feature
* @param traitToChange
* @return is f2 relevant for changes to changeOrigin
*/
private boolean match(Feature changeOrigin, Clabject originContainingClabject ,Feature f2, EStructuralFeature traitToChange, String oldValue){
String originName = traitToChange.getName().equals("name") ? oldValue : changeOrigin.getName();
//This is a dirty hack for the case the user enters -1 potency
//in this case it can for some reason happen that oldvalue becomes
//null
oldValue = traitToChange.getName().equals("durability") && oldValue == null ? changeOrigin.getDurabilityAsString() : oldValue;
int originDurability = traitToChange.getName().equals("durability") ? Integer.parseInt(oldValue) : changeOrigin.getDurability();
if (originName == null || originName.length() == 0 || !originName.equals(f2.getName()))
return false;
//Both changeOrigin and f2 have -1 durability
if ((originDurability == -1) && (originDurability == f2.getDurability()))
return true;
int f1Level = originContainingClabject.getLevel();
int f2Level = f2.getClabject().getLevel();
if (f1Level < f2Level){
if (originDurability == -1)
return true;
else if (f2.getDurability() == -1)
return originDurability == -1;
else
return f2.getDurability() == originDurability - (f2Level - f1Level);
}
else{
if (originDurability == -1)
return f2.getDurability() == -1;
else if (f2.getDurability() == -1)
return true;
else
return originDurability == f2.getDurability() - (f1Level - f2Level);
}
}
}