comparison src/com/go/trove/net/LazySocket.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.net.*;
56 import java.io.*;
57
58 /******************************************************************************
59 * A socket implementation that lazily establishs a connection. It only
60 * connects when actually needed. Setting options and getting I/O streams will
61 * not force a connection to be established. As soon as a read or write
62 * operation is performed, a connection is established.
63 * <p>
64 * If the first write operation requires a connection to be established, then a
65 * recycled connection is requested. The connection is tested by writing the
66 * data to it. If this fails, a new connection is requested and the operation
67 * is tried again.
68 *
69 * @author Brian S O'Neill
70 * @version
71 * <!--$$Revision: 1.1 $-->, <!--$$JustDate:--> 00/12/05 <!-- $-->
72 */
73 class LazySocket extends Socket {
74 private final Impl mImpl;
75
76 public LazySocket(SocketFactory factory) throws SocketException {
77 this(factory, null, factory.getDefaultTimeout());
78 }
79
80 public LazySocket(SocketFactory factory, Object session)
81 throws SocketException
82 {
83 this(factory, session, factory.getDefaultTimeout());
84 }
85
86 public LazySocket(SocketFactory factory, long timeout)
87 throws SocketException
88 {
89 this(factory, null, timeout);
90 }
91
92 public LazySocket(SocketFactory factory, Object session, long timeout)
93 throws SocketException
94 {
95 this(new Impl(factory, session, timeout));
96 }
97
98 private LazySocket(Impl impl) throws SocketException {
99 super(impl);
100 mImpl = impl;
101 }
102
103 /**
104 * Returns the internal wrapped socket or null if not connected. After
105 * calling recycle, this LazySocket instance is closed.
106 */
107 CheckedSocket recycle() {
108 CheckedSocket s;
109 if (mImpl.mClosed) {
110 s = null;
111 }
112 else {
113 s = mImpl.mSocket;
114 mImpl.mSocket = null;
115 try {
116 mImpl.close();
117 }
118 catch (IOException e) {
119 }
120 }
121 return s;
122 }
123
124 private static class Impl extends SocketImpl {
125 private final SocketFactory mFactory;
126 private final Object mSession;
127 private final long mTimeout;
128
129 private boolean mClosed;
130 private CheckedSocket mSocket;
131
132 private Object[] mOptions;
133
134 private InputStream mIn;
135 private OutputStream mOut;
136
137 public Impl(SocketFactory factory, Object session, long timeout) {
138 mFactory = factory;
139 mSession = session;
140 mTimeout = timeout;
141 }
142
143 public void setOption(int optId, Object value) throws SocketException {
144 int optionIndex;
145
146 switch (optId) {
147 case TCP_NODELAY:
148 optionIndex = 0;
149 break;
150 case SO_LINGER:
151 optionIndex = 1;
152 break;
153 case SO_TIMEOUT:
154 optionIndex = 2;
155 break;
156 case SO_SNDBUF:
157 optionIndex = 3;
158 break;
159 case SO_RCVBUF:
160 optionIndex = 4;
161 break;
162 case SO_BINDADDR:
163 case SO_REUSEADDR:
164 case IP_MULTICAST_IF:
165 default:
166 throw new SocketException("Invalid option: " + optId);
167 }
168
169 if (mOptions == null) {
170 mOptions = new Object[5];
171 }
172
173 mOptions[optionIndex] = value;
174
175 if (mSocket == null) {
176 return;
177 }
178
179 switch (optId) {
180 case TCP_NODELAY:
181 mSocket.setTcpNoDelay(((Boolean)value).booleanValue());
182 break;
183 case SO_LINGER:
184 if (value instanceof Boolean) {
185 mSocket.setSoLinger(((Boolean)value).booleanValue(), 0);
186 }
187 else {
188 mSocket.setSoLinger(true, ((Integer)value).intValue());
189 }
190 break;
191 case SO_TIMEOUT:
192 mSocket.setSoTimeout(((Integer)value).intValue());
193 break;
194 case SO_SNDBUF:
195 mSocket.setSendBufferSize(((Integer)value).intValue());
196 break;
197 case SO_RCVBUF:
198 mSocket.setReceiveBufferSize(((Integer)value).intValue());
199 break;
200 }
201 }
202
203 public Object getOption(int optId) throws SocketException {
204 Socket socket = createSocket();
205
206 switch (optId) {
207 case TCP_NODELAY:
208 return socket.getTcpNoDelay() ? Boolean.TRUE : Boolean.FALSE;
209 case SO_BINDADDR:
210 return socket.getLocalAddress();
211 case SO_LINGER:
212 return new Integer(socket.getSoLinger());
213 case SO_TIMEOUT:
214 return new Integer(socket.getSoTimeout());
215 case SO_SNDBUF:
216 return new Integer(socket.getSendBufferSize());
217 case SO_RCVBUF:
218 return new Integer(socket.getReceiveBufferSize());
219 case SO_REUSEADDR:
220 case IP_MULTICAST_IF:
221 default:
222 throw new SocketException("Invalid option: " + optId);
223 }
224 }
225
226 protected InputStream getInputStream() throws IOException {
227 if (mIn == null) {
228 mIn = new In();
229 }
230 return mIn;
231 }
232
233 protected OutputStream getOutputStream() throws IOException {
234 if (mOut == null) {
235 mOut = new Out();
236 }
237 return mOut;
238 }
239
240 protected int available() throws IOException {
241 return getInputStream().available();
242 }
243
244 protected void close() throws IOException {
245 if (!mClosed) {
246 mClosed = true;
247 if (mSocket != null) {
248 mSocket.close();
249 }
250 }
251 }
252
253 protected InetAddress getInetAddress() {
254 if (mSocket != null) {
255 return mSocket.getInetAddress();
256 }
257 else {
258 return mFactory.getInetAddressAndPort(mSession).getInetAddress();
259 }
260 }
261
262 protected int getPort() {
263 if (mSocket != null) {
264 return mSocket.getPort();
265 }
266 else {
267 return mFactory.getInetAddressAndPort(mSession).getPort();
268 }
269 }
270
271 protected int getLocalPort() {
272 if (mSocket != null) {
273 return mSocket.getLocalPort();
274 }
275 else {
276 return -1;
277 }
278 }
279
280 Socket createSocket() throws SocketException {
281 if (mSocket != null) {
282 return mSocket;
283 }
284
285 if (mClosed) {
286 throw new SocketException("Socket is closed");
287 }
288
289 mSocket = mFactory.createSocket(mSession, mTimeout);
290 applyOptions();
291
292 return mSocket;
293 }
294
295 Socket getSocket(byte[] data, int off, int len)
296 throws SocketException
297 {
298 if (mSocket != null) {
299 return mSocket;
300 }
301
302 if (mClosed) {
303 throw new SocketException("Socket is closed");
304 }
305
306 long timeout = mTimeout;
307 long start;
308 if (timeout > 0) {
309 start = System.currentTimeMillis();
310 }
311 else {
312 start = 0;
313 }
314
315 try {
316 mSocket = mFactory.getSocket(mSession, timeout);
317 applyOptions();
318 OutputStream out = mSocket.getOutputStream();
319 out.write(data, off, len);
320 out.flush();
321 }
322 catch (Exception e) {
323 if (mSocket != null) {
324 try {
325 mSocket.close();
326 }
327 catch (Exception e2) {
328 }
329 }
330
331 if (timeout > 0) {
332 timeout = timeout - (System.currentTimeMillis() - start);
333 if (timeout < 0) {
334 timeout = 0;
335 }
336 }
337
338 mSocket = mFactory.createSocket(mSession, timeout);
339 applyOptions();
340 try {
341 OutputStream out = mSocket.getOutputStream();
342 out.write(data, off, len);
343 out.flush();
344 }
345 catch (IOException e2) {
346 throw new SocketException(e2.getMessage());
347 }
348 }
349
350 return mSocket;
351 }
352
353 private void applyOptions() throws SocketException {
354 if (mOptions == null || mSocket == null) {
355 return;
356 }
357
358 Object[] options = mOptions;
359 Object value;
360
361 if ((value = options[0]) != null) {
362 mSocket.setTcpNoDelay(((Boolean)value).booleanValue());
363 }
364 if ((value = options[1]) != null) {
365 if (value instanceof Boolean) {
366 mSocket.setSoLinger(((Boolean)value).booleanValue(), 0);
367 }
368 else {
369 mSocket.setSoLinger(true, ((Integer)value).intValue());
370 }
371 }
372 if ((value = options[2]) != null) {
373 mSocket.setSoTimeout(((Integer)value).intValue());
374 }
375 if ((value = options[3]) != null) {
376 mSocket.setSendBufferSize(((Integer)value).intValue());
377 }
378 if ((value = options[4]) != null) {
379 mSocket.setReceiveBufferSize(((Integer)value).intValue());
380 }
381 }
382
383 protected void create(boolean stream) throws IOException {
384 error();
385 }
386
387 protected void connect(String host, int port) throws IOException {
388 error();
389 }
390
391 protected void connect(InetAddress host, int port) throws IOException {
392 error();
393 }
394
395 protected void connect(SocketAddress host,
396 int port) throws IOException {
397 error();
398 }
399
400 protected void bind(InetAddress host, int port) throws IOException {
401 error();
402 }
403
404 protected void listen(int backlog) throws IOException {
405 error();
406 }
407
408 protected void accept(SocketImpl s) throws IOException {
409 error();
410 }
411
412 protected void sendUrgentData(int aByte) throws IOException {
413 throw new UnsupportedOperationException();
414 }
415
416 private void error() throws IOException {
417 throw new IOException("Unsupported operation");
418 }
419
420 private class In extends InputStream {
421 private InputStream mStream;
422
423 public int read() throws IOException {
424 return getStream().read();
425 }
426
427 public int read(byte[] b) throws IOException {
428 return getStream().read(b);
429 }
430
431 public int read(byte[] b, int off, int len) throws IOException {
432 return getStream().read(b, off, len);
433 }
434
435 public long skip(long n) throws IOException {
436 return getStream().skip(n);
437 }
438
439 public int available() throws IOException {
440 return getStream().available();
441 }
442
443 public void close() throws IOException {
444 if (mStream != null) {
445 mStream.close();
446 }
447 Impl.this.close();
448 }
449
450 public void mark(int readlimit) {
451 try {
452 getStream().mark(readlimit);
453 }
454 catch (IOException e) {
455 }
456 }
457
458 public void reset() throws IOException {
459 if (mStream == null) {
460 throw new IOException("Stream not marked");
461 }
462 else {
463 mStream.reset();
464 }
465 }
466
467 public boolean markSupported() {
468 try {
469 return getStream().markSupported();
470 }
471 catch (IOException e) {
472 return false;
473 }
474 }
475
476 private InputStream getStream() throws IOException {
477 if (mStream == null) {
478 mStream = createSocket().getInputStream();
479 }
480 return mStream;
481 }
482 }
483
484 private class Out extends OutputStream {
485 private OutputStream mStream;
486
487 public void write(int b) throws IOException {
488 write(new byte[] {(byte)b}, 0, 1);
489 }
490
491 public void write(byte[] b) throws IOException {
492 write(b, 0, b.length);
493 }
494
495 public void write(byte[] b, int off, int len) throws IOException {
496 if (mStream == null) {
497 mStream = getSocket(b, off, len).getOutputStream();
498 }
499 else {
500 mStream.write(b, off, len);
501 }
502 }
503
504 public void flush() throws IOException {
505 if (mStream != null) {
506 mStream.flush();
507 }
508 }
509
510 public void close() throws IOException {
511 if (mStream != null) {
512 mStream.close();
513 }
514 Impl.this.close();
515 }
516 }
517 }
518 }