org.eclipselabs.agrum.services.model.plugin.parser.ModelParser.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipselabs.agrum.services.model.plugin.parser.ModelParser.java

Source

/***********************************************************************
 * Copyright (c) 2013, Atos
 *
 * 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:
 *    Anthony Fernandes Pires (Atos/ONERA) - initial API and implementation
 **********************************************************************/

package org.eclipselabs.agrum.services.model.plugin.parser;

import java.util.ArrayList;
import java.util.Iterator;

import org.antlr.runtime.RecognitionException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.uml2.uml.Pseudostate;
import org.eclipse.uml2.uml.PseudostateKind;
import org.eclipse.uml2.uml.State;
import org.eclipse.uml2.uml.StateMachine;
import org.eclipse.uml2.uml.Transition;
import org.eclipse.uml2.uml.Trigger;
import org.eclipselabs.agrum.elements.acsl.basics.AssumesClause;
import org.eclipselabs.agrum.elements.acsl.basics.Behavior;
import org.eclipselabs.agrum.elements.acsl.basics.ACSLSymbol;
import org.eclipselabs.agrum.elements.acsl.basics.EnsuresClause;
import org.eclipselabs.agrum.elements.acsl.basics.FunctionContract;
import org.eclipselabs.agrum.elements.acsl.basics.RequiresClause;
import org.eclipselabs.agrum.elements.acsl.basics.VariableCondition;
import org.eclipselabs.agrum.elements.acsl.statemachine.SMAssumesClause;
import org.eclipselabs.agrum.elements.acsl.statemachine.SMBehavior;
import org.eclipselabs.agrum.elements.acsl.statemachine.SMNoOtherTransitionsEnsuresClause;
import org.eclipselabs.agrum.elements.acsl.statemachine.SMTransitionEnsuresClause;
import org.eclipselabs.agrum.services.generator.exceptions.ModelConstructionException;
import org.eclipselabs.agrum.services.generator.exceptions.OCLTranslationException;
import org.eclipselabs.agrum.services.ocl.parser.OCLParser;

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterators;

/**
 * The class <code>ModelParser</code> represents the generator to .
 * @version 0.1.0
 * @author Anthony Fernandes Pires (Atos/ONERA)
 */
public abstract class ModelParser {

    /**
     * The <code> true </code>value in ACSL
     */
    private final static String ACSL_true = "\\true";

    /**
     * The value of the return of the transition fonction
     */
    private final static String outputStateVariableName = "\\result";

    /**
     * The name of the event representing a clock tick
     */
    private final static String clockTriggerName = "tick";

    /**
     * The representation of the empty set value in our approach
     */
    private final static String emptySetName = "Null";

    /**
     * To get an iterator on each state of the state machine
     * @param s - the state machine
     * @return the iterator 
     */
    private static Iterator<State> StateIterator(StateMachine s) {
        Predicate<Object> allStates = Predicates.instanceOf(State.class);
        Iterator<EObject> result = Iterators.filter(s.eAllContents(), allStates);
        Iterator<State> states = Iterators.transform(result, new com.google.common.base.Function<EObject, State>() {
            @Override
            public State apply(EObject arg0) {
                return (State) arg0;
            }
        });
        return states;
    }

    /**
     * To get an iterator on each state of the state machine which possessed at least one outgoing transition with a tick event trigger
     * @param s - the state machine
     * @return the iterator 
     */
    private static Iterator<State> tickStateIterator(StateMachine s) {
        Iterator<State> states_iter = StateIterator(s);
        Iterator<State> new_states_iter = Iterators.filter(states_iter,
                new com.google.common.base.Predicate<State>() {
                    @Override
                    public boolean apply(State arg0) {
                        for (Transition t : arg0.getOutgoings())
                            for (Trigger trg : t.getTriggers()) {
                                if (trg.getEvent().getName().equals(clockTriggerName))
                                    return true;
                            }
                        return false;
                    }
                });
        return new_states_iter;
    }

