Chapter 4 - Session
The Session is at the heart of MINA : every time a client connects to the server, a new session is created, and will be kept in memory until the client is disconnected.
A session is used to store persistent informations about the connection, plus any kind of information the server might need to use during the request processing, and eventually during the whole session life.
Session state
A session has a state, which will evolve during time.
- Connected : the session has been created and is available
- Idle : the session hasn‘t processed any request for at least a period of time (this period is configurable)
- Idle for read : no read has actually been made for a period of time
- Idle for write : no write has actually been made for a period of time
- Idle for both : no read nor write for a period of time
- Closing : the session is being closed (the remaining messages are being flushed, cleaning up is not terminated)
- Closed : The session is now closed, nothing else can be done to revive it.
The following state diagram exposes all the possible states and transitions :
Configuration
Many different parameters can be set for a specific session :
- receive buffer size
- sending buffer size
- Idle time
- Write timeOut
plus other configuration, depending on the transport type used (see Chapter 6 - Transports)
Managing user-defined attributes
It might be necessary to store some data which may be used later. This is done using the dedicated data structure associated which each session. This is a key-value association, which can store any type of data the developer might want to keep remanent.
For instance, if you want to track the number of request a user has sent since the session has been created, it‘s easy to store it into this map: just create a key that will be associated with this value.
... int counterValue = session.getAttribute( "counter" ); session.setAttribute( "counter", counterValue + 1 ); ...
We have a way to handle stored Attributes into the session : an Attribute is a key/value pair, which can be added, removed and read from the session‘s container.
This container is created automatically when the session is created, and will be disposed when the session is terminated.
Defining the container
As we said, this container is a key/value container, which default to a Map, but it‘s also possible to define another data structure if one want to handle long lived data, or to avoid storing all those data in memory if they are large : we can implement an interface and a factory that will be used to create this container when the session is created.
This snippet of code shows how the container is created during the session initialization :
protected final void initSession(IoSession session, IoFuture future, IoSessionInitializer sessionInitializer) { ... try { ((AbstractIoSession) session).setAttributeMap(session.getService() .getSessionDataStructureFactory().getAttributeMap(session)); } catch (IoSessionInitializationException e) { throw e; } catch (Exception e) { throw new IoSessionInitializationException( "Failed to initialize an attributeMap.", e); } ...
and here is the factory interface we can implement if we want to define another kind of container :
public interface IoSessionDataStructureFactory { /** * Returns an {@link IoSessionAttributeMap} which is going to be associated * with the specified <tt>session</tt>. Please note that the returned * implementation must be thread-safe. */ IoSessionAttributeMap getAttributeMap(IoSession session) throws Exception; }
Filter chain
Each session is associated with a chain of filters, which will be processed when an incoming request or an outgoing message is received or emitted. Those filters are specific for each session individually, even if most of the cases, we will use the very same chain of filters for all the existing sessions.
However, it‘s possible to dynamically modify the chain for a single session, for instance by adding a Logger Filter in the chain for a specific session.
Statistics
Each session also keep a track of records about what has been done for the session :
- number of bytes received/sent
- number of messages received/sent
- Idle status
- throughput
and many other useful informations.
Handler
Last, not least, a session is attached to a Handler, in charge of dispatching the messages to your application. This handler will also send pack response by using the session, simply by calling the write() method :
... session.write( <your message> ); ...