blob: b5f76b2fd65120a208e5e26986173ffa02209f1b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 Zeligsoft (2009) Limited 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
*******************************************************************************/
package org.eclipse.papyrusrt.xtumlrt.util
import org.eclipse.papyrusrt.xtumlrt.statemach.CompositeState
import org.eclipse.papyrusrt.xtumlrt.statemach.ChoicePoint
import org.eclipse.papyrusrt.xtumlrt.statemach.DeepHistory
import org.eclipse.papyrusrt.xtumlrt.statemach.EntryPoint
import org.eclipse.papyrusrt.xtumlrt.statemach.ExitPoint
import org.eclipse.papyrusrt.xtumlrt.statemach.InitialPoint
import org.eclipse.papyrusrt.xtumlrt.statemach.JunctionPoint
import org.eclipse.papyrusrt.xtumlrt.statemach.Pseudostate
import org.eclipse.papyrusrt.xtumlrt.statemach.State
import org.eclipse.papyrusrt.xtumlrt.statemach.StateMachine
import org.eclipse.papyrusrt.xtumlrt.statemach.Transition
import org.eclipse.papyrusrt.xtumlrt.statemach.Vertex
import static extension org.eclipse.papyrusrt.xtumlrt.util.XTUMLRTStateMachineUtil.*
import java.util.Collection
import java.util.List
/**
* This class provides extension methods that implement "virtual state machine
* inheritance" as described in the UML-RT profile. This provides operations to,
* for example, obtain all the states and transitions inside a composite state
* including those inherited and those refined, as well as operations to obtain
* the inherited transitions to and from a state.
*
* <p>
*/
class XTUMLRTSMVirtualInheritanceExtensions
{
/**
* Returns the initial point of the state machine if it has one, or the
* inherited initial point, if there is one along the inheritance hierarchy.
*/
static dispatch def InitialPoint getActualInitialPoint( StateMachine stateMachine )
{
if (stateMachine.top === null) return null
stateMachine.top.actualInitialPoint
}
static dispatch def InitialPoint getActualInitialPoint( CompositeState state )
{
if (state.hasInitial) state.initial
else
{
val refinedState = state.redefinedState
if (refinedState !== null && refinedState instanceof CompositeState)
refinedState.actualInitialPoint
}
}
/**
* Returns the initial point of the state machine if it has one, or the
* inherited initial point, if there is one along the inheritance hierarchy.
*/
static dispatch def DeepHistory getActualDeepHistory( StateMachine stateMachine )
{
if (stateMachine.top === null) return null
stateMachine.top.actualDeepHistory
}
static dispatch def DeepHistory getActualDeepHistory( CompositeState state )
{
if (state.hasDeepHistory) state.deepHistory
else
{
val refinedState = state.redefinedState
if (refinedState !== null && refinedState instanceof CompositeState)
refinedState.actualDeepHistory
}
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited choice points,
* <li> the set of new choice points which are neither inherited, not redefinitions
* </ol>
*/
static def dispatch Iterable<ChoicePoint> getAllChoicePoints( StateMachine stateMachine )
{
if (stateMachine.top === null) return #[];
stateMachine.top.allChoicePoints
}
static def dispatch Iterable<ChoicePoint> getAllChoicePoints( State state )
{
#[]
}
static def dispatch Iterable<ChoicePoint> getAllChoicePoints( CompositeState state )
{
val List<ChoicePoint> allChoicePoints = newArrayList
if (state !== null)
{
allChoicePoints.addAll( state.choicePoints )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
allChoicePoints.addAll( redefinedState.allChoicePoints )
}
}
allChoicePoints
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited connection points, and
* <li> the set of new connection points which are not inherited
* </ol>
*/
static def Iterable<Pseudostate> getAllConnectionPoints( State state )
{
val List<Pseudostate> allConnectionPoints = newArrayList
if (state !== null)
{
if (state.connectionPoints !== null)
allConnectionPoints.addAll( state.connectionPoints )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedPseudostates = redefinedState.allConnectionPoints
allConnectionPoints.addAll( inheritedPseudostates )
}
}
allConnectionPoints
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited incoming transitions that have not been
* redefined,
* <li> the set of incoming transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new incoming transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllDirectIncomingTransitions( Vertex v )
{
val List<Transition> allTransitions = newArrayList
if (v !== null)
{
allTransitions.addAll( v.directIncomingTransitions )
if (v instanceof State)
{
val redefinedState = v.redefines as State
if (redefinedState !== null)
{
val inheritedTransitions = redefinedState.allDirectIncomingTransitions
for (t : inheritedTransitions)
{
val container = v.ownerState as CompositeState
if ( container !== null && !container.redefines(t) )
allTransitions.add(t)
}
}
}
}
allTransitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited outgoing transitions that have not been
* redefined,
* <li> the set of outgoing transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new outgoing transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllDirectOutgoingTransitions( Vertex v )
{
val List<Transition> allTransitions = newArrayList
if (v !== null)
{
allTransitions.addAll( v.directOutgoingTransitions )
if (v instanceof State)
{
val redefinedState = v.redefines as State
if (redefinedState !== null)
{
val inheritedTransitions = redefinedState.allDirectOutgoingTransitions
for (t : inheritedTransitions)
{
val container = v.ownerState as CompositeState
if ( container !== null && !container.redefines(t) )
allTransitions.add(t)
}
}
}
}
allTransitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited entry points, and
* <li> the set of new entry points which are not inherited
* </ol>
*/
static def Iterable<EntryPoint> getAllEntryPoints( State state )
{
val List<EntryPoint> allEntryPoints = newArrayList
if (state !== null)
{
if (state.entryPoints !== null)
allEntryPoints.addAll( state.entryPoints )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedPseudostates = redefinedState.allEntryPoints
allEntryPoints.addAll( inheritedPseudostates )
}
}
allEntryPoints
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited entry points, and
* <li> the set of new entry points which are not inherited
* </ol>
*/
static def Iterable<ExitPoint> getAllExitPoints( State state )
{
val List<ExitPoint> allExitPoints = newArrayList
if (state !== null)
{
if (state.entryPoints !== null)
allExitPoints.addAll( state.exitPoints )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedPseudostates = redefinedState.allExitPoints
allExitPoints.addAll( inheritedPseudostates )
}
}
allExitPoints
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited incoming transitions that have not been
* redefined,
* <li> the set of incoming transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new incoming transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllIncomingTransitions( State s )
{
val List<Transition> transitions = newArrayList
transitions.addAll( s.allDirectIncomingTransitions )
transitions.addAll( s.allIndirectIncomingTransitions )
transitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited incoming transitions that have not been
* redefined,
* <li> the set of incoming transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new incoming transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllIndirectIncomingTransitions( State s )
{
val List<Transition> allTransitions = newArrayList
if (s !== null)
{
allTransitions.addAll( s.indirectIncomingTransitions )
val redefinedState = s.redefinedState
if (redefinedState !== null)
{
val inheritedTransitions = redefinedState.allIndirectIncomingTransitions
for (t : inheritedTransitions)
{
val container = s.ownerState as CompositeState
if ( container !== null && !container.redefines(t) )
allTransitions.add(t)
}
}
}
allTransitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited outgoing transitions that have not been
* redefined,
* <li> the set of outgoing transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new outgoing transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllIndirectOutgoingTransitions( State s )
{
val List<Transition> allTransitions = newArrayList
if (s !== null)
{
allTransitions.addAll( s.indirectOutgoingTransitions )
val redefinedState = s.redefinedState
if (redefinedState !== null)
{
val inheritedTransitions = redefinedState.allIndirectOutgoingTransitions
for (t : inheritedTransitions)
{
val container = s.ownerState as CompositeState
if ( container !== null && !container.redefines(t) )
allTransitions.add(t)
}
}
}
allTransitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited junction points,
* <li> the set of new junction points which are neither inherited, not redefinitions
* </ol>
*/
static def dispatch Iterable<JunctionPoint> getAllJunctionPoints( StateMachine stateMachine )
{
if (stateMachine.top === null) return #[];
stateMachine.top.allJunctionPoints
}
static def dispatch Iterable<JunctionPoint> getAllJunctionPoints( State state )
{
#[]
}
static def dispatch Iterable<JunctionPoint> getAllJunctionPoints( CompositeState state )
{
val List<JunctionPoint> allJunctionPoints = newArrayList
if (state !== null)
{
allJunctionPoints.addAll( state.junctionPoints )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
allJunctionPoints.addAll( redefinedState.allJunctionPoints )
}
}
allJunctionPoints
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited outgoing transitions that have not been
* redefined,
* <li> the set of outgoing transitions that are redefinitions of states
* in the extended composite state, and
* <li> the set of new outgoing transitions which are neither inherited,
* not redefinitions
* </ol>
*
* <p> The last two sets are already present in the vertex container,
* so this method takes those transitions in that container and adds all
* inherited transitions for which there is no transition in the container
* redefining them.
*/
static def Iterable<Transition> getAllOutgoingTransitions( State s )
{
val List<Transition> transitions = newArrayList
transitions.addAll( s.allDirectOutgoingTransitions )
transitions.addAll( s.allIndirectOutgoingTransitions )
transitions
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited (internal) pseudostates, and
* <li> the set of new (internal) pseudostates which are not inherited
* </ol>
*
* <p> The last two sets are already present in the given region, so this method takes
* those states in the current region and adds all inherited states for which there is
* no state in the given region redefining them.
*/
static dispatch def Iterable<Pseudostate> getAllPseudostates( StateMachine stateMachine )
{
if (stateMachine.top === null) return #[];
stateMachine.top.allPseudostates
}
static dispatch def Iterable<Pseudostate> getAllPseudostates( State state )
{
#[]
}
static dispatch def Iterable<Pseudostate> getAllPseudostates( CompositeState state )
{
val List<Pseudostate> allPseudostates = newArrayList
if (state !== null)
{
allPseudostates.addAll( state.pseudostates )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedPseudostates = redefinedState.allPseudostates
allPseudostates.addAll( inheritedPseudostates )
}
}
allPseudostates
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited states that have not been redefined,
* <li> the set of states that are redefinitions of states in the extended region, and
* <li> the set of new states which are neither inherited, not redefinitions
* </ol>
*
* <p> The last two sets are already present in the given region, so this method takes
* those states in the current region and adds all inherited states for which there is
* no state in the given region redefining them.
*/
static def dispatch Iterable<State> getAllSubstates( StateMachine stateMachine )
{
if (stateMachine.top === null) return #[];
stateMachine.top.allSubstates
}
static def dispatch Iterable<State> getAllSubstates( State state )
{
#[]
}
static def dispatch Iterable<State> getAllSubstates( CompositeState state )
{
val List<State> allStates = newArrayList
if (state !== null)
{
allStates.addAll( state.substates )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedStates = redefinedState.allSubstates
for (s : inheritedStates)
{
if (!state.redefines(s))
allStates.add(s)
}
}
}
allStates
}
/**
* Returns the union of:
*
* <ol>
* <li> the set inherited transitions that have not been redefined,
* <li> the set of transitions that are redefinitions of states in the extended region, and
* <li> the set of new transitions which are neither inherited, not redefinitions
* </ol>
*
* <p> The last two sets are already present in the given region, so this method takes
* those states in the current region and adds all inherited states for which there is
* no state in the given region redefining them.
*/
static def dispatch Iterable<Transition> getAllTransitions( StateMachine stateMachine )
{
if (stateMachine.top === null) return #[];
stateMachine.top.allTransitions
}
static def dispatch Iterable<Transition> getAllTransitions( State state )
{
#[]
}
static def dispatch Iterable<Transition> getAllTransitions( CompositeState state )
{
val List<Transition> allTransitions = newArrayList
if (state !== null)
{
allTransitions.addAll( state.transitions )
val redefinedState = state.redefinedState
if (redefinedState !== null)
{
val inheritedStates = redefinedState.allTransitions
for (s : inheritedStates)
{
if (!state.redefines(s))
allTransitions.add(s)
}
}
}
allTransitions
}
/**
* Returns the state redefined by the given state or null if it doesn't
* redefine any.
*/
static def State getRedefinedState( State s )
{
if (s === null || s.redefines === null || !(s.redefines instanceof State))
null
else
s.redefines as State
}
/**
* Returns a collection of states from the extended composite state that
* have been redefined in the given composite state.
*/
static def Iterable<State> getRedefinedStates( CompositeState state )
{
state.stateRedefinitions.map [ it.redefinedState ]
}
/**
* Returns the state redefined by the given state or null if it doesn't
* redefine any.
*/
static def Transition getRedefinedTransition( Transition t )
{
if (t === null || t.redefines === null || !(t.redefines instanceof Transition))
null
else
t.redefines as Transition
}
/**
* Returns a collection of transitions from the extended composite state
* that have been redefined in the given composite state.
*/
static def Iterable<Transition> getRedefinedTransitions( CompositeState state )
{
state.transitionRedefinitions.map [ it.redefinedTransition ]
}
/**
* Returns the collection of states which are redefinitions of a state in
* the extended composite state. In other words, it returns the collection
* of substates of the given composite state which redefine some state.
*/
static def Collection<State> getStateRedefinitions( CompositeState state )
{
val List<State> states = newArrayList
if (state !== null)
{
for (s : state.substates)
{
if (s.redefinedState !== null)
states.add(s)
}
}
states
}
/**
* Returns the collection of transitions which are redefinitions of a
* transition in the extended composite state. In other words, it returns
* the collection of transitions of the given composite state that redefine
* some transition.
*/
static def Collection<Transition> getTransitionRedefinitions( CompositeState state )
{
val List<Transition> transitions = newArrayList
if (state !== null)
{
for (t : state.transitions)
{
if (t.redefinedTransition !== null)
transitions.add(t)
}
}
transitions
}
/**
* Returns the source vertex of a given transition inside a given composite
* state which may be an extended state of the state containing the "real"
* source of the transition. This is, if transition t is inside (composite)
* state r because it was inherited, this is, t is defined in and actually
* belongs to a (composite) state r' redefined by r, then the real source s'
* of t is in r', but there may be a vertex s in r which redefines s', and
* therefore it should be considered the source of t in r.
*
* <p> The following diagram describes the situation: t in r is inherited
* from r', and its real source is s' and target is d'. This method returns
* s, the source of t in r.
* <p>
* <pre>
* <code>
* parent state r': s' --t--> d'
* ^ ^ ^
* | | |
* extended state r: s --t--> d
* </code>
* </pre>
*
*/
static def Vertex getTransitionSourceInState( Transition t, CompositeState r )
{
// Check if the source is one of the pseudostates, owned or inherited by r
for (s : r.allPseudostates)
{
if (t.sourceVertex === s)
return s
}
// Check if the source is one of the states, owned or inherited by r or a connection
// point for any such state
val statesToConsider = newArrayList
statesToConsider.add( r )
statesToConsider.addAll( r.allSubstates )
for (s : statesToConsider )
{
var v = s
// Go up the chain of state redefinitions looking for the actual source.
while (v !== null)
{
// Check if the source is the given state...
if (t.sourceVertex === v)
return s
// Check if it is the deep history pseudostate if the state is composite
if (v instanceof CompositeState)
{
val h = v.deepHistory
if (t.sourceVertex === h)
return h
}
// ... or if it is one of its connection (exit) points
if (v.connectionPoints !== null)
{
for (p : v.connectionPoints)
{
if (t.sourceVertex === p)
// p is not owned by r but we still need to report it, and since
// p is a pseudostate and non-redefinable, it must be inherited
// by s (TODO: unless it has been explicitly excluded, in which
// case we should report s)
return p
}
}
// If not, go up to the state that v redefines.
v = v.redefinedState
}
}
}
/**
* Returns the target vertex of a given transition inside a given composite
* state which may be an extended state of the state containing the "real"
* target of the transition. This is, if transition t is inside (composite)
* state r because it was inherited, this is, t is defined in and actually
* belongs to a (composite) state r' redefined by r, then the real target s'
* of t is in r', but there may be a vertex s in r which redefines s', and
* therefore it should be considered the target of t in r.
*
* <p> The following diagram describes the situation: t in r is inherited
* from r', and its real target is s' and target is d'. This method returns
* s, the target of t in r.
* <p>
* <pre>
* <code>
* parent state r': s' --t--> d'
* ^ ^ ^
* | | |
* extended state r: s --t--> d
* </code>
* </pre>
*
*/
static def Vertex getTransitionTargetInState( Transition t, CompositeState r )
{
// Check if the source is one of the pseudostates, owned or inherited by r
for (s : r.allPseudostates)
{
if (t.targetVertex === s)
return s
}
// Check if the target is one of the states, owned or inherited by r or a connection
// point for any such state
val statesToConsider = newArrayList
statesToConsider.add( r )
statesToConsider.addAll( r.allSubstates )
for (s : statesToConsider )
{
var v = s
// Go up the chain of state redefinitions looking for the actual target.
while (v !== null)
{
// Check if the source is the given state...
if (t.targetVertex === v)
return s
// Check if it is the deep history pseudostate if the state is composite
if (v instanceof CompositeState)
{
val h = v.deepHistory
if (t.targetVertex === h)
return h
}
// ... or if it is one of its connection (exit) points
if (v.connectionPoints !== null)
{
for (p : v.connectionPoints)
{
if (t.targetVertex === p)
// p is not owned by r but we still need to report it, and since
// p is a pseudostate and non-redefinable, it must be inherited
// by s (TODO: unless it has been explicitly excluded, in which
// case we should report s)
return p
}
}
// If not, go up to the state that v redefines.
v = v.redefinedState
}
}
}
/**
* Returns true is the given state from the region extended by the given region is
* redefined in the given region.
*
* @param compositeState - A {@link CompositeState}
* @param state - A {@link State}
* @return {@code true} iff:
* <ol>
* <li> {@code state} is a substate of the composite state that
* is extended by the given {@code compositeState} and
* <li> {@code state} is redefined by some state in the given
* {@code compositeState}
* </ol>
*/
static def dispatch redefines( CompositeState compositeState, State state )
{
compositeState.redefinedStates.exists [it == state]
}
/**
* Returns true is the given transition from the region extended by the given region is
* redefined in the given region.
*
* @param compositeState - A {@link CompositeState}
* @param transition - A {@link Transition}
* @return {@code true} iff:
* <ol>
* <li> {@code transition} is a transition in the composite state
* extended by the given {@code compositeState} and
* <li> {@code transition} is redefined by some transition in the
* given {@code compositeState}
* </ol>
*/
static def dispatch redefines(CompositeState compositeState, Transition transition)
{
compositeState.redefinedTransitions.exists [it == transition]
}
}