org.eclipse.jetty.server.nio.BlockingChannelConnector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
//
// ========================================================================
// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ByteChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.ChannelEndPoint;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ConcurrentHashSet;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------------------------- */
/** Blocking NIO connector.
* This connector uses efficient NIO buffers with a traditional blocking thread model.
* Direct NIO buffers are used and a thread is allocated per connections.
*
* This connector is best used when there are a few very active connections.
*
* @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
*
*
*
*/
public class BlockingChannelConnector extends AbstractNIOConnector
{
private static final Logger LOG = Log.getLogger(BlockingChannelConnector.class);
private transient ServerSocketChannel _acceptChannel;
private final Set _endpoints = new ConcurrentHashSet();
/* ------------------------------------------------------------ */
/** Constructor.
*
*/
public BlockingChannelConnector()
{
}
/* ------------------------------------------------------------ */
public Object getConnection()
{
return _acceptChannel;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.AbstractConnector#doStart()
*/
@Override
protected void doStart() throws Exception
{
super.doStart();
getThreadPool().dispatch(new Runnable()
{
public void run()
{
while (isRunning())
{
try
{
Thread.sleep(400);
long now=System.currentTimeMillis();
for (BlockingChannelEndPoint endp : _endpoints)
{
endp.checkIdleTimestamp(now);
}
}
catch(InterruptedException e)
{
LOG.ignore(e);
}
catch(Exception e)
{
LOG.warn(e);
}
}
}
});
}
/* ------------------------------------------------------------ */
public void open() throws IOException
{
// Create a new server socket and set to non blocking mode
_acceptChannel= ServerSocketChannel.open();
_acceptChannel.configureBlocking(true);
// Bind the server socket to the local host and port
InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
_acceptChannel.socket().bind(addr,getAcceptQueueSize());
}
/* ------------------------------------------------------------ */
public void close() throws IOException
{
if (_acceptChannel != null)
_acceptChannel.close();
_acceptChannel=null;
}
/* ------------------------------------------------------------ */
@Override
public void accept(int acceptorID)
throws IOException, InterruptedException
{
SocketChannel channel = _acceptChannel.accept();
channel.configureBlocking(true);
Socket socket=channel.socket();
configure(socket);
BlockingChannelEndPoint connection=new BlockingChannelEndPoint(channel);
connection.dispatch();
}
/* ------------------------------------------------------------------------------- */
@Override
public void customize(EndPoint endpoint, Request request)
throws IOException
{
super.customize(endpoint, request);
endpoint.setMaxIdleTime(_maxIdleTime);
configure(((SocketChannel)endpoint.getTransport()).socket());
}
/* ------------------------------------------------------------------------------- */
public int getLocalPort()
{
if (_acceptChannel==null || !_acceptChannel.isOpen())
return -1;
return _acceptChannel.socket().getLocalPort();
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
private class BlockingChannelEndPoint extends ChannelEndPoint implements Runnable, ConnectedEndPoint
{
private Connection _connection;
private int _timeout;
private volatile long _idleTimestamp;
BlockingChannelEndPoint(ByteChannel channel)
throws IOException
{
super(channel,BlockingChannelConnector.this._maxIdleTime);
_connection = new BlockingHttpConnection(BlockingChannelConnector.this,this,getServer());
}
/* ------------------------------------------------------------ */
/** Get the connection.
* @return the connection
*/
public Connection getConnection()
{
return _connection;
}
/* ------------------------------------------------------------ */
public void setConnection(Connection connection)
{
_connection=connection;
}
/* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now)
{
if (_idleTimestamp!=0 && _timeout>0 && now>(_idleTimestamp+_timeout))
{
idleExpired();
}
}
/* ------------------------------------------------------------ */
protected void idleExpired()
{
try
{
super.close();
}
catch (IOException e)
{
LOG.ignore(e);
}
}
/* ------------------------------------------------------------ */
void dispatch() throws IOException
{
if (!getThreadPool().dispatch(this))
{
LOG.warn("dispatch failed for {}",_connection);
super.close();
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#fill(org.eclipse.jetty.io.Buffer)
*/
@Override
public int fill(Buffer buffer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.fill(buffer);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.Buffer)
*/
@Override
public int flush(Buffer buffer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.flush(buffer);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.io.nio.ChannelEndPoint#flush(org.eclipse.jetty.io.Buffer, org.eclipse.jetty.io.Buffer, org.eclipse.jetty.io.Buffer)
*/
@Override
public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
{
_idleTimestamp=System.currentTimeMillis();
return super.flush(header,buffer,trailer);
}
/* ------------------------------------------------------------ */
public void run()
{
try
{
_timeout=getMaxIdleTime();
connectionOpened(_connection);
_endpoints.add(this);
while (isOpen())
{
_idleTimestamp=System.currentTimeMillis();
if (_connection.isIdle())
{
if (getServer().getThreadPool().isLowOnThreads())
{
int lrmit = getLowResourcesMaxIdleTime();
if (lrmit>=0 && _timeout!= lrmit)
{
_timeout=lrmit;
}
}
}
else
{
if (_timeout!=getMaxIdleTime())
{
_timeout=getMaxIdleTime();
}
}
_connection = _connection.handle();
}
}
catch (EofException e)
{
LOG.debug("EOF", e);
try{BlockingChannelEndPoint.this.close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch (HttpException e)
{
LOG.debug("BAD", e);
try{super.close();}
catch(IOException e2){LOG.ignore(e2);}
}
catch(Throwable e)
{
LOG.warn("handle failed",e);
try{super.close();}
catch(IOException e2){LOG.ignore(e2);}
}
finally
{
connectionClosed(_connection);
_endpoints.remove(this);
// wait for client to close, but if not, close ourselves.
try
{
if (!_socket.isClosed())
{
long timestamp=System.currentTimeMillis();
int max_idle=getMaxIdleTime();
_socket.setSoTimeout(getMaxIdleTime());
int c=0;
do
{
c = _socket.getInputStream().read();
}
while (c>=0 && (System.currentTimeMillis()-timestamp)r(%s),open=%b,ishut=%b,oshut=%b}-{%s}",
hashCode(),
_socket.getRemoteSocketAddress(),
_socket.getLocalSocketAddress(),
isOpen(),
isInputShutdown(),
isOutputShutdown(),
_connection);
}
}
}