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                             int lrmit = getLowResourceMaxIdleTime();
157                             if (lrmit>=0 && _sotimeout!= lrmit)
158                             {
159                                 _sotimeout=lrmit;
160                                 ((SocketChannel)getTransport()).socket().setSoTimeout(_sotimeout);
161                             }
162                         }
163                     }
164                     _connection.handle();
165                 }
166             }
167             catch (EofException e)
168             {
169                 Log.debug("EOF", e);
170                 try{close();}
171                 catch(IOException e2){Log.ignore(e2);}
172             }
173             catch (HttpException e)
174             {
175                 Log.debug("BAD", e);
176                 try{close();}
177                 catch(IOException e2){Log.ignore(e2);}
178             }
179             catch(Throwable e)
180             {
181                 Log.warn("handle failed",e);
182                 try{close();}
183                 catch(IOException e2){Log.ignore(e2);}
184             }
185             finally
186             {
187                 connectionClosed(_connection);
188             }
189         }
190     }
191 }