/***************************************************************************** * Copyright (c) 2010 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: * CEA LIST - Initial API and implementation * *****************************************************************************/ package org.eclipse.papyrus.uml.textedit.state.xtext.validation; import java.util.ArrayList; import java.util.List; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.BehaviorKind; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.DoRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.EntryRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.ExitRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.StateRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.SubmachineRule; import org.eclipse.papyrus.uml.textedit.state.xtext.umlState.UmlStatePackage; import org.eclipse.papyrus.uml.textedit.state.xtext.validation.AbstractUmlStateJavaValidator; import org.eclipse.uml2.uml.Activity; import org.eclipse.uml2.uml.Behavior; import org.eclipse.uml2.uml.Element; import org.eclipse.uml2.uml.Namespace; import org.eclipse.uml2.uml.OpaqueBehavior; import org.eclipse.uml2.uml.StateMachine; import org.eclipse.uml2.uml.Vertex; import org.eclipse.xtext.gmf.glue.edit.part.PopupXtextEditorHelper; import org.eclipse.xtext.validation.Check; public class UmlStateJavaValidator extends AbstractUmlStateJavaValidator { private static Namespace model ; private static Element contextElement ; private static boolean valid_StateName = true ; private static boolean valid_SubMachineRule = true ; public static void init(Element _contextElement) { contextElement = _contextElement ; if (contextElement != null) { Element elem = contextElement.getOwner() ; while (elem.getOwner() != null) { elem = elem.getOwner() ; } model = (Namespace)elem ; } } public static Namespace getModel() { return model ; } public static Element getContextElement() { return contextElement ; } public static boolean validate() { return valid_StateName && valid_SubMachineRule ; } /** * First checks if the new name being attributed to the edited state is already used by another state in the region. * Then, notifies (via warning) any of the potential Behavior deletion implied by the textual specification * (either DoActivity, Enty, or Exit behaviors) * * @param stateRule */ @Check public void checkStateName (StateRule stateRule) { if (PopupXtextEditorHelper.context == null) return ; if (stateRule.getName() == null || stateRule.getName().equals("")) return ; // // first, checks if the new name of the State is already used by another state in the region // org.eclipse.uml2.uml.State editedState = (org.eclipse.uml2.uml.State) PopupXtextEditorHelper.context ; List<String> alreadyUsedNames = new ArrayList<String>() ; for (Vertex v : editedState.getContainer().getSubvertices()) { if (v instanceof org.eclipse.uml2.uml.State) { org.eclipse.uml2.uml.State s = (org.eclipse.uml2.uml.State) v ; if (s != editedState) { alreadyUsedNames.add("" + s.getName()) ; } } } String newName = "" + stateRule.getName() ; if (alreadyUsedNames.contains("" + newName)) warning("Name " + newName + " is already used by another State in this Region", UmlStatePackage.eINSTANCE.getStateRule_Name()) ; // Check if ConnectionPointReference exist when one delete the submachine reference: not allowed! if((stateRule.getSubmachine() == null) && !editedState.getConnections().isEmpty()){ error(getErrorMessageForSubmachineState(), UmlStatePackage.eINSTANCE.getStateRule_Submachine()) ; valid_StateName = false ; } else { valid_StateName = true ; } // // Then, checks if the textual specification implies deletion of the DoActivity, Entry or Exit behavior // and raises warnings accordingly // boolean deletionOfDoActivity = editedState.getDoActivity()!=null && stateRule.getDo()==null ; boolean deletionOfExit = editedState.getExit()!=null && stateRule.getExit()==null ; boolean deletionOfEntry = editedState.getEntry()!=null && stateRule.getEntry()==null; if (deletionOfDoActivity) { warning(getBehaviorKindAsString( getBehaviorKind(editedState.getDoActivity()) ) + " " + editedState.getDoActivity().getName() + " will be deleted", UmlStatePackage.eINSTANCE.getStateRule_Name()) ; } if (deletionOfExit) { warning(getBehaviorKindAsString( getBehaviorKind(editedState.getExit()) ) + " " + editedState.getExit().getName() + " will be deleted", UmlStatePackage.eINSTANCE.getStateRule_Name()) ; } if (deletionOfEntry) { warning(getBehaviorKindAsString( getBehaviorKind(editedState.getEntry()) ) + " " + editedState.getEntry().getName() + " will be deleted", UmlStatePackage.eINSTANCE.getStateRule_Name()) ; } } /** * Notifies (via a Warning) the potential impact of changing the kind (i.e., Activity, StateMachine or OpaqueBehavior) * of the DoActivity behavior. * * @param doRule */ @Check public void checkDoRule (DoRule doRule) { if (PopupXtextEditorHelper.context == null) return ; if (doRule.getKind() == null) return ; if (doRule.getBehaviorName() == null || doRule.getBehaviorName().equals("")) return ; org.eclipse.uml2.uml.State editedState = (org.eclipse.uml2.uml.State) PopupXtextEditorHelper.context ; BehaviorKind oldDoKind = getBehaviorKind(editedState.getDoActivity()) ; BehaviorKind newDoKind = doRule.getKind() ; if (oldDoKind != null) { if (oldDoKind != newDoKind) { warning("Changing the kind of " + doRule.getBehaviorName() + " from <<" + getBehaviorKindAsString(oldDoKind) + ">> to <<" + getBehaviorKindAsString(newDoKind) + ">> will cause the deletion of " + getBehaviorKindAsString(oldDoKind) + " " + doRule.getBehaviorName() + ". Any changes made to " + getBehaviorKindAsString(oldDoKind) + " " + doRule.getBehaviorName() + " will be lost", UmlStatePackage.eINSTANCE.getDoRule_Kind()) ; } } } /** * Notifies (via a Warning) the potential impact of changing the kind (i.e., Activity, StateMachine or OpaqueBehavior) * of the Entry behavior. * * @param entryRule */ @Check public void checkEntryRule (EntryRule entryRule) { if (PopupXtextEditorHelper.context == null) return ; if (entryRule.getKind() == null) return ; if (entryRule.getBehaviorName() == null || entryRule.getBehaviorName().equals("")) return ; org.eclipse.uml2.uml.State editedState = (org.eclipse.uml2.uml.State) PopupXtextEditorHelper.context ; BehaviorKind oldDoKind = getBehaviorKind(editedState.getEntry()) ; BehaviorKind newDoKind = entryRule.getKind() ; if (oldDoKind != null) { if (oldDoKind != newDoKind) { warning("Changing the kind of " + entryRule.getBehaviorName() + " from <<" + getBehaviorKindAsString(oldDoKind) + ">> to <<" + getBehaviorKindAsString(newDoKind) + ">> will cause the deletion of " + getBehaviorKindAsString(oldDoKind) + " " + entryRule.getBehaviorName() + ". Any changes made to " + getBehaviorKindAsString(oldDoKind) + " " + entryRule.getBehaviorName() + " will be lost", UmlStatePackage.eINSTANCE.getEntryRule_Kind()) ; } } } /** * Notifies (via a Warning) the potential impact of changing the kind (i.e., Activity, StateMachine or OpaqueBehavior) * of the Entry behavior. * * @param exitRule */ @Check public void checkExitRule (ExitRule exitRule) { if (PopupXtextEditorHelper.context == null) return ; if (exitRule.getKind() == null) return ; if (exitRule.getBehaviorName() == null || exitRule.getBehaviorName().equals("")) return ; org.eclipse.uml2.uml.State editedState = (org.eclipse.uml2.uml.State) PopupXtextEditorHelper.context ; BehaviorKind oldDoKind = getBehaviorKind(editedState.getExit()) ; BehaviorKind newDoKind = exitRule.getKind() ; if (oldDoKind != null) { if (oldDoKind != newDoKind) { warning("Changing the kind of " + exitRule.getBehaviorName() + " from <<" + getBehaviorKindAsString(oldDoKind) + ">> to <<" + getBehaviorKindAsString(newDoKind) + ">> will cause the deletion of " + getBehaviorKindAsString(oldDoKind) + " " + exitRule.getBehaviorName() + ". Any changes made to " + getBehaviorKindAsString(oldDoKind) + " " + exitRule.getBehaviorName() + " will be lost", UmlStatePackage.eINSTANCE.getExitRule_Kind()) ; } } } @Check public void checkSubmachineRule(SubmachineRule rule) { if (contextElement == null || ! (contextElement instanceof org.eclipse.uml2.uml.State)) return ; org.eclipse.uml2.uml.State contextState = (org.eclipse.uml2.uml.State)contextElement ; if (contextState.isOrthogonal()) { error(getErrorMessageForOrthogonalState(), UmlStatePackage.eINSTANCE.getSubmachineRule_Submachine()) ; valid_SubMachineRule = false ; } else { valid_SubMachineRule = true ; } if (contextState.isComposite()) { error(getErrorMessageForCompositeState(), UmlStatePackage.eINSTANCE.getSubmachineRule_Submachine()) ; valid_SubMachineRule = false ; } else { valid_SubMachineRule = true ; } } //*****************// // Utility methods // //*****************// private String getErrorMessageForOrthogonalState() { return "An orthogonal state cannot reference a submachine." ; } private String getErrorMessageForCompositeState() { return "A composite state cannot reference a submachine." ; } private String getErrorMessageForSubmachineState() { return "A simple state cannot have ConnectionPointReferences. You should delete them before removing the reference to the submachine." ; } private static BehaviorKind getBehaviorKind(Behavior behavior) { if (behavior == null) return null ; if (behavior instanceof Activity) return BehaviorKind.ACTIVITY ; if (behavior instanceof OpaqueBehavior) return BehaviorKind.OPAQUE_BEHAVIOR ; if (behavior instanceof StateMachine) return BehaviorKind.STATE_MACHINE ; return null ; } private static String getBehaviorKindAsString(BehaviorKind behaviorKind) { if (behaviorKind == BehaviorKind.ACTIVITY) return "Activity" ; if (behaviorKind == BehaviorKind.OPAQUE_BEHAVIOR) return "OpaqueBehavior" ; if (behaviorKind == BehaviorKind.STATE_MACHINE) return "StateMachine" ; return "" ; } }