Saturday, May 30, 2009

Implementing a Diameter Peer State Machine using Test Driven Development (Part 1).

RFC3588 (Diameter Base Protocol), specifically par. 5.6, contains specification about a finite state machine that MUST be observed by all Diameter implementations.

In this article we will see how to implement a peer state machine using Test Driven Development. Note that this is only the first part of the whole article.
The following is an extract (just the first entry) of the RFC table (you can found that on the previously mentioned paragraph) that illustrates the peer state machine :

I choose that entry because "Closed" is the peer initial state.
As you can see when the peer is in that state it can receive only two kind of events:

1) Start : A diameter application has signaled that a connection should be initiated with the peer;
2) R-Conn-CER : An acknowledgement is received stating that the transport connection has been established, and the associated Capability Exchange Request (CER) has arrived.

The first event must be associated with the following action on the peer :

1) I-Snd-Conn-Req (Initiator Sends Connection Request) : A transport connection is initiated with the peer;

After the peer successfully processed the action its new state MUST be "Wait-Conn-Ack".

The second event, R-Conn-CER, is firing the following actions on the peer :

1) R-Accept : The incoming connection associated with the R-Conn-CER is accepted as the responder connection;
2) Process-CER : The CER associated with the R-Conn-CER is processed.
3) R-Snd-CEA (Receiver Sends CEA)

After those three actions, the peer must be in "R-Open" state.

Well, of course if you have a look at the whole table there are a lot of states / actions / events but for simplicity we can assume that we are handling only with the "Closed" state. The whole article can be applied to other table entries.

First implicit requirement is that we should have a Peer class, it must have an internal state and the initial value of that state should be "Closed".
So, for a first implementation of our test case I'd like to write something like this :

package com.gazzax.diameter.peer;

public class PeerStateMachineTestCase
{
@Test
public void initialState()
{
Peer peer = new Peer();
assertTrue(peer.currentStateIs(peer.CLOSED));
}
}

Obviously, the test doesn't compile for several reasons; First of all, we need a Peer class :) So let's create it!

package com.gazzax.diameter.peer;

public class Peer
{
}

One little step ahead! But it is not sufficient because the TestCase still doesn't compile :( There's no a currentStateIs(...) method on the Peer class!
Note that that method is accepting a parameter that represents a peer state. Peer's states are typed instance members of peer class and they have a default visibility. Why? Because in that way we can see / use them on our test case without breaking encapsulation (PeerStateMachineTestCase and Peer are in the same package even if they usually reside in different source folders)

NOTE : the current state of the peer IS NOT exposed (it is a private member). You can only have an indirect / read-only access through the currentStateIs(...) method.
This is done because we don't want break enapsulation and therefore peer state invariants.

Anyway, the state machine table suggests that

- a peer, regardless its state, should be able to receive a signal;
- the concrete handling of that signal (fired actions and next state) depends on the current state of the peer;

So, this suggests me that a peer state itself shuold be able to receive a signal. Here is the peer state interface:

package com.gazzax.diameter.peer;

public interface State
{
void signal(PeerEventType event) throws WrongEventException;
}

Where

- PeerEventType is an enumeration of all defined event types; for the current example it will look like this :

package com.gazzax.diameter.peer;

public enum PeerEventType
{
START,
R_CONN_CER
}

- WrongEventException : that will be thrown when the received event type is violating the rules defined on the peer state machine table. I mean, when the peer will receive a wrong event according with its current state. I mean, when the current state of the peer doesn't recognize the received event type as valid.

We left the TestCase with compilation errors. We need a currentStateIs(State peerState) method. Let's write it with a dummy implementation!

public class Peer
{
private final State CLOSED;

boolean currentStateIs(State state)
{
return false;
}
}

Now code should compile :)
Run again the test case and you will see the red bar! Bad? Absolutely not, that means "Progress"! Another little step ahead!

What is the minimal thing / adjustment that we could do in order to get a green bar?

public class Peer
{
private final State CLOSED;

boolean currentStateIs(State state)
{
return true;
}
}

Run again the test and...et voilĂ ! We got a green bar! Another little step ahead!

Friday, May 15, 2009

Dependency Injection with EJB 2.x

Very often, I see in an EJB 2.x environment message driven or session beans with the following code :

public void onMessage(Message message)
{
Connection connection = null;
try
{
Context ctx = new Context();
DataSource datasource = (DataSource)ctx.lookup("jdbc/ds");
Connection connetion = ....
// Do somethign with connection
} catch(NamingException exception)
{
// Do something
} catch(SQLException exception)
{
// Do something
} finally
{
try { connection.close(); } catch(Exception ignore) {}
}
}

...or (better) using a service locator :

public void onMessage(Message message)
{
Connection connection = null;
try
{
ServiceLocator serviceLocator = new ServiceLocator();
DataSource datasource = serviceLocator.getDataSource("jdbc/ds");
Connection connetion = ....
// Do somethign with connection
} catch(NamingException exception)
{
// Do something
} catch(SQLException exception)
{
// Do something
} finally
{
try { connection.close(); } catch(Exception ignore) {}
}
}

