view src/org/eclipse/jetty/server/nio/SelectChannelConnector.java @ 934:fe461f7cfc8e

simplify AsyncContinuation
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 09 Oct 2016 21:03:00 -0600
parents 54308d65265a
children 0541b6034003
line wrap: on
line source

//
//  ========================================================================
//  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.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.AsyncConnection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
import org.eclipse.jetty.server.AsyncHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;

/* ------------------------------------------------------------------------------- */
/**
 * Selecting NIO connector.
 * <p>
 * This connector uses efficient NIO buffers with a non blocking threading model. Direct NIO buffers
 * are used and threads are only allocated to connections with requests. Synchronization is used to
 * simulate blocking for the servlet API, and any unflushed content at the end of request handling
 * is written asynchronously.
 * </p>
 * <p>
 * This connector is best used when there are a many connections that have idle periods.
 * </p>
 * <p>
 * When used with {@link org.eclipse.jetty.continuation.Continuation}, threadless waits are supported.
 * If a filter or servlet returns after calling {@link Continuation#suspend()} or when a
 * runtime exception is thrown from a call to {@link Continuation#undispatch()}, Jetty will
 * will not send a response to the client. Instead the thread is released and the Continuation is
 * placed on the timer queue. If the Continuation timeout expires, or it's
 * resume method is called, then the request is again allocated a thread and the request is retried.
 * The limitation of this approach is that request content is not available on the retried request,
 * thus if possible it should be read after the continuation or saved as a request attribute or as the
 * associated object of the Continuation instance.
 * </p>
 *
 * @org.apache.xbean.XBean element="nioConnector" description="Creates an NIO based socket connector"
 */
public class SelectChannelConnector extends Connector
{
	private final SelectorManager _manager = new ConnectorSelectorManager();

	public SelectChannelConnector(Server server,int port)
	{
		super(server,port);
		_manager.setMaxIdleTime(getMaxIdleTime());
		addBean(_manager,true);
		setAcceptors(Math.max(1,(Runtime.getRuntime().availableProcessors()+3)/4));
	}
	
	@Override
	public final void accept() throws IOException
	{
		ServerSocketChannel server = _acceptChannel;

		if (server!=null && server.isOpen() && _manager.isStarted())
		{
			SocketChannel channel = server.accept();
			channel.configureBlocking(false);
			Socket socket = channel.socket();
			configure(socket);
			_manager.register(channel);
		}
	}

	@Override
	public void customize(EndPoint endpoint, Request request) throws IOException
	{
		request.setTimeStamp(System.currentTimeMillis());
		endpoint.setMaxIdleTime(_maxIdleTime);
		super.customize(endpoint, request);
	}

	@Override
	public void persist(EndPoint endpoint) throws IOException
	{
		AsyncEndPoint aEndp = ((AsyncEndPoint)endpoint);
		aEndp.setCheckForIdle(true);
		super.persist(endpoint);
	}

	@Override
	protected synchronized void doStart() throws Exception
	{
		_manager.setSelectSets(getAcceptors());
		_manager.setMaxIdleTime(getMaxIdleTime());
		_manager.setLowResourcesConnections(0);

		if (_acceptChannel == null)
		{
			// Create a new server socket
			_acceptChannel = ServerSocketChannel.open();
			// Set to blocking mode
			_acceptChannel.configureBlocking(true);

			// Bind the server socket to the local host and port
			_acceptChannel.socket().setReuseAddress(true);
			InetSocketAddress addr = getHost()==null?new InetSocketAddress(port):new InetSocketAddress(getHost(),port);
			_acceptChannel.bind(addr);
			if( _acceptChannel.socket().getLocalPort() != port)
				throw new IOException("Server channel not bound");
		}

		super.doStart();
	}

	protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
	{
		SelectChannelEndPoint endp= new SelectChannelEndPoint(channel,selectSet,key, SelectChannelConnector.this._maxIdleTime);
		endp.setConnection(selectSet.getManager().newConnection(channel,endp, key.attachment()));
		return endp;
	}

	protected void endPointClosed(SelectChannelEndPoint endpoint)
	{
		endpoint.getConnection().onClose();
	}

	protected AsyncConnection newConnection(SocketChannel channel,final AsyncEndPoint endpoint)
	{
		return new AsyncHttpConnection(SelectChannelConnector.this,endpoint,server);
	}


	private final class ConnectorSelectorManager extends SelectorManager
	{
		@Override
		public void execute(Runnable task)
		{
			server.threadPool.execute(task);
		}

		@Override
		protected void endPointClosed(final SelectChannelEndPoint endpoint)
		{
			SelectChannelConnector.this.endPointClosed(endpoint);
		}

		@Override
		public AsyncConnection newConnection(SocketChannel channel,AsyncEndPoint endpoint, Object attachment)
		{
			return SelectChannelConnector.this.newConnection(channel,endpoint);
		}

		@Override
		protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey sKey) throws IOException
		{
			return SelectChannelConnector.this.newEndPoint(channel,selectSet,sKey);
		}
	}
}