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.ConnectedEndPoint;
25  import org.eclipse.jetty.io.Connection;
26  import org.eclipse.jetty.io.EndPoint;
27  import org.eclipse.jetty.io.EofException;
28  import org.eclipse.jetty.io.nio.ChannelEndPoint;
29  import org.eclipse.jetty.server.HttpConnection;
30  import org.eclipse.jetty.server.Request;
31  import org.eclipse.jetty.util.log.Log;
32  
33  
34  /* ------------------------------------------------------------------------------- */
35  /**  Blocking NIO connector.
36   * This connector uses efficient NIO buffers with a traditional blocking thread model.
37   * Direct NIO buffers are used and a thread is allocated per connections.
38   * 
39   * This connector is best used when there are a few very active connections.
40   * 
41   * @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
42   * 
43   * 
44   *
45   */
46  public class BlockingChannelConnector extends AbstractNIOConnector 
47  {
48      private transient ServerSocketChannel _acceptChannel;
49      
50      /* ------------------------------------------------------------ */
51      /** Constructor.
52       * 
53       */
54      public BlockingChannelConnector()
55      {
56      }
57  
58      /* ------------------------------------------------------------ */
59      public Object getConnection()
60      {
61          return _acceptChannel;
62      }
63      
64      /* ------------------------------------------------------------ */
65      public void open() throws IOException
66      {
67          // Create a new server socket and set to non blocking mode
68          _acceptChannel= ServerSocketChannel.open();
69          _acceptChannel.configureBlocking(true);
70  
71          // Bind the server socket to the local host and port
72          InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
73          _acceptChannel.socket().bind(addr,getAcceptQueueSize());
74      }
75  
76      /* ------------------------------------------------------------ */
77      public void close() throws IOException
78      {
79          if (_acceptChannel != null)
80              _acceptChannel.close();
81          _acceptChannel=null;
82      }
83      
84      /* ------------------------------------------------------------ */
85      @Override
86      public void accept(int acceptorID)
87      	throws IOException, InterruptedException
88      {   
89          SocketChannel channel = _acceptChannel.accept();
90          channel.configureBlocking(true);
91          Socket socket=channel.socket();
92          configure(socket);
93  
94          ConnectorEndPoint connection=new ConnectorEndPoint(channel);
95          connection.dispatch();
96      }
97      
98      /* ------------------------------------------------------------------------------- */
99      @Override
100     public void customize(EndPoint endpoint, Request request)
101         throws IOException
102     {
103         super.customize(endpoint, request);
104         endpoint.setMaxIdleTime(_maxIdleTime);
105         configure(((SocketChannel)endpoint.getTransport()).socket());
106     }
107 
108 
109     /* ------------------------------------------------------------------------------- */
110     public int getLocalPort()
111     {
112         if (_acceptChannel==null || !_acceptChannel.isOpen())
113             return -1;
114         return _acceptChannel.socket().getLocalPort();
115     }
116     
117     /* ------------------------------------------------------------------------------- */
118     /* ------------------------------------------------------------------------------- */
119     /* ------------------------------------------------------------------------------- */
120     private class ConnectorEndPoint extends ChannelEndPoint implements Runnable, ConnectedEndPoint
121     {
122         Connection _connection;
123         boolean _dispatched=false;
124         int _sotimeout;
125         
126         ConnectorEndPoint(ByteChannel channel) 
127             throws IOException
128         {
129             super(channel,BlockingChannelConnector.this._maxIdleTime);
130             _connection = new HttpConnection(BlockingChannelConnector.this,this,getServer());
131         }
132         
133         /* ------------------------------------------------------------ */
134         /** Get the connection.
135          * @return the connection
136          */
137         public Connection getConnection()
138         {
139             return _connection;
140         }
141         
142         /* ------------------------------------------------------------ */
143         public void setConnection(Connection connection)
144         {
145             _connection=connection;
146         }
147 
148         /* ------------------------------------------------------------ */
149         void dispatch() throws IOException
150         {
151             if (!getThreadPool().dispatch(this))
152             {
153                 Log.warn("dispatch failed for  {}",_connection);
154                 ConnectorEndPoint.this.close();
155             }
156         }
157         
158         public void run()
159         {
160             try
161             {
162                 connectionOpened(_connection);
163 
164                 while (isOpen())
165                 {
166                     if (_connection.isIdle())
167                     {
168                         if (getServer().getThreadPool().isLowOnThreads())
169                         {
170                             int lrmit = getLowResourcesMaxIdleTime();
171                             if (lrmit>=0 && _sotimeout!= lrmit)
172                             {
173                                 _sotimeout=lrmit;
174                                 ((SocketChannel)getTransport()).socket().setSoTimeout(_sotimeout);
175                             }
176                         }
177                     }
178                     
179                     _connection = _connection.handle();
180                 }
181             }
182             catch (EofException e)
183             {
184                 Log.debug("EOF", e);
185                 try{ConnectorEndPoint.this.close();}
186                 catch(IOException e2){Log.ignore(e2);}
187             }
188             catch (HttpException e)
189             {
190                 Log.debug("BAD", e);
191                 try{ConnectorEndPoint.this.close();}
192                 catch(IOException e2){Log.ignore(e2);}
193             }
194             catch(Throwable e)
195             {
196                 Log.warn("handle failed",e);
197                 try{ConnectorEndPoint.this.close();}
198                 catch(IOException e2){Log.ignore(e2);}
199             }
200             finally
201             {
202                 connectionClosed(_connection);
203             }
204         }
205     }
206 }