blob: 96387b9cb143531cc8238777e3c9e998ffe9822f [file] [log] [blame]
/*
* Copyright (c) 2005, 2017 IBM Corporation, CEA, 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:
* IBM - initial API and implementation
* Kenn Hussey (CEA) - 327039, 351774, 418466, 451350, 485756, 513200
*
*/
package org.eclipse.uml2.uml.internal.operations;
import java.util.Map;
import org.eclipse.emf.common.util.BasicDiagnostic;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.DiagnosticChain;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.uml2.uml.BehavioredClassifier;
import org.eclipse.uml2.uml.RedefinableElement;
import org.eclipse.uml2.uml.Region;
import org.eclipse.uml2.uml.State;
import org.eclipse.uml2.uml.StateMachine;
import org.eclipse.uml2.uml.Vertex;
import org.eclipse.uml2.uml.util.UMLValidator;
/**
* <!-- begin-user-doc -->
* A static utility class that provides operations related to '<em><b>State Machine</b></em>' model objects.
* <!-- end-user-doc -->
*
* <p>
* The following operations are supported:
* </p>
* <ul>
* <li>{@link org.eclipse.uml2.uml.StateMachine#validateConnectionPoints(org.eclipse.emf.common.util.DiagnosticChain, java.util.Map) <em>Validate Connection Points</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#validateClassifierContext(org.eclipse.emf.common.util.DiagnosticChain, java.util.Map) <em>Validate Classifier Context</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#validateMethod(org.eclipse.emf.common.util.DiagnosticChain, java.util.Map) <em>Validate Method</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#validateContextClassifier(org.eclipse.emf.common.util.DiagnosticChain, java.util.Map) <em>Validate Context Classifier</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#LCA(org.eclipse.uml2.uml.Vertex, org.eclipse.uml2.uml.Vertex) <em>LCA</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#ancestor(org.eclipse.uml2.uml.Vertex, org.eclipse.uml2.uml.Vertex) <em>Ancestor</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#LCAState(org.eclipse.uml2.uml.Vertex, org.eclipse.uml2.uml.Vertex) <em>LCA State</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#isConsistentWith(org.eclipse.uml2.uml.RedefinableElement) <em>Is Consistent With</em>}</li>
* <li>{@link org.eclipse.uml2.uml.StateMachine#isRedefinitionContextValid(org.eclipse.uml2.uml.RedefinableElement) <em>Is Redefinition Context Valid</em>}</li>
* </ul>
*
* @generated
*/
public class StateMachineOperations
extends BehaviorOperations {
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected StateMachineOperations() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The Classifier context of a StateMachine cannot be an Interface.
* _'context' <> null implies not _'context'.oclIsKindOf(Interface)
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* @param diagnostics The chain of diagnostics to which problems are to be appended.
* @param context The cache of context-specific information.
* <!-- end-model-doc -->
* @generated
*/
public static boolean validateClassifierContext(StateMachine stateMachine,
DiagnosticChain diagnostics, Map<Object, Object> context) {
// TODO: implement this method
// -> specify the condition that violates the invariant
// -> verify the details of the diagnostic, including severity and message
// Ensure that you remove @generated or mark it @generated NOT
if (false) {
if (diagnostics != null) {
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR,
UMLValidator.DIAGNOSTIC_SOURCE,
UMLValidator.STATE_MACHINE__CLASSIFIER_CONTEXT,
org.eclipse.emf.ecore.plugin.EcorePlugin.INSTANCE.getString(
"_UI_GenericInvariant_diagnostic", //$NON-NLS-1$
new Object[]{"validateClassifierContext", //$NON-NLS-1$
org.eclipse.emf.ecore.util.EObjectValidator
.getObjectLabel(stateMachine, context)}),
new Object[]{stateMachine}));
}
return false;
}
return true;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The context Classifier of the method StateMachine of a BehavioralFeature must be the Classifier that owns the BehavioralFeature.
* specification <> null implies ( _'context' <> null and specification.featuringClassifier->exists(c | c = _'context'))
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* @param diagnostics The chain of diagnostics to which problems are to be appended.
* @param context The cache of context-specific information.
* <!-- end-model-doc -->
* @generated
*/
public static boolean validateContextClassifier(StateMachine stateMachine,
DiagnosticChain diagnostics, Map<Object, Object> context) {
// TODO: implement this method
// -> specify the condition that violates the invariant
// -> verify the details of the diagnostic, including severity and message
// Ensure that you remove @generated or mark it @generated NOT
if (false) {
if (diagnostics != null) {
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR,
UMLValidator.DIAGNOSTIC_SOURCE,
UMLValidator.STATE_MACHINE__CONTEXT_CLASSIFIER,
org.eclipse.emf.ecore.plugin.EcorePlugin.INSTANCE.getString(
"_UI_GenericInvariant_diagnostic", //$NON-NLS-1$
new Object[]{"validateContextClassifier", //$NON-NLS-1$
org.eclipse.emf.ecore.util.EObjectValidator
.getObjectLabel(stateMachine, context)}),
new Object[]{stateMachine}));
}
return false;
}
return true;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The operation LCA(s1,s2) returns the Region that is the least common ancestor of Vertices s1 and s2, based on the StateMachine containment hierarchy.
* result = (if ancestor(s1, s2) then
* s2.container
* else
* if ancestor(s2, s1) then
* s1.container
* else
* LCA(s1.container.state, s2.container.state)
* endif
* endif)
* <p>From package UML::StateMachines.</p>
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static Region LCA(StateMachine stateMachine, Vertex s1, Vertex s2) {
if (ancestor(stateMachine, s1, s2)) {
return s2.getContainer();
} else if (ancestor(stateMachine, s2, s1)) {
return s1.getContainer();
} else {
Region container1 = s1.getContainer();
State state1 = container1 == null
? null
: container1.getState();
Region container2 = s2.getContainer();
State state2 = container2 == null
? null
: container2.getState();
return state1 != null && state2 != null
? LCA(stateMachine, state1, state2)
: null;
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The query ancestor(s1, s2) checks whether Vertex s2 is an ancestor of Vertex s1.
* result = (if (s2 = s1) then
* true
* else
* if s1.container.stateMachine->notEmpty() then
* true
* else
* if s2.container.stateMachine->notEmpty() then
* false
* else
* ancestor(s1, s2.container.state)
* endif
* endif
* endif )
* <p>From package UML::StateMachines.</p>
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static boolean ancestor(StateMachine stateMachine, Vertex s1,
Vertex s2) {
if (s1 == s2) {
return true;
} else {
Region container1 = s1.getContainer();
if (container1 != null && container1.getStateMachine() != null) {
return true;
} else {
Region container2 = s2.getContainer();
if (container2 != null) {
if (container2.getStateMachine() != null) {
return false;
} else {
State state2 = container2.getState();
if (state2 != null) {
return ancestor(stateMachine, s1, state2);
}
}
}
return false;
}
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* This utility funciton is like the LCA, except that it returns the nearest composite State that contains both input Vertices.
* result = (if v2.oclIsTypeOf(State) and ancestor(v1, v2) then
* v2.oclAsType(State)
* else if v1.oclIsTypeOf(State) and ancestor(v2, v1) then
* v1.oclAsType(State)
* else if (v1.container.state->isEmpty() or v2.container.state->isEmpty()) then
* null.oclAsType(State)
* else LCAState(v1.container.state, v2.container.state)
* endif endif endif)
* <p>From package UML::StateMachines.</p>
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static State LCAState(StateMachine stateMachine, Vertex v1,
Vertex v2) {
if (v2 instanceof State && ancestor(stateMachine, v1, v2)) {
return (State) v2;
} else if (v1 instanceof State && ancestor(stateMachine, v2, v1)) {
return (State) v1;
} else {
Region container1 = v1.getContainer();
State state1 = container1 == null
? null
: container1.getState();
Region container2 = v2.getContainer();
State state2 = container2 == null
? null
: container2.getState();
return state1 == null || state2 == null
? null
: LCAState(stateMachine, state1, state2);
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The connection points of a StateMachine are Pseudostates of kind entry point or exit point.
* connectionPoint->forAll (kind = PseudostateKind::entryPoint or kind = PseudostateKind::exitPoint)
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* @param diagnostics The chain of diagnostics to which problems are to be appended.
* @param context The cache of context-specific information.
* <!-- end-model-doc -->
* @generated
*/
public static boolean validateConnectionPoints(StateMachine stateMachine,
DiagnosticChain diagnostics, Map<Object, Object> context) {
// TODO: implement this method
// -> specify the condition that violates the invariant
// -> verify the details of the diagnostic, including severity and message
// Ensure that you remove @generated or mark it @generated NOT
if (false) {
if (diagnostics != null) {
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR,
UMLValidator.DIAGNOSTIC_SOURCE,
UMLValidator.STATE_MACHINE__CONNECTION_POINTS,
org.eclipse.emf.ecore.plugin.EcorePlugin.INSTANCE.getString(
"_UI_GenericInvariant_diagnostic", //$NON-NLS-1$
new Object[]{"validateConnectionPoints", //$NON-NLS-1$
org.eclipse.emf.ecore.util.EObjectValidator
.getObjectLabel(stateMachine, context)}),
new Object[]{stateMachine}));
}
return false;
}
return true;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* A StateMachine as the method for a BehavioralFeature cannot have entry/exit connection points.
* specification <> null implies connectionPoint->isEmpty()
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* @param diagnostics The chain of diagnostics to which problems are to be appended.
* @param context The cache of context-specific information.
* <!-- end-model-doc -->
* @generated
*/
public static boolean validateMethod(StateMachine stateMachine,
DiagnosticChain diagnostics, Map<Object, Object> context) {
// TODO: implement this method
// -> specify the condition that violates the invariant
// -> verify the details of the diagnostic, including severity and message
// Ensure that you remove @generated or mark it @generated NOT
if (false) {
if (diagnostics != null) {
diagnostics.add(new BasicDiagnostic(Diagnostic.ERROR,
UMLValidator.DIAGNOSTIC_SOURCE,
UMLValidator.STATE_MACHINE__METHOD,
org.eclipse.emf.ecore.plugin.EcorePlugin.INSTANCE.getString(
"_UI_GenericInvariant_diagnostic", //$NON-NLS-1$
new Object[]{"validateMethod", //$NON-NLS-1$
org.eclipse.emf.ecore.util.EObjectValidator
.getObjectLabel(stateMachine, context)}),
new Object[]{stateMachine}));
}
return false;
}
return true;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The query isConsistentWith() specifies that a redefining State is consistent with a redefined State provided that the redefining State is an extension of the redefined State A simple State can be redefined (extended) to become a composite State (by adding one or more Regions) and a composite State can be redefined (extended) by adding Regions and by adding Vertices, States, and Transitions to inherited Regions. All States may add or replace entry, exit, and 'doActivity' Behaviors.
* redefiningElement.isRedefinitionContextValid(self)
* result = (-- the following is merely a default body; it is expected that the specific form of this constraint will be specified by profiles
* true)
* <p>From package UML::StateMachines.</p>
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static boolean isConsistentWith(StateMachine stateMachine,
RedefinableElement redefiningElement) {
if (redefiningElement != null
&& redefiningElement.isRedefinitionContextValid(stateMachine)) {
StateMachine redefiningStateMachine = (StateMachine) redefiningElement;
EList<Region> allRegions = getAllRegions(stateMachine);
for (Region redefiningRegion : redefiningStateMachine
.getRegions()) {
Region extendedRegion = redefiningRegion.getExtendedRegion();
if (allRegions.contains(extendedRegion)
&& !extendedRegion.isConsistentWith(redefiningRegion)) {
return false;
}
}
return true;
}
return false;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* <!-- begin-model-doc -->
* The query isRedefinitionContextValid() specifies whether the redefinition context of a StateMachine is properly related to the redefinition contexts of the specified StateMachine to allow this element to redefine the other. The context Classifier of a redefining StateMachine must redefine the context Classifier of the redefined StateMachine.
* result = (if redefinedElement.oclIsKindOf(StateMachine) then
* let redefinedStateMachine : StateMachine = redefinedElement.oclAsType(StateMachine) in
* self._'context'().oclAsType(BehavioredClassifier).redefinedClassifier->
* includes(redefinedStateMachine._'context'())
* else
* false
* endif)
* <p>From package UML::StateMachines.</p>
* @param stateMachine The receiving '<em><b>State Machine</b></em>' model object.
* <!-- end-model-doc -->
* @generated NOT
*/
public static boolean isRedefinitionContextValid(StateMachine stateMachine,
RedefinableElement redefinedElement) {
if (redefinedElement instanceof StateMachine) {
BehavioredClassifier context = stateMachine.getContext();
BehavioredClassifier parentContext = ((StateMachine) redefinedElement)
.getContext();
return context == null
? parentContext == null
&& stateMachine.allParents().contains(redefinedElement)
: parentContext != null
&& context.allParents().contains(parentContext);
}
return false;
}
protected static EList<StateMachine> getAllExtendedStateMachines(
StateMachine stateMachine,
EList<StateMachine> allExtendedStateMachines) {
for (StateMachine extendedStateMachine : stateMachine
.getExtendedStateMachines()) {
if (allExtendedStateMachines.add(extendedStateMachine)) {
getAllExtendedStateMachines(extendedStateMachine,
allExtendedStateMachines);
}
}
return allExtendedStateMachines;
}
protected static EList<StateMachine> getAllExtendedStateMachines(
StateMachine stateMachine) {
return getAllExtendedStateMachines(stateMachine,
new UniqueEList.FastCompare<StateMachine>());
}
protected static EList<Region> getAllRegions(StateMachine stateMachine) {
EList<Region> allRegions = new UniqueEList.FastCompare<Region>(
stateMachine.getRegions());
for (StateMachine extendedStateMachine : getAllExtendedStateMachines(
stateMachine)) {
allRegions.addAll(extendedStateMachine.getRegions());
}
return RedefinableElementOperations
.excludeRedefinedElements(allRegions);
}
} // StateMachineOperations