1 52 53 package com.go.trove.net; 54 55 import java.net.*; 56 import java.io.*; 57 58 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 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 bind(InetAddress host, int port) throws IOException { 396 error(); 397 } 398 399 protected void listen(int backlog) throws IOException { 400 error(); 401 } 402 403 protected void accept(SocketImpl s) throws IOException { 404 error(); 405 } 406 407 private void error() throws IOException { 408 throw new IOException("Unsupported operation"); 409 } 410 411 private class In extends InputStream { 412 private InputStream mStream; 413 414 public int read() throws IOException { 415 return getStream().read(); 416 } 417 418 public int read(byte[] b) throws IOException { 419 return getStream().read(b); 420 } 421 422 public int read(byte[] b, int off, int len) throws IOException { 423 return getStream().read(b, off, len); 424 } 425 426 public long skip(long n) throws IOException { 427 return getStream().skip(n); 428 } 429 430 public int available() throws IOException { 431 return getStream().available(); 432 } 433 434 public void close() throws IOException { 435 if (mStream != null) { 436 mStream.close(); 437 } 438 Impl.this.close(); 439 } 440 441 public void mark(int readlimit) { 442 try { 443 getStream().mark(readlimit); 444 } 445 catch (IOException e) { 446 } 447 } 448 449 public void reset() throws IOException { 450 if (mStream == null) { 451 throw new IOException("Stream not marked"); 452 } 453 else { 454 mStream.reset(); 455 } 456 } 457 458 public boolean markSupported() { 459 try { 460 return getStream().markSupported(); 461 } 462 catch (IOException e) { 463 return false; 464 } 465 } 466 467 private InputStream getStream() throws IOException { 468 if (mStream == null) { 469 mStream = createSocket().getInputStream(); 470 } 471 return mStream; 472 } 473 } 474 475 private class Out extends OutputStream { 476 private OutputStream mStream; 477 478 public void write(int b) throws IOException { 479 write(new byte[] {(byte)b}, 0, 1); 480 } 481 482 public void write(byte[] b) throws IOException { 483 write(b, 0, b.length); 484 } 485 486 public void write(byte[] b, int off, int len) throws IOException { 487 if (mStream == null) { 488 mStream = getSocket(b, off, len).getOutputStream(); 489 } 490 else { 491 mStream.write(b, off, len); 492 } 493 } 494 495 public void flush() throws IOException { 496 if (mStream != null) { 497 mStream.flush(); 498 } 499 } 500 501 public void close() throws IOException { 502 if (mStream != null) { 503 mStream.close(); 504 } 505 Impl.this.close(); 506 } 507 } 508 } 509 } 510 | Popular Tags |