2 * Written by Dawid Kurzyniec and released to the public domain, as explained
3 * at http://creativecommons.org/licenses/publicdomain
6 //package edu.emory.mathcs.util.net;
10 import java.nio.channels.*;
13 * Wrapper for sockets which enables to add functionality in subclasses
14 * on top of existing, connected sockets. It is useful when direct subclassing
15 * of delegate socket class is not possible, e.g. if the delegate socket is
16 * created by a library. Possible usage example is socket factory chaining.
17 * This class delegates all socket-related requests to the wrapped delegate,
20 * @author Dawid Kurzyniec
23 public abstract class SocketWrapper extends Socket {
26 * the wrapped delegate socket.
28 protected final Socket delegate;
31 * Creates new socket wrapper for a given socket. The delegate
32 * must be connected and bound and it must not be closed.
33 * @param delegate the delegate socket to wrap
34 * @throws SocketException if the delegate socket is closed, not bound,
37 protected SocketWrapper(Socket delegate) throws SocketException {
38 super(new WrappingSocketImpl(delegate));
39 this.delegate = delegate;
40 System.out.println("Creating SocketWrapper $Rev$");
43 public SocketChannel getChannel() {
44 return delegate.getChannel();
48 * Returns true, indicating that the socket is bound.
52 public boolean isBound() {
56 public boolean isClosed() {
57 return super.isClosed() || delegate.isClosed();
61 * Returns true, indicating that the socket is connected.
65 public boolean isConnected() {
69 public boolean isInputShutdown() {
70 return super.isInputShutdown() || delegate.isInputShutdown();
73 public boolean isOutputShutdown() {
74 return super.isInputShutdown() || delegate.isOutputShutdown();
77 private static class WrappingSocketImpl extends SocketImpl {
78 private final Socket delegate;
79 WrappingSocketImpl(Socket delegate) throws SocketException {
80 if (delegate == null) {
81 throw new NullPointerException();
83 if (delegate.isClosed()) {
84 throw new SocketException("Delegate server socket is closed");
86 if (!(delegate.isBound())) {
87 throw new SocketException("Delegate server socket is not bound");
89 if (!(delegate.isConnected())) {
90 throw new SocketException("Delegate server socket is not connected");
92 this.delegate = delegate;
95 protected void create(boolean stream) {}
97 protected void connect(String host, int port) {
98 // delegate is always connected, thus this method is never called
99 throw new UnsupportedOperationException();
102 protected void connect(InetAddress address, int port) {
103 // delegate is always connected, thus this method is never called
104 throw new UnsupportedOperationException();
107 protected void connect(SocketAddress address, int timeout) {
108 // delegate is always connected, thus this method is never called
109 throw new UnsupportedOperationException();
112 protected void bind(InetAddress host, int port) {
113 // delegate is always bound, thus this method is never called
114 throw new UnsupportedOperationException();
117 protected void listen(int backlog) {
118 // this wrapper is never used by a ServerSocket
119 throw new UnsupportedOperationException();
122 protected void accept(SocketImpl s) {
123 // this wrapper is never used by a ServerSocket
124 throw new UnsupportedOperationException();
127 protected InputStream getInputStream() throws IOException {
128 return delegate.getInputStream();
131 protected OutputStream getOutputStream() throws IOException {
132 return delegate.getOutputStream();
135 protected int available() throws IOException {
136 return getInputStream().available();
139 protected void close() throws IOException {
140 System.out.println("Calling delegate.close");
144 protected void shutdownInput() throws IOException {
145 delegate.shutdownInput();
148 protected void shutdownOutput() throws IOException {
149 delegate.shutdownOutput();
152 protected FileDescriptor getFileDescriptor() {
153 // this wrapper is never used by a ServerSocket
154 throw new UnsupportedOperationException();
157 protected InetAddress getInetAddress() {
158 return delegate.getInetAddress();
161 protected int getPort() {
162 return delegate.getPort();
165 protected boolean supportsUrgentData() {
166 return false; // must be overridden in sub-class
169 protected void sendUrgentData (int data) throws IOException {
170 delegate.sendUrgentData(data);
173 protected int getLocalPort() {
174 return delegate.getLocalPort();
177 public Object getOption(int optID) throws SocketException {
179 case SocketOptions.IP_TOS:
180 return new Integer(delegate.getTrafficClass());
181 case SocketOptions.SO_BINDADDR:
182 return delegate.getLocalAddress();
183 case SocketOptions.SO_KEEPALIVE:
184 return Boolean.valueOf(delegate.getKeepAlive());
185 case SocketOptions.SO_LINGER:
186 return new Integer(delegate.getSoLinger());
187 case SocketOptions.SO_OOBINLINE:
188 return Boolean.valueOf(delegate.getOOBInline());
189 case SocketOptions.SO_RCVBUF:
190 return new Integer(delegate.getReceiveBufferSize());
191 case SocketOptions.SO_REUSEADDR:
192 return Boolean.valueOf(delegate.getReuseAddress());
193 case SocketOptions.SO_SNDBUF:
194 return new Integer(delegate.getSendBufferSize());
195 case SocketOptions.SO_TIMEOUT:
196 return new Integer(delegate.getSoTimeout());
197 case SocketOptions.TCP_NODELAY:
198 return Boolean.valueOf(delegate.getTcpNoDelay());
199 case SocketOptions.SO_BROADCAST:
201 throw new IllegalArgumentException("Unsupported option type");
205 public void setOption(int optID, Object value) throws SocketException {
207 case SocketOptions.SO_BINDADDR:
208 throw new IllegalArgumentException("Socket is bound");
209 case SocketOptions.SO_KEEPALIVE:
210 delegate.setKeepAlive(((Boolean)value).booleanValue());
212 case SocketOptions.SO_LINGER:
213 if (value instanceof Boolean) {
214 delegate.setSoLinger(((Boolean)value).booleanValue(), 0);
217 delegate.setSoLinger(true, ((Integer)value).intValue());
220 case SocketOptions.SO_OOBINLINE:
221 delegate.setOOBInline(((Boolean)value).booleanValue());
223 case SocketOptions.SO_RCVBUF:
224 delegate.setReceiveBufferSize(((Integer)value).intValue());
226 case SocketOptions.SO_REUSEADDR:
227 delegate.setReuseAddress(((Boolean)value).booleanValue());
229 case SocketOptions.SO_SNDBUF:
230 delegate.setSendBufferSize(((Integer)value).intValue());
232 case SocketOptions.SO_TIMEOUT:
233 delegate.setSoTimeout(((Integer)value).intValue());
235 case SocketOptions.TCP_NODELAY:
236 delegate.setTcpNoDelay(((Boolean)value).booleanValue());
238 case SocketOptions.SO_BROADCAST:
240 throw new IllegalArgumentException("Unsupported option type");
245 public void close() throws IOException {
246 System.out.println("Calling SocketWrapper.delegate.close");
250 public boolean equals(Object obj) {
251 if (!(obj instanceof SocketWrapper)) return false;
252 SocketWrapper that = (SocketWrapper)obj;
253 return this.delegate.equals(that.delegate);
256 public int hashCode() {
257 return delegate.hashCode() ^ 0x01010101;
259 public String toString() {
260 return "<SocketWrapper " + super.toString() + "(delegating to " + delegate.toString() + ")" + ">";