/* * Written by Dawid Kurzyniec and released to the public domain, as explained * at http://creativecommons.org/licenses/publicdomain */ //package edu.emory.mathcs.util.net; import java.io.*; import java.net.*; import java.nio.channels.*; /** * Wrapper for sockets which enables to add functionality in subclasses * on top of existing, connected sockets. It is useful when direct subclassing * of delegate socket class is not possible, e.g. if the delegate socket is * created by a library. Possible usage example is socket factory chaining. * This class delegates all socket-related requests to the wrapped delegate, * as of JDK 1.4. * * @author Dawid Kurzyniec * @version 1.4 */ public abstract class SocketWrapper extends Socket { /** * the wrapped delegate socket. */ protected final Socket delegate; /** * Creates new socket wrapper for a given socket. The delegate * must be connected and bound and it must not be closed. * @param delegate the delegate socket to wrap * @throws SocketException if the delegate socket is closed, not bound, * or not connected */ protected SocketWrapper(Socket delegate) throws SocketException { super(new WrappingSocketImpl(delegate)); this.delegate = delegate; } public SocketChannel getChannel() { return delegate.getChannel(); } /** * Returns true, indicating that the socket is bound. * * @return true */ public boolean isBound() { return true; } public boolean isClosed() { return super.isClosed() || delegate.isClosed(); } /** * Returns true, indicating that the socket is connected. * * @return true */ public boolean isConnected() { return true; } public boolean isInputShutdown() { return super.isInputShutdown() || delegate.isInputShutdown(); } public boolean isOutputShutdown() { return super.isInputShutdown() || delegate.isOutputShutdown(); } private static class WrappingSocketImpl extends SocketImpl { private final Socket delegate; WrappingSocketImpl(Socket delegate) throws SocketException { if (delegate == null) { throw new NullPointerException(); } if (delegate.isClosed()) { throw new SocketException("Delegate server socket is closed"); } if (!(delegate.isBound())) { throw new SocketException("Delegate server socket is not bound"); } if (!(delegate.isConnected())) { throw new SocketException("Delegate server socket is not connected"); } this.delegate = delegate; } protected void create(boolean stream) {} protected void connect(String host, int port) { // delegate is always connected, thus this method is never called throw new UnsupportedOperationException(); } protected void connect(InetAddress address, int port) { // delegate is always connected, thus this method is never called throw new UnsupportedOperationException(); } protected void connect(SocketAddress address, int timeout) { // delegate is always connected, thus this method is never called throw new UnsupportedOperationException(); } protected void bind(InetAddress host, int port) { // delegate is always bound, thus this method is never called throw new UnsupportedOperationException(); } protected void listen(int backlog) { // this wrapper is never used by a ServerSocket throw new UnsupportedOperationException(); } protected void accept(SocketImpl s) { // this wrapper is never used by a ServerSocket throw new UnsupportedOperationException(); } protected InputStream getInputStream() throws IOException { return delegate.getInputStream(); } protected OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } protected int available() throws IOException { return getInputStream().available(); } protected void close() throws IOException { delegate.close(); } protected void shutdownInput() throws IOException { delegate.shutdownInput(); } protected void shutdownOutput() throws IOException { delegate.shutdownOutput(); } protected FileDescriptor getFileDescriptor() { // this wrapper is never used by a ServerSocket throw new UnsupportedOperationException(); } protected InetAddress getInetAddress() { return delegate.getInetAddress(); } protected int getPort() { return delegate.getPort(); } protected boolean supportsUrgentData() { return false; // must be overridden in sub-class } protected void sendUrgentData (int data) throws IOException { delegate.sendUrgentData(data); } protected int getLocalPort() { return delegate.getLocalPort(); } public Object getOption(int optID) throws SocketException { switch (optID) { case SocketOptions.IP_TOS: return new Integer(delegate.getTrafficClass()); case SocketOptions.SO_BINDADDR: return delegate.getLocalAddress(); case SocketOptions.SO_KEEPALIVE: return Boolean.valueOf(delegate.getKeepAlive()); case SocketOptions.SO_LINGER: return new Integer(delegate.getSoLinger()); case SocketOptions.SO_OOBINLINE: return Boolean.valueOf(delegate.getOOBInline()); case SocketOptions.SO_RCVBUF: return new Integer(delegate.getReceiveBufferSize()); case SocketOptions.SO_REUSEADDR: return Boolean.valueOf(delegate.getReuseAddress()); case SocketOptions.SO_SNDBUF: return new Integer(delegate.getSendBufferSize()); case SocketOptions.SO_TIMEOUT: return new Integer(delegate.getSoTimeout()); case SocketOptions.TCP_NODELAY: return Boolean.valueOf(delegate.getTcpNoDelay()); case SocketOptions.SO_BROADCAST: default: throw new IllegalArgumentException("Unsupported option type"); } } public void setOption(int optID, Object value) throws SocketException { switch (optID) { case SocketOptions.SO_BINDADDR: throw new IllegalArgumentException("Socket is bound"); case SocketOptions.SO_KEEPALIVE: delegate.setKeepAlive(((Boolean)value).booleanValue()); break; case SocketOptions.SO_LINGER: if (value instanceof Boolean) { delegate.setSoLinger(((Boolean)value).booleanValue(), 0); } else { delegate.setSoLinger(true, ((Integer)value).intValue()); } break; case SocketOptions.SO_OOBINLINE: delegate.setOOBInline(((Boolean)value).booleanValue()); break; case SocketOptions.SO_RCVBUF: delegate.setReceiveBufferSize(((Integer)value).intValue()); break; case SocketOptions.SO_REUSEADDR: delegate.setReuseAddress(((Boolean)value).booleanValue()); break; case SocketOptions.SO_SNDBUF: delegate.setSendBufferSize(((Integer)value).intValue()); break; case SocketOptions.SO_TIMEOUT: delegate.setSoTimeout(((Integer)value).intValue()); break; case SocketOptions.TCP_NODELAY: delegate.setTcpNoDelay(((Boolean)value).booleanValue()); break; case SocketOptions.SO_BROADCAST: default: throw new IllegalArgumentException("Unsupported option type"); } } } public boolean equals(Object obj) { if (!(obj instanceof SocketWrapper)) return false; SocketWrapper that = (SocketWrapper)obj; return this.delegate.equals(that.delegate); } public int hashCode() { return delegate.hashCode() ^ 0x01010101; } }