View Javadoc

1   // ========================================================================
2   // Copyright (c) 2003-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13   
14  package org.eclipse.jetty.server.nio;
15  
16  import java.io.IOException;
17  import java.net.InetSocketAddress;
18  import java.net.Socket;
19  import java.nio.channels.ByteChannel;
20  import java.nio.channels.ServerSocketChannel;
21  import java.nio.channels.SocketChannel;
22  
23  import org.eclipse.jetty.http.HttpException;
24  import org.eclipse.jetty.io.EndPoint;
25  import org.eclipse.jetty.io.EofException;
26  import org.eclipse.jetty.io.nio.ChannelEndPoint;
27  import org.eclipse.jetty.server.HttpConnection;
28  import org.eclipse.jetty.server.Request;
29  import org.eclipse.jetty.util.log.Log;
30  
31  
32  /* ------------------------------------------------------------------------------- */
33  /**  Blocking NIO connector.
34   * This connector uses efficient NIO buffers with a traditional blocking thread model.
35   * Direct NIO buffers are used and a thread is allocated per connections.
36   * 
37   * This connector is best used when there are a few very active connections.
38   * 
39   * @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
40   * 
41   * 
42   *
43   */
44  public class BlockingChannelConnector extends AbstractNIOConnector 
45  {
46      private transient ServerSocketChannel _acceptChannel;
47      
48      /* ------------------------------------------------------------ */
49      /** Constructor.
50       * 
51       */
52      public BlockingChannelConnector()
53      {
54      }
55  
56      /* ------------------------------------------------------------ */
57      public Object getConnection()
58      {
59          return _acceptChannel;
60      }
61      
62      /* ------------------------------------------------------------ */
63      public void open() throws IOException
64      {
65          // Create a new server socket and set to non blocking mode
66          _acceptChannel= ServerSocketChannel.open();
67          _acceptChannel.configureBlocking(true);
68  
69          // Bind the server socket to the local host and port
70          InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
71          _acceptChannel.socket().bind(addr,getAcceptQueueSize());
72      }
73  
74      /* ------------------------------------------------------------ */
75      public void close() throws IOException
76      {
77          if (_acceptChannel != null)
78              _acceptChannel.close();
79          _acceptChannel=null;
80      }
81      
82      /* ------------------------------------------------------------ */
83      public void accept(int acceptorID)
84      	throws IOException, InterruptedException
85      {   
86          SocketChannel channel = _acceptChannel.accept();
87          channel.configureBlocking(true);
88          Socket socket=channel.socket();
89          configure(socket);
90  
91          Connection connection=new Connection(channel);
92          connection.dispatch();
93      }
94      
95      /* ------------------------------------------------------------------------------- */
96      public void customize(EndPoint endpoint, Request request)
97          throws IOException
98      {
99          Connection connection = (Connection)endpoint;
100         if (connection._sotimeout!=_maxIdleTime)
101         {
102             connection._sotimeout=_maxIdleTime;
103             ((SocketChannel)endpoint.getTransport()).socket().setSoTimeout(_maxIdleTime);
104         }
105               
106         super.customize(endpoint, request);
107         configure(((SocketChannel)endpoint.getTransport()).socket());
108     }
109 
110 
111     /* ------------------------------------------------------------------------------- */
112     public int getLocalPort()
113     {
114         if (_acceptChannel==null || !_acceptChannel.isOpen())
115             return -1;
116         return _acceptChannel.socket().getLocalPort();
117     }
118     
119     /* ------------------------------------------------------------------------------- */
120     /* ------------------------------------------------------------------------------- */
121     /* ------------------------------------------------------------------------------- */
122     private class Connection extends ChannelEndPoint implements Runnable
123     {
124         final HttpConnection _connection;
125         boolean _dispatched=false;
126         int _sotimeout;
127         
128         Connection(ByteChannel channel) 
129         {
130             super(channel);
131             _connection = new HttpConnection(BlockingChannelConnector.this,this,getServer());
132         }
133         
134         void dispatch() throws IOException
135         {
136             if (!getThreadPool().dispatch(this))
137             {
138                 Log.warn("dispatch failed for  {}",_connection);
139                 Connection.this.close();
140             }
141         }
142         
143         public void run()
144         {
145             try
146             {
147                 connectionOpened(_connection);
148                 
149                 while (isOpen())
150                 {
151                     if (_connection.isIdle())
152                     {
153                         if (getServer().getThreadPool().isLowOnThreads())
154                         {
155                             int lrmit = getLowResourceMaxIdleTime();
156                             if (lrmit>=0 && _sotimeout!= lrmit)
157                             {
158                                 _sotimeout=lrmit;
159                                 ((SocketChannel)getTransport()).socket().setSoTimeout(_sotimeout);
160                             }
161                         }
162                     }
163                     _connection.handle();
164                 }
165             }
166             catch (EofException e)
167             {
168                 Log.debug("EOF", e);
169                 try{Connection.this.close();}
170                 catch(IOException e2){Log.ignore(e2);}
171             }
172             catch (HttpException e)
173             {
174                 Log.debug("BAD", e);
175                 try{Connection.this.close();}
176                 catch(IOException e2){Log.ignore(e2);}
177             }
178             catch(Throwable e)
179             {
180                 Log.warn("handle failed",e);
181                 try{Connection.this.close();}
182                 catch(IOException e2){Log.ignore(e2);}
183             }
184             finally
185             {
186                 connectionClosed(_connection);
187             }
188         }
189     }
190 }