001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-nio/src/main/java/org/apache/http/impl/nio/reactor/IOSessionImpl.java $
003: * $Revision: 613298 $
004: * $Date: 2008-01-18 23:09:22 +0100 (Fri, 18 Jan 2008) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.nio.reactor;
033:
034: import java.io.IOException;
035: import java.net.SocketAddress;
036: import java.nio.channels.ByteChannel;
037: import java.nio.channels.Channel;
038: import java.nio.channels.SelectionKey;
039: import java.nio.channels.SocketChannel;
040: import java.util.Collections;
041: import java.util.HashMap;
042: import java.util.Map;
043:
044: import org.apache.http.nio.reactor.IOSession;
045: import org.apache.http.nio.reactor.SessionBufferStatus;
046:
047: public class IOSessionImpl implements IOSession {
048:
049: private volatile int status;
050:
051: private final SelectionKey key;
052: private final ByteChannel channel;
053: private final SessionClosedCallback callback;
054: private final Map<String, Object> attributes;
055:
056: private SessionBufferStatus bufferStatus;
057: private int socketTimeout;
058:
059: public IOSessionImpl(final SelectionKey key,
060: final SessionClosedCallback callback) {
061: super ();
062: if (key == null) {
063: throw new IllegalArgumentException(
064: "Selection key may not be null");
065: }
066: this .key = key;
067: this .channel = (ByteChannel) this .key.channel();
068: this .callback = callback;
069: this .attributes = Collections
070: .synchronizedMap(new HashMap<String, Object>());
071: this .socketTimeout = 0;
072: this .status = ACTIVE;
073: }
074:
075: public ByteChannel channel() {
076: return this .channel;
077: }
078:
079: public SocketAddress getLocalAddress() {
080: Channel channel = this .key.channel();
081: if (channel instanceof SocketChannel) {
082: return ((SocketChannel) channel).socket()
083: .getLocalSocketAddress();
084: } else {
085: return null;
086: }
087: }
088:
089: public SocketAddress getRemoteAddress() {
090: Channel channel = this .key.channel();
091: if (channel instanceof SocketChannel) {
092: return ((SocketChannel) channel).socket()
093: .getRemoteSocketAddress();
094: } else {
095: return null;
096: }
097: }
098:
099: public int getEventMask() {
100: return this .key.interestOps();
101: }
102:
103: public void setEventMask(int ops) {
104: if (this .status == CLOSED) {
105: return;
106: }
107: synchronized (this .key) {
108: this .key.interestOps(ops);
109: this .key.selector().wakeup();
110: }
111: }
112:
113: public void setEvent(int op) {
114: if (this .status == CLOSED) {
115: return;
116: }
117: synchronized (this .key) {
118: int ops = this .key.interestOps();
119: this .key.interestOps(ops | op);
120: this .key.selector().wakeup();
121: }
122: }
123:
124: public void clearEvent(int op) {
125: if (this .status == CLOSED) {
126: return;
127: }
128: synchronized (this .key) {
129: int ops = this .key.interestOps();
130: this .key.interestOps(ops & ~op);
131: this .key.selector().wakeup();
132: }
133: }
134:
135: public int getSocketTimeout() {
136: return this .socketTimeout;
137: }
138:
139: public void setSocketTimeout(int timeout) {
140: this .socketTimeout = timeout;
141: }
142:
143: public void close() {
144: if (this .status == CLOSED) {
145: return;
146: }
147: this .status = CLOSED;
148: this .key.cancel();
149: try {
150: this .key.channel().close();
151: } catch (IOException ex) {
152: // Munching exceptions is not nice
153: // but in this case it is justified
154: }
155: if (this .callback != null) {
156: this .callback.sessionClosed(this );
157: }
158: if (this .key.selector().isOpen()) {
159: this .key.selector().wakeup();
160: }
161: }
162:
163: public int getStatus() {
164: return this .status;
165: }
166:
167: public boolean isClosed() {
168: return this .status == CLOSED || !this .key.isValid();
169: }
170:
171: public void shutdown() {
172: // For this type of session, a close() does exactly
173: // what we need and nothing more.
174: close();
175: }
176:
177: public boolean hasBufferedInput() {
178: return this .bufferStatus != null
179: && this .bufferStatus.hasBufferedInput();
180: }
181:
182: public boolean hasBufferedOutput() {
183: return this .bufferStatus != null
184: && this .bufferStatus.hasBufferedOutput();
185: }
186:
187: public void setBufferStatus(final SessionBufferStatus bufferStatus) {
188: this .bufferStatus = bufferStatus;
189: }
190:
191: public Object getAttribute(final String name) {
192: return this .attributes.get(name);
193: }
194:
195: public Object removeAttribute(final String name) {
196: return this .attributes.remove(name);
197: }
198:
199: public void setAttribute(final String name, final Object obj) {
200: this .attributes.put(name, obj);
201: }
202:
203: private static void formatOps(final StringBuffer buffer, int ops) {
204: buffer.append('[');
205: if ((ops & SelectionKey.OP_READ) > 0) {
206: buffer.append('r');
207: }
208: if ((ops & SelectionKey.OP_WRITE) > 0) {
209: buffer.append('w');
210: }
211: if ((ops & SelectionKey.OP_ACCEPT) > 0) {
212: buffer.append('a');
213: }
214: if ((ops & SelectionKey.OP_CONNECT) > 0) {
215: buffer.append('c');
216: }
217: buffer.append(']');
218: }
219:
220: @Override
221: public String toString() {
222: StringBuffer buffer = new StringBuffer();
223: buffer.append("[");
224: if (this .key.isValid()) {
225: buffer.append("interested ops: ");
226: formatOps(buffer, this .key.interestOps());
227: buffer.append("; ready ops: ");
228: formatOps(buffer, this .key.readyOps());
229: } else {
230: buffer.append("invalid");
231: }
232: buffer.append("]");
233: return buffer.toString();
234: }
235:
236: }
|