001: // ========================================================================
002: // Copyright 2003-2005 Mort Bay Consulting Pty. Ltd.
003: // ------------------------------------------------------------------------
004: // Licensed under the Apache License, Version 2.0 (the "License");
005: // you may not use this file except in compliance with the License.
006: // You may obtain a copy of the License at
007: // http://www.apache.org/licenses/LICENSE-2.0
008: // Unless required by applicable law or agreed to in writing, software
009: // distributed under the License is distributed on an "AS IS" BASIS,
010: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011: // See the License for the specific language governing permissions and
012: // limitations under the License.
013: // ========================================================================
014:
015: package org.mortbay.jetty.nio;
016:
017: import java.io.IOException;
018: import java.net.InetSocketAddress;
019: import java.net.Socket;
020: import java.nio.channels.ByteChannel;
021: import java.nio.channels.ServerSocketChannel;
022: import java.nio.channels.SocketChannel;
023:
024: import org.mortbay.io.Buffer;
025: import org.mortbay.io.EndPoint;
026: import org.mortbay.io.nio.ChannelEndPoint;
027: import org.mortbay.jetty.EofException;
028: import org.mortbay.jetty.HttpConnection;
029: import org.mortbay.jetty.HttpException;
030: import org.mortbay.jetty.Request;
031: import org.mortbay.log.Log;
032:
033: /* ------------------------------------------------------------------------------- */
034: /** Blocking NIO connector.
035: * This connector uses efficient NIO buffers with a traditional blocking thread model.
036: * Direct NIO buffers are used and a thread is allocated per connections.
037: *
038: * This connector is best used when there are a few very active connections.
039: *
040: * @org.apache.xbean.XBean element="blockingNioConnector" description="Creates a blocking NIO based socket connector"
041: *
042: * @author gregw
043: *
044: */
045: public class BlockingChannelConnector extends AbstractNIOConnector {
046: private transient ServerSocketChannel _acceptChannel;
047:
048: /* ------------------------------------------------------------ */
049: /** Constructor.
050: *
051: */
052: public BlockingChannelConnector() {
053: }
054:
055: /* ------------------------------------------------------------ */
056: public Object getConnection() {
057: return _acceptChannel;
058: }
059:
060: /* ------------------------------------------------------------ */
061: public void open() throws IOException {
062: // Create a new server socket and set to non blocking mode
063: _acceptChannel = ServerSocketChannel.open();
064: _acceptChannel.configureBlocking(true);
065:
066: // Bind the server socket to the local host and port
067: InetSocketAddress addr = getHost() == null ? new InetSocketAddress(
068: getPort())
069: : new InetSocketAddress(getHost(), getPort());
070: _acceptChannel.socket().bind(addr, getAcceptQueueSize());
071: }
072:
073: /* ------------------------------------------------------------ */
074: public void close() throws IOException {
075: if (_acceptChannel != null)
076: _acceptChannel.close();
077: _acceptChannel = null;
078: }
079:
080: /* ------------------------------------------------------------ */
081: public void accept(int acceptorID) throws IOException,
082: InterruptedException {
083: SocketChannel channel = _acceptChannel.accept();
084: channel.configureBlocking(true);
085: Socket socket = channel.socket();
086: configure(socket);
087:
088: Connection connection = new Connection(channel);
089: connection.dispatch();
090: }
091:
092: /* ------------------------------------------------------------------------------- */
093: public void customize(EndPoint endpoint, Request request)
094: throws IOException {
095: Connection connection = (Connection) endpoint;
096: if (connection._sotimeout != _maxIdleTime) {
097: connection._sotimeout = _maxIdleTime;
098: ((SocketChannel) endpoint.getTransport()).socket()
099: .setSoTimeout(_maxIdleTime);
100: }
101:
102: super .customize(endpoint, request);
103: configure(((SocketChannel) endpoint.getTransport()).socket());
104: }
105:
106: /* ------------------------------------------------------------------------------- */
107: public int getLocalPort() {
108: if (_acceptChannel == null || !_acceptChannel.isOpen())
109: return -1;
110: return _acceptChannel.socket().getLocalPort();
111: }
112:
113: /* ------------------------------------------------------------------------------- */
114: /* ------------------------------------------------------------------------------- */
115: /* ------------------------------------------------------------------------------- */
116: private class Connection extends ChannelEndPoint implements
117: Runnable {
118: boolean _dispatched = false;
119: HttpConnection _connection;
120: int _sotimeout;
121:
122: Connection(ByteChannel channel) {
123: super (channel);
124: _connection = new HttpConnection(
125: BlockingChannelConnector.this , this , getServer());
126: }
127:
128: void dispatch() throws IOException {
129: if (!getThreadPool().dispatch(this )) {
130: Log.warn("dispatch failed for {}", _connection);
131: close();
132: }
133: }
134:
135: public void run() {
136: try {
137: connectionOpened(_connection);
138:
139: while (isOpen()) {
140: if (_connection.isIdle()) {
141: if (getServer().getThreadPool()
142: .isLowOnThreads()) {
143: if (_sotimeout != getLowResourceMaxIdleTime()) {
144: _sotimeout = getLowResourceMaxIdleTime();
145: ((SocketChannel) getTransport())
146: .socket().setSoTimeout(
147: _sotimeout);
148: }
149: }
150: }
151: _connection.handle();
152: }
153: } catch (EofException e) {
154: Log.debug("EOF", e);
155: try {
156: close();
157: } catch (IOException e2) {
158: Log.ignore(e2);
159: }
160: } catch (HttpException e) {
161: Log.debug("BAD", e);
162: try {
163: close();
164: } catch (IOException e2) {
165: Log.ignore(e2);
166: }
167: } catch (Throwable e) {
168: Log.warn("handle failed", e);
169: try {
170: close();
171: } catch (IOException e2) {
172: Log.ignore(e2);
173: }
174: } finally {
175: connectionClosed(_connection);
176: }
177: }
178: }
179: }
|