View Javadoc

1   // ========================================================================
2   // Copyright 2003-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14   
15  package org.mortbay.jetty.nio;
16  
17  import java.io.IOException;
18  import java.net.InetSocketAddress;
19  import java.net.Socket;
20  import java.nio.channels.ByteChannel;
21  import java.nio.channels.ServerSocketChannel;
22  import java.nio.channels.SocketChannel;
23  
24  import org.mortbay.io.EndPoint;
25  import org.mortbay.io.nio.ChannelEndPoint;
26  import org.mortbay.jetty.EofException;
27  import org.mortbay.jetty.HttpConnection;
28  import org.mortbay.jetty.HttpException;
29  import org.mortbay.jetty.Request;
30  import org.mortbay.log.Log;
31  
32  
33  /* ------------------------------------------------------------------------------- */
34  /**  Blocking NIO connector.
35   * This connector uses efficient NIO buffers with a traditional blocking thread model.
36   * Direct NIO buffers are used and a thread is allocated per connections.
37   * 
38   * This connector is best used when there are a few very active connections.
39   * 
40   * @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
41   * 
42   * @author gregw
43   *
44   */
45  public class BlockingChannelConnector extends AbstractNIOConnector 
46  {
47      private transient ServerSocketChannel _acceptChannel;
48      
49      /* ------------------------------------------------------------ */
50      /** Constructor.
51       * 
52       */
53      public BlockingChannelConnector()
54      {
55      }
56  
57      /* ------------------------------------------------------------ */
58      public Object getConnection()
59      {
60          return _acceptChannel;
61      }
62      
63      /* ------------------------------------------------------------ */
64      public void open() throws IOException
65      {
66          // Create a new server socket and set to non blocking mode
67          _acceptChannel= ServerSocketChannel.open();
68          _acceptChannel.configureBlocking(true);
69  
70          // Bind the server socket to the local host and port
71          InetSocketAddress addr = getHost()==null?new InetSocketAddress(getPort()):new InetSocketAddress(getHost(),getPort());
72          _acceptChannel.socket().bind(addr,getAcceptQueueSize());
73      }
74  
75      /* ------------------------------------------------------------ */
76      public void close() throws IOException
77      {
78          if (_acceptChannel != null)
79              _acceptChannel.close();
80          _acceptChannel=null;
81      }
82      
83      /* ------------------------------------------------------------ */
84      public void accept(int acceptorID)
85      	throws IOException, InterruptedException
86      {   
87          SocketChannel channel = _acceptChannel.accept();
88          channel.configureBlocking(true);
89          Socket socket=channel.socket();
90          configure(socket);
91  
92          Connection connection=new Connection(channel);
93          connection.dispatch();
94      }
95      
96      /* ------------------------------------------------------------------------------- */
97      public void customize(EndPoint endpoint, Request request)
98          throws IOException
99      {
100         Connection connection = (Connection)endpoint;
101         if (connection._sotimeout!=_maxIdleTime)
102         {
103             connection._sotimeout=_maxIdleTime;
104             ((SocketChannel)endpoint.getTransport()).socket().setSoTimeout(_maxIdleTime);
105         }
106               
107         super.customize(endpoint, request);
108         configure(((SocketChannel)endpoint.getTransport()).socket());
109     }
110 
111 
112     /* ------------------------------------------------------------------------------- */
113     public int getLocalPort()
114     {
115         if (_acceptChannel==null || !_acceptChannel.isOpen())
116             return -1;
117         return _acceptChannel.socket().getLocalPort();
118     }
119     
120     /* ------------------------------------------------------------------------------- */
121     /* ------------------------------------------------------------------------------- */
122     /* ------------------------------------------------------------------------------- */
123     private class Connection extends ChannelEndPoint implements Runnable
124     {
125         boolean _dispatched=false;
126         HttpConnection _connection;
127         int _sotimeout;
128         
129         Connection(ByteChannel channel) 
130         {
131             super(channel);
132             _connection = new HttpConnection(BlockingChannelConnector.this,this,getServer());
133         }
134         
135         void dispatch() throws IOException
136         {
137             if (!getThreadPool().dispatch(this))
138             {
139                 Log.warn("dispatch failed for  {}",_connection);
140                 close();
141             }
142         }
143         
144         public void run()
145         {
146             try
147             {
148                 connectionOpened(_connection);
149                 
150                 while (isOpen())
151                 {
152                     if (_connection.isIdle())
153                     {
154                         if (getServer().getThreadPool().isLowOnThreads())
155                         {
156                             if (_sotimeout!=getLowResourceMaxIdleTime())
157                             {
158                                 _sotimeout=getLowResourceMaxIdleTime();
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{close();}
170                 catch(IOException e2){Log.ignore(e2);}
171             }
172             catch (HttpException e)
173             {
174                 Log.debug("BAD", e);
175                 try{close();}
176                 catch(IOException e2){Log.ignore(e2);}
177             }
178             catch(Throwable e)
179             {
180                 Log.warn("handle failed",e);
181                 try{close();}
182                 catch(IOException e2){Log.ignore(e2);}
183             }
184             finally
185             {
186                 connectionClosed(_connection);
187             }
188         }
189     }
190 }