- When a peer is in "Closed" state and receives a START signal it must
- take a I-Snd-Conn-Req action : this is currently a missing point;
- change its state to Wait-Conn-Ack : we did that in the last episode :)
- take the following 3 actions : R-Accept, Process-CER and R-Snd-CEA.
- change its state to R-Open.
Following the same approach we used for the "Start" signal, we can write another test method :
public class PeerStateMachineTestCase
{
....@Test
....public void rConnCerSignal()
...{
......Peer peer = new Peer();
......peer.signal(PeerEventType.R_CONN_CER);
......assertTrue(peer.currentStateIs(peer.R_OPEN);
...}
}
PeerEventType.R_CONN_CER is not giving any compiler warning because we already added it in the first part.
What is really missing(from a compiler perspective) is a R_OPEN member instance on Peer class:
public class Peer
{
....final State CLOSED = new State(){};
....final State WAIT_CONN_ACK = new State(){};
....final State R_OPEN = new State(){};
...
...
}
Now our test compiles fine but it gives us a red bar: after PeerEventType.R_CONN_CER signal has been received peer is not (as expected) in R_OPEN state but in WAIT_CONN_ACK :(
This is reasonable if we remember the Peer.signal(...) implementation we did last time :
public void signal(PeerEventType type)
{
....currentState = WAIT_CONN_ACK;
}
With the new R_CONN_CER signal this implementation is not working anymore so we need to rewrite the method in order to let the peer properly react to a given signal. The most obvious solution could be :
public void signal(PeerEventType type)
{
....if (currentState == CLOSED)
....{........if (type == START)
........{............currentState = WAIT_CONN_ACK;
........}
........else if (type == R_CONN_CER)
........{............currentState = R_OPEN;
........}
....}
}
Without any doubt it's working but
- If you have a look at the state machine table defined on RFC 3588 you'll quickly realize that this approach will result in a looot of "if / else if" statements;
- personally I believe that the transition state is something related with the state itself, while in the implementation above we made that part of the Peer logic.
- Add a new state member instance;
- Modify the signal method.
- we already have something that tell us what is the current state;
- that thing is an object (an instance of State)
- obviously that object could have its own state and methods;
(Interface State)
void signal(PeerEventType eventType) throws WrongEventException;
Now each instance of State must implements this method which is supposed to
- Change the state of the hosting Peer instance (remember that our State instances are inner classes);
- Raise an exception if a wrong (not allowed) signal is received;
....final State CLOSED = new State()
....{
........public void signal(PeerEventType eventType) throws WrongEventException
........{............switch (eventType)
............{................case START :
................{....................currentState = WAIT_CONN_ACK;
....................break;
................}
................case R_CONN_CER :
................{....................currentState = R_OPEN;
....................break;
................}
................default :
................{....................throw new WrongEventException("Some useful message");
................}
............}
........}....};
Of course, in order to get things working as expected, we need to modify the Peer.signal method :
public void signal(PeerEventType type) throws WrongEventTypeException
{
....currentState.signal(type);
}
Now our 2 test methods should correctly work.
See you soon for the last part :)
Ciao
Andrea
No comments:
Post a Comment