29207328c20b32775c57ad70ae968f7a7f6920bb
[invirt/packages/invirt-vnc-client.git] / SocketWrapper.java
1 /*
2  * Written by Dawid Kurzyniec and released to the public domain, as explained
3  * at http://creativecommons.org/licenses/publicdomain
4  */
5
6 //package edu.emory.mathcs.util.net;
7
8 import java.io.*;
9 import java.net.*;
10 import java.nio.channels.*;
11
12 /**
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,
18  * as of JDK 1.4.
19  *
20  * @author Dawid Kurzyniec
21  * @version 1.4
22  */
23 public abstract class SocketWrapper extends Socket {
24
25     /**
26      * the wrapped delegate socket.
27      */
28     protected final Socket delegate;
29
30     /**
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,
35      *                         or not connected
36      */
37     protected SocketWrapper(Socket delegate) throws SocketException {
38         super(new WrappingSocketImpl(delegate));
39         this.delegate = delegate;
40     }
41
42     public SocketChannel getChannel() {
43         return delegate.getChannel();
44     }
45
46     /**
47      * Returns true, indicating that the socket is bound.
48      *
49      * @return true
50      */
51     public boolean isBound() {
52         return true;
53     }
54
55     public boolean isClosed() {
56         return super.isClosed() || delegate.isClosed();
57     }
58
59     /**
60      * Returns true, indicating that the socket is connected.
61      *
62      * @return true
63      */
64     public boolean isConnected() {
65         return true;
66     }
67
68     public boolean isInputShutdown() {
69         return super.isInputShutdown() || delegate.isInputShutdown();
70     }
71
72     public boolean isOutputShutdown() {
73         return super.isInputShutdown() || delegate.isOutputShutdown();
74     }
75
76     private static class WrappingSocketImpl extends SocketImpl {
77         private final Socket delegate;
78         WrappingSocketImpl(Socket delegate) throws SocketException {
79             if (delegate == null) {
80                 throw new NullPointerException();
81             }
82             if (delegate.isClosed()) {
83                 throw new SocketException("Delegate server socket is closed");
84             }
85             if (!(delegate.isBound())) {
86                 throw new SocketException("Delegate server socket is not bound");
87             }
88             if (!(delegate.isConnected())) {
89                 throw new SocketException("Delegate server socket is not connected");
90             }
91             this.delegate = delegate;
92         }
93
94         protected void create(boolean stream) {}
95
96         protected void connect(String host, int port) {
97             // delegate is always connected, thus this method is never called
98             throw new UnsupportedOperationException();
99         }
100
101         protected void connect(InetAddress address, int port) {
102             // delegate is always connected, thus this method is never called
103             throw new UnsupportedOperationException();
104         }
105
106         protected void connect(SocketAddress address, int timeout) {
107             // delegate is always connected, thus this method is never called
108             throw new UnsupportedOperationException();
109         }
110
111         protected void bind(InetAddress host, int port) {
112             // delegate is always bound, thus this method is never called
113             throw new UnsupportedOperationException();
114         }
115
116         protected void listen(int backlog) {
117             // this wrapper is never used by a ServerSocket
118             throw new UnsupportedOperationException();
119         }
120
121         protected void accept(SocketImpl s) {
122             // this wrapper is never used by a ServerSocket
123             throw new UnsupportedOperationException();
124         }
125
126         protected InputStream getInputStream() throws IOException {
127             return delegate.getInputStream();
128         }
129
130         protected OutputStream getOutputStream() throws IOException {
131             return delegate.getOutputStream();
132         }
133
134         protected int available() throws IOException {
135             return getInputStream().available();
136         }
137
138         protected void close() throws IOException {
139             delegate.close();
140         }
141
142         protected void shutdownInput() throws IOException {
143             delegate.shutdownInput();
144         }
145
146         protected void shutdownOutput() throws IOException {
147             delegate.shutdownOutput();
148         }
149
150         protected FileDescriptor getFileDescriptor() {
151             // this wrapper is never used by a ServerSocket
152             throw new UnsupportedOperationException();
153         }
154
155         protected InetAddress getInetAddress() {
156             return delegate.getInetAddress();
157         }
158
159         protected int getPort() {
160             return delegate.getPort();
161         }
162
163         protected boolean supportsUrgentData() {
164             return false; // must be overridden in sub-class
165         }
166
167         protected void sendUrgentData (int data) throws IOException {
168             delegate.sendUrgentData(data);
169         }
170
171         protected int getLocalPort() {
172             return delegate.getLocalPort();
173         }
174
175         public Object getOption(int optID) throws SocketException {
176             switch (optID) {
177                 case SocketOptions.IP_TOS:
178                     return new Integer(delegate.getTrafficClass());
179                 case SocketOptions.SO_BINDADDR:
180                     return delegate.getLocalAddress();
181                 case SocketOptions.SO_KEEPALIVE:
182                     return Boolean.valueOf(delegate.getKeepAlive());
183                 case SocketOptions.SO_LINGER:
184                     return new Integer(delegate.getSoLinger());
185                 case SocketOptions.SO_OOBINLINE:
186                     return Boolean.valueOf(delegate.getOOBInline());
187                 case SocketOptions.SO_RCVBUF:
188                     return new Integer(delegate.getReceiveBufferSize());
189                 case SocketOptions.SO_REUSEADDR:
190                     return Boolean.valueOf(delegate.getReuseAddress());
191                 case SocketOptions.SO_SNDBUF:
192                     return new Integer(delegate.getSendBufferSize());
193                 case SocketOptions.SO_TIMEOUT:
194                     return new Integer(delegate.getSoTimeout());
195                 case SocketOptions.TCP_NODELAY:
196                     return Boolean.valueOf(delegate.getTcpNoDelay());
197                 case SocketOptions.SO_BROADCAST:
198                 default:
199                     throw new IllegalArgumentException("Unsupported option type");
200             }
201         }
202
203         public void setOption(int optID, Object value) throws SocketException {
204             switch (optID) {
205                 case SocketOptions.SO_BINDADDR:
206                     throw new IllegalArgumentException("Socket is bound");
207                 case SocketOptions.SO_KEEPALIVE:
208                     delegate.setKeepAlive(((Boolean)value).booleanValue());
209                     break;
210                 case SocketOptions.SO_LINGER:
211                     if (value instanceof Boolean) {
212                         delegate.setSoLinger(((Boolean)value).booleanValue(), 0);
213                     }
214                     else {
215                         delegate.setSoLinger(true, ((Integer)value).intValue());
216                     }
217                     break;
218                 case SocketOptions.SO_OOBINLINE:
219                     delegate.setOOBInline(((Boolean)value).booleanValue());
220                     break;
221                 case SocketOptions.SO_RCVBUF:
222                     delegate.setReceiveBufferSize(((Integer)value).intValue());
223                     break;
224                 case SocketOptions.SO_REUSEADDR:
225                     delegate.setReuseAddress(((Boolean)value).booleanValue());
226                     break;
227                 case SocketOptions.SO_SNDBUF:
228                     delegate.setSendBufferSize(((Integer)value).intValue());
229                     break;
230                 case SocketOptions.SO_TIMEOUT:
231                     delegate.setSoTimeout(((Integer)value).intValue());
232                     break;
233                 case SocketOptions.TCP_NODELAY:
234                     delegate.setTcpNoDelay(((Boolean)value).booleanValue());
235                     break;
236                 case SocketOptions.SO_BROADCAST:
237                 default:
238                     throw new IllegalArgumentException("Unsupported option type");
239             }
240         }
241     }
242
243     public boolean equals(Object obj) {
244         if (!(obj instanceof SocketWrapper)) return false;
245         SocketWrapper that = (SocketWrapper)obj;
246         return this.delegate.equals(that.delegate);
247     }
248
249     public int hashCode() {
250         return delegate.hashCode() ^ 0x01010101;
251     }
252 }