What is the problem? That piece of code (doesn't matter if it belongs to a session or a message driven bean) should IMO contains only business logic;
I mean, the logic that should make sense, from a business point of view, of that EJB.
Now, again, what is the problem? JDBC Code? Why don't we use a Data Gateway (or in general a data access pattern)?
Yes, that's right, but that's not the point.
Let's make a strong precondition supposing that jdbc code is part of business logic.
What else?

Look at this line of code :

} catch(NamingException exception)
{
// Do something
}

This exception is thrown when some problem occurs with naming service. The funny thing is that we are looking up the resource (a datasource in this case) each time this method is called. What is the problem?

There are at least three issues :

1) Each call to Context.lookup(...) is theoretically a remote call. Here that call is done each time a message arrives. You may think that code could be optimized, looking up the resource the first time, but you must in any case catch the Naming Exception (even if the lookup isn't really executed)
2) What you need is the resource that is bound with the naming service under the name "jdbc/ds", not the naming service itself. Once you got it, you have all what you need in order to retrieve valid database connections. So you should use that lookup code once and only once.
3) NamingException is not a business excepiton...the corresponding "throwing" code it's not part of the business logic too, but the onMessage(), where only the business logic should be, must contain the try-catch statement in order to handle a scenario where a naming service occurs...EACH TIME THE CODE IS EXECUTED!.

The usage of a service locator doesn't solve the problem completely : even if we cache the resource (on service locator), we will avoid the 1) & 2) but not the 3th issue.
In fact the signature of the getDatasource(...) method is throwing a NamingException and therefore the calling code must catch it everytime.

The ideal solution should:

1) make a lookup call only once;
2) catch the naming exception only once (when the lookup call is executed)
3) in case of naming exception (naming service failure) the call should be repeated until the resource is available.

public void GxMessageDriven implements MessageDrivenBean, MessageListener
{
private DataSource datasource;

public void onMessage()
{
// Here we can use directly the datasource instance that
// has been self-injected in ejbCreate() method at startup.
Connection connection = null;
try
{
connection = datasource.getConnection()
} catch(SQLException exception)
{
...
} finally
{
try { connection.close } catch(Exception ignore){}
}
}

public void ejbCreate()
{
try
{
// Using a service locator should be better
Context ctx = new InitialContext();
datasource = (DataSource) ctx.lookup("jdbc/ds");
} catch(NamingException exception)
{
// This ejb cannot be initialized because a needed resource cannot be retrieved
}
}
}

As you can see the lookup code (and the corresponding catch of the NamingException) is executed only once in the ejbCreate().
The first obvious consequence is that within onMessage() method the datasource member instance is used directly because it is already intialized.
There's only remaining open issue : what happens if the lookup fails in the ejbCreate? Basically that means the onMessage method will throw a NullPointerException and obviously we don't want that :)
If you are thinking about an if statement within the onMessage method :

if (datasource != null)
{
....
}

That means probably you didn't read my previous post : I hate if statements :) I think is better to equipe the ejb component with a state pattern in the following way :

1) create a member instance which will represent the current state of the component:

private MessageListener currentState;

2) create one inner class which represents the WORKING state:

private final MessageListener WORKING = new MessageListener()
{
public void onMessage()
{
// Here we can use directly the datasource instance that
// has been self-injected in ejbCreate() method at startup.

Connection connection = null;
try
{
connection = datasource.getConnection()
} catch(SQLException exception)
{
...
} finally
{
try { connection.close } catch(Exception ignore){}
}
}
}

3) Create another inner class which represents the OFF state :

private final MessageListener OFF = new MessageListener()
{
public void onMessage(Message message)
{
try
{
Context ctx = new InitialContext();
datasource = (DataSource) ctx.lookup("jdbc/ds");

// State change : OFF --> WORKING
currentState = WORKING;

// Process the message
currentState.onMessage(message);
} catch(NamingException exception)
{
// Don't change current state...resource is not yet available
}
}
}

4) Update the memeber instance variable in order to set the OFF state as default state.

private MessageListener currentState = OFF;

At this point, you should probably see that the ejbCreate is no longer useful because the check is made by the OFF state the first time the component raises up.

So, the final code should look like this :

public void GxMessageDriven implements MessageDrivenBean, MessageListener
{
private final MessageListener OFF = new MessageListener()
{
public void onMessage(Message message)
{
try
{
Context ctx = new InitialContext();
datasource = (DataSource) ctx.lookup("jdbc/ds");

// State change : OFF --> WORKING
currentState = WORKING;

// Process the message using the working state
currentState.onMessage(message);
} catch(NamingException exception)
{
// Don't change current state...resource is not yet available
}
}
}

private final MessageListener WORKING = new MessageListener()
{
public void onMessage()
{
// Here we can use directly the datasource instance that
// has been self-injected in ejbCreate() method at startup.

Connection connection = null;
try
{
connection = datasource.getConnection()
} catch(SQLException exception)
{
//...
} finally
{
try { connection.close } catch(Exception ignore){}
}
}
}
private DataSource datasource;
private MessageListener currentState= OFF;
}