/* $Id: StateMachinesFactoryMDRImpl.java 18451 2010-06-21 11:57:41Z mvw $ ***************************************************************************** * Copyright (c) 2009-2010 Contributors - see below * 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: * tfmorris * mvw ***************************************************************************** * * Some portions of this file was previously release using the BSD License: */ // Copyright (c) 1996-2008 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph appear in all copies. This software program and // documentation are copyrighted by The Regents of the University of // California. The software program and documentation are supplied "AS // IS", without any accompanying services from The Regents. The Regents // does not warrant that the operation of the program will be // uninterrupted or error-free. The end-user understands that the program // was developed for research purposes and is advised not to rely // exclusively on the program for any reason. IN NO EVENT SHALL THE // UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, // SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, // ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF // THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE // PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, // UPDATES, ENHANCEMENTS, OR MODIFICATIONS. package org.argouml.model.mdr; import java.util.Collection; import org.apache.log4j.Logger; import org.argouml.model.StateMachinesFactory; import org.omg.uml.behavioralelements.statemachines.CallEvent; import org.omg.uml.behavioralelements.statemachines.ChangeEvent; import org.omg.uml.behavioralelements.statemachines.CompositeState; import org.omg.uml.behavioralelements.statemachines.Event; import org.omg.uml.behavioralelements.statemachines.FinalState; import org.omg.uml.behavioralelements.statemachines.Guard; import org.omg.uml.behavioralelements.statemachines.Pseudostate; import org.omg.uml.behavioralelements.statemachines.SignalEvent; import org.omg.uml.behavioralelements.statemachines.SimpleState; import org.omg.uml.behavioralelements.statemachines.State; import org.omg.uml.behavioralelements.statemachines.StateMachine; import org.omg.uml.behavioralelements.statemachines.StateMachinesPackage; import org.omg.uml.behavioralelements.statemachines.StateVertex; import org.omg.uml.behavioralelements.statemachines.StubState; import org.omg.uml.behavioralelements.statemachines.SubmachineState; import org.omg.uml.behavioralelements.statemachines.SynchState; import org.omg.uml.behavioralelements.statemachines.TimeEvent; import org.omg.uml.behavioralelements.statemachines.Transition; import org.omg.uml.foundation.core.BehavioralFeature; import org.omg.uml.foundation.core.ModelElement; import org.omg.uml.foundation.core.Namespace; import org.omg.uml.foundation.core.Operation; import org.omg.uml.foundation.core.UmlClass; import org.omg.uml.foundation.datatypes.BooleanExpression; import org.omg.uml.foundation.datatypes.PseudostateKindEnum; import org.omg.uml.foundation.datatypes.TimeExpression; /** * Factory to create UML classes for the UML BehaviorialElements::StateMachines * package.<p> * * Abstract metatypes from the UML metamodel do not have create methods.<p> * * @since ARGO0.19.3 * @author Bob Tarling * @author Ludovic Maître * @author Tom Morris */ class StateMachinesFactoryMDRImpl extends AbstractUmlModelFactoryMDR implements StateMachinesFactory { /** * Logger */ private Logger LOG = Logger.getLogger(StateMachinesFactoryMDRImpl.class); /** * The model implementation. */ private MDRModelImplementation modelImpl; /** * Package-private constructor. * * @param implementation * To get other helpers and factories. */ StateMachinesFactoryMDRImpl(MDRModelImplementation implementation) { modelImpl = implementation; } private StateMachinesPackage getSmPackage() { return modelImpl.getUmlPackage().getStateMachines(); } public CallEvent createCallEvent() { CallEvent myCallEvent = getSmPackage().getCallEvent().createCallEvent(); super.initialize(myCallEvent); return myCallEvent; } public ChangeEvent createChangeEvent() { ChangeEvent myChangeEvent = getSmPackage().getChangeEvent() .createChangeEvent(); super.initialize(myChangeEvent); return myChangeEvent; } public CompositeState createCompositeState() { CompositeState myCompositeState = getSmPackage().getCompositeState() .createCompositeState(); super.initialize(myCompositeState); return myCompositeState; } public FinalState createFinalState() { FinalState myFinalState = getSmPackage().getFinalState().createFinalState(); super.initialize(myFinalState); return myFinalState; } public Guard createGuard() { Guard myGuard = getSmPackage().getGuard().createGuard(); super.initialize(myGuard); return myGuard; } public Pseudostate createPseudostate() { Pseudostate myPseudostate = getSmPackage().getPseudostate() .createPseudostate(); super.initialize(myPseudostate); return myPseudostate; } public SignalEvent createSignalEvent() { SignalEvent mySignalEvent = getSmPackage().getSignalEvent() .createSignalEvent(); super.initialize(mySignalEvent); return mySignalEvent; } public SimpleState createSimpleState() { SimpleState mySimpleState = getSmPackage().getSimpleState() .createSimpleState(); super.initialize(mySimpleState); return mySimpleState; } public StateMachine createStateMachine() { StateMachine myStateMachine = getSmPackage().getStateMachine() .createStateMachine(); super.initialize(myStateMachine); return myStateMachine; } public StubState createStubState() { StubState myStubState = getSmPackage().getStubState().createStubState(); super.initialize(myStubState); return myStubState; } public SubmachineState createSubmachineState() { SubmachineState mySubmachineState = getSmPackage().getSubmachineState() .createSubmachineState(); super.initialize(mySubmachineState); return mySubmachineState; } public SynchState createSynchState() { SynchState mySynchState = getSmPackage().getSynchState().createSynchState(); super.initialize(mySynchState); return mySynchState; } public TimeEvent createTimeEvent() { TimeEvent myTimeEvent = getSmPackage().getTimeEvent().createTimeEvent(); super.initialize(myTimeEvent); return myTimeEvent; } public Transition createTransition() { Transition myTransition = getSmPackage().getTransition().createTransition(); super.initialize(myTransition); return myTransition; } public CompositeState buildCompositeStateOnStateMachine( Object statemachine) { if (statemachine instanceof StateMachine) { StateMachine sm = (StateMachine) statemachine; CompositeState top = createCompositeState(); top.setStateMachine(sm); top.setName("top"); sm.setTop(top); assert top.equals(sm.getTop()); return top; } throw new IllegalArgumentException("statemachine"); } public StateMachine buildStateMachine(Object oContext) { if (oContext != null && (modelImpl.getStateMachinesHelper(). isAddingStatemachineAllowed(oContext))) { StateMachine machine = createStateMachine(); ModelElement modelelement = (ModelElement) oContext; machine.setContext(modelelement); if (modelelement instanceof BehavioralFeature) { modelelement = ((BehavioralFeature) modelelement).getOwner(); } if (modelelement instanceof Namespace) { Namespace namespace = (Namespace) modelelement; /* Follow well-formedness rule for a Class [2]. * See issue 4282. Do not use a class * as the namespace for a statemachine: */ while (namespace instanceof UmlClass) { Namespace pns = namespace.getNamespace(); if (pns == null) break; namespace = pns; } machine.setNamespace(namespace); } State top = buildCompositeStateOnStateMachine(machine); assert top.equals(machine.getTop()); return machine; } throw new IllegalArgumentException("In buildStateMachine: " + "context null or not legal"); } public Transition buildTransition(Object owningState, Object source, Object dest) { if (!(owningState instanceof CompositeState)) { throw new IllegalArgumentException("owningState"); } if (!(source instanceof StateVertex)) { throw new IllegalArgumentException("source"); } if (!(dest instanceof StateVertex)) { throw new IllegalArgumentException("dest"); } CompositeState compositeState = (CompositeState) owningState; if (compositeState.getSubvertex().contains(source) && compositeState.getSubvertex().contains(dest)) { Transition trans = createTransition(); compositeState.getInternalTransition().add(trans); trans.setSource((StateVertex) source); trans.setTarget((StateVertex) dest); return trans; } throw new IllegalArgumentException("In buildTransition: " + "arguments not legal"); } public Pseudostate buildPseudoState(Object compositeState) { if (compositeState instanceof CompositeState) { Pseudostate state = createPseudostate(); state.setKind(PseudostateKindEnum.PK_CHOICE); state.setContainer((CompositeState) compositeState); ((CompositeState) compositeState).getSubvertex().add(state); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public SynchState buildSynchState(Object compositeState) { if (compositeState instanceof CompositeState) { SynchState state = createSynchState(); state.setBound(0); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public StubState buildStubState(Object compositeState) { if (compositeState instanceof CompositeState) { StubState state = createStubState(); state.setReferenceState(""); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public CompositeState buildCompositeState(Object compositeState) { if (compositeState instanceof CompositeState) { CompositeState state = createCompositeState(); state.setConcurrent(false); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public SimpleState buildSimpleState(Object compositeState) { if (compositeState instanceof CompositeState) { SimpleState state = createSimpleState(); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public FinalState buildFinalState(Object compositeState) { if (compositeState instanceof CompositeState) { FinalState state = createFinalState(); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public SubmachineState buildSubmachineState(Object compositeState) { if (compositeState instanceof CompositeState) { SubmachineState state = createSubmachineState(); state.setContainer((CompositeState) compositeState); return state; } throw new IllegalArgumentException( "Argument must be a CompositeState"); } public Transition buildInternalTransition(Object state) { if (state instanceof State) { Transition trans = createTransition(); ((State) state).getInternalTransition().add(trans); trans.setSource((State) state); trans.setTarget((State) state); return trans; } throw new IllegalArgumentException("Argument must be a State"); } public Transition buildTransition(Object source, Object target) { if (source instanceof StateVertex && target instanceof StateVertex) { Transition trans = createTransition(); trans.setSource((StateVertex) source); trans.setTarget((StateVertex) target); trans.setStateMachine((StateMachine) modelImpl. getStateMachinesHelper().getStateMachine(source)); return trans; } throw new IllegalArgumentException(); } public CallEvent buildCallEvent(Object ns) { CallEvent event = createCallEvent(); event.setNamespace((Namespace) ns); event.setName(""); return event; } public CallEvent buildCallEvent(Object trans, String name, Object ns) { if (!(trans instanceof Transition)) { throw new IllegalArgumentException(); } CallEvent evt = createCallEvent(); evt.setNamespace((Namespace) ns); String operationName = (name.indexOf("(") > 0) ? name.substring(0, name.indexOf("(")).trim() : name.trim(); evt.setName(operationName); Object op = modelImpl.getStateMachinesHelper().findOperationByName( trans, operationName); if (op != null) { evt.setOperation((Operation) op); } return evt; } public SignalEvent buildSignalEvent(Object ns) { SignalEvent event = createSignalEvent(); event.setNamespace((Namespace) ns); event.setName(""); return event; } public SignalEvent buildSignalEvent(String name, Object ns) { SignalEvent event = createSignalEvent(); event.setNamespace((Namespace) ns); event.setName(name); return event; } public TimeEvent buildTimeEvent(Object ns) { TimeEvent event = createTimeEvent(); event.setNamespace((Namespace) ns); event.setName(""); return event; } public TimeEvent buildTimeEvent(String s, Object ns) { TimeEvent event = createTimeEvent(); event.setNamespace((Namespace) ns); event.setName(""); Object te = modelImpl.getDataTypesFactory().createTimeExpression("", s); event.setWhen((TimeExpression) te); return event; } public ChangeEvent buildChangeEvent(Object ns) { ChangeEvent event = createChangeEvent(); event.setNamespace((Namespace) ns); event.setName(""); return event; } public ChangeEvent buildChangeEvent(String expression, Object ns) { ChangeEvent event = buildChangeEvent(ns); Object ce = modelImpl.getDataTypesFactory() .createBooleanExpression("", expression); event.setChangeExpression((BooleanExpression) ce); return event; } public Guard buildGuard(Object transition) { if (transition instanceof Transition) { Transition t = (Transition) transition; if (t.getGuard() != null) { LOG.warn("Replacing Guard " + t.getGuard().getName() + " on Transition " + t.getName()); } Guard guard = createGuard(); guard.setTransition((Transition) transition); return guard; } throw new IllegalArgumentException("transition: " + transition); } /** * @param elem * the UML element to be deleted */ void deleteCallEvent(Object elem) { if (!(elem instanceof CallEvent)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteChangeEvent(Object elem) { if (!(elem instanceof ChangeEvent)) { throw new IllegalArgumentException(); } } /** * Deletes any associated subVertices. * * This also enforces the following well-formedness rule. * <p>Well formedness rule 4.12.3.1 CompositeState * [4] There have to be at least two composite substates in a * concurrent composite state.<p> * If this is broken by deletion of substate then we delete the other * remaining substate and convert the composite state to non-concurrent * * @param elem * the UML element to be deleted */ void deleteCompositeState(Object elem) { if (!(elem instanceof CompositeState)) { throw new IllegalArgumentException(); } final CompositeState compositeState = (CompositeState) elem; for (StateVertex vertex : compositeState.getSubvertex()) { modelImpl.getUmlFactory().delete(vertex); } final CompositeState containingCompositeState = compositeState.getContainer(); // Well formedness rule 4.12.3.1 CompositeState // [4] There have to be at least two composite substates in a // concurrent composite state. // If this is broken by deletion of substate then we delete the other // remaining substates. if (containingCompositeState != null && containingCompositeState.isConcurrent()) { final Collection<StateVertex> siblings = containingCompositeState.getSubvertex(); final int substatesRemaining = siblings.size(); if (substatesRemaining == 2) { for (StateVertex sibling : siblings) { if (sibling != compositeState) { modelImpl.getUmlFactory().delete(sibling); } } } } } /** * @param elem * the UML element to be deleted */ void deleteEvent(Object elem) { if (!(elem instanceof Event)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteFinalState(Object elem) { if (!(elem instanceof FinalState)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteGuard(Object elem) { if (!(elem instanceof Guard)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deletePseudostate(Object elem) { if (!(elem instanceof Pseudostate)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteSignalEvent(Object elem) { if (!(elem instanceof SignalEvent)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteState(Object elem) { if (!(elem instanceof State)) { throw new IllegalArgumentException(); } State state = (State) elem; deleteNonNull(state.getDoActivity()); deleteNonNull(state.getEntry()); deleteNonNull(state.getExit()); modelImpl.getUmlHelper().deleteCollection( state.getInternalTransition()); } private void deleteNonNull(ModelElement action) { if (action != null) { modelImpl.getUmlFactory().delete(action); } } /** * @param elem * the UML element to be deleted */ void deleteSimpleState(Object elem) { if (!(elem instanceof SimpleState)) { throw new IllegalArgumentException(); } } /** * deletes its top state, which is a composite state (state vertex). * Delete any submachine states which depend on this StateMachine. * * @param elem * the state machine to be removed. */ void deleteStateMachine(Object elem) { if (!(elem instanceof StateMachine)) { throw new IllegalArgumentException(); } StateMachine stateMachine = (StateMachine) elem; // This shouldn't be required since it's a composite, but there's // a bug in the version of MDR that we use (20050711) that causes // it to fail to delete aggregate elements which are single valued // and where the aggregate end is listed second in the association // defined in the metamodel. - tfm 20080713 State top = stateMachine.getTop(); if (top != null) { modelImpl.getUmlFactory().delete(top); } modelImpl.getUmlHelper().deleteCollection( stateMachine.getSubmachineState()); } /** * Deletes the outgoing and incoming transitions of a statevertex. * <p> * * @param elem * the UML element to be deleted */ void deleteStateVertex(Object elem) { if (!(elem instanceof StateVertex)) { throw new IllegalArgumentException(); } modelImpl.getUmlHelper().deleteCollection( ((StateVertex) elem).getIncoming()); modelImpl.getUmlHelper().deleteCollection( ((StateVertex) elem).getOutgoing()); } /** * @param elem * the UML element to be deleted */ void deleteStubState(Object elem) { if (!(elem instanceof StubState)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteSubmachineState(Object elem) { if (!(elem instanceof SubmachineState)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteSynchState(Object elem) { if (!(elem instanceof SynchState)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteTimeEvent(Object elem) { if (!(elem instanceof TimeEvent)) { throw new IllegalArgumentException(); } } /** * @param elem * the UML element to be deleted */ void deleteTransition(Object elem) { if (!(elem instanceof Transition)) { throw new IllegalArgumentException(); } final Transition transition = (Transition) elem; final Guard guard = transition.getGuard(); if (guard != null) { // This shouldn't be required since it's a composite, but there's // a bug in the version of MDR that we use (20050711) that causes // it to fail to delete aggregate elements which are single valued // and where the aggregate end is listed second in the association // defined in the metamodel. - tfm 20080713 modelImpl.getUmlFactory().delete(guard); } // The effect will get deleted automatically by MDR, unlike the Guard. } }