Browse Source

Fix serializing of specification elements during refactorings (#1684)

* Ensure model consistency during refactoring to avoid serialization exceptions

* Re-Link changed specifications after renaming.

This fixes the problem of failing subsequent renaming refactorings.

* No need to copy actions as they are already detached

* Always parse and link specifications after refactoring

This solves several issues where refactorings are executed on a dirty state because of previous refactoring steps.

* Ensure all specification elements are parsed and linked after refactoring

* Remove entry/exit reactions after all actions have been moved.

If reaction is removed before copying the contained actions, we loose existing cross references during copy step.

* Ensure only reaction actions for a specified event type are unfolded to a transition.

* Added specification element parsing for refactoring tests, to ensure the model is valid before after a refactoring is executed.

* Combined internalExecute of refactoring commands with parsing and linking of specficiation elements.

This ensures that a statechart model is always valid after a refactoring.

* Renamed the doInternalExecute method. Removed explicit linking and parsing of specification elements in refactoring tests, because this is now done always after internalExecute for each refactoring.

* removed unnessecary collection and unsued imports.
Robert Rudi 7 years ago
parent
commit
0baae3346d

+ 12 - 0
plugins/org.yakindu.sct.model.sgraph/src/org/yakindu/sct/model/sgraph/resource/AbstractSCTResource.java

@@ -343,6 +343,16 @@ public abstract class AbstractSCTResource extends XMIResourceImpl {
 			}
 		}
 	}