    /**
     * To get an iterator on each state of the state machine which possessed at least one outgoing transition with a completion event trigger
     * @param s - the state machine
     * @return the iterator
     */
    private static Iterator<State> completionStateIterator(StateMachine s) {
        Iterator<State> states_iter = StateIterator(s);
        Iterator<State> new_states_iter = Iterators.filter(states_iter,
                new com.google.common.base.Predicate<State>() {
                    @Override
                    public boolean apply(State arg0) {
                        for (Transition t : arg0.getOutgoings())
                            if (t.getTriggers().isEmpty())
                                return true;
                        return false;
                    }
                });
        return new_states_iter;
    }

    /**
     * To get an iterator on each outgoing transition of a state, which possessed a tick event as trigger
     * @param s - the state
     * @return the iterator
     */
    private static Iterator<Transition> tickTransitionIterator(State s) {
        Predicate<Object> allTransitions = Predicates.instanceOf(Transition.class);
        Iterator<Transition> transitions = Iterators.filter(s.getOutgoings().listIterator(), allTransitions);

        transitions = Iterators.filter(transitions, new com.google.common.base.Predicate<Transition>() {

            @Override
            public boolean apply(Transition arg0) {
                for (Trigger trg : arg0.getTriggers()) {
                    if (trg.getEvent().getName().equals(clockTriggerName))
                        return true;
                }
                return false;
            }
        });
        return transitions;
    }

    /**
     * To get an iterator on each outgoing transition of a state, which possessed a tick event as trigger
     * @param s - the state
     * @return the iterator
     */
    private static Iterator<Transition> completionTransitionIterator(State s) {
        Predicate<Object> allTransitions = Predicates.instanceOf(Transition.class);
        Iterator<Transition> transitions = Iterators.filter(s.getOutgoings().listIterator(), allTransitions);

        transitions = Iterators.filter(transitions, new com.google.common.base.Predicate<Transition>() {

            @Override
            public boolean apply(Transition arg0) {
                if (arg0.getTriggers().isEmpty())
                    return true;
                return false;
            }
        });
        return transitions;
    }

    /**
     * To get an iterator on each pseudostate of the state machine
     * @param s the state machine
     * @return the iterator
     */
    private static Iterator<Pseudostate> pseudostateIterator(StateMachine s) {
        Predicate<Object> allPseudostates = Predicates.instanceOf(Pseudostate.class);
        Iterator<EObject> result = Iterators.filter(s.eAllContents(), allPseudostates);
        Iterator<Pseudostate> pseudostates = Iterators.transform(result,
                new com.google.common.base.Function<EObject, Pseudostate>() {
                    @Override
                    public Pseudostate apply(EObject arg0) {
                        return (Pseudostate) arg0;
                    }
                });
        return pseudostates;
    }

    /**
     * Method to create the behavior of a state according to the kind of transitions to verified (depending on the event defined as trigger)
     * @param state_variable_name - the name representing the current state of the state machine in the code
     * @param s - the state
     * @param iter - the iterator to analyse the outgoing transitions of the state
     * @return the behavior
     * @throws RecognitionException
     * @throws OCLTranslationException
     */
    private static Behavior createBehavior(String state_variable_name, State s, Iterator<Transition> iter)
            throws RecognitionException, OCLTranslationException {
        SMAssumesClause ass = new SMAssumesClause(
                new VariableCondition(state_variable_name, ACSLSymbol.EQUAL.toString(), s.getName()));
        SMBehavior beh = new SMBehavior(s.getName(), ass, new ArrayList<EnsuresClause>());
        //for all outgoing transitions
        ArrayList<String> conditions = new ArrayList<String>();
        for (Iterator<Transition> iterT = iter; iterT.hasNext();) {
            Transition t = iterT.next();
            //create the output condition on the targeted state
            VariableCondition bexp = new VariableCondition(outputStateVariableName, ACSLSymbol.EQUAL.toString(),
                    t.getTarget().getName());
            //initialize the condition with the guard default value, true
            String condition = ACSL_true;
            //If a guard is defined, translate the condition in ACSL
            if (!t.getOwnedRules().isEmpty()) {
                //Creation of the ensures clause of this transition
                condition = "("
                        + OCLParser.parseOCLCondition(t.getOwnedRules().get(0).getSpecification().stringValue())
                        + ")";
            }

            conditions.add(condition);
            //Creation of the ensures clause of this transition
            SMTransitionEnsuresClause ens = new SMTransitionEnsuresClause(condition, bexp);

            //Addition of the ensures clause to the behavior of the state
            beh.addEnsuresClause(ens);
        }

        String condExp = "";
        for (Iterator<String> condItr = conditions.iterator(); condItr.hasNext();) {
            String str = condItr.next();
            condExp = condExp + ACSLSymbol.NOT + str;
            if (condItr.hasNext())
                condExp = condExp + ACSLSymbol.AND.toString();

        }

        SMNoOtherTransitionsEnsuresClause condEns = new SMNoOtherTransitionsEnsuresClause(condExp,
                new VariableCondition(outputStateVariableName, ACSLSymbol.EQUAL.toString(), emptySetName));
        beh.addEnsuresClause(condEns);

        return beh;
    }

