/**
* <copyright>
* </copyright>
*
* $Id$
*/
package org.eclipse.etrice.generator.etricegen.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.etrice.core.room.ActorClass;
import org.eclipse.etrice.core.room.ContinuationTransition;
import org.eclipse.etrice.core.room.DetailCode;
import org.eclipse.etrice.core.room.InterfaceItem;
import org.eclipse.etrice.core.room.MessageFromIf;
import org.eclipse.etrice.core.room.State;
import org.eclipse.etrice.core.room.StateGraphItem;
import org.eclipse.etrice.core.room.StateGraphNode;
import org.eclipse.etrice.core.room.Transition;
import org.eclipse.etrice.core.room.TransitionTerminal;
import org.eclipse.etrice.core.room.Trigger;
import org.eclipse.etrice.core.room.impl.ActorClassImpl;
import org.eclipse.emf.ecore.util.EcoreUtil.Copier;
import org.eclipse.etrice.core.naming.RoomNameProvider;
import org.eclipse.etrice.core.room.BaseState;
import org.eclipse.etrice.core.room.ChoicePoint;
import org.eclipse.etrice.core.room.ChoicepointTerminal;
import org.eclipse.etrice.core.room.EntryPoint;
import org.eclipse.etrice.core.room.ExitPoint;
import org.eclipse.etrice.core.room.ExternalPort;
import org.eclipse.etrice.core.room.InitialTransition;
import org.eclipse.etrice.core.room.Message;
import org.eclipse.etrice.core.room.NonInitialTransition;
import org.eclipse.etrice.core.room.Port;
import org.eclipse.etrice.core.room.RefinedState;
import org.eclipse.etrice.core.room.RoomFactory;
import org.eclipse.etrice.core.room.RoomPackage;
import org.eclipse.etrice.core.room.SAPRef;
import org.eclipse.etrice.core.room.SPPRef;
import org.eclipse.etrice.core.room.ServiceImplementation;
import org.eclipse.etrice.core.room.StateGraph;
import org.eclipse.etrice.core.room.StateTerminal;
import org.eclipse.etrice.core.room.SubStateTrPointTerminal;
import org.eclipse.etrice.core.room.TrPoint;
import org.eclipse.etrice.core.room.TrPointTerminal;
import org.eclipse.etrice.core.room.TransitionPoint;
import org.eclipse.etrice.core.room.TriggeredTransition;
import org.eclipse.etrice.core.room.TypedID;
import org.eclipse.etrice.generator.etricegen.ActiveTrigger;
import org.eclipse.etrice.generator.etricegen.ETriceGenFactory;
import org.eclipse.etrice.generator.etricegen.ETriceGenPackage;
import org.eclipse.etrice.generator.etricegen.ExpandedActorClass;
import org.eclipse.etrice.generator.etricegen.IDiagnostician;
import org.eclipse.etrice.generator.etricegen.TransitionChain;
/**
* <!-- begin-user-doc -->
* An implementation of the model object '<em><b>Expanded Actor Class</b></em>'.
* <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>{@link org.eclipse.etrice.generator.etricegen.impl.ExpandedActorClassImpl#getActorClass <em>Actor Class</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class ExpandedActorClassImpl extends ActorClassImpl implements ExpandedActorClass {
private class NodeData {
private LinkedList<Transition> inTrans = new LinkedList<Transition>();
private LinkedList<Transition> outTrans = new LinkedList<Transition>();
private LinkedList<Transition> loopTrans = null;
LinkedList<Transition> getInTrans() {
return inTrans;
}
LinkedList<Transition> getOutTrans() {
return outTrans;
}
LinkedList<Transition> getLoopTransitions() {
if (loopTrans==null) {
loopTrans = new LinkedList<Transition>();
for (Transition t : getOutTrans()) {
// outgoing transitions always are NonInitialTransitions
NonInitialTransition tr = (NonInitialTransition) t;
if (tr.getFrom() instanceof StateTerminal) {
if (tr.getTo() instanceof StateTerminal) {
if (((StateTerminal)tr.getFrom()).getState() == ((StateTerminal)tr.getTo()).getState())
loopTrans.add(tr);
}
}
else if (tr.getFrom() instanceof TrPointTerminal) {
if (tr.getTo() instanceof TrPointTerminal) {
if (((TrPointTerminal)tr.getFrom()).getTrPoint() == ((TrPointTerminal)tr.getTo()).getTrPoint())
loopTrans.add(tr);
}
}
}
}
return loopTrans;
}
}
/**
* The cached value of the '{@link #getActorClass() <em>Actor Class</em>}' reference.
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @see #getActorClass()
* @generated
* @ordered
*/
protected ActorClass actorClass;
private static final String TRIGGER_SEP = "#";
private IDiagnostician validator;
private boolean prepared = false;
private HashSet<StateGraphItem> ownObjects = null;
private HashMap<InterfaceItem, Integer> ifitem2localId = null;
private HashMap<StateGraphNode, NodeData> node2data = null;
private HashMap<State, LinkedList<ActiveTrigger>> state2triggers = null;
private HashMap<String, MessageFromIf> triggerstring2mif = null;
private LinkedList<TransitionChain> trchains = null;
private HashMap<Transition, TransitionChain> trans2chain = null;
private HashMap<EObject, EObject> copy2orig = null;
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
protected ExpandedActorClassImpl() {
super();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
protected EClass eStaticClass() {
return ETriceGenPackage.Literals.EXPANDED_ACTOR_CLASS;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public ActorClass getActorClass() {
if (actorClass != null && actorClass.eIsProxy()) {
InternalEObject oldActorClass = (InternalEObject)actorClass;
actorClass = (ActorClass)eResolveProxy(oldActorClass);
if (actorClass != oldActorClass) {
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.RESOLVE, ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS, oldActorClass, actorClass));
}
}
return actorClass;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public ActorClass basicGetActorClass() {
return actorClass;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
public void setActorClass(ActorClass newActorClass) {
ActorClass oldActorClass = actorClass;
actorClass = newActorClass;
if (eNotificationRequired())
eNotify(new ENotificationImpl(this, Notification.SET, ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS, oldActorClass, actorClass));
}
private void validationError(String msg, EObject obj) {
validationError(msg, obj, -1);
}
private void validationError(String msg, EObject obj, int feature) {
validator.error(msg, copy2orig.get(obj), feature);
}
private void buildStateGraph() {
// create a list of super classes, super first, sub-classes last
LinkedList<StateGraph> sms = new LinkedList<StateGraph>();
ActorClass orig = getActorClass();
if (orig.getStateMachine()!=null)
sms.addFirst(orig.getStateMachine());
while (orig.getBase()!=null) {
orig = orig.getBase();
if (orig.getStateMachine()!=null)
sms.addFirst(orig.getStateMachine());
}
// create a self contained copy of all actor classes
// references to interface items (ports, saps and spps) point to contents of the original actor class
//Collection<StateGraph> all = EcoreUtil.copyAll(sms);
// we use the copier directly since we need access to the map
Copier copier = new Copier();
Collection<StateGraph> all = copier.copyAll(sms);
copier.copyReferences();
for (EObject o : copier.keySet()) {
EObject c = copier.get(o);
copy2orig.put(c, o);
}
// remove self from this list
StateGraph self = null;
for (Iterator<StateGraph> it = all.iterator(); it.hasNext();) {
self = it.next();
}
all.remove(self);
// now we move all base class state machine contents to our state machine
StateGraph sm = RoomFactory.eINSTANCE.createStateGraph();
setStateMachine(sm);
for (StateGraph sml : all) {
sm.getChPoints().addAll(sml.getChPoints());
sm.getStates().addAll(sml.getStates());
sm.getTrPoints().addAll(sml.getTrPoints());
sm.getTransitions().addAll(sml.getTransitions());
}
// then we relocate the refined state contents to their respective base state and remove all refined states
relocateRefinedStateContents(sm, true);
if (getActorClass().getStateMachine()!=null) {
TreeIterator<EObject> it = self.eAllContents();
while (it.hasNext()) {
EObject obj = it.next();
if (obj instanceof StateGraphItem)
addOwnObject((StateGraphItem)obj);
}
sm.getChPoints().addAll(self.getChPoints());
sm.getStates().addAll(self.getStates());
sm.getTrPoints().addAll(self.getTrPoints());
sm.getTransitions().addAll(self.getTransitions());
// then we relocate the refined state contents to their respective base state while keeping all refined states
relocateRefinedStateContents(sm, false);
}
}
/**
* remove refined states and relocate their respective contents to the
* corresponding base state
* @param sg - the current context (will be called recursively)
* @param remove - if true the refined states are removed, if false they are moved
* to be siblings of their base states
*/
private void relocateRefinedStateContents(StateGraph sg, boolean remove) {
LinkedList<RefinedState> refinedstates = new LinkedList<RefinedState>();
for (State s : sg.getStates()) {
if (s instanceof RefinedState) {
RefinedState rs = (RefinedState) s;
refinedstates.add(rs);
BaseState bs = rs.getBase();
if (!remove) {
StateGraph parent = (StateGraph) bs.eContainer();
parent.getStates().add(rs);
}
// relocate contents
StateGraph fromSG = rs.getSubgraph();
if (fromSG!=null) {
StateGraph toSG = bs.getSubgraph();
if (toSG==null) {
toSG = RoomFactory.eINSTANCE.createStateGraph();
bs.setSubgraph(toSG);
}
toSG.getChPoints().addAll(fromSG.getChPoints());
toSG.getStates().addAll(fromSG.getStates());
toSG.getTrPoints().addAll(fromSG.getTrPoints());
toSG.getTransitions().addAll(fromSG.getTransitions());
}
}
}
if (remove) {
// remove empty refined states
sg.getStates().removeAll(refinedstates);
}
// recurse down into states
for (State s : sg.getStates()) {
if (s.getSubgraph()!=null)
relocateRefinedStateContents(s.getSubgraph(), remove);
}
}
private void addOutgoingTransition(StateGraphNode node, Transition t) {
NodeData data = node2data.get(node);
if (data==null) {
data = new NodeData();
node2data.put(node, data);
}
data.getOutTrans().add(t);
}
private void addIncomingTransition(StateGraphNode node, Transition t) {
NodeData data = node2data.get(node);
if (data==null) {
data = new NodeData();
node2data.put(node, data);
}
data.getInTrans().add(t);
}
private void findOutgoingTransitions(StateGraph sg) {
// depth first: recurse into sub graphs of states
for (State s : sg.getStates()) {
if (s.getSubgraph()!=null)
findOutgoingTransitions(s.getSubgraph());
}
for (Transition t : sg.getTransitions()) {
addIncomingTransition(getAdjustedTargetNode(t), t);
if (t instanceof NonInitialTransition) {
addOutgoingTransition(getNode(((NonInitialTransition)t).getFrom()), t);
}
}
}
private void doChecks(StateGraph sg) {
// check if empty
if (sg.getTransitions().isEmpty() && sg.getStates().isEmpty()
&& sg.getChPoints().isEmpty() && sg.getTrPoints().isEmpty())
return;
int initCount = 0;
for (Transition t : sg.getTransitions()) {
if (t instanceof InitialTransition)
++initCount;
}
if (initCount==0) {
if (sg.eContainer() instanceof State) {
if (!isAbstract()) {
// having no initial transition in a nested state is valid only if there is no transition to history
// except of self transitions
// i.e. no incoming transition of the state itself
NodeData data = node2data.get((State)sg.eContainer());
if (data!=null && data.getLoopTransitions().size()!=data.getInTrans().size())
validationError(getName()+": Having no initial transition in a nested state is valid only if there is no transition to history except of self transitions!", sg.eContainer(), RoomPackage.STATE__SUBGRAPH);
}
}
else {
validationError(getName()+": The TOP level has to have an initial transition!", sg, RoomPackage.STATE_GRAPH__TRANSITIONS);
}
}
else {
if (initCount>1)
validationError(getName()+": There has to be exactly one initial transition!", sg, RoomPackage.STATE_GRAPH__TRANSITIONS);
}
for (ChoicePoint cp : sg.getChPoints()) {
NodeData data = node2data.get(cp);
if (data==null) {
validationError(getName()+": ChoicePoint is not connected!", cp, -1);
}
else {
if (data.getInTrans().size()!=1)
validationError(getName()+": ChoicePoint has "+data.getInTrans().size()+" incoming transitions!", cp, -1);
if (data.getOutTrans().size()<2)
validationError(getName()+": ChoicePoint should have 2 or more branches but has "+data.getOutTrans().size(), cp, -1);
if (getDefaultBranch(data.getOutTrans())==null)
validationError(getName()+": ChoicePoint has no default branch!", cp, -1);
if (!data.getLoopTransitions().isEmpty())
validationError(getName()+": ChoicePoint is connected to itself!", cp, -1);
}
}
for (TrPoint tp : sg.getTrPoints()) {
NodeData data = node2data.get(tp);
if (data==null) {
if (!getActorClass(tp).isAbstract())
validationError(getName()+": TrPoint is not connected", tp, -1);
}
else {
if ((tp instanceof EntryPoint)||(tp instanceof ExitPoint)) {
// non-abstract classes must have incoming transitions for entry and exit points
if (!isAbstract() && data.getInTrans().isEmpty())
validationError(getName()+": TrPoint has no incoming transition!", tp, -1);
if (getActorClass(tp).isAbstract()) {
// transition points inherited from abstract base classes
// (of from abstract classes themselves) must not have more than one outgoing transition
if (data.getOutTrans().size()>1)
validationError(getName()+": TrPoint must have at most one outgoing transition!", tp, -1);
}
else {
// non-abstract or non-inherited transition points must have one outgoing transition
if (data.getOutTrans().size()!=1)
validationError(getName()+": TrPoint must have exactly one outgoing transition!", tp, -1);
}
if (!data.getLoopTransitions().isEmpty())
validationError(getName()+": TrPoint must have no self transitions!", tp, -1);
}
else if (tp instanceof TransitionPoint) {
if (data.getOutTrans().size()<data.getLoopTransitions().size())
validationError(getName()+": TrPoint must have no incoming transitions!", tp, -1);
}
}
}
// recurse into sub graphs of states
for (State s : sg.getStates()) {
if (s.getSubgraph()!=null)
doChecks(s.getSubgraph());
}
}
private void findTriggersOfState(State s) {
LinkedList<ActiveTrigger> triggers = new LinkedList<ActiveTrigger>();
HashMap<String, ActiveTrigger> caughtTriggers = new HashMap<String, ActiveTrigger>();
collectTriggersAndTransitions(s, caughtTriggers, triggers);
state2triggers.put(s, triggers);
}
private String getTriggerString(MessageFromIf mifp) {
return mifp.getFrom().getName()+TRIGGER_SEP+mifp.getMessage().getName();
}
private void collectOutgoingTransitions(EList<Transition> sameLevelTransitions,
HashMap<String, ActiveTrigger> caughtTriggers,
LinkedList<ActiveTrigger> triggers) {
for (Transition t : sameLevelTransitions) {
if (t instanceof TriggeredTransition) {
TriggeredTransition tt = (TriggeredTransition) t;
for (Trigger trig : ((TriggeredTransition)t).getTriggers()) {
for (MessageFromIf mifp : trig.getMsgFromIfPairs()) {
String tr = getTriggerString(mifp);
ActiveTrigger at = caughtTriggers.get(tr);
if (at==null) {
// this is a new trigger (and our unique point of ActiveTrigger creation)
at = ETriceGenFactory.eINSTANCE.createActiveTrigger();
at.setMsg(mifp.getMessage());
at.setIfitem(mifp.getFrom());
at.setTrigger(tr);
at.getTransitions().add(tt);
caughtTriggers.put(tr, at);
triggers.add(at);
}
else {
// check consistency of guards
TriggeredTransition lastChecked = null;
boolean isNotGuarded = true;
for (TriggeredTransition t2 : at.getTransitions()) {
for (Trigger trig2 : t2.getTriggers()) {
if (isMatching(trig2, tr)) {
if (trig2.getGuard()!=null)
if (trig2.getGuard().getGuard()!=null)
if (!trig2.getGuard().getGuard().getCommands().isEmpty())
isNotGuarded = false;
lastChecked = t2;
}
}
}
if (lastChecked!=null) {
if (!isNotGuarded) {
boolean guardRequired = false;
if (lastChecked.getFrom() instanceof TrPoint)
if (lastChecked.eContainer()==tt.eContainer())
// lastChecked and tt originate in TrPoints of the same super state
guardRequired = true;
if (tt.getFrom()==lastChecked.getFrom())
// lastChecked and tt originate in the same State or TrPoint
guardRequired = true;
if (guardRequired) {
if (trig.getGuard()==null)
validationError("Transitions with same trigger on same level have to be guarded!", t, RoomPackage.TRIGGERED_TRANSITION__TRIGGERS);
if (trig.getGuard().getGuard()==null)
validationError("Transitions with same trigger on same level have to be guarded!", t, RoomPackage.TRIGGERED_TRANSITION__TRIGGERS);
if (!trig.getGuard().getGuard().getCommands().isEmpty())
validationError("Transitions with same trigger on same level have to be guarded!", t, RoomPackage.TRIGGERED_TRANSITION__TRIGGERS);
}
at.getTransitions().add(tt);
}
// else this transition is inactive
}
else {
at.getTransitions().add(tt);
}
}
}
}
}
}
}
private void collectTriggersAndTransitions(State s,
HashMap<String, ActiveTrigger> caughtTriggers,
LinkedList<ActiveTrigger> triggers) {
// consider outgoing transitions of this state
collectOutgoingTransitions(getOutgoingTransitions(s), caughtTriggers, triggers);
// consider TransitionPoint transitions
if (s.eContainer() instanceof StateGraph) {
StateGraph sg = (StateGraph) s.eContainer();
BasicEList<Transition> trpTransitions = new BasicEList<Transition>();
for (TrPoint tp : sg.getTrPoints()) {
trpTransitions.addAll(getOutgoingTransitions(tp));
}
collectOutgoingTransitions(trpTransitions, caughtTriggers, triggers);
// go to surrounding context
if (sg.eContainer() instanceof State) {
collectTriggersAndTransitions((State) sg.eContainer(), caughtTriggers, triggers);
}
}
else {
// this should never happen
assert(false): "A State must always reside in a StateGraph!";
}
}
private void findLeafStateTriggers(StateGraph sg) {
for (State s : sg.getStates()) {
if (s.getSubgraph()!=null)
findLeafStateTriggers(s.getSubgraph());
else
findTriggersOfState(s);
}
}
private void fillTriggerStringMap() {
// improve performance using maps name2ifitem and name2msgs
HashMap<String, InterfaceItem> name2ifitem = new HashMap<String, InterfaceItem>();
HashMap<String, EList<Message>> name2msgs = new HashMap<String, EList<Message>>();
ActorClass ac = getActorClass();
while (ac!=null) {
for (Port ip : ac.getIntPorts()) {
mapPort(ip, name2ifitem, name2msgs);
}
for (ExternalPort ep : ac.getExtPorts()) {
mapPort(ep.getIfport(), name2ifitem, name2msgs);
}
for (SAPRef sap : ac.getStrSAPs()) {
mapSAP(sap, name2ifitem, name2msgs);
}
for (ServiceImplementation spp : ac.getServiceImplementations()) {
mapSPP(spp.getSpp(), name2ifitem, name2msgs);
}
ac = ac.getBase();
}
// compute a set of all trigger strings
HashSet<String> triggers = new HashSet<String>();
for (LinkedList<ActiveTrigger> ttlist : state2triggers.values()) {
for (ActiveTrigger tt : ttlist) {
triggers.add(tt.getTrigger());
}
}
// now fill triggerstring2mif
for (String trig : triggers) {
String[] parts = trig.split(TRIGGER_SEP);
// this should always hold true
assert(parts.length==2): "By our convention triggers are composed of two parts separated by "
+TRIGGER_SEP+". Here we have '"+trig+"' which doesn't consist of two parts!";
InterfaceItem ii = name2ifitem.get(parts[0]);
// this should always hold true
assert(ii!=null): "The name '"+parts[0]+"' did not match an interface item (in name2ifitem)!";
EList<Message> msgs = name2msgs.get(parts[0]);
// this should always hold true
assert(msgs!=null): "The name '"+parts[0]+"' did not match an interface item (in name2msgs)!";
Message msg = null;
for (Message m : msgs) {
if (m.getName().equals(parts[1]))
msg = m;
}
// this should always hold true
assert(msg!=null): "The message '"+parts[1]+"' did not match a message!";
MessageFromIf mif = RoomFactory.eINSTANCE.createMessageFromIf();
mif.setFrom(ii);
mif.setMessage(msg);
triggerstring2mif.put(trig, mif);
}
}
private void mapPort(Port p, HashMap<String, InterfaceItem> name2ifitem,
HashMap<String, EList<Message>> name2msgs) {
name2ifitem.put(p.getName(), p);
if (p.isConjugated())
name2msgs.put(p.getName(), p.getProtocol().getOutgoingMessages());
else
name2msgs.put(p.getName(), p.getProtocol().getIncomingMessages());
}
private void mapSAP(SAPRef sap, HashMap<String, InterfaceItem> name2ifitem,
HashMap<String, EList<Message>> name2msgs) {
name2ifitem.put(sap.getName(), sap);
// sap is conjugated wrt to the protocol
name2msgs.put(sap.getName(), sap.getProtocol().getOutgoingMessages());
}
private void mapSPP(SPPRef spp, HashMap<String, InterfaceItem> name2ifitem,
HashMap<String, EList<Message>> name2msgs) {
name2ifitem.put(spp.getName(), spp);
// spp is regular wrt to the protocol
name2msgs.put(spp.getName(), spp.getProtocol().getIncomingMessages());
}
private void addTransitionChain(Transition t) {
TransitionChain tc = ETriceGenFactory.eINSTANCE.createTransitionChain();
tc.setTransition(t);
if (t instanceof TriggeredTransition) {
List<TypedID> args = null;
boolean first = true;
for (Trigger tr : ((TriggeredTransition)t).getTriggers()) {
for (MessageFromIf mif : tr.getMsgFromIfPairs()) {
if (first) {
first = false;
args = mif.getMessage().getArguments();
}
else {
if (args.size()>0) {
if (mif.getMessage().getArguments().size()!=args.size()) {
validationError("If one MessageFromIf has data all have to have data for a given transition!", mif.getMessage());
}
else {
for (TypedID arg : args) {
TypedID a = mif.getMessage().getArguments().get(0);
if (arg.getType().getPrim()!=a.getType().getPrim())
validationError("The data types of all MessageFromIf have to be the same!", mif.getMessage());
if (arg.getType().getType()!=a.getType().getType())
validationError("The data types of all MessageFromIf have to be the same!", mif.getMessage());
}
}
}
else {
if (mif.getMessage().getArguments().size()!=0)
validationError("If one MessageFromIf has no data all have to have no data for a given transition!", mif.getMessage());
}
}
}
}
if (first)
validationError("Triggered transition has to have a message from interface!", t);
}
collectChainTransitions(tc, t);
trchains.add(tc);
}
private void collectChainTransitions(TransitionChain tc,
Transition t) {
trans2chain.put(t, tc);
// should always hold true
// assert(t instanceof NonInitialTransition): "A transition chain must not contain initial transitions!";
StateGraphNode node = getNode(t.getTo());
// the chain ends if a state is reached
if (node instanceof State)
return;
// the chain ends if source and destination coincide
if (t instanceof NonInitialTransition && node==getNode(((NonInitialTransition)t).getFrom()))
return;
for (Transition next : getOutgoingTransitions(node)) {
// from the second transition in the chain on we have:
if (next instanceof TriggeredTransition)
validationError("Segments following the triggering transition can have no triggers!\n", next, -1);
collectChainTransitions(tc, next);
}
}
private void findTransitionChains(StateGraph sg) {
for (Transition t : sg.getTransitions()) {
if (t instanceof TriggeredTransition) {
addTransitionChain(t);
}
else if (t instanceof InitialTransition) {
addTransitionChain(t);
}
}
// recurse into sub graphs of states
for (State s : sg.getStates()) {
if (s.getSubgraph()!=null)
findTransitionChains(s.getSubgraph());
}
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public void prepare(IDiagnostician validator) {
if (prepared)
return;
prepared = true;
this.validator = validator;
ifitem2localId = new HashMap<InterfaceItem, Integer>();
ownObjects = new HashSet<StateGraphItem>();
node2data = new HashMap<StateGraphNode, NodeData>();
state2triggers = new HashMap<State, LinkedList<ActiveTrigger>>();
triggerstring2mif = new HashMap<String, MessageFromIf>();
trchains = new LinkedList<TransitionChain>();
trans2chain = new HashMap<Transition, TransitionChain>();
copy2orig = new HashMap<EObject, EObject>();
buildStateGraph();
computeInterfaceItemLocalIds(getActorClass(), 0);
findOutgoingTransitions(getStateMachine());
doChecks(getStateMachine());
assert(!validator.isFailed()): "Checks failed!";
findLeafStateTriggers(getStateMachine());
fillTriggerStringMap();
findTransitionChains(getStateMachine());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public void release() {
if (!prepared)
return;
prepared = false;
// release resources
ifitem2localId = null;
ownObjects = null;
node2data = null;
state2triggers = null;
triggerstring2mif = null;
trchains = null;
trans2chain = null;
copy2orig = null;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public void addOwnObject(StateGraphItem obj) {
ownObjects.add(obj);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean isOwnObject(StateGraphItem obj) {
return ownObjects.contains(obj);
}
private int computeInterfaceItemLocalIds(ActorClass ac, int offset) {
if (ac.getBase()!=null)
// first recurse into base class
offset = computeInterfaceItemLocalIds(ac.getBase(), offset);
for (ExternalPort ep : ac.getExtPorts()) {
ifitem2localId.put(ep.getIfport(), offset);
++offset;
}
for (Port ip : ac.getIntPorts()) {
ifitem2localId.put(ip, offset);
++offset;
}
for (SAPRef sap : ac.getStrSAPs()) {
ifitem2localId.put(sap, offset);
++offset;
}
for (ServiceImplementation svc : ac.getServiceImplementations()) {
ifitem2localId.put(svc.getSpp(), offset);
++offset;
}
return offset;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public int getInterfaceItemLocalId(InterfaceItem ifitem) {
Integer localId = ifitem2localId.get(ifitem);
if (localId!=null)
return localId.intValue();
else
return -1;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean hasStateMachine() {
ActorClass ac = getActorClass();
while (ac!=null) {
if (ac.getStateMachine()!=null)
return true;
ac = ac.getBase();
}
return false;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String getCode(DetailCode code) {
if (code.getCommands().isEmpty())
return "";
String result = "";
for (String cmd : code.getCommands()) {
result += cmd + "\n";
}
return result;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String getTriggerCodeName(MessageFromIf mif) {
return "TRIG_"+mif.getFrom().getName()+"__"+mif.getMessage().getName();
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String getTriggerCodeName(String trigger) {
String[] parts = trigger.split(TRIGGER_SEP);
return "TRIG_"+parts[0]+"__"+parts[1];
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<Transition> getOutgoingTransitions(StateGraphNode node) {
NodeData data = node2data.get(node);
if (data==null)
return new BasicEList<Transition>();
else
return new BasicEList<Transition>(data.getOutTrans());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<Transition> getIncomingTransitions(StateGraphNode node) {
NodeData data = node2data.get(node);
if (data==null)
return new BasicEList<Transition>();
else
return new BasicEList<Transition>(data.getInTrans());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<ActiveTrigger> getActiveTriggers(State state) {
LinkedList<ActiveTrigger> triggers = state2triggers.get(state);
if (triggers==null)
return new BasicEList<ActiveTrigger>();
else
return new BasicEList<ActiveTrigger>(triggers);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<MessageFromIf> getTriggers() {
return new BasicEList<MessageFromIf>(triggerstring2mif.values());
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<MessageFromIf> getOwnTriggers() {
BasicEList<MessageFromIf> result = new BasicEList<MessageFromIf>();
HashSet<InterfaceItem> ownIfItems = new HashSet<InterfaceItem>();
ownIfItems.addAll(getActorClass().getIntPorts());
for (ExternalPort ep : getActorClass().getExtPorts()) {
ownIfItems.add(ep.getIfport());
}
ownIfItems.addAll(getActorClass().getStrSAPs());
for (ServiceImplementation svc : getActorClass().getServiceImplementations()) {
ownIfItems.add(svc.getSpp());
}
for(MessageFromIf mif : triggerstring2mif.values()) {
if (ownIfItems.contains(mif.getFrom()))
result.add(mif);
}
Collections.sort(result, new Comparator<MessageFromIf>() {
@Override
public int compare(MessageFromIf o1, MessageFromIf o2) {
return getTriggerCodeName(o1).compareTo(getTriggerCodeName(o2));
}
});
return result;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public String getMessageID(MessageFromIf mif) {
if (mif.getFrom() instanceof Port) {
Port p = (Port) mif.getFrom();
return p.getProtocol().getName()+(p.isConjugated()?".OUT_":".IN_")+mif.getMessage().getName();
}
else if (mif.getFrom() instanceof SAPRef) {
SAPRef sap = (SAPRef) mif.getFrom();
return sap.getProtocol().getName()+".OUT_"+mif.getMessage().getName();
}
else if (mif.getFrom() instanceof SPPRef) {
SPPRef spp = (SPPRef) mif.getFrom();
return spp.getProtocol().getName()+".IN_"+mif.getMessage().getName();
}
return "unknown interface item";
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public TransitionChain getChain(Transition trans) {
return trans2chain.get(trans);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<TransitionChain> getTransitionChains() {
return new BasicEList<TransitionChain>(trchains);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public EList<TransitionChain> getOwnTransitionChains() {
BasicEList<TransitionChain> result = new BasicEList<TransitionChain>();
for (TransitionChain tc : trchains) {
if (isOwnObject(tc.getTransition()))
result.add(tc);
}
Collections.sort(result, new Comparator<TransitionChain>() {
@Override
public int compare(TransitionChain o1, TransitionChain o2) {
return RoomNameProvider.getFullPath(o1.getTransition()).compareTo(RoomNameProvider.getFullPath(o2.getTransition()));
}
});
return result;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public StateGraphNode getNode(TransitionTerminal tt) {
if (tt instanceof StateTerminal)
return ((StateTerminal)tt).getState();
else if (tt instanceof TrPointTerminal)
return ((TrPointTerminal)tt).getTrPoint();
else if (tt instanceof SubStateTrPointTerminal)
return ((SubStateTrPointTerminal)tt).getTrPoint();
else if (tt instanceof ChoicepointTerminal)
return ((ChoicepointTerminal)tt).getCp();
return null;
}
private StateGraphNode getAdjustedTargetNode(Transition t) {
StateGraphNode node = getNode(t.getTo());
if (node instanceof EntryPoint) {
NodeData data = node2data.get(node);
if (data==null || data.getOutTrans().isEmpty()) {
if (getActorClass(node).isAbstract()) {
if (node.eContainer().eContainer() instanceof State) {
// in this case
State newTarget = (State) node.eContainer().eContainer();
BaseState newBaseTarget = (newTarget instanceof BaseState)? (BaseState)newTarget:((RefinedState)newTarget).getBase();
StateTerminal st = RoomFactory.eINSTANCE.createStateTerminal();
st.setState(newBaseTarget);
t.setTo(st);
node = newBaseTarget;
}
}
}
}
return node;
}
private ActorClass getActorClass(EObject node) {
node = copy2orig.get(node);
while (node!=null) {
if (node instanceof ActorClass)
return (ActorClass) node;
node = node.eContainer();
}
return null;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public boolean isMatching(Trigger trig, String trigstr) {
for (MessageFromIf mifp2 : trig.getMsgFromIfPairs()) {
String tr2 = getTriggerString(mifp2);
if (tr2.equals(trigstr))
return true;
}
return false;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated NOT
*/
public ContinuationTransition getDefaultBranch(EList<Transition> out) {
return getDefaultBranch((List<Transition>)out);
}
private ContinuationTransition getDefaultBranch(List<Transition> out) {
for (Transition t : out) {
if (t instanceof ContinuationTransition)
return (ContinuationTransition) t;
}
return null;
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS:
if (resolve) return getActorClass();
return basicGetActorClass();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS:
setActorClass((ActorClass)newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS:
setActorClass((ActorClass)null);
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc -->
* <!-- end-user-doc -->
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case ETriceGenPackage.EXPANDED_ACTOR_CLASS__ACTOR_CLASS:
return actorClass != null;
}
return super.eIsSet(featureID);
}
} //ExpandedActorClassImpl