+	
+	public void parseSpecificationElements() {
+		TreeIterator<EObject> iter = getAllContents();
+		while (iter.hasNext()) {
+			EObject currentObject = iter.next();
+			if (currentObject instanceof SpecificationElement) {
+				parseSpecificationElement((SpecificationElement) currentObject);
+			}
+		}
+	}
 
 	protected void linkSpecificationElement(SpecificationElement element) {
 		isLinking = true;
@@ -368,8 +378,10 @@ public abstract class AbstractSCTResource extends XMIResourceImpl {
 				serializeStatechart((Statechart) element);
 			}
 		} catch (XtextSerializationException ex) {
+			ex.printStackTrace();
 			// Leave the old specification
 		} catch (IConcreteSyntaxValidator.InvalidConcreteSyntaxException ex) {
+			ex.printStackTrace();
 			// Leave the old specification
 		} finally {
 			isSerializing = false;

+ 20 - 2
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/AbstractRefactoring.java

@@ -95,7 +95,7 @@ public abstract class AbstractRefactoring<T extends Object> implements IRefactor
 			protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info)
 					throws ExecutionException {
 				try {
-					internalExecute();
+					executeRefactoring();
 				} catch (Exception ex) {
 					return CommandResult.newErrorCommandResult(ex);
 				}
@@ -120,12 +120,30 @@ public abstract class AbstractRefactoring<T extends Object> implements IRefactor
 	protected boolean internalDoUndo() {
 		return true;
 	}
-
+	
+    /**
+     * Combines the internal command execution call with the parsing and linking of the specification elements.
+     */
+	protected void executeRefactoring() {
+		internalExecute();
+		parseAndLinkSpecificationElements();
+	}
 	/**
 	 * Is called within {@link IRefactoring#execute()} method.
 	 */
 	protected abstract void internalExecute();
 
+	/**
+	 * Parses and links the specification elements of {@link AbstractRefactoring#getResource()}
+	 */
+	protected void parseAndLinkSpecificationElements() {
+		Resource resource = getResource();
+		if (resource instanceof AbstractSCTResource) {
+			((AbstractSCTResource) resource).parseSpecificationElements();
+			((AbstractSCTResource) resource).linkSpecificationElements();
+		}
+	}
+	
 	/**
 	 * Getter for the editing domain of the resource used in this refactoring.
 	 * 

+ 15 - 12
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/impl/FoldIncomingActionsRefactoring.java

@@ -26,7 +26,6 @@ import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.ReactionTrigger;
 import org.yakindu.sct.model.stext.stext.StextFactory;
 import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
-
 /**
  * Implementation for 'fold incoming actions' refactoring. This refactoring
  * moves actions of incoming transitions to the entry block of a state. Actions
@@ -98,13 +97,14 @@ public class FoldIncomingActionsRefactoring extends AbstractRefactoring<State> {
 				.getFirstEntryActions(getContextObject());
 
 		if (actionsOriginal == null) {
-			actionsOriginal = createEntryBlock();
+			actionsOriginal = createEntryBlock(actionsToAdd);
+		} else {
+			actionsOriginal.addAll(actionsToAdd);
 		}
 
-		actionsOriginal.addAll(actionsToAdd);
 	}
 
-	private EList<Expression> createEntryBlock() {
+	private EList<Expression> createEntryBlock(List<Expression> actionsToAdd) {
 		EList<Expression> actionsOriginal;
 		LocalReaction newLocalReaction = StextFactory.eINSTANCE
 				.createLocalReaction();
@@ -116,6 +116,7 @@ public class FoldIncomingActionsRefactoring extends AbstractRefactoring<State> {
 
 		newLocalReaction.setTrigger(newReactionTrigger);
 		newReactionTrigger.getTriggers().add(entryEvent);
+		newReactionEffect.getActions().addAll(actionsToAdd);
 		newLocalReaction.setEffect(newReactionEffect);
 
 		Scope scope = getContextObject().getScopes().get(0);
@@ -128,15 +129,17 @@ public class FoldIncomingActionsRefactoring extends AbstractRefactoring<State> {
 	private void removeLastActions(EList<Transition> transitions, int number) {
 
 		for (Transition transition : transitions) {
-			List<Expression> actionsToRemove = getLastActions(transition,
-					number);
-			for (Expression action : actionsToRemove) {
-				EcoreUtil.delete(action);
-			}
-			// delete transition's effect when no more actions left
+			List<Expression> actionsToRemove = getLastActions(transition, number);
 			Effect effect = transition.getEffect();
-			if (!helper.hasAtLeastOneAction(transition) && effect != null) {
-				EcoreUtil.delete(transition.getEffect());
+			if (effect instanceof ReactionEffect
+					&& actionsToRemove.size() == ((ReactionEffect) effect).getActions().size()) {
+				// we need to remove all actions, so just remove the effect
+				// recursively which avoids serializer exceptions
+				EcoreUtil.delete(effect, true);
+			} else {
+				for (Expression action : actionsToRemove) {
+					EcoreUtil.delete(action);
+				}
 			}
 		}
 	}

+ 13 - 9
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/impl/FoldOutgoingActionsRefactoring.java

@@ -98,13 +98,14 @@ public class FoldOutgoingActionsRefactoring extends AbstractRefactoring<State> {
 				.getFirstExitActions(getContextObject());
 
 		if (actionsOriginal == null) {
-			actionsOriginal = createExitBlock();
+			actionsOriginal = createExitBlock(actionsToAdd);
+		} else {
+			actionsOriginal.addAll(actionsToAdd);
 		}
 
-		actionsOriginal.addAll(actionsToAdd);
 	}
 
-	private EList<Expression> createExitBlock() {
+	private EList<Expression> createExitBlock(List<Expression> actionsToAdd) {
 		EList<Expression> actionsOriginal;
 		LocalReaction newLocalReaction = StextFactory.eINSTANCE
 				.createLocalReaction();
@@ -116,6 +117,8 @@ public class FoldOutgoingActionsRefactoring extends AbstractRefactoring<State> {
 
 		newLocalReaction.setTrigger(newReactionTrigger);
 		newReactionTrigger.getTriggers().add(exitEvent);
+		
+		newReactionEffect.getActions().addAll(actionsToAdd);
 		newLocalReaction.setEffect(newReactionEffect);
 
 		Scope scope = getContextObject().getScopes().get(0);
@@ -130,13 +133,14 @@ public class FoldOutgoingActionsRefactoring extends AbstractRefactoring<State> {
 		for (Transition transition : transitions) {
 			List<Expression> actionsToRemove = getFirstActions(transition,
 					number);
-			for (Expression action : actionsToRemove) {
-				EcoreUtil.delete(action);
-			}
-			// delete transition's effect when no more actions left
 			Effect effect = transition.getEffect();
-			if (!helper.hasAtLeastOneAction(transition) && effect != null) {
-				EcoreUtil.delete(effect);
+			if (effect instanceof ReactionEffect && actionsToRemove.size() == ((ReactionEffect)effect).getActions().size()) {
+				// we need to remove all actions, so just remove the effect recursively which avoids serializer exceptions
+				EcoreUtil.delete(effect, true);
+			} else {
+				for (Expression action : actionsToRemove) {
+					EcoreUtil.delete(action);
+				}
 			}
 		}
 	}

+ 6 - 29
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/impl/RenameRefactoring.java

@@ -13,25 +13,19 @@ package org.yakindu.sct.refactoring.refactor.impl;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 import org.eclipse.emf.common.util.EList;
 import org.eclipse.emf.ecore.EObject;
 import org.eclipse.emf.ecore.resource.Resource;
 import org.eclipse.emf.ecore.util.EcoreUtil;
-import org.eclipse.xtext.EcoreUtil2;
 import org.yakindu.base.base.NamedElement;
 import org.yakindu.base.expressions.expressions.ElementReferenceExpression;
 import org.yakindu.base.expressions.expressions.FeatureCall;
-import org.yakindu.sct.model.sgraph.SpecificationElement;
-import org.yakindu.sct.model.sgraph.resource.AbstractSCTResource;
 import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
 
-import com.google.common.collect.Sets;
-
 /**
- * Renames the context object and all references to it.
- * <br><br>
+ * Renames the context object and all references to it. <br>
+ * <br>
  * Context:
  * <ul>
  * <li>A {@link NamedElement}.</li>
@@ -47,17 +41,17 @@ import com.google.common.collect.Sets;
 public class RenameRefactoring extends AbstractRefactoring<NamedElement> {
 
 	String newName;
-	
+
 	public void setNewName(String newName) {
 		this.newName = newName;
 	}
-	
+
 	@Override
 	public void setContextObjects(List<NamedElement> contextObject) {
 		this.newName = null;
 		super.setContextObjects(contextObject);
 	}
-	
+
 	@Override
 	public boolean isExecutable() {
 		return (getContextObject() != null);
@@ -65,34 +59,18 @@ public class RenameRefactoring extends AbstractRefactoring<NamedElement> {
 
 	@Override
 	protected void internalExecute() {
-
 		NamedElement element = getContextObject();
-		
 		Collection<EObject> elementReferers = findReferers(element);
 		element.setName(newName);
-
-		AbstractSCTResource res = (AbstractSCTResource) getResource();
-		Set<SpecificationElement> specificationsToParse = Sets.newHashSet();
-		
 		for (EObject referer : elementReferers) {
 			if (referer instanceof FeatureCall) {
 				FeatureCall featureCall = (FeatureCall) referer;
 				featureCall.setFeature(element);
-				SpecificationElement spec = EcoreUtil2.getContainerOfType(
-						referer, SpecificationElement.class);
-				specificationsToParse.add(spec);
 			} else if (referer instanceof ElementReferenceExpression) {
 				ElementReferenceExpression expr = (ElementReferenceExpression) referer;
 				expr.setReference(element);
-				SpecificationElement spec = EcoreUtil2.getContainerOfType(
-						referer, SpecificationElement.class);
-				specificationsToParse.add(spec);
 			}
 		}
-		// TODO parsing is an workaround here for linking problem
-		for (SpecificationElement spec : specificationsToParse) {
-			res.parseSpecificationElement(spec);
-		}
 	}
 
 	private Collection<EObject> findReferers(EObject referedElement) {
@@ -105,8 +83,7 @@ public class RenameRefactoring extends AbstractRefactoring<NamedElement> {
 		return result;
 	}
 
-	private Collection<EObject> searchForReferers(EObject referedElement,
-			EList<EObject> contents) {
+	private Collection<EObject> searchForReferers(EObject referedElement, EList<EObject> contents) {
 		Collection<EObject> result = new HashSet<EObject>();
 		for (EObject content : contents) {
 			for (EObject crossRef : content.eCrossReferences()) {

+ 7 - 7
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/impl/UnfoldEntryActionsRefactoring.java

@@ -19,9 +19,9 @@ import org.yakindu.base.expressions.expressions.Expression;
 import org.yakindu.sct.model.sgraph.Effect;
 import org.yakindu.sct.model.sgraph.State;
 import org.yakindu.sct.model.sgraph.Transition;
+import org.yakindu.sct.model.stext.stext.EntryEvent;
 import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.StextFactory;
-import org.yakindu.sct.model.stext.stext.impl.EntryEventImpl;
 import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
 /**
  * This refactoring moves entry actions of a state to its incoming transitions.
@@ -72,17 +72,18 @@ public class UnfoldEntryActionsRefactoring extends AbstractRefactoring<State> {
 	private void unfoldEntryActions() {
 		List<Expression> actionsToUnfold = new ArrayList<Expression>(
 				helper.extractAllLocalActionsForEventType(getContextObject(),
-						EntryEventImpl.class));
+						EntryEvent.class));
 		addActionsToIncomingTransitions(actionsToUnfold);
+		
+		helper.removeReactionsOfEventType(getContextObject().getLocalReactions(), EntryEvent.class);
 	}
 
 	private void addActionsToIncomingTransitions(List<Expression> actionsToAdd) {
-
 		for (Transition transition : getContextObject()
 				.getIncomingTransitions()) {
-			addActionsToTransition(transition, EcoreUtil.copyAll(actionsToAdd));
-		}
 
+			addActionsToTransition(transition,  EcoreUtil.copyAll(actionsToAdd));
+		}
 	}
 
 	private void addActionsToTransition(final Transition transition,
@@ -95,10 +96,9 @@ public class UnfoldEntryActionsRefactoring extends AbstractRefactoring<State> {
 			reactionEffect.getActions().addAll(actionsToAdd);
 		} else {
 			reactionEffect = StextFactory.eINSTANCE.createReactionEffect();
+			reactionEffect.getActions().addAll(actionsToAdd);
 			transition.setEffect(reactionEffect);
 		}
-		reactionEffect.getActions().addAll(actionsToAdd);
-
 	}
 
 	@Override

+ 7 - 7
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/refactor/impl/UnfoldExitActionsRefactoring.java

@@ -19,9 +19,9 @@ import org.yakindu.base.expressions.expressions.Expression;
 import org.yakindu.sct.model.sgraph.Effect;
 import org.yakindu.sct.model.sgraph.State;
 import org.yakindu.sct.model.sgraph.Transition;
+import org.yakindu.sct.model.stext.stext.ExitEvent;
 import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.StextFactory;
-import org.yakindu.sct.model.stext.stext.impl.ExitEventImpl;
 import org.yakindu.sct.refactoring.refactor.AbstractRefactoring;
 /**
  * This refactoring moves exit actions of a state to its outgoing transitions.
@@ -73,8 +73,10 @@ public class UnfoldExitActionsRefactoring extends AbstractRefactoring<State> {
 	private void unfoldExitActions() {
 		List<Expression> actionsToUnfold = new ArrayList<Expression>(
 				helper.extractAllLocalActionsForEventType(getContextObject(),
-						ExitEventImpl.class));
+						ExitEvent.class));
 		addActionsToOutgoingTransitions(actionsToUnfold);
+		
+		helper.removeReactionsOfEventType(getContextObject().getLocalReactions(), ExitEvent.class);
 	}
 
 	private void addActionsToOutgoingTransitions(List<Expression> actionsToAdd) {
@@ -84,18 +86,16 @@ public class UnfoldExitActionsRefactoring extends AbstractRefactoring<State> {
 		}
 	}
 
-	private void addActionsToTransition(final Transition transition,
-			final Collection<Expression> actionsToAdd) {
+	private void addActionsToTransition(final Transition transition, final Collection<Expression> actionsToAdd) {
 
 		Effect effect = transition.getEffect();
 		if (effect instanceof ReactionEffect) {
 			ReactionEffect reactionEffect = (ReactionEffect) effect;
 			reactionEffect.getActions().addAll(0, actionsToAdd);
 		} else {
-			ReactionEffect reactionEffect = StextFactory.eINSTANCE
-					.createReactionEffect();
-			transition.setEffect(reactionEffect);
+			ReactionEffect reactionEffect = StextFactory.eINSTANCE.createReactionEffect();
 			reactionEffect.getActions().addAll(actionsToAdd);
+			transition.setEffect(reactionEffect);
 		}
 	}
 

+ 85 - 65
plugins/org.yakindu.sct.refactoring/src/org/yakindu/sct/refactoring/utils/RefactoringHelper.java

@@ -37,14 +37,14 @@ import org.yakindu.sct.model.stext.stext.ReactionEffect;
 import org.yakindu.sct.model.stext.stext.ReactionTrigger;
 
 /**
- * Utility class providing several convenience methods used in refactoring commands.
+ * Utility class providing several convenience methods used in refactoring
+ * commands.
  * 
  * @author thomas kutz - Initial contribution and API
  *
  */
 public class RefactoringHelper {
 
-	
 	/**
 	 * Collects all actions of the specified transitions and returns them.
 	 * 
@@ -58,16 +58,16 @@ public class RefactoringHelper {
 			if (effect instanceof ReactionEffect) {
 				ReactionEffect reactionEffect = (ReactionEffect) effect;
 				allActions.add(reactionEffect.getActions());
-			}
-			else {
-				allActions.add(Collections.<Expression>emptyList());
+			} else {
+				allActions.add(Collections.<Expression> emptyList());
 			}
 		}
 		return allActions;
 	}
-	
+
 	/**
 	 * Checks if the specified state has at least one entry action.
+	 * 
 	 * @param state
 	 * @return true if condition is satisfied, false otherwise.
 	 */
@@ -78,9 +78,10 @@ public class RefactoringHelper {
 		}
 		return false;
 	}
-	
+
 	/**
 	 * Checks if the specified state has at least one exit action.
+	 * 
 	 * @param state
 	 * @return true if condition is satisfied, false otherwise.
 	 */
@@ -91,18 +92,18 @@ public class RefactoringHelper {
 		}
 		return false;
 	}