    /**
     * Method to get the function contract corresponding to the state machine for transitions with tick event trigger.
     * @param state_variable_name - the name representing the current state of the state machine in the code
     * @param sm - the state machine
     * @return the function contract
     * @throws ModelConstructionException
     * @throws RecognitionException
     * @throws OCLTranslationException
     */
    public static FunctionContract parseStateMachineForTick(String state_variable_name, StateMachine sm)
            throws ModelConstructionException, RecognitionException, OCLTranslationException {
        //check StateMachine model
        FunctionContract ctr = new FunctionContract(new ArrayList<RequiresClause>(), new ArrayList<Behavior>());

        //for states with tick event on trigger of some outgoing transition
        for (Iterator<State> iterS = tickStateIterator(sm); iterS.hasNext();) {
            State s = iterS.next();

            //Creation of the behavior
            Behavior beh = createBehavior(state_variable_name, s, tickTransitionIterator(s));

            //Addition of the behavior of the state to the function contract
            ctr.addBehavior(beh);
        }

        String exp = "";
        for (Iterator<State> iterS = tickStateIterator(sm); iterS.hasNext();) {
            State s = iterS.next();
            exp = exp + new VariableCondition(state_variable_name, ACSLSymbol.DIF.toString(), s.getName());
            if (iterS.hasNext())
                exp = exp + ACSLSymbol.AND.toString();

        }
        AssumesClause assOtherStates = new AssumesClause(exp);
        SMBehavior behOtherStates = new SMBehavior("OtherStates", assOtherStates, new ArrayList<EnsuresClause>());
        behOtherStates.addEnsuresClause(
                new EnsuresClause(outputStateVariableName + ACSLSymbol.EQUAL.toString() + emptySetName));

        ctr.addBehavior(behOtherStates);

        return ctr;
    }

