blob: 52b8159eb8c1829b3360fc538b348c28df334484 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<title>Chapter 4 - Session &mdash; Apache MINA</title>
<link href="/assets/css/common.css" rel="stylesheet" type="text/css"/>
<link href="/assets/css/mina.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<script src="https://www.apachecon.com/event-images/snippet.js"></script>
<div id="container">
<div id="header">
<div id="subProjectsNavBar">
<a href="/">
Apache MINA Project
</a>
&nbsp;|&nbsp;
<a href="/mina-project/">
<strong>MINA</strong>
</a>
&nbsp;|&nbsp;
<a href="/asyncweb-project/">
AsyncWeb
</a>
&nbsp;|&nbsp;
<a href="/ftpserver-project/">
FtpServer
</a>
&nbsp;|&nbsp;
<a href="/sshd-project/">
SSHD
</a>
&nbsp;|&nbsp;
<a href="/vysper-project/">
Vysper
</a>
</div>
</div>
<div id="content">
<div id="leftColumn">
<div id="navigation">
<a class="acevent" data-format="wide" data-width="170"></a>
<h5>Social Networks</h5>
<ul>
<li><a href="https://fosstodon.org/@apachemina">Apache MINA Mastodon</a></li>
</ul>
<h5>Latest Downloads</h5>
<ul>
<li><a href="/mina-project/downloads_2_0.html">Mina 2.0.25</a></li>
<li><a href="/mina-project/downloads_2_1.html">Mina 2.1.8</a></li>
<li><a href="/mina-project/downloads_2_2.html">Mina 2.2.3</a></li>
<li><a href="/mina-project/downloads_old.html">Mina old versions</a></li>
</ul>
<h5>Documentation</h5>
<ul>
<li><a href="/mina-project/documentation.html" class="external-link" rel="nofollow">Base documentation</a></li>
<li><a href="/mina-project/userguide/user-guide-toc.html" class="external-link" rel="nofollow">User guide</a></li>
<li><a href="/mina-project/2.2-vs-2.1.html" class="external-link" rel="nofollow">2.2 vs 2.1</a></li>
<li><a href="/mina-project/2.1-vs-2.0.html" class="external-link" rel="nofollow">2.1 vs 2.0</a></li>
<li><a href="/mina-project/features.html" class="external-link" rel="nofollow">Features</a></li>
<li><a href="/mina-project/road-map.html" class="external-link" rel="nofollow">Road Map</a></li>
<li><a href="/mina-project/quick-start-guide.html" class="external-link" rel="nofollow">Quick Start Guide</a></li>
<li><a href="/mina-project/faq.html" class="external-link" rel="nofollow">FAQ</a></li>
</ul>
<h5>Resources</h5>
<ul>
<li><a href="/mina-project/mailing-lists.html" class="external-link" rel="nofollow">Mailing lists &amp; IRC</a></li>
<li><a href="/mina-project/issue-tracking.html" class="external-link" rel="nofollow">Issue tracking</a></li>
<li><a href="/mina-project/sources.html" class="external-link" rel="nofollow">Sources</a></li>
<li><a href="/mina-project/gen-docs/latest-2.0/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.0.25</a></li>
<li><a href="/mina-project/gen-docs/latest-2.1/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.1.8</a></li>
<li><a href="/mina-project/gen-docs/latest-2.2/apidocs/index.html" class="external-link" rel="nofollow">API Javadoc 2.2.3</a></li>
<li><a href="/mina-project/gen-docs/latest-2.0/xref/index.html" class="external-link" rel="nofollow">API xref 2.0.25</a></li>
<li><a href="/mina-project/gen-docs/latest-2.1/xref/index.html" class="external-link" rel="nofollow">API xref 2.1.8</a></li>
<li><a href="/mina-project/gen-docs/latest-2.2/xref/index.html" class="external-link" rel="nofollow">API xref 2.2.3</a></li>
<li><a href="/mina-project/performances.html" class="external-link" rel="nofollow">Performances</a></li>
<li><a href="/mina-project/testimonials.html" class="external-link" rel="nofollow">Testimonials</a></li>
<li><a href="/mina-project/conferences.html" class="external-link" rel="nofollow">Conferences</a></li>
<li><a href="/mina-project/developer-guide.html" class="external-link" rel="nofollow">Developers Guide</a></li>
<li><a href="/mina-project/related-projects.html" class="external-link" rel="nofollow">Related Projects</a></li>
<li><a href="https://people.apache.org/~vgritsenko/stats/projects/mina.html" class="external-link" rel="nofollow">Statistics</a></li>
</ul>
<h5>Community</h5>
<ul>
<li><a href="https://www.apache.org/foundation/contributing.html" class="external-link" rel="nofollow">Contributing</a></li>
<li><a href="/contributors.html" class="external-link" rel="nofollow">Team</a></li>
<li><a href="/special-thanks.html" class="external-link" rel="nofollow">Special Thanks</a></li>
<li><a href="https://www.apache.org/security/" class="external-link" rel="nofollow">Security</a></li>
</ul>
<h5>About Apache</h5>
<ul>
<li><a href="https://www.apache.org" class="external-link" rel="nofollow">Apache main site</a></li>
<li><a href="https://www.apache.org/licenses/" class="external-link" rel="nofollow">License</a></li>
<li><a href="https://www.apache.org/foundation/sponsorship.html" title="The ASF sponsorship program" class="external-link" rel="nofollow">Sponsorship program</a></li>
<li><a href="https://www.apache.org/foundation/thanks.html" class="external-link" rel="nofollow">Thanks</a></li>
</ul>
<h3><a name="Navigation-Upcoming"></a>Upcoming</h3>
<ul>
<li>No event</li>
</ul>
</div>
</div>
<div id="rightColumn">
<div class="nav">
<div class="nav_prev">
<a href="../ch3-service/ch3-service.html">Chapter 3 - Service</a>
</div>
<div class="nav_up">
<a href="../user-guide-toc.html">User Guide</a>
</div>
<div class="nav_next">
<a href="../ch5-filters/ch5-filters.html">Chapter 5 - Filters</a>
</div>
<div class="clearfix"></div>
</div>
<h1 id="chapter-4---session">Chapter 4 - Session</h1>
<ul>
<li><a href="ch4.1-session-configuration.html">4.1 - Session Configuration</a></li>
<li><a href="ch4.2-session-statistics.html">4.2 - Session Statistics</a></li>
</ul>
<h2 id="introduction">Introduction</h2>
<p>The Session is at the heart of MINA : every time a client connects to the server, a new session is created on the server, and will be kept in memory until the client is disconnected. If you are using MINA on the client side, every time you connect to a server, a session will be created on the client too.</p>
<p>A session is used to store persistent information about the connection, plus any kind of information the client or the server might need to use during the request processing, and eventually during the whole session life.</p>
<p>This is also your access point for any operation you need to do on a session : sending messages, closing the session, etc&hellip;</p>
<div class="note" markdown="1">
It is critical to understand that due to the asynchrnous very nature of NIO, reading from a session does not make a lot of sense. Actually, your application get signalled whe some incoming message has arrived, and this is the IoHandler which is responsible for handling such event.
<p>In other words, don&rsquo;t call session.read(). Never.</p>
</div>
<h2 id="session-state">Session state</h2>
<p>A session has a state, which will evolve during time.</p>
<ul>
<li>Created : the session has just been created</li>
<li>Connected : the session has been created and is available</li>
<li>Idle : the session hasn&rsquo;t processed any request for at least a period of time (this period is configurable)
<ul>
<li>Idle for read : no read has actually been made for a period of time</li>
<li>Idle for write : no write has actually been made for a period of time</li>
<li>Idle for both : no read nor write for a period of time</li>
</ul>
</li>
<li>Secured : the TLS layer has been initialised</li>
<li>Unsecured : The TLS layer has been shut down</li>
<li>Closing : the session is being closed (the remaining messages are being flushed, cleaning up is not terminated)</li>
<li>Input closed : the input part of the socket has been closed</li>
<li>Closed : The session is now closed, nothing else can be done to revive it. This is actually not a real state : when teh session is closed, it&rsquo;s removed.</li>
</ul>
<p>The following state diagram exposes all the possible states and transitions :</p>
<p><img src="/assets/img/mina/session-state.png" alt=""></p>
<p>We have a set of methods to get some information about the session status.</p>
<p>Session status :</p>
<ul>
<li>isActive() : tells if the session is valid (it might mean different things depending on the implementation)</li>
<li>isBothIdle() : tells if the session is idling on reads and writes</li>
<li>isClosing() : tells if the session is already being closed</li>
<li>isConnected() : tells if the session is active (ie, not in the closing mode)</li>
<li>isIdle( idling status ) : tells if the session is idling on a specific state (read or write)</li>
<li>isReadIdle() : tells if the session is idling on reads</li>
<li>isReadSuspended() : tells if the session is not allowed to read messsages</li>
<li>isScheduledForFlush() : tells if the session has pending messages that are to be written</li>
<li>isSecured() : tells if teh TLS layer is active and initialized</li>
<li>isServer() : tells if the session is on the server side</li>
<li>isWriteIdle() : tells if the session is idling on writes</li>
<li>isWriteSuspended() : tells if the session is not allowed to write messsages</li>
</ul>
<h2 id="opening-a-session">Opening a session</h2>
<p>Actually, there is nothing you have to do : it&rsquo;s automatic ! Every time a remote peer connect to a server, the server will create a new connection. On the client side, every time you connect to a server, a session will be created.</p>
<p>This session is passed as an argument to your handler, so that you can do something with it in your application. On the client side, when you do connect to a server, you can get back the created session this way :</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
ConnectFuture connectionFuture <span style="color:#666">=</span> connector<span style="color:#666">.</span><span style="color:#b44">connect</span><span style="color:#666">(</span>address<span style="color:#666">)</span><span style="color:#666">;</span>
connectionFuture<span style="color:#666">.</span><span style="color:#b44">awaitUninterruptibly</span><span style="color:#666">(</span><span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#a2f;font-weight:bold">if</span> <span style="color:#666">(</span><span style="color:#666">!</span>connectionFuture<span style="color:#666">.</span><span style="color:#b44">isConnected</span><span style="color:#666">(</span><span style="color:#666">)</span><span style="color:#666">)</span> <span style="color:#666">{</span>
<span style="color:#a2f;font-weight:bold">return</span> <span style="color:#a2f;font-weight:bold">false</span><span style="color:#666">;</span>
<span style="color:#666">}</span>
session <span style="color:#666">=</span> connectionFuture<span style="color:#666">.</span><span style="color:#b44">getSession</span><span style="color:#666">(</span><span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
</code></pre></div><p>You can also do it in a shortest way :</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
session <span style="color:#666">=</span> connector<span style="color:#666">.</span><span style="color:#b44">connect</span><span style="color:#666">(</span>address<span style="color:#666">)</span><span style="color:#666">.</span><span style="color:#b44">getSession</span><span style="color:#666">(</span><span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
</code></pre></div><h2 id="initialization">Initialization</h2>
<p>When a new session is created, it has to be initialized. This is done using the default IoService configuration, but you can update this configuration later on. Actually, when the session is created, we internally create a copy of the default IoService configuration that is stored within the session, and this is this configuration instance that will be used (and that can be modified).</p>
<p>This initialization will also starts the statistics counters, create the Attributes container, associate a write queue to to the session (this is where the messages will be enqueued until they have been sent), and ultimately, would you have provided a specific task to do during this phase, it will call it.</p>
<h2 id="closing-a-session">Closing a session</h2>
<p>A session can be closed in 4 ways, two of which are explicit :</p>
<ul>
<li>calling the <em>closeNow()</em> method (explicit)</li>
<li>calling the <em>closeOnFlush()</em> method (explicit)</li>
<li>when the remote peer has nicely closed the connection</li>
<li>if an exception occurs</li>
</ul>
<p>(note there are two deprecated methods that should not anymore be used : <em>close(boolean)</em> and <em>close()</em>)</p>
<h3 id="explicit-closure">Explicit closure</h3>
<p>The first two methods can be called anywhere in your application, the big difference is one (<em>closeNow()</em>) will simply close the session, discarding any message waiting to be transmitted to the peer, while the <em>closeOnFlush()</em> will wait until any pending message has been transmitted to the peer.</p>
<div class="note" markdown="1">
Be aware that if the remote peer is not anymore connected, the session that you are closing using a _closeOnFlush()_ call will never be destroyed, unless you also handle its idleness, or before the system TCP timeout has closed the socket - which might take hours -. Always manage idleness in your applications.
</div>
<h3 id="remote-peer-closing">Remote peer closing</h3>
<p>When the remote peer closes the session properly, the session will be closed, and all the pending messages will be discarded. This is usually the way it works.</p>
<p>However, sometime, the remote peer does not properly close the connection (this could happen when the cable is brutally unplugged). In this case, the session never get informed about the disconnection. The only way to know about it is to regularly check for the session state : if it&rsquo;s idle for more than a specific amount of time - it has to be configured -, then the application can decide to close the session. Otherwise, the session will be closed eventually when the TCP timeout will be reached (it can take hours&hellip;).</p>
<h3 id="exception">Exception</h3>
<p>In some case, an exception will occur that will cause the session to be closed. Typically, when a session is being created, we may face an issue, and the session will be immediately closed. One other possibility is that we can&rsquo;t write some message, for instance because the channel has been closed : we then close the session.</p>
<p>All in all, every time we met an exception while processing a session, this session will be closed.</p>
<p>Of course, your application will be informed through the <em>ExceptionCaught</em> event.</p>
<h2 id="configuration">Configuration</h2>
<p>Many different parameters can be set for a specific session :</p>
<ul>
<li>receive buffer size</li>
<li>sending buffer size</li>
<li>Idle time</li>
<li>Write timeOut</li>
<li>&hellip;</li>
</ul>
<p>plus other configuration, depending on the transport type used (see Chapter 6 - Transports).</p>
<p>All those configuration parameters are stored into the <em>IoSessionConfig</em> object, which can be get from the session using the <em>session.getConfig()</em> method.</p>
<p>For further information about the session configuration, see <a href="ch4.1-session-configuration.html">Chapter 4.1 - Session Configuration</a></p>
<h2 id="managing-user-defined-attributes">Managing user-defined attributes</h2>
<p>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 permanent along the session&rsquo;s life.</p>
<p>For instance, if you want to track the number of request a user has sent since the session has been created, it&rsquo;s easy to store it into this map: just create a key that will be associated with this value.</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
<span style="color:#0b0;font-weight:bold">int</span> counterValue <span style="color:#666">=</span> session<span style="color:#666">.</span><span style="color:#b44">getAttribute</span><span style="color:#666">(</span> <span style="color:#b44">&#34;counter&#34;</span> <span style="color:#666">)</span><span style="color:#666">;</span>
session<span style="color:#666">.</span><span style="color:#b44">setAttribute</span><span style="color:#666">(</span> <span style="color:#b44">&#34;counter&#34;</span><span style="color:#666">,</span> counterValue <span style="color:#666">+</span> 1 <span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
</code></pre></div><p>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&rsquo;s container.</p>
<p>This container is created automatically when the session is created, and will be disposed when the session is terminated.</p>
<h3 id="the-session-container">The session container</h3>
<p>As we said, this container is a key/value container, which default to a Map, but it&rsquo;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.</p>
<p>This snippet of code shows how the container is created during the session initialization :</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"> <span style="color:#a2f;font-weight:bold">protected</span> <span style="color:#a2f;font-weight:bold">final</span> <span style="color:#0b0;font-weight:bold">void</span> <span style="color:#00a000">initSession</span><span style="color:#666">(</span>IoSession session<span style="color:#666">,</span>
IoFuture future<span style="color:#666">,</span> IoSessionInitializer sessionInitializer<span style="color:#666">)</span> <span style="color:#666">{</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
<span style="color:#a2f;font-weight:bold">try</span> <span style="color:#666">{</span>
<span style="color:#666">(</span><span style="color:#666">(</span>AbstractIoSession<span style="color:#666">)</span> session<span style="color:#666">)</span><span style="color:#666">.</span><span style="color:#b44">setAttributeMap</span><span style="color:#666">(</span>session<span style="color:#666">.</span><span style="color:#b44">getService</span><span style="color:#666">(</span><span style="color:#666">)</span>
<span style="color:#666">.</span><span style="color:#b44">getSessionDataStructureFactory</span><span style="color:#666">(</span><span style="color:#666">)</span><span style="color:#666">.</span><span style="color:#b44">getAttributeMap</span><span style="color:#666">(</span>session<span style="color:#666">)</span><span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">}</span> <span style="color:#a2f;font-weight:bold">catch</span> <span style="color:#666">(</span>IoSessionInitializationException e<span style="color:#666">)</span> <span style="color:#666">{</span>
<span style="color:#a2f;font-weight:bold">throw</span> e<span style="color:#666">;</span>
<span style="color:#666">}</span> <span style="color:#a2f;font-weight:bold">catch</span> <span style="color:#666">(</span>Exception e<span style="color:#666">)</span> <span style="color:#666">{</span>
<span style="color:#a2f;font-weight:bold">throw</span> <span style="color:#a2f;font-weight:bold">new</span> IoSessionInitializationException<span style="color:#666">(</span>
<span style="color:#b44">&#34;Failed to initialize an attributeMap.&#34;</span><span style="color:#666">,</span> e<span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">}</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
</code></pre></div><p>and here is the factory interface we can implement if we want to define another kind of container :</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#a2f;font-weight:bold">public</span> <span style="color:#a2f;font-weight:bold">interface</span> <span style="color:#00f">IoSessionDataStructureFactory</span> <span style="color:#666">{</span>
<span style="color:#080;font-style:italic">/**
</span><span style="color:#080;font-style:italic"> * Returns an {@link IoSessionAttributeMap} which is going to be associated
</span><span style="color:#080;font-style:italic"> * with the specified &lt;tt&gt;session&lt;/tt&gt;. Please note that the returned
</span><span style="color:#080;font-style:italic"> * implementation must be thread-safe.
</span><span style="color:#080;font-style:italic"> */</span>
IoSessionAttributeMap <span style="color:#00a000">getAttributeMap</span><span style="color:#666">(</span>IoSession session<span style="color:#666">)</span> <span style="color:#a2f;font-weight:bold">throws</span> Exception<span style="color:#666">;</span>
<span style="color:#666">}</span>
</code></pre></div><h3 id="the-session-attributes-access">The session attributes access</h3>
<p>There are many methods available to manipulate the session&rsquo;s attributes :</p>
<ul>
<li>boolean containsAttribute(Object key) : tells if a given attribute is present</li>
<li>Object getAttribute(Object key) : gets the value for a given attribute</li>
<li>Object getAttribute(Object key, Object defaultValue) : gets the value for a given attribute, or a default value if absent</li>
<li>Set&lt;Object&gt; getAttributeKeys() : gets the set of all the stored attributes</li>
<li>Object removeAttribute(Object key) : remove a given attribute</li>
<li>boolean removeAttribute(Object key, Object value) : remove a given attribute/value pair</li>
<li>boolean replaceAttribute(Object key, Object oldValue, Object newValue) : replace a give attribute/value pair</li>
<li>Object setAttribute(Object key) : adds a new attribute with no value</li>
<li>Object setAttribute(Object key, Object value) : adds a new attribute/value pair</li>
<li>Object setAttributeIfAbsent(Object key) : adds a new attribute with no value, if it does not already exist</li>
<li>Object setAttributeIfAbsent(Object key, Object value) : adds a new attribute/value pair, if it does not already exist</li>
</ul>
<p>All those methods allows your application to store, remove, get or update the attributes stored into your session. Also note that some attributes are used internally by MINA : don&rsquo;t lightly modify those you didn&rsquo;t create !</p>
<h2 id="filter-chain">Filter chain</h2>
<p>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.</p>
<p>However, it&rsquo;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.</p>
<h2 id="statistics">Statistics</h2>
<p>Each session also keep a track of records about what has been done for the session :</p>
<ul>
<li>number of bytes received/sent</li>
<li>number of messages received/sent</li>
<li>Idle status</li>
<li>throughput</li>
</ul>
<p>and many other useful information.</p>
<p>For further information about the session statistics, see <a href="ch4.2-session-statistics.html">Chapter 4.2 - Session Statistics</a></p>
<h2 id="handler">Handler</h2>
<p>Last, not least, a session is attached to a Handler, in charge of dispatching the messages to your application. This handler will also send back response by using the session, simply by calling the write() method :</p>
<div class="highlight"><pre style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-java" data-lang="java"><span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
session<span style="color:#666">.</span><span style="color:#b44">write</span><span style="color:#666">(</span> <span style="color:#666">&lt;</span>your message<span style="color:#666">&gt;</span> <span style="color:#666">)</span><span style="color:#666">;</span>
<span style="color:#666">.</span><span style="color:#666">.</span><span style="color:#666">.</span>
</code></pre></div>
<div class="nav">
<div class="nav_prev">
<a href="../ch3-service/ch3-service.html">Chapter 3 - Service</a>
</div>
<div class="nav_up">
<a href="../user-guide-toc.html">User Guide</a>
</div>
<div class="nav_next">
<a href="../ch5-filters/ch5-filters.html">Chapter 5 - Filters</a>
</div>
<div class="clearfix"></div>
</div>
</div>
<div id="endContent"></div>
</div>
<div id="footer">
&copy; 2003-2024, <a href="https://www.apache.org">The Apache Software Foundation</a> - <a href="https://privacy.apache.org/policies/privacy-policy-public.html">Privacy Policy</a><br />
Apache MINA, MINA, Apache Vysper, Vysper, Apache SSHd, SSHd, Apache FtpServer, FtpServer, Apache AsyncWeb, AsyncWeb,
Apache, the Apache feather logo, and the Apache Mina project logos are trademarks of The Apache Software Foundation.
</div>
</div>
</body>
</html>