comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:3dc0c5604566
1 /* ====================================================================
2 * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3 * ====================================================================
4 * The Tea Software License, Version 1.1
5 *
6 * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in
17 * the documentation and/or other materials provided with the
18 * distribution.
19 *
20 * 3. The end-user documentation included with the redistribution,
21 * if any, must include the following acknowledgment:
22 * "This product includes software developed by the
23 * Walt Disney Internet Group (http://opensource.go.com/)."
24 * Alternately, this acknowledgment may appear in the software itself,
25 * if and wherever such third-party acknowledgments normally appear.
26 *
27 * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28 * not be used to endorse or promote products derived from this
29 * software without prior written permission. For written
30 * permission, please contact opensource@dig.com.
31 *
32 * 5. Products derived from this software may not be called "Tea",
33 * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34 * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35 * written permission of the Walt Disney Internet Group.
36 *
37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40 * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * For more information about Tea, please see http://opensource.go.com/.
51 */
52
53 package com.go.trove.net;
54
55 import java.io.*;
56 import java.net.*;
57 import java.util.*;
58
59 /******************************************************************************
60 * Socket factory implementation that pools connections to one wrapped socket
61 * factory. Sessions are ignored on all requests. Consider wrapping with a
62 * {@link LazySocketFactory} for automatic checking against pooled connections
63 * that may have been closed.
64 *
65 * @author Brian S O'Neill
66 * @version
67 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/05 <!-- $-->
68 */
69 public class PooledSocketFactory implements SocketFactory {
70 private final SocketFactory mFactory;
71 private final long mTimeout;
72
73 // Stack of Sockets.
74 private final Stack mPool = new Stack();
75
76 private CheckedSocket.ExceptionListener mListener;
77
78 public PooledSocketFactory(SocketFactory factory) {
79 this(factory, factory.getDefaultTimeout());
80 }
81
82 public PooledSocketFactory(SocketFactory factory, long timeout) {
83 mFactory = factory;
84 mTimeout = timeout;
85
86 mListener = new CheckedSocket.ExceptionListener() {
87 public void exceptionOccurred(CheckedSocket s,
88 Exception e, int count) {
89 // Only act on the first exception.
90 if (count == 1) {
91 // Assume all the pooled connections are bad, so ditch 'em.
92 clear();
93 }
94 }
95 };
96 }
97
98 public InetAddressAndPort getInetAddressAndPort() {
99 return mFactory.getInetAddressAndPort();
100 }
101
102 public InetAddressAndPort getInetAddressAndPort(Object session) {
103 return mFactory.getInetAddressAndPort();
104 }
105
106 public long getDefaultTimeout() {
107 return mTimeout;
108 }
109
110 public CheckedSocket createSocket()
111 throws ConnectException, SocketException
112 {
113 return createSocket(null, mTimeout);
114 }
115
116 public CheckedSocket createSocket(Object session)
117 throws ConnectException, SocketException
118 {
119 return createSocket(mTimeout);
120 }
121
122 public CheckedSocket createSocket(long timeout)
123 throws ConnectException, SocketException
124 {
125 return new PooledSocket(mFactory.createSocket(timeout));
126 }
127
128 public CheckedSocket createSocket(Object session, long timeout)
129 throws ConnectException, SocketException
130 {
131 return createSocket(timeout);
132 }
133
134 public CheckedSocket getSocket()
135 throws ConnectException, SocketException
136 {
137 return getSocket(mTimeout);
138 }
139
140 public CheckedSocket getSocket(Object session)
141 throws ConnectException, SocketException
142 {
143 return getSocket(mTimeout);
144 }
145
146 public CheckedSocket getSocket(long timeout)
147 throws ConnectException, SocketException
148 {
149 synchronized (mPool) {
150 if (mPool.size() > 0) {
151 return new PooledSocket((Socket)mPool.pop());
152 }
153 }
154
155 return new PooledSocket(mFactory.createSocket(timeout));
156 }
157
158 public CheckedSocket getSocket(Object session, long timeout)
159 throws ConnectException, SocketException
160 {
161 return getSocket(timeout);
162 }
163
164 public void recycleSocket(CheckedSocket socket)
165 throws SocketException, IllegalArgumentException
166 {
167 if (socket != null) {
168 if (socket instanceof PooledSocket) {
169 PooledSocket psock = (PooledSocket)socket;
170
171 if (psock.getOwner() == this) {
172 psock.removeExceptionListener(mListener);
173 Socket s = psock.recycle();
174 if (s != null) {
175 mPool.push(s);
176 }
177 return;
178 }
179 }
180
181 throw new IllegalArgumentException
182 ("Socket did not originate from this pool");
183 }
184 }
185
186 public void clear() {
187 synchronized (mPool) {
188 while (mPool.size() > 0) {
189 try {
190 ((Socket)mPool.pop()).close();
191 }
192 catch (IOException e) {
193 }
194 }
195 }
196 }
197
198 public int getAvailableCount() {
199 return mPool.size();
200 }
201
202 /**
203 * This class does two things. First, it supports virtual socket closure.
204 * After a socket is put back into the pool, it can't be used again, but
205 * the internal socket is still open.
206 *
207 * This class also tracks exceptions checks if this socket can be recycled.
208 */
209 private class PooledSocket extends CheckedSocket {
210 private InputStream mIn;
211 private OutputStream mOut;
212 private boolean mClosed;
213
214 public PooledSocket(Socket s) throws SocketException {
215 super(s);
216 addExceptionListener(mListener);
217 }
218
219 public synchronized InputStream getInputStream() throws IOException {
220 if (mIn != null) {
221 return mIn;
222 }
223
224 final InputStream mStream = super.getInputStream();
225
226 mIn = new InputStream() {
227 public int read() throws IOException {
228 check();
229 return mStream.read();
230 }
231
232 public int read(byte[] b) throws IOException {
233 check();
234 return mStream.read(b);
235 }
236
237 public int read(byte[] b, int off, int len) throws IOException{
238 check();
239 return mStream.read(b, off, len);
240 }
241
242 public long skip(long n) throws IOException {
243 check();
244 return mStream.skip(n);
245 }
246
247 public int available() throws IOException {
248 check();
249 return mStream.available();
250 }
251
252 public void close() throws IOException {
253 if (doClose()) {
254 mStream.close();
255 }
256 }
257
258 public void mark(int readlimit) {
259 mStream.mark(readlimit);
260 }
261
262 public void reset() throws IOException {
263 check();
264 mStream.reset();
265 }
266
267 public boolean markSupported() {
268 return mStream.markSupported();
269 }
270 };
271
272 return mIn;
273 }
274
275 public synchronized OutputStream getOutputStream() throws IOException {
276 if (mOut != null) {
277 return mOut;
278 }
279
280 final OutputStream mStream = super.getOutputStream();
281
282 mOut = new OutputStream() {
283 public void write(int b) throws IOException {
284 check();
285 mStream.write(b);
286 }
287
288 public void write(byte[] b) throws IOException {
289 check();
290 mStream.write(b);
291 }
292
293 public void write(byte[] b, int off, int len) throws IOException {
294 check();
295 mStream.write(b, off, len);
296 }
297
298 public void flush() throws IOException {
299 check();
300 mStream.flush();
301 }
302
303 public void close() throws IOException {
304 if (doClose()){
305 mStream.close();
306 }
307 }
308 };
309
310 return mOut;
311 }
312
313 public void setTcpNoDelay(boolean on) throws SocketException {
314 check();
315 super.setTcpNoDelay(on);
316 }
317
318 public boolean getTcpNoDelay() throws SocketException {
319 check();
320 return super.getTcpNoDelay();
321 }
322
323 public void setSoLinger(boolean on, int linger) throws SocketException {
324 check();
325 super.setSoLinger(on, linger);
326 }
327
328 public int getSoLinger() throws SocketException {
329 check();
330 return super.getSoLinger();
331 }
332
333 public void setSoTimeout(int timeout) throws SocketException {
334 check();
335 super.setSoTimeout(timeout);
336 }
337
338 public int getSoTimeout() throws SocketException {
339 check();
340 return super.getSoTimeout();
341 }
342
343 public void setSendBufferSize(int size) throws SocketException {
344 check();
345 super.setSendBufferSize(size);
346 }
347
348 public int getSendBufferSize() throws SocketException {
349 check();
350 return super.getSendBufferSize();
351 }
352
353 public void setReceiveBufferSize(int size) throws SocketException {
354 check();
355 super.setReceiveBufferSize(size);
356 }
357
358 public int getReceiveBufferSize() throws SocketException {
359 check();
360 return super.getReceiveBufferSize();
361 }
362
363 public void close() throws IOException {
364 if (doClose()) {
365 super.close();
366 }
367 }
368
369 SocketFactory getOwner() {
370 return PooledSocketFactory.this;
371 }
372
373 Socket recycle() throws SocketException {
374 if (mClosed) {
375 return null;
376 }
377 else if (getExceptionCount() != 0) {
378 try {
379 close();
380 }
381 catch (IOException e) {
382 throw new SocketException(e.getMessage());
383 }
384 return null;
385 }
386 else {
387 mClosed = true;
388 return mSocket;
389 }
390 }
391
392 boolean doClose() {
393 return (mClosed) ? false : (mClosed = true);
394 }
395
396 void check() throws SocketException {
397 if (mClosed) {
398 throw new SocketException("Socket closed");
399 }
400 }
401 }
402 }