/** * Copyright (c) 2012-2016 Marsha Chechik, Alessio Di Sandro, Michalis Famelis, * Rick Salay. * 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: * Alessio Di Sandro - Implementation. */ package edu.toronto.cs.se.modelepedia.statemachine_mavo.operator; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; import edu.toronto.cs.se.mmint.mid.GenericElement; import edu.toronto.cs.se.mmint.mid.MID; import edu.toronto.cs.se.mmint.mid.Model; import edu.toronto.cs.se.mmint.mid.operator.impl.OperatorImpl; import edu.toronto.cs.se.mmint.mid.utils.FileUtils; import edu.toronto.cs.se.modelepedia.statemachine_mavo.AbstractState; import edu.toronto.cs.se.modelepedia.statemachine_mavo.State; import edu.toronto.cs.se.modelepedia.statemachine_mavo.StateMachine; import edu.toronto.cs.se.modelepedia.statemachine_mavo.StateMachine_MAVOFactory; import edu.toronto.cs.se.modelepedia.statemachine_mavo.Transition; public class ParallelComposition extends OperatorImpl { // input-output private final static @NonNull String IN_MODEL1 = "sm1"; private final static @NonNull String IN_MODEL2 = "sm2"; private final static @NonNull String OUT_MODEL = "composed"; private final static @NonNull String COMPOSITION_INFIX = "-"; private void createComposedTransition(@NonNull StateMachine composedSM, @NonNull Transition transition, State composedStateSrc, State composedStateTgt) { //TODO Generate unique formula vars Transition composedTransition = StateMachine_MAVOFactory.eINSTANCE.createTransition(); composedTransition.setTrigger(transition.getTrigger()); composedTransition.setFormulaVariable(transition.getFormulaVariable() + "_" + composedStateSrc.getFormulaVariable() + "2" + composedStateTgt.getFormulaVariable()); composedSM.getTransitions().add(composedTransition); composedTransition.setSource(composedStateSrc); composedTransition.setTarget(composedStateTgt); } private void createComposedTransitions(@NonNull StateMachine composedSM, @NonNull StateMachine smToCompose, @NonNull Transition transition, @NonNull Map<String, State> composedStates, boolean transitionFirst) { for (AbstractState stateToCompose : smToCompose.getStates()) { String composedStateNameSrc, composedStateNameTgt; if (transitionFirst) { composedStateNameSrc = transition.getSource().getName() + COMPOSITION_INFIX + stateToCompose.getName(); composedStateNameTgt = transition.getTarget().getName() + COMPOSITION_INFIX + stateToCompose.getName(); } else { composedStateNameSrc = stateToCompose.getName() + COMPOSITION_INFIX + transition.getSource().getName(); composedStateNameTgt = stateToCompose.getName() + COMPOSITION_INFIX + transition.getTarget().getName(); } createComposedTransition(composedSM, transition, composedStates.get(composedStateNameSrc), composedStates.get(composedStateNameTgt)); } } private @NonNull Map<String, Set<Transition>> getTriggers(@NonNull StateMachine sm) { return sm.getTransitions().stream() .collect(Collectors.groupingBy( Transition::getTrigger, Collectors.toSet())); } private @NonNull StateMachine compose(StateMachine sm1, StateMachine sm2) { Map<String, Set<Transition>> triggers1 = getTriggers(sm1); Map<String, Set<Transition>> triggers2 = getTriggers(sm2); Map<String, State> composedStates = new HashMap<>(); StateMachine composedSM = StateMachine_MAVOFactory.eINSTANCE.createStateMachine(); // create all states first.. for (AbstractState state1 : sm1.getStates()) { //TODO MMINT[STATEMACHINE] Fix initial and final state not having mavo annotations if (!(state1 instanceof State)) { continue; } for (AbstractState state2 : sm2.getStates()) { if (!(state2 instanceof State)) { continue; } State composedState = StateMachine_MAVOFactory.eINSTANCE.createState(); String composedStateName = state1.getName() + COMPOSITION_INFIX + state2.getName(); String composedStateFormulaVar = ((State) state1).getFormulaVariable() + COMPOSITION_INFIX + ((State) state2).getFormulaVariable(); composedState.setName(composedStateName); composedState.setFormulaVariable(composedStateFormulaVar); composedStates.put(composedStateName, composedState); composedSM.getStates().add(composedState); } } // ..then create transitions for (Transition transition1 : sm1.getTransitions()) { Set<Transition> transitions2SameTrigger = triggers2.get(transition1.getTrigger()); if (transitions2SameTrigger != null) { // sync for (Transition transition2 : transitions2SameTrigger) { String composedStateName = transition1.getSource().getName() + COMPOSITION_INFIX + transition2.getSource().getName(); State composedStateSrc = composedStates.get(composedStateName); composedStateName = transition1.getTarget().getName() + COMPOSITION_INFIX + transition2.getTarget().getName(); State composedStateTgt = composedStates.get(composedStateName); createComposedTransition(composedSM, transition1, composedStateSrc, composedStateTgt); } } else { createComposedTransitions(composedSM, sm2, transition1, composedStates, true); } } for (Transition transition2 : sm2.getTransitions()) { if (triggers1.get(transition2.getTrigger()) != null) { // sync already done continue; } createComposedTransitions(composedSM, sm1, transition2, composedStates, false); } return composedSM; } @Override public Map<String, Model> run( Map<String, Model> inputsByName, Map<String, GenericElement> genericsByName, Map<String, MID> outputMIDsByName) throws Exception { // input Model smModel1 = inputsByName.get(IN_MODEL1); Model smModel2 = inputsByName.get(IN_MODEL2); MID instanceMID = outputMIDsByName.get(OUT_MODEL); // parallel composition StateMachine composedSM = compose((StateMachine) smModel1.getEMFInstanceRoot(), (StateMachine) smModel2.getEMFInstanceRoot()); // output String composedModelUri = FileUtils.replaceFileNameInUri(smModel1.getUri(), smModel1.getName() + "+" + smModel2.getName()); FileUtils.writeModelFile(composedSM, composedModelUri, true); Model composedModel = smModel1.getMetatype().createInstanceAndEditor(composedModelUri, instanceMID); Map<String, Model> outputsByName = new HashMap<>(); outputsByName.put(OUT_MODEL, composedModel); return outputsByName; } }