1 52 53 package com.go.trove.net; 54 55 import java.io.*; 56 import java.net.*; 57 import java.util.*; 58 import com.go.trove.util.*; 59 60 67 public class SocketConnector { 68 private static final int CONNECT_THREAD_MAX = 5; 71 72 private static Map mConnectors = 74 Collections.synchronizedMap(new SoftHashMap()); 75 76 81 public static Socket connect(String host, int port, long timeout) 82 throws SocketException 83 { 84 return connect((Object )host, port, timeout); 85 } 86 87 88 93 public static Socket connect(InetAddress address, int port, long timeout) 94 throws SocketException 95 { 96 return connect((Object )address, port, timeout); 97 } 98 99 105 private static Socket connect(Object address, int port, long timeout) 106 throws SocketException 107 { 108 Key key = new Key(address, port); 109 ThreadPool pool; 110 synchronized (mConnectors) { 111 pool = (ThreadPool)mConnectors.get(key); 112 if (pool == null) { 113 pool = new ThreadPool 114 ("SocketConnector[" + key + ']', CONNECT_THREAD_MAX); 115 pool.setIdleTimeout(10000); 116 mConnectors.put(key, pool); 117 } 118 } 119 120 Connector connector = new Connector(key); 121 Thread thread; 122 123 long start; 124 if (timeout > 0) { 125 start = System.currentTimeMillis(); 126 } 127 else { 128 start = 0; 129 } 130 131 try { 132 thread = pool.start(connector, timeout); 133 } 134 catch (InterruptedException e) { 135 return null; 136 } 137 138 if (timeout > 0) { 139 timeout = timeout - (System.currentTimeMillis() - start); 140 if (timeout < 0) { 141 timeout = 0; 142 } 143 } 144 145 try { 146 Socket socket = connector.connect(timeout); 147 if (socket != null) { 148 return socket; 149 } 150 } 151 catch (InterruptedException e) { 152 } 153 154 thread.interrupt(); 155 return null; 156 } 157 158 private SocketConnector() { 159 } 160 161 private static class Key { 162 final Object mAddress; 163 final int mPort; 164 165 Key(Object address, int port) { 166 mAddress = address; 167 mPort = port; 168 } 169 170 public boolean equals(Object obj) { 171 if (obj instanceof Key) { 172 Key key = (Key)obj; 173 return key.mAddress.equals(mAddress) && key.mPort == mPort; 174 } 175 return false; 176 } 177 178 public int hashCode() { 179 return mAddress.hashCode() + mPort; 180 } 181 182 public String toString() { 183 if (mAddress instanceof InetAddress) { 184 return ((InetAddress)mAddress).getHostAddress() + ':' + mPort; 185 } 186 else { 187 return String.valueOf(mAddress) + ':' + mPort; 188 } 189 } 190 } 191 192 private static class Connector implements Runnable { 193 private final Key mKey; 194 private Object mSocketOrException; 195 private boolean mDoneWaiting; 196 197 public Connector(Key key) { 198 mKey = key; 199 } 200 201 public synchronized Socket connect(long timeout) 202 throws SocketException, InterruptedException 203 { 204 try { 205 if (mSocketOrException == null) { 206 if (timeout < 0) { 207 wait(); 208 } 209 else if (timeout > 0) { 210 wait(timeout); 211 } 212 else { 213 return null; 214 } 215 } 216 } 217 finally { 218 mDoneWaiting = true; 219 } 220 221 if (mSocketOrException instanceof Socket) { 222 return (Socket)mSocketOrException; 223 } 224 else if (mSocketOrException instanceof InterruptedIOException) { 225 throw new InterruptedException (); 226 } 227 else if (mSocketOrException instanceof Exception ) { 228 throw new SocketException 229 ("Unable to connect to " + mKey + ", " + 230 ((Exception )mSocketOrException).getMessage()); 231 } 232 233 return null; 234 } 235 236 public void run() { 237 try { 238 Socket socket; 239 Object address = mKey.mAddress; 240 if (address instanceof InetAddress) { 241 socket = new Socket((InetAddress)address, mKey.mPort); 242 } 243 else { 244 socket = new Socket(String.valueOf(address), mKey.mPort); 245 } 246 247 synchronized (this) { 248 if (mDoneWaiting) { 249 try { 250 socket.close(); 251 } 252 catch (IOException e) { 253 } 254 } 255 else { 256 mSocketOrException = socket; 257 notify(); 258 } 259 } 260 } 261 catch (Exception e) { 262 synchronized (this) { 263 mSocketOrException = e; 264 notify(); 265 } 266 } 267 } 268 } 269 } 270 | Popular Tags |