/graphwalker-labs

A module for experimenting with new stuff, things we think might be cool to try out, but not reelly considered as production ready.

Primary LanguageJavaScript

The FsmFactory is inspired by the NModel project from Microsoft Research, https://nmodel.codeplex.com/, which later developed into the SpecExplorer. FsmFactory does only one thing: It creates a finite state chart from a class using the @Transition annotation.

The concept is:

  • a class implements Serializable.
  • Annotates methods that represents transitions using the @Transition. A transition is when some state changes. Some properties are changing values.
  • In a stateful system, transitions are only allowed under certain circumstances. This is done by accompanying guard methods to the transition method. They share the same method name, except that the guard has a the word On prefixed to the name.

Consider following code: (See also book Model-based Software Testing and Analysis with C#, the example with Client and Server. http://www.cambridge.org/se/academic/subjects/computer-science/software-engineering-and-development/model-based-software-testing-and-analysis-c?format=PB)

        FsmFactory factory = new FsmFactory();
        Model model = factory.create(new ClientServer());
        System.out.println(DotFileFactory.createDot(model));

and where the ClientServer class looks like:

public class ClientServer implements Serializable {

    public enum Socket { None, Created, Bound, Listening, Connecting,
        Connected, Disconnected, Closed }

    public enum Phase { Send, ServerReceive, ClientReceive }

    // Control state
    public Socket serverSocket = Socket.None;
    public Socket clientSocket = Socket.None;
    public Phase phase = Phase.Send;

    // Server enabling conditions and actions
    public boolean OnServerSocket() {
        return (serverSocket == Socket.None);
    }

    @Transition
    public void ServerSocket() {
        serverSocket = Socket.Created;
    }

    public boolean OnServerBind() {
        return (serverSocket == Socket.Created);
    }

    @Transition
    public void ServerBind()
    {
        serverSocket = Socket.Bound;
    }

    public boolean OnServerListen()
    {
        return (serverSocket == Socket.Bound);
    }

    @Transition
    public void ServerListen()
    {
        serverSocket = Socket.Listening;
    }

    public boolean OnServerAccept()
    {
        return (serverSocket == Socket.Listening
            && clientSocket == Socket.Connecting);
    }

    @Transition
    public void ServerAccept()
    {
        serverSocket = Socket.Connected; clientSocket = Socket.Connected;
    }

    public boolean OnServerReceive()
    {
        return (serverSocket == Socket.Connected
            && phase == Phase.ServerReceive);
    }


    // No parameter needed here, client always sends same thing
    @Transition
    public void ServerReceive()
    {
        phase = Phase.Send;
    }

    public boolean OnServerSend()
    {
        return (serverSocket == Socket.Connected
            && phase == Phase.Send
            && clientSocket == Socket.Connected);
    }

    // Parameter here, server can send different temperatures
    @Transition
    public void ServerSend()
    {
        phase = Phase.ClientReceive;
    }

    public boolean OnServerCloseConnection()
    {
        return (serverSocket == Socket.Connected);
    }

    @Transition
    public void ServerCloseConnection()
    {
        serverSocket = Socket.Disconnected;
    }

    // Prevent Client crashing - does sending to closed partner crash?
    public boolean OnServerClose()
    {
        return (serverSocket != Socket.None
            // && serverSocket != Socket.Listening
            && serverSocket != Socket.Connected
            && serverSocket != Socket.Closed);
    }

    @Transition
    public void ServerClose()
    {
        serverSocket = Socket.Closed;
    }

    // Client enabling conditions and actions

    public boolean OnClientSocket()
    {
        return (clientSocket == Socket.None);
    }

    @Transition
    public void ClientSocket()
    {
        clientSocket = Socket.Created;
    }

    public boolean OnClientConnect()
    {
        return (clientSocket == Socket.Created
            && serverSocket == Socket.Listening);
    }

    @Transition
    public void ClientConnect()
    {
        clientSocket = Socket.Connecting;
    }

    public boolean OnClientSend()
    {
        return (clientSocket == Socket.Connected
            && phase == Phase.Send);
    }

    // No parameter needed here, client always sends the same thing
    @Transition
    public void ClientSend()
    {
        phase = Phase.ServerReceive;
    }

    public boolean OnClientReceive()
    {
        return (clientSocket == Socket.Connected
            && phase == Phase.ClientReceive);
    }

    // Return value needed here, server sends different values
    @Transition
    public void ClientReceive()
    {
        phase = Phase.Send;
    }

    public boolean OnClientClose()
    {
        return (clientSocket == Socket.Connected
            && phase == Phase.Send);
    }

    @Transition
    public void ClientClose() {
        clientSocket = Socket.Closed;
    }
}

The FsmFactory will create a state chart, when written and visialized by graphviz and dot, will look like: (using dot -Tsvg clientserver.dot > login.svg) Alt text