*
* @see java.lang.Thread#run()
*/
public void run()
{
Timer timer = null;
this._readpool = ThreadPoolFactory.createFixedThreadPool( this._serverInfo.getMaxReadProcessors(),
this._readGroup );
// create a global ThreadPool for network write operations
this._writePool = ThreadPoolFactory.createFixedThreadPool( this._serverInfo.getMaxWriteProcessors(),
this._writeGroup );
// shall we monitor the ThreadPools and resize them
// according to server load (this will also recreate died worker
// threads)
if ( this._serverInfo.isAutomaticThreadPoolResize() )
{
timer = new Timer();
// schedule a monitor task for the read-process-thread-pool
timer.schedule( new ThreadPoolResizer( this._readpool, this._serverInfo.getMaxReadProcessors(),
EJConstants.EJOE_POOL_RESIZER_SHRINKWAIT ), this._serverInfo
.getPoolResizePeriod(), this._serverInfo.getPoolResizePeriod() );
// schedule a monitor task for the writer-thread-pool
timer.schedule( new ThreadPoolResizer( this._writePool, this._serverInfo.getMaxWriteProcessors(),
EJConstants.EJOE_POOL_RESIZER_SHRINKWAIT ), this._serverInfo
.getPoolResizePeriod(), this._serverInfo.getPoolResizePeriod() );
}
try
{
Iterator it;
SocketChannel cChannel;
SelectionKey selKey;
ConnectionHeader clientInfo;
Set keys;
while ( !isInterrupted() )
{
this._load = 0;
// (pre)register interested socket channels
registerAspirants();
// just try endless new selects until there are interested
// socket channels
if ( _selector.select() == 0 ) continue;
keys = this._selector.selectedKeys();
this._load = keys.size();
it = this._selector.selectedKeys().iterator();
// loop over all selected channels, just take care of thread
// interruption
while ( it.hasNext() && !isInterrupted() )
{
selKey = (SelectionKey) it.next();
// remove the SelectionKey from the Iterator otherwise it
// will be lost
it.remove();
try
{
// validate the key
if ( !selKey.isValid() ) continue;
// at least our ConnectionAcceptor has created a client
// ConnectionHeader
clientInfo = (ConnectionHeader) selKey.attachment();
// first check read-availbility
if ( selKey.isReadable() )
{
// get the underlying socket channel
cChannel = (SocketChannel) selKey.channel();
// cancel the channels registration with our
// Selector
selKey.cancel();
// little bit paranoia
if ( cChannel != null && cChannel.isOpen() )
{
// don't we support NIO?
if ( !this._serverInfo.hasNonBlockingReadWrite() )
{
logger.log( Level.FINEST,
"Setting socket to blocking mode for further io operations..." );
// prepare the channel for upcoming blocking
// network operations
cChannel.configureBlocking( true );
}
// schedule a asynchronious read-process operation
this._readpool.invokeLater( new ConnectionReader( this, this._serverInfo, clientInfo ) );
}
}
else if ( selKey.isWritable() )
{
// get the underlying socket channel
cChannel = (SocketChannel) selKey.channel();
// cancel the channels registration with our
// Selector
selKey.cancel();
// little bit paranoia
if ( cChannel != null && cChannel.isOpen() )
{
// don't we support NIO?
if ( !this._serverInfo.hasNonBlockingReadWrite() )
{
if ( !clientInfo.hasAttachment() ) continue;
// prepare the channel for upcoming blocking
// network operations
cChannel.configureBlocking( true );
}
// schedule a asynchronious socket-write
// operation
this._writePool
.invokeLater( new ConnectionWriter( this, this._serverInfo, clientInfo ) );
}
}
}
catch ( CancelledKeyException cke )
{
logger.log( Level.WARNING, "Key cancelled!", cke );
}
finally
{
this._load--;
}
}
}
}
catch ( IOException e )
{
logger.log( Level.SEVERE, "!!! IOException occured !!! ", e );
throw new RuntimeException( e );
}
finally
{
// kill our ThreadPool monitors if existent
if ( timer != null ) timer.cancel();
try
{
// shutdown the Read-Process-ThreadPool if existent
if ( this._readpool != null )