Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'extraplugins/propertylifecycle/org.eclipse.papyrus.propertylifecycle/src/org/eclipse/papyrus/propertylifecycle/utils/PropertyLifecycleManager.java')
-rwxr-xr-xextraplugins/propertylifecycle/org.eclipse.papyrus.propertylifecycle/src/org/eclipse/papyrus/propertylifecycle/utils/PropertyLifecycleManager.java575
1 files changed, 575 insertions, 0 deletions
diff --git a/extraplugins/propertylifecycle/org.eclipse.papyrus.propertylifecycle/src/org/eclipse/papyrus/propertylifecycle/utils/PropertyLifecycleManager.java b/extraplugins/propertylifecycle/org.eclipse.papyrus.propertylifecycle/src/org/eclipse/papyrus/propertylifecycle/utils/PropertyLifecycleManager.java
new file mode 100755
index 00000000000..9a71489714b
--- /dev/null
+++ b/extraplugins/propertylifecycle/org.eclipse.papyrus.propertylifecycle/src/org/eclipse/papyrus/propertylifecycle/utils/PropertyLifecycleManager.java
@@ -0,0 +1,575 @@
+/*****************************************************************************
+ * Copyright (c) 2015 CEA LIST 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:
+ * CEA LIST - Initial API and implementation
+ *
+ *****************************************************************************/
+
+package org.eclipse.papyrus.propertylifecycle.utils;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.gmf.runtime.common.core.command.CompositeCommand;
+import org.eclipse.gmf.runtime.common.core.command.ICommand;
+import org.eclipse.gmf.runtime.emf.type.core.ElementTypeRegistry;
+import org.eclipse.gmf.runtime.emf.type.core.IElementType;
+import org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand;
+import org.eclipse.gmf.runtime.emf.type.core.requests.AbstractEditCommandRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.ReorientRelationshipRequest;
+import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
+import org.eclipse.papyrus.infra.types.core.impl.ConfiguredHintedMetamodelElementType;
+import org.eclipse.papyrus.infra.types.core.impl.ConfiguredHintedSpecializationElementType;
+import org.eclipse.papyrus.propertylifecycle.Activator;
+import org.eclipse.papyrus.propertylifecycle.ElementContainer;
+import org.eclipse.papyrus.propertylifecycle.ElementProperty;
+import org.eclipse.papyrus.propertylifecycle.StrategyElement;
+import org.eclipse.papyrus.propertylifecycle.commands.LifeCycleEditElementCommand;
+import org.eclipse.papyrus.propertylifecycle.preferences.utils.PropertyLifecyclePreferencesManager;
+
+
+/**
+ * Used to match the handled element against the selected strategies
+ *
+ */
+public class PropertyLifecycleManager {
+
+ /** The manager containing all the strategies informations */
+ private PropertyLifecyclePreferencesManager preferencesManager = new PropertyLifecyclePreferencesManager();
+
+ /** The element's type */
+ private IElementType elementType;
+
+ /** The handled element */
+ private EObject element;
+
+ /** The list of all loaded processors (reflexively accessed) */
+ private Map<String, Object> accessedProcessors = new HashMap<String, Object>();
+
+ /** The command encompassing the changes to the handled element */
+ private ICommand command;
+
+ /** The request used to extract the element's contextual informations */
+ private AbstractEditCommandRequest request;
+
+ /** The depth to which the strategies will be matched against the handled element's contents */
+ private int depth;
+
+
+ /**
+ *
+ * Constructor. Default depth set to -1
+ *
+ * @param request
+ * The {@link org.eclipse.gmf.runtime.emf.type.core.requests.AbstractEditCommandRequest} of the edited element
+ */
+ public PropertyLifecycleManager(AbstractEditCommandRequest request) {
+ this(request, -1);
+ }
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param request
+ * The {@link org.eclipse.gmf.runtime.emf.type.core.requests.AbstractEditCommandRequest} of the edited element
+ * @param depth
+ * The depth to which the strategies will be matched against the handled element's contents. Negative numbers for infinite depth.
+ */
+ public PropertyLifecycleManager(AbstractEditCommandRequest request, int depth) {
+ this.request = request;
+ setElementsVariables(this.request);
+ this.depth = depth;
+ }
+
+ /**
+ * Set the variables {@link #element} and {@link #elementType} used to filter the strategies
+ *
+ * @param request
+ * The manipulated {@link org.eclipse.gmf.runtime.emf.type.core.requests.AbstractEditCommandRequest}
+ */
+ private void setElementsVariables(AbstractEditCommandRequest request) {
+ if (request instanceof CreateElementRequest) {
+ CreateElementRequest createRequest = (CreateElementRequest) request;
+ elementType = createRequest.getElementType();
+ // TODO do a better job at fishing out the created element
+ // Object object = createRequest.getElementsToEdit().get(0);
+ // element = object instanceof EObject ? (EObject) object : null;
+ element = ((CreateElementRequest) request).getNewElement();
+ }
+
+ if (request instanceof ConfigureRequest) {
+ ConfigureRequest confRequest = ((ConfigureRequest) request);
+ elementType = confRequest.getTypeToConfigure();
+ element = confRequest.getElementToConfigure();
+ }
+
+ if (request instanceof ReorientRelationshipRequest) {
+ ReorientRelationshipRequest reorientRequest = (ReorientRelationshipRequest) request;
+ element = reorientRequest.getRelationship();
+ String testString = element.eClass().getInstanceClassName();
+ // TODO find an alternative to this placeholder element type
+ IElementType papyrusType = ElementTypeRegistry.getInstance().getType(testString.replace("org.eclipse.uml2", "org.eclipse.papyrus"));
+ elementType = papyrusType != null ? papyrusType : ElementTypeRegistry.getInstance().getElementType(element.eClass());
+ }
+
+ if (request instanceof SetRequest) {
+ SetRequest setRequest = (SetRequest) request;
+ element = setRequest.getElementToEdit();
+ String testString = element.eClass().getInstanceClassName();
+ // TODO find an alternative to this placeholder element type
+ IElementType papyrusType = ElementTypeRegistry.getInstance().getType(testString.replace("org.eclipse.uml2", "org.eclipse.papyrus"));
+ elementType = papyrusType != null ? papyrusType : ElementTypeRegistry.getInstance().getElementType(element.eClass());
+ }
+
+ }
+
+
+ /**
+ * Construct the {@link org.eclipse.gmf.runtime.common.core.command.ICommand} of the edition
+ *
+ * @return
+ * The {@link org.eclipse.gmf.runtime.common.core.command.CompositeCommand} from the different changes brought by the current strategies
+ */
+ public ICommand setAssociatedPropertyValues() {
+
+ // This will avoid an NPE later and indicates that there is not yet a way to deal with the given request
+ if (elementType == null || element == null) {
+ return command;
+ }
+
+ Collection<StrategyElement> matchingStrategies = new LinkedList<StrategyElement>();
+ matchingStrategies.addAll(preferencesManager.retrieveAllStrategies());
+
+ matchingStrategies = filterOnContext(matchingStrategies, elementType, element);
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, matchingStrategies.size() + ": " + matchingStrategies);
+
+ if (matchingStrategies.size() > 0) {
+ Set<String> modifiableFeatures = getAllModifiableFeatures(matchingStrategies);
+
+ if (modifiableFeatures.size() > 0) {
+ HashMap<String, ElementProperty> newFeatureValues = getNewFeatureValues(matchingStrategies, modifiableFeatures);
+
+ for (EStructuralFeature elementFeature : element.eClass().getEAllStructuralFeatures()) {
+ String featureLabel = elementFeature.getName();
+ if (newFeatureValues.keySet().contains(featureLabel)) {
+ ElementProperty featureStrategy = newFeatureValues.get(featureLabel);
+ if (command == null) {
+ command = getAssociatedCommand(featureLabel, featureStrategy, request);
+ } else {
+ command = CompositeCommand.compose(command, getAssociatedCommand(featureLabel, featureStrategy, request));
+ }
+ }
+ }
+ }
+ }
+
+ // Iterate on all the nested elements, if any, to match them against the current strategies
+ applyStrategiesToContents(element);
+
+ return command;
+ }
+
+
+ /**
+ * Filter regrouping all the contextual information in which the element is created
+ *
+ * @param strategies
+ * The possible strategies
+ * @param elementType
+ * The element type of the element
+ * @param element
+ * The element
+ * @return
+ * The list of Strategies matching the element
+ */
+ private Collection<StrategyElement> filterOnContext(Collection<StrategyElement> strategies, IElementType elementType, EObject element) {
+ Map<String, StrategyElement> matchingStrategies = new HashMap<String, StrategyElement>();
+ // LinkedList<IElementType> elementSuperTypes = new LinkedList<IElementType>(Arrays.asList(elementType.getAllSuperTypes()));
+ String trimmedID = getTrimmedID(elementType);
+ if (elementType != null) {
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, "IElementType_ID: " + elementType.getId());
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, "IElementType_trimmedID: " + trimmedID);
+ }
+
+ for (StrategyElement strategy : strategies) {
+
+ if (trimmedID == null) {
+ continue;
+ }
+
+ // Filter on the specified element specializedType
+ if (!filterOnElement(elementType, element, strategy)) {
+ continue;
+ }
+
+ // Verify that the user specified a container to the strategy element
+ if (!filterOnContainer(element, strategy)) {
+ continue;
+ }
+
+ // Filtered list
+ matchingStrategies.put(strategy.getId(), strategy);
+ }
+
+ return matchingStrategies.values();
+
+ }
+
+
+ /**
+ * Filter based on the element's {@link org.eclipse.gmf.runtime.emf.type.core.ElementType}
+ * and its possible {@link org.eclipse.gmf.runtime.emf.type.core.SpecializationType}
+ *
+ * @param elementType
+ * The element type of the element
+ * @param element
+ * The element's EObject
+ * @param strategy
+ * The strategy the element is being matched against
+ * @return
+ * If the element is a match to the strategy or not
+ */
+ private boolean filterOnElement(IElementType elementType, EObject element, StrategyElement strategy) {
+ IElementType strategyBaseType = ElementTypeRegistry.getInstance().getType(strategy.getBaseType());
+ IElementType strategySpeType = ElementTypeRegistry.getInstance().getType(strategy.getSpecializedType());
+
+ // 1- Filter on the element baseType
+ if (strategyBaseType == null) {
+ return false;
+ }
+ // TEST1 - BEGIN
+ if (strategyBaseType instanceof ConfiguredHintedMetamodelElementType) {
+ ConfiguredHintedMetamodelElementType metatype = (ConfiguredHintedMetamodelElementType) strategyBaseType;
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "ConfiguredHintedMetamodelElementType: " + metatype);
+ }
+ if (strategyBaseType instanceof ConfiguredHintedSpecializationElementType) {
+ ConfiguredHintedSpecializationElementType spetype = (ConfiguredHintedSpecializationElementType) strategyBaseType;
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "ConfiguredHintedSpecializationElementType: " + spetype);
+ }
+ // TEST1 - END
+
+ if (strategyBaseType.equals(ElementTypeRegistry.getInstance().getType("org.eclipse.papyrus.uml.Element"))) {
+ return true;
+ }
+ // If the base type is a metamodel type, there are no matchers to use
+ if (strategyBaseType instanceof ConfiguredHintedMetamodelElementType) {
+ ConfiguredHintedMetamodelElementType metaType = (ConfiguredHintedMetamodelElementType) strategyBaseType;
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "element: " + metaType.getEClass());
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "element: " + element.eClass());
+
+ if (!metaType.getEClass().equals(element.eClass())) {
+ return false;
+ }
+ }
+ // If the base type is a specialization type as the base type, there is a matcher available
+ if (strategyBaseType instanceof ConfiguredHintedSpecializationElementType) {
+ ConfiguredHintedSpecializationElementType speType = (ConfiguredHintedSpecializationElementType) strategyBaseType;
+
+ if (speType.getMatcher() == null) {
+ // FIXME there are no matchers for: Extend(UseCase),
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, speType.getId() + ", hasNoMatcher");
+ return false;
+ } else {
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, speType.getId());
+ if (!speType.getMatcher().matches(element)) {
+ return false;
+ }
+ }
+ }
+
+ // 2- Filter on the element specializedType
+ if (strategySpeType != null && elementType != null && !Arrays.asList(elementType.getAllSuperTypes()).contains(strategySpeType)) {
+ return false;
+ }
+
+
+ // All the previous conditions are met
+ return true;
+ }
+
+
+ /**
+ * Go through all the specified strategy's containers
+ *
+ * @param element
+ * The element
+ * @param strategy
+ * The strategy
+ * @return
+ * If the element's container is a match or not
+ */
+ private boolean filterOnContainer(EObject element, StrategyElement strategy) {
+ Collection<ElementContainer> strategyContainers = strategy.getElementContainers();
+ Boolean skip = true;
+
+ // There were no specified containers hence the condition is always verified
+ if (strategyContainers == null || strategyContainers.size() < 1) {
+ return true;
+ }
+
+ for (ElementContainer container : strategyContainers) {
+ // Filter on the possible element's container
+ skip = matchContainers(element.eContainer(), container);
+ if (skip) {
+ return true;
+ }
+ }
+
+ // All the previous conditions are met
+ return false;
+ }
+
+
+ /**
+ * Go through all the specified strategy's container and its containers
+ *
+ * @param element
+ * The element
+ * @param container
+ * The {@link org.eclipse.papyrus.propertylifecycle.ElementContainer container} specified in the strategy
+ * @return
+ * If the element's container is a match or not
+ */
+ private boolean matchContainers(EObject element, ElementContainer container) {
+ IElementType containerBaseType = ElementTypeRegistry.getInstance().getType(container.getBaseType());
+ IElementType containerSpeType = ElementTypeRegistry.getInstance().getType(container.getSpecializedType());
+
+ // 1- Filter on the element baseType
+ if (containerBaseType == null) {
+ return false;
+ }
+
+ // If the base type is a metamodel type, there are no matchers to use
+ if (containerBaseType instanceof ConfiguredHintedMetamodelElementType) {
+ ConfiguredHintedMetamodelElementType metaType = (ConfiguredHintedMetamodelElementType) containerBaseType;
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "container: " + metaType.getEClass());
+ Activator.log.trace(Activator.PLCSTRATEGY_TYPES_TRACE, "container: " + element.eClass());
+
+ if (!metaType.getEClass().equals(element.eClass())) {
+ return false;
+ }
+ }
+ // If the base type is a specialization type as the base type, there is a matcher available
+ if (containerBaseType instanceof ConfiguredHintedSpecializationElementType) {
+ ConfiguredHintedSpecializationElementType speType = (ConfiguredHintedSpecializationElementType) containerBaseType;
+
+ if (!speType.getMatcher().matches(element)) {
+ return false;
+ }
+ }
+
+ // 2- Filter on the element specializedType
+ // As there are no way to link an eObject to a specific elementType we only verify that the specialized type is contained by the baseType
+ if (containerSpeType != null && !Arrays.asList(containerBaseType.getAllSuperTypes()).contains(containerSpeType)) {
+ return false;
+ }
+
+ // 3- Filter on the possible element's container
+ if (container.getContainersContainer() != null) {
+ if (!matchContainers(element.eContainer(), container.getContainersContainer())) {
+ return false;
+ }
+ }
+
+
+ // All the previous conditions are met
+ return true;
+ }
+
+
+ /**
+ * The possible changes brought by the current strategies
+ *
+ * @param strategies
+ * The strategies applicable to the element
+ * @return
+ * The list containing all the features affected by the applicable strategies
+ */
+ private Set<String> getAllModifiableFeatures(Collection<StrategyElement> strategies) {
+ Set<String> modifiableFeatures = new HashSet<String>();
+
+ for (StrategyElement strategy : strategies) {
+ for (ElementProperty property : strategy.getElementProperties()) {
+ // The user did not set a label
+ if (property.getFeatureLabel() == null) {
+ continue;
+ }
+ modifiableFeatures.add(property.getFeatureLabel());
+ }
+ }
+
+ return modifiableFeatures;
+ }
+
+
+ /**
+ * filter the possible strategies applicable to the features of the element and selecting them by their associated priorities
+ *
+ * @param strategies
+ * The strategies applicable to the element
+ * @param modifiableFeatures
+ * The features that can be modified by them
+ * @return
+ * The map detailing which changes will be applied to the modifiable features of the element
+ */
+ private HashMap<String, ElementProperty> getNewFeatureValues(Collection<StrategyElement> strategies, Set<String> modifiableFeatures) {
+ HashMap<String, ElementProperty> newFeatureValues = new HashMap<String, ElementProperty>();
+
+ for (String featureLabel : modifiableFeatures) {
+ ElementProperty priorityProperty = filterOnPriority(featureLabel, strategies);
+ newFeatureValues.put(featureLabel, priorityProperty);
+ }
+
+ return newFeatureValues;
+ }
+
+
+ /**
+ * Filter the possible changes based on their priority
+ *
+ * @param featureLabel
+ * The label of the element's feature to change
+ * @param strategies
+ * The strategies applicable to the element
+ * @return
+ * The selected behavior
+ */
+ private ElementProperty filterOnPriority(String featureLabel, Collection<StrategyElement> strategies) {
+ HashMap<Integer, ElementProperty> weightedStrategies = new HashMap<Integer, ElementProperty>();
+ int priority = 0;
+
+ for (StrategyElement strategy : strategies) {
+ for (ElementProperty property : strategy.getElementProperties()) {
+ if (featureLabel.equals(property.getFeatureLabel())) {
+ // The user did not set a priority
+ if (property.getPriority() == null) {
+ weightedStrategies.put(0, property);
+ continue;
+ }
+
+ // The user defined this property value to be immutable
+ if (property.getPriority() < 0) {
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, "Immutable priority: " + property.getPriority());
+ return property;
+ }
+
+ weightedStrategies.put(property.getPriority(), property);
+ priority = priority < property.getPriority() ? property.getPriority() : priority;
+ }
+ }
+ }
+
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, "Highest priority: " + priority);
+ return weightedStrategies.get(priority);
+ }
+
+
+ /**
+ * Get the associated {@link org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand} corresponding to the modifications on the element
+ *
+ * @param featureLabel
+ * The label of the feature to edit
+ * @param featureStrategy
+ * The strategy applied to this feature
+ * @return
+ * The {@link org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand}
+ * with its associated {@link org.eclipse.gmf.runtime.common.core.command.CommandResult}
+ */
+ private EditElementCommand getAssociatedCommand(String featureLabel, ElementProperty featureStrategy, AbstractEditCommandRequest request) {
+ return new LifeCycleEditElementCommand("LifecycleEditCommand", element, request, featureLabel, featureStrategy, accessedProcessors);
+ }
+
+
+ /**
+ * This method calls on the {@link #setAssociatedPropertyValues()} for the contents of the edited element
+ * It will do so until the maximum depth has been reached (set in the constructor)
+ *
+ * @param element
+ * The edited element
+ */
+ private void applyStrategiesToContents(EObject element) {
+ // The max depth has been reached
+ if (depth == 0) {
+ return;
+ }
+
+ if (element.eContents().size() > 0) {
+ // Increase the depth of the matching
+ depth -= 1;
+ for (EObject eObject : element.eContents()) {
+ // Reinitialize the element to test against the current strategies
+ this.element = eObject;
+ // TODO find an alternative (more precise) to this default value
+ this.elementType = ElementTypeRegistry.getInstance().getElementType(eObject.eClass());
+ setAssociatedPropertyValues();
+ }
+ }
+ }
+
+
+ /**
+ * @param elementType
+ * The element's type
+ * @return
+ * The element type ID trimmed of any graphical extension
+ */
+ private String getTrimmedID(IElementType elementType) {
+ if (elementType == null) {
+ return null;
+ }
+
+ if (!graphicalIDMatcher(elementType.getId())) {
+ // The ID is already not a graphical one
+ return elementType.getId();
+ }
+
+ IElementType[] elementSuperTypes = elementType.getAllSuperTypes();
+ LinkedList<IElementType> superTypes = new LinkedList<IElementType>(Arrays.asList(elementSuperTypes));
+ for (int i = elementSuperTypes.length - 1; i > 0; i--) {
+ String typeID = superTypes.get(i).getId();
+ Activator.log.trace(Activator.PLCSTRATEGY_TRACE, "typeID: " + typeID);
+
+ if (!graphicalIDMatcher(typeID)) {
+ return typeID;
+ }
+ }
+
+ // A chain of graphical IDs, albeit nigh impossible, could lead to this case
+ return null;
+ }
+
+
+ /**
+ * Detect the presence of a graphical extension in the element type ID
+ *
+ * @param typeID
+ * The element type ID
+ * @return
+ * isGraphical or not
+ */
+ private boolean graphicalIDMatcher(String typeID) {
+ if (typeID.matches("[A-Za-z].+_[0-9]+")) { // $NON-NLS-1$
+ // The type ID is graphical
+ return true;
+ }
+
+ return false;
+ }
+
+}

Back to the top