Lab3 Yves Conselvan

aluno: Yves Conselvan
ano/sem: 2008/2o.
data do laboratório (num. da semana) : ???

Introdução

Neste laboratório nossa tarefa foi implementar uma biblioteca de maquina de estados finitos para utilizar em aplicações Java, e implementar uma aplicação de teste. Para esta tarefa fomos orientado a criar um pacote contendo todas as classes necessárias à maquina de estados.

Desenvolvimento

No desenvolvimento do pacote StateMachine utilizei a seguinte estrutura de classes.

classes.jpg

A classe StateMachine é a classe principal do pacote, que manipula a criação de estados e eventos, as classes State e Event representam respectivamente um estado e um evento da maquina de estados.

Na classe StateMachine utilizei HashMap's para fazer a ligação entre nome de evento ou estado e o objeto do tipo Event ou State.

class StateMachine
{
    ...
    private HashMap<String, State> states = new HashMap<String, State>();
    private HashMap<String, Event> events = new HashMap<String, Event>();
    ...
}

Dentro da classe State ficam as informações sobre as transições que o estado pode executar. Utilizando um HashMap é feita a ligação entre nome do evento, e nome do estado para o qual irá transitar com aquele evento. Para fazer esta ligação criei o método appendTransition na classe State. Dessa forma ficou sem sentido a utilização de uma classe para representar as transições.

class State
{
    ...
    StateCommand onEnter = null;
    HashMap<String, String> transitions = new HashMap<String, String>();
 
    ...
 
    public void appendTransition(String eventName, String toState)
    {
        transitions.put(eventName, toState);
    }
 
    ...    
 
}

Utilizando essa estrutura a transição dos estados é feita utilizando o método fireEvent da classe State, que irá retornar o nome do estado para o qual a máquina deverá transitar. Caso não exista no HashMap nenhuma chave com o nome do evento será lançada uma exceção UndefinedTransitionException.

public String fireEvent(String eventName) throws UndefinedTransitionException
    {
        String nextStateName = null;
        if ((nextStateName = transitions.get(eventName)) == null)
        {
            throw new UndefinedTransitionException();
        }
        return nextStateName;
    }

Na classe Event as ações de guarda podem ser adicionadas utilizando o método setGuard, e a classe possuiu o método verifyEventGuards que é chamado pela classe StateMachine ao se tentar disparar um evento.

class Event
{
    ...
    public void setGuard(EventGuard g)
    {
        guards.add(g);
    }
 
    public boolean verifyEventGuards()
    {
        boolean canFire = true;
        for (EventGuard guard : guards)
        {
            if (!guard.shouldPerform())
            {
                canFire = false;
                break;
            }
        }
        return canFire;
    }
   ...
}

Os métodos stateEnter da classe State e eventSuccess da classe Event são chamados pelo objeto da classe StateMachine ao se transitar de estado.

class State
{
    ...
    public void stateEnter()
    {
        if (onEnter != null)        
        {
            onEnter.execute();
        }
    }
}
 
class Event {
    ...
    public void eventSuccess(String previousEvent)
    {
        if (this.onSuccess != null)        
        {
            this.onSuccess.execute(previousEvent);
        }
    }
}

Função responsável pelo disparamento do evento na classe StateMachine

class StateMachine
{
    ...
    public boolean fireEvent(String name) throws UndefinedTransitionException
    {
        boolean fired = false;  
        Event event;
        String previousState;
        event = getEventByName(name);
        if (event.verifyEventGuards())
        {
            if (currentState != null)
            {  
                previousState = getCurrentStateName();
                currentState = getStateByName(currentState.fireEvent(name));
                currentState.stateEnter();
                event.eventSuccess(previousState);
                fired = true;
                notifyObservers();
            }             
        }               
        return fired;
    }
    ...
}

Na classe StateMachine o método appendTransitionToEvent é o responśavel pela distribuição das relações "evento - estado de chegada" para cada estado.
Disponível com duas assinaturas uma apenas formata os dados na forma adequada para passar à função que efetivamente realiza o trabalho.

class StateMachine
{
    ...
    public void appendTransitionToEvent(String event, String fromState, String toState)
    {
        String[] fromStates = new String[1];
        fromStates[0] = fromState;
        appendTransitionToEvent(event, fromStates, toState);
    }
 
    public void appendTransitionToEvent(String event, String[] fromState, String toState)
    {
        State stateToAppend;
        for (String from : fromState)
        {
            if ((stateToAppend = getStateByName(from)) != null)
            {
                stateToAppend.appendTransition(event, toState);
            }
        }
    }
    ...
}

O método setGuardToEvent da classe StateMachine apenas delega para o evento a adição da condição de guarda.

class StateMachine
{
    ...
    public void setGuardToEvent(String event,EventGuard g)
    {
        Event eventToGuard;
        if ((eventToGuard = (Event)events.get(event)) != null)
        {
            eventToGuard.setGuard(g);
        }
    }
    ...
}

Ainda na classe StateMachine criei métodos para retornar os objetos de Event e State a partir do nome. Inclui nestas funções o lançamento de exceçõs no caso de um evento ou estado não existir.

class StateMachine
{
    ...
    private State getStateByName(String stateName)
    {
        State retState = null;
        if ((retState = states.get(stateName)) == null) 
        {   
            throw new UndefinedStateError();
        }            
        return retState;
    }
 
    private Event getEventByName(String eventName)
    {
        Event retEvent = null;
        if ((retEvent = events.get(eventName)) == null) 
        {   
            throw new UndefinedEventError();
        }            
        return retEvent;
    }
 
}

Implementada a máquina de estados executei os testes e apresento abaixo o resultado e as saídas.

testes.jpg

Saida:

saida.jpg

Para teste da máquina de estados implementei a aplicação de exemplo com as classes Professor e Turma, e também implementei o outro exemplo.

teste_maquina.jpg

Diagrama de estados da implementação feita

estados.jpg

Conclusão

Na implementação da máquina de estados utilizamos o padrão Observer para trocar informação entre as entidades e não deixá-las muito acopladas. Para facilitar a utilização da máquina de estados foi utilizada herança a partir da classe WithSM

Add a New Comment
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License