-	
+
 	/**
-	 * Checks if at least one of the outgoing transitions of the specified state leaves a parent composite
-	 * of this state which has exit actions.
+	 * Checks if at least one of the outgoing transitions of the specified state
+	 * leaves a parent composite of this state which has exit actions.
 	 * 
-	 * @param state 
+	 * @param state
 	 * @return true if condition is satisfied, false otherwise
 	 */
 	public boolean oneOutgoingTransitionLeavesCompositeWithExitActions(State state) {
 
 		Set<State> sourceParentStates = new HashSet<State>(getParentStates(state));
-		
+
 		for (Transition transition : state.getOutgoingTransitions()) {
 			// all parent states of target need to be contained in the set of
 			// the source's parent states
@@ -117,17 +118,18 @@ public class RefactoringHelper {
 		}
 		return false;
 	}
-	
+
 	/**
-	 * Checks if at least one of the incoming transitions of the specified state enters a parent composite
-	 * of this state which has entry actions. 
+	 * Checks if at least one of the incoming transitions of the specified state
+	 * enters a parent composite of this state which has entry actions.
+	 * 
 	 * @param state
 	 * @return true if condition is satisfied, false otherwise
 	 */
 	public boolean oneIncomingTransitionEntersCompositeWithEntryActions(State state) {
 
 		Set<State> targetParentStates = new HashSet<State>(getParentStates(state));
-		
+
 		for (Transition transition : state.getIncomingTransitions()) {
 			// all parent states of source need to be contained in the set of
 			// the target's parent states
@@ -142,14 +144,15 @@ public class RefactoringHelper {
 		}
 		return false;
 	}
-	
+
 	/**
-	 * Returns the entry actions of a state.
-	 * Returns null if no entry block is defined.
-	 * If multiple entry blocks are defined, only the actions of the first one are returned.
+	 * Returns the entry actions of a state. Returns null if no entry block is
+	 * defined. If multiple entry blocks are defined, only the actions of the first
+	 * one are returned.
 	 * 
 	 * @param state
-	 * @return list of actions of the first entry block defined in the specified state
+	 * @return list of actions of the first entry block defined in the specified
+	 *         state
 	 */
 	public EList<Expression> getFirstEntryActions(State state) {
 		EList<Reaction> localReactions = state.getLocalReactions();
@@ -160,21 +163,22 @@ public class RefactoringHelper {
 				EList<EventSpec> triggers = reactionTrigger.getTriggers();
 				for (EventSpec eventSpec : triggers) {
 					if (eventSpec instanceof EntryEvent && reaction.getEffect() instanceof ReactionEffect) {
-						return ((ReactionEffect)reaction.getEffect()).getActions();
+						return ((ReactionEffect) reaction.getEffect()).getActions();
 					}
 				}
 			}
 		}
 		return null;
 	}
-	
+
 	/**
-	 * Returns the exit actions of a state.
-	 * Returns null if no exit block is defined.
-	 * If multiple exit blocks are defined, only the actions of the first one are returned.
+	 * Returns the exit actions of a state. Returns null if no exit block is
+	 * defined. If multiple exit blocks are defined, only the actions of the first
+	 * one are returned.
 	 * 
 	 * @param state
-	 * @return list of actions of the first exit block defined in the specified state
+	 * @return list of actions of the first exit block defined in the specified
+	 *         state
 	 */
 	public EList<Expression> getFirstExitActions(State state) {
 		EList<Reaction> localReactions = state.getLocalReactions();
@@ -185,7 +189,7 @@ public class RefactoringHelper {
 				EList<EventSpec> triggers = reactionTrigger.getTriggers();
 				for (EventSpec eventSpec : triggers) {
 					if (eventSpec instanceof ExitEvent && reaction.getEffect() instanceof ReactionEffect) {
-						return ((ReactionEffect)reaction.getEffect()).getActions();
+						return ((ReactionEffect) reaction.getEffect()).getActions();
 					}
 				}
 			}
@@ -194,6 +198,7 @@ public class RefactoringHelper {
 	}
 	/**
 	 * Checks if the effect definition of a transition contains at least one action.
+	 * 
 	 * @param transition
 	 * @return true if the condition is satisfied, false otherwise
 	 */
@@ -206,45 +211,47 @@ public class RefactoringHelper {
 		}
 		return false;
 	}
-	
+
 	/**
-	 * Collects all actions of the specified state which have the specified type. The collected actions are deleted from their
-	 * current containers and returned.
+	 * Collects all actions of the specified state which have the specified type.
+	 * 
 	 * @param state
 	 * @param eventType
 	 * @return all actions of the specified state which have the specified type
 	 */
 	public List<Expression> extractAllLocalActionsForEventType(State state, Class<? extends EventSpec> eventType) {
-		// creating new collection required to delete its elements with EcoreUtil 
-		List<Reaction> localReactions = new ArrayList<Reaction>(state.getLocalReactions());
 		List<Expression> resultActions = new ArrayList<Expression>();
-		for (Reaction reaction : localReactions) {
-			if (!(reaction.getEffect() instanceof ReactionEffect) || !(reaction.getTrigger() instanceof ReactionTrigger)) {
+		for (Reaction reaction : state.getLocalReactions()) {
+			if (!(reaction.getEffect() instanceof ReactionEffect)
+					|| !(reaction.getTrigger() instanceof ReactionTrigger)) {
 				continue;
 			}
-			
-			ReactionTrigger reactionTrigger = (ReactionTrigger) reaction.getTrigger();
-			ReactionEffect reactionEffect = (ReactionEffect)reaction.getEffect();
-			List<EventSpec> triggers = new ArrayList<EventSpec>(reactionTrigger.getTriggers());
-			
-			if (containsOnlyEventsOfType(triggers, eventType)) {
-				EList<Expression> entryActions = reactionEffect.getActions();
-				resultActions.addAll(entryActions);
-				EcoreUtil.remove(reaction);
-			}
-			else if (containsAtLeastOneEventOfType(triggers, eventType)) {
-				EList<Expression> entryActions = reactionEffect.getActions();
-				resultActions.addAll(entryActions);
-				deleteAllEventsOfType(triggers, eventType);
-			}
+			resultActions.addAll(getReactionEffectActionsForEventType(reaction, eventType));
 		}
 		return resultActions;
 	}
-	
+
+	/**
+	 * Returns all actions for the specified reaction and event type.
+	 * 
+	 * @param eventType
+	 * @param reaction
+	 * @return
+	 */
+	protected List<Expression> getReactionEffectActionsForEventType(Reaction reaction,
+			Class<? extends EventSpec> eventType) {
+		EList<EventSpec> triggers = ((ReactionTrigger) reaction.getTrigger()).getTriggers();
+		if (containsAtLeastOneEventOfType(triggers, eventType)) {
+			return ((ReactionEffect) reaction.getEffect()).getActions();
+		}
+		return Collections.emptyList();
+	}
+
 	/**
 	 * Returns all parent states of the specified child state.
 	 * 
-	 * @param state child state
+	 * @param state
+	 *            child state
 	 * @return all parent states of the specified child state
 	 */
 	// TODO are hierarchies of regions possible?
@@ -258,18 +265,30 @@ public class RefactoringHelper {
 		}
 		return parentStates;
 	}
-	
+
 	private void deleteAllEventsOfType(List<EventSpec> events, Class<? extends EventSpec> eventType) {
 		for (EventSpec event : events) {
-			if (event.getClass().getName().equals(eventType.getName())) {
+			if (eventType.isAssignableFrom(event.getClass())) {
 				EcoreUtil.remove(event);
 			}
 		}
 	}
 
+	public void removeReactionsOfEventType(EList<Reaction> reactions, Class<? extends EventSpec> eventType) {
+		for (Reaction reaction : reactions) {
+			List<EventSpec> triggers = new ArrayList<EventSpec>(
+					((ReactionTrigger) reaction.getTrigger()).getTriggers());
+			if (containsOnlyEventsOfType(triggers, eventType)) {
+				EcoreUtil.remove(reaction);
+			} else if (containsAtLeastOneEventOfType(triggers, eventType)) {
+				deleteAllEventsOfType(triggers, eventType);
+			}
+		}
+	}
+
 	private boolean containsAtLeastOneEventOfType(List<EventSpec> events, Class<? extends EventSpec> eventType) {
 		for (EventSpec event : events) {
-			if (event.getClass().getName().equals(eventType.getName())) {
+			if (eventType.isAssignableFrom(event.getClass())) {
 				return true;
 			}
 		}
@@ -278,7 +297,7 @@ public class RefactoringHelper {
 
 	private boolean containsOnlyEventsOfType(List<EventSpec> events, Class<? extends EventSpec> eventType) {
 		for (EventSpec event : events) {
-			if (!event.getClass().getName().equals(eventType.getName())) {
+			if (!eventType.isAssignableFrom(event.getClass())) {
 				return false;
 			}
 		}
@@ -286,17 +305,16 @@ public class RefactoringHelper {
 	}
 
 	/**
-	 * Checks if all given transitions have at least one action.
-	 * Returns false for empty lists.
+	 * Checks if all given transitions have at least one action. Returns false for
+	 * empty lists.
 	 * 
 	 * @param transitions
 	 * @return
 	 */
-	public boolean haveAllAtLeastOneAction(
-			EList<Transition> transitions) {
+	public boolean haveAllAtLeastOneAction(EList<Transition> transitions) {
 		if (transitions.isEmpty())
 			return false;
-		
+
 		for (Transition transition : transitions) {
 			if (!hasAtLeastOneAction(transition)) {
 				return false;
@@ -304,9 +322,11 @@ public class RefactoringHelper {
 		}
 		return true;
 	}
-	
+
 	/**
-	 * Returns for the given semantic element the notation view element in the given diagram
+	 * Returns for the given semantic element the notation view element in the given
+	 * diagram
+	 * 
 	 * @param semanticElement
 	 * @param diagram
 	 * @return
@@ -322,7 +342,7 @@ public class RefactoringHelper {
 				}
 			}
 		}
-		throw new IllegalArgumentException("No view found for semantic element "+semanticElement);
+		throw new IllegalArgumentException("No view found for semantic element " + semanticElement);
 	}
-	
+
 }

+ 1 - 2
test-plugins/org.yakindu.sct.refactoring.tests/src/org/yakindu/sct/refactoring/refactor/StateBasedRefactoringTest.java

@@ -37,9 +37,8 @@ public abstract class StateBasedRefactoringTest extends RefactoringTest {
 		AbstractRefactoring<?> refactoring = getRefactoring(state);
 		AbstractSCTResource initialRes = (AbstractSCTResource) initial.eResource();
 		initialRes.setSerializerEnabled(true);
-		refactoring.internalExecute();
+		refactoring.executeRefactoring();
 		initialRes.setSerializerEnabled(false);
-		initialRes.linkSpecificationElements();
 
 		Statechart expected = models.loadStatechartFromResource(pathToExpectedSct);
 

+ 0 - 1
test-plugins/org.yakindu.sct.refactoring.tests/src/org/yakindu/sct/refactoring/refactor/ViewBasedRefactoringTest.java

@@ -39,7 +39,6 @@ public abstract class ViewBasedRefactoringTest extends RefactoringTest {
 		initialRes.setSerializerEnabled(true);
 		refactoring.execute();
 		initialRes.setSerializerEnabled(false);
-		initialRes.linkSpecificationElements();
 
 		Statechart expected = models
 				.loadStatechartFromResource(pathToExpectedSct);

+ 0 - 1
test-plugins/org.yakindu.sct.refactoring.tests/src/org/yakindu/sct/refactoring/refactor/impl/RenameRefactoringTest.java

@@ -135,7 +135,6 @@ public class RenameRefactoringTest extends RefactoringTest {
 		refactoring.internalExecute();
 		initialRes.setSerializerEnabled(false);
 
-		initialRes.linkSpecificationElements();
 
 		compareStatecharts(initial, expected);
 	}