    /**
     * Method to get the function contract corresponding to the state machine for transitions with completion event trigger.
     * @param state_variable_name - the name representing the current state of the state machine in the code
     * @param sm - the state machine
     * @return the function contract corresponding to the state machine for transitions with completion event trigger.
     * @throws ModelConstructionException
     * @throws RecognitionException
     * @throws OCLTranslationException
     */
    public static FunctionContract parseStateMachineForCompletion(String state_variable_name, StateMachine sm)
            throws ModelConstructionException, RecognitionException, OCLTranslationException {

        FunctionContract ctr = new FunctionContract(new ArrayList<RequiresClause>(), new ArrayList<Behavior>());

        //parse the initial state (unique pseudostate in the statemachine)
        for (Iterator<Pseudostate> iterP = pseudostateIterator(sm); iterP.hasNext();) {
            Pseudostate p = iterP.next();
            SMBehavior beh = new SMBehavior(p.getName(),
                    new SMAssumesClause(
                            new VariableCondition(state_variable_name, ACSLSymbol.EQUAL.toString(), p.getName())),
                    new ArrayList<EnsuresClause>());
            for (Iterator<Transition> iterT = p.getOutgoings().iterator(); iterT.hasNext();) {
                Transition t = iterT.next();
                beh.addEnsuresClause(new SMTransitionEnsuresClause(ACSL_true, new VariableCondition(
                        outputStateVariableName, ACSLSymbol.EQUAL.toString(), t.getTarget().getName())));
            }
            beh.addEnsuresClause(new SMNoOtherTransitionsEnsuresClause(ACSLSymbol.NOT.toString() + ACSL_true,
                    new VariableCondition(outputStateVariableName, ACSLSymbol.EQUAL.toString(), emptySetName)));
            ctr.addBehavior(beh);
        }

        //for states with completion event on trigger of some outgoing transition
        for (Iterator<State> iterS = completionStateIterator(sm); iterS.hasNext();) {
            State s = iterS.next();

            //Creation of the behavior
            Behavior beh = createBehavior(state_variable_name, s, completionTransitionIterator(s));

            //Addition of the behavior of the state to the function contract
            ctr.addBehavior(beh);
        }
        ArrayList<String> al = new ArrayList<String>();

        for (Iterator<Pseudostate> iterP = pseudostateIterator(sm); iterP.hasNext();) {
            Pseudostate p = iterP.next();
            al.add(p.getName());
        }
        String exp = "";
        for (Iterator<State> iterS = completionStateIterator(sm); iterS.hasNext();) {
            State s = iterS.next();
            al.add(s.getName());
        }

        for (Iterator<String> itr = al.iterator(); itr.hasNext();) {
            String str = itr.next();
            exp = exp + new VariableCondition(state_variable_name, ACSLSymbol.DIF.toString(), str);
            if (itr.hasNext())
                exp = exp + ACSLSymbol.AND.toString();

        }

        AssumesClause assOtherStates = new AssumesClause(exp);
        SMBehavior behOtherStates = new SMBehavior("OtherStates", assOtherStates, new ArrayList<EnsuresClause>());
        behOtherStates.addEnsuresClause(
                new EnsuresClause(outputStateVariableName + ACSLSymbol.EQUAL.toString() + emptySetName));

        ctr.addBehavior(behOtherStates);

        return ctr;
    }

    /**
     * check if the state machine is well-formed
     * @param sm - the state machine to check
     * @throws ModelConstructionException
     */
    public static void checkStateMachineModelling(StateMachine sm) throws ModelConstructionException {
        if (sm.getRegions().size() > 1)
            throw new ModelConstructionException(
                    "There are more than one region in statemachine " + sm.getName() + ".");
        if (!pseudostateIterator(sm).hasNext())
            throw new ModelConstructionException(
                    "No initial pseudostate has been defined for statemachine " + sm.getName() + ".");
        ;

        //parse the initial state (unique pseudostate in the statemachine)
        for (Iterator<Pseudostate> iterP = pseudostateIterator(sm); iterP.hasNext();) {
            Pseudostate p = iterP.next();
            if (iterP.hasNext() || p.getKind() != PseudostateKind.INITIAL_LITERAL)
                throw new ModelConstructionException("Wrong pseudostates defined in statemachine " + sm.getName()
                        + ", only an Initial pseudostate is autorized.");
            for (Iterator<Transition> iterT = p.getOutgoings().iterator(); iterT.hasNext();) {
                Transition t = iterT.next();
                if (iterT.hasNext())
                    throw new ModelConstructionException(
                            "Too many outgoing transitions for the initial pseudostate " + p.getName()
                                    + " in statemachine " + sm.getName() + ", only one autorized.");
                if (!t.eContents().isEmpty())
                    throw new ModelConstructionException(
                            "The outgoing transition of the initial pseudostate " + p.getName()
                                    + " in statemachine " + sm.getName() + " must not contain trigger or guard.");
            }
        }
    }

}