Mercurial > hg > blitz_condensed
diff src/com/go/trove/net/PooledSocketFactory.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/com/go/trove/net/PooledSocketFactory.java Sat Mar 21 11:00:06 2009 +0000 @@ -0,0 +1,402 @@ +/* ==================================================================== + * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group + * ==================================================================== + * The Tea Software License, Version 1.1 + * + * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Walt Disney Internet Group (http://opensource.go.com/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact opensource@dig.com. + * + * 5. Products derived from this software may not be called "Tea", + * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet", + * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior + * written permission of the Walt Disney Internet Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * For more information about Tea, please see http://opensource.go.com/. + */ + +package com.go.trove.net; + +import java.io.*; +import java.net.*; +import java.util.*; + +/****************************************************************************** + * Socket factory implementation that pools connections to one wrapped socket + * factory. Sessions are ignored on all requests. Consider wrapping with a + * {@link LazySocketFactory} for automatic checking against pooled connections + * that may have been closed. + * + * @author Brian S O'Neill + * @version + * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/05 <!-- $--> + */ +public class PooledSocketFactory implements SocketFactory { + private final SocketFactory mFactory; + private final long mTimeout; + + // Stack of Sockets. + private final Stack mPool = new Stack(); + + private CheckedSocket.ExceptionListener mListener; + + public PooledSocketFactory(SocketFactory factory) { + this(factory, factory.getDefaultTimeout()); + } + + public PooledSocketFactory(SocketFactory factory, long timeout) { + mFactory = factory; + mTimeout = timeout; + + mListener = new CheckedSocket.ExceptionListener() { + public void exceptionOccurred(CheckedSocket s, + Exception e, int count) { + // Only act on the first exception. + if (count == 1) { + // Assume all the pooled connections are bad, so ditch 'em. + clear(); + } + } + }; + } + + public InetAddressAndPort getInetAddressAndPort() { + return mFactory.getInetAddressAndPort(); + } + + public InetAddressAndPort getInetAddressAndPort(Object session) { + return mFactory.getInetAddressAndPort(); + } + + public long getDefaultTimeout() { + return mTimeout; + } + + public CheckedSocket createSocket() + throws ConnectException, SocketException + { + return createSocket(null, mTimeout); + } + + public CheckedSocket createSocket(Object session) + throws ConnectException, SocketException + { + return createSocket(mTimeout); + } + + public CheckedSocket createSocket(long timeout) + throws ConnectException, SocketException + { + return new PooledSocket(mFactory.createSocket(timeout)); + } + + public CheckedSocket createSocket(Object session, long timeout) + throws ConnectException, SocketException + { + return createSocket(timeout); + } + + public CheckedSocket getSocket() + throws ConnectException, SocketException + { + return getSocket(mTimeout); + } + + public CheckedSocket getSocket(Object session) + throws ConnectException, SocketException + { + return getSocket(mTimeout); + } + + public CheckedSocket getSocket(long timeout) + throws ConnectException, SocketException + { + synchronized (mPool) { + if (mPool.size() > 0) { + return new PooledSocket((Socket)mPool.pop()); + } + } + + return new PooledSocket(mFactory.createSocket(timeout)); + } + + public CheckedSocket getSocket(Object session, long timeout) + throws ConnectException, SocketException + { + return getSocket(timeout); + } + + public void recycleSocket(CheckedSocket socket) + throws SocketException, IllegalArgumentException + { + if (socket != null) { + if (socket instanceof PooledSocket) { + PooledSocket psock = (PooledSocket)socket; + + if (psock.getOwner() == this) { + psock.removeExceptionListener(mListener); + Socket s = psock.recycle(); + if (s != null) { + mPool.push(s); + } + return; + } + } + + throw new IllegalArgumentException + ("Socket did not originate from this pool"); + } + } + + public void clear() { + synchronized (mPool) { + while (mPool.size() > 0) { + try { + ((Socket)mPool.pop()).close(); + } + catch (IOException e) { + } + } + } + } + + public int getAvailableCount() { + return mPool.size(); + } + + /** + * This class does two things. First, it supports virtual socket closure. + * After a socket is put back into the pool, it can't be used again, but + * the internal socket is still open. + * + * This class also tracks exceptions checks if this socket can be recycled. + */ + private class PooledSocket extends CheckedSocket { + private InputStream mIn; + private OutputStream mOut; + private boolean mClosed; + + public PooledSocket(Socket s) throws SocketException { + super(s); + addExceptionListener(mListener); + } + + public synchronized InputStream getInputStream() throws IOException { + if (mIn != null) { + return mIn; + } + + final InputStream mStream = super.getInputStream(); + + mIn = new InputStream() { + public int read() throws IOException { + check(); + return mStream.read(); + } + + public int read(byte[] b) throws IOException { + check(); + return mStream.read(b); + } + + public int read(byte[] b, int off, int len) throws IOException{ + check(); + return mStream.read(b, off, len); + } + + public long skip(long n) throws IOException { + check(); + return mStream.skip(n); + } + + public int available() throws IOException { + check(); + return mStream.available(); + } + + public void close() throws IOException { + if (doClose()) { + mStream.close(); + } + } + + public void mark(int readlimit) { + mStream.mark(readlimit); + } + + public void reset() throws IOException { + check(); + mStream.reset(); + } + + public boolean markSupported() { + return mStream.markSupported(); + } + }; + + return mIn; + } + + public synchronized OutputStream getOutputStream() throws IOException { + if (mOut != null) { + return mOut; + } + + final OutputStream mStream = super.getOutputStream(); + + mOut = new OutputStream() { + public void write(int b) throws IOException { + check(); + mStream.write(b); + } + + public void write(byte[] b) throws IOException { + check(); + mStream.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException { + check(); + mStream.write(b, off, len); + } + + public void flush() throws IOException { + check(); + mStream.flush(); + } + + public void close() throws IOException { + if (doClose()){ + mStream.close(); + } + } + }; + + return mOut; + } + + public void setTcpNoDelay(boolean on) throws SocketException { + check(); + super.setTcpNoDelay(on); + } + + public boolean getTcpNoDelay() throws SocketException { + check(); + return super.getTcpNoDelay(); + } + + public void setSoLinger(boolean on, int linger) throws SocketException { + check(); + super.setSoLinger(on, linger); + } + + public int getSoLinger() throws SocketException { + check(); + return super.getSoLinger(); + } + + public void setSoTimeout(int timeout) throws SocketException { + check(); + super.setSoTimeout(timeout); + } + + public int getSoTimeout() throws SocketException { + check(); + return super.getSoTimeout(); + } + + public void setSendBufferSize(int size) throws SocketException { + check(); + super.setSendBufferSize(size); + } + + public int getSendBufferSize() throws SocketException { + check(); + return super.getSendBufferSize(); + } + + public void setReceiveBufferSize(int size) throws SocketException { + check(); + super.setReceiveBufferSize(size); + } + + public int getReceiveBufferSize() throws SocketException { + check(); + return super.getReceiveBufferSize(); + } + + public void close() throws IOException { + if (doClose()) { + super.close(); + } + } + + SocketFactory getOwner() { + return PooledSocketFactory.this; + } + + Socket recycle() throws SocketException { + if (mClosed) { + return null; + } + else if (getExceptionCount() != 0) { + try { + close(); + } + catch (IOException e) { + throw new SocketException(e.getMessage()); + } + return null; + } + else { + mClosed = true; + return mSocket; + } + } + + boolean doClose() { + return (mClosed) ? false : (mClosed = true); + } + + void check() throws SocketException { + if (mClosed) { + throw new SocketException("Socket closed"); + } + } + } +}