1 18 package org.objectweb.perseus.pool.lib; 19 20 import org.objectweb.perseus.pool.api.Pool; 21 import org.objectweb.perseus.pool.api.PoolAttributes; 22 import org.objectweb.perseus.pool.api.PoolMatchFactory; 23 import org.objectweb.perseus.pool.api.PoolException; 24 import org.objectweb.perseus.dependency.api.DependencyGraph; 25 import org.objectweb.perseus.dependency.api.DeadLockException; 26 import org.objectweb.fractal.api.control.BindingController; 27 import org.objectweb.util.monolog.api.Logger; 28 import org.objectweb.util.monolog.api.BasicLevel; 29 30 import java.util.Collection ; 31 import java.util.Collections ; 32 import java.util.HashMap ; 33 import java.util.List ; 34 import java.util.ArrayList ; 35 import java.util.Calendar ; 36 37 49 public class ArrayListPool 50 implements Pool, PoolAttributes, BindingController { 51 52 public final static String POOL_MATCH_FACTORY_BINDING = "pool-match-factory"; 53 public final static String DEPENDENCY_GRAPH_BINDING = "dependency-graph"; 54 55 58 public final static int UNLIMITED = -1; 59 60 63 public final static int DEFAULT_MIN_SIZE = 0; 64 65 68 public final static int DEFAULT_MAX_SIZE = UNLIMITED; 69 70 73 public final static int DEFAULT_TIME_OUT = 300; 74 75 private PoolMatchFactory matchFactory = null; 76 private long freettl = 0; 77 private long ttl = 0; 78 private long timeOut = DEFAULT_TIME_OUT; 79 private int minSize = DEFAULT_MIN_SIZE; 80 private int maxSize = DEFAULT_MAX_SIZE; 81 private List free = new ArrayList (); 82 private List timesOfFree = new ArrayList (); 83 private HashMap res2ttl = new HashMap (); 84 private List used = new ArrayList (); 85 private List users = new ArrayList (); 86 private boolean started = false; 87 private Logger logger = null; 88 private DependencyGraph dg = null; 89 90 91 94 private void cleanExpiredResource() { 95 long time = 0; 96 if (freettl > 0 || ttl > 0) { 97 time = Calendar.getInstance().getTimeInMillis(); 98 for(int i=0; i<free.size();) { 99 boolean remove = false; Object resource = free.get(i); 101 if (freettl > 0) { 102 Long l = (Long ) timesOfFree.get(i); 103 if (l == null) { 104 throw new IllegalThreadStateException ("The resource '" + resource + "' has no inactivettl !"); 105 } 106 remove = (time - l.longValue()) > freettl; 107 if (remove && logger != null && logger.isLoggable(BasicLevel.INFO)) { 108 logger.log(BasicLevel.INFO, "Resource is being destroyed (too long time unused): '" + resource + "'."); 109 } 110 } 111 if (!remove && ttl > 0) { 112 Long l = (Long ) res2ttl.get(resource); 114 if (l == null) { 115 throw new IllegalThreadStateException ("The resource '" + resource + "' has no ttl !"); 116 } 117 remove = (time - l.longValue()) > ttl; 118 if (remove && logger != null && logger.isLoggable(BasicLevel.INFO)) { 119 logger.log(BasicLevel.INFO, "Resource is being destroyed (too old): '" + resource + "'."); 120 } 121 } 122 if (remove) { 123 free.remove(i); 125 if (freettl > 0) { 126 timesOfFree.remove(i); 127 } 128 if (ttl>0) { 129 res2ttl.remove(resource); 130 } 131 matchFactory.destroyResource(resource); 132 } else { 133 i++; 134 } 135 } 136 } 137 } 138 139 private void updateToMinsize(Object hints) throws PoolException { 140 cleanExpiredResource(); 141 int delta = minSize - free.size() - used.size(); 142 if (matchFactory != null && delta>0) { 143 for(int i=0; i<delta; i++) { 144 Object resource = createResource(hints); 145 free.add(resource); 146 if (freettl > 0) { 147 timesOfFree.add(new Long (Calendar.getInstance().getTimeInMillis())); 148 } 149 150 } 151 } 152 } 153 154 private Object createResource(Object hints) throws PoolException { 155 Object resource = matchFactory.createResource(hints); 156 if (resource == null) { 157 if (started) { 158 throw new PoolException("The pool resource factory does not create a new resource with the hints: " + hints); 159 } else if (logger != null) { 160 logger.log(BasicLevel.WARN, "The pool resource factory does not create a new resource with the hints: " + hints); 161 } 162 } else { 163 long t = 0; 164 if (ttl > 0) { 165 t = Calendar.getInstance().getTimeInMillis(); 166 res2ttl.put(resource, new Long (t)); 167 } 168 if (logger != null && logger.isLoggable(BasicLevel.INFO)) { 169 logger.log(BasicLevel.INFO, "Resource created" 170 + (t == 0 ? "" : " (born:" + t + ")") 171 + ": '" + resource + "'."); 172 } 173 } 174 return resource; 175 } 176 177 private void updateToMaxsize() { 178 cleanExpiredResource(); 179 if (maxSize != UNLIMITED) { 180 int delta = free.size() + used.size() - maxSize; 181 if (delta > 0) { 183 for (int i = 0; i < delta && !free.isEmpty(); i++) { 184 int j = free.size() - 1; 185 Object resource = free.remove(j); 186 if (freettl > 0) { 187 timesOfFree.remove(j); 188 } 189 if (logger != null && logger.isLoggable(BasicLevel.INFO)) { 190 logger.log(BasicLevel.INFO, "Resource destroyed: '" + resource + "'."); 191 } 192 matchFactory.destroyResource(resource); 193 } 194 } 195 } 196 } 197 198 199 202 public String [] listFc() { 203 return new String [] { 204 POOL_MATCH_FACTORY_BINDING, DEPENDENCY_GRAPH_BINDING }; 205 } 206 207 public Object lookupFc(String clientItfName) { 208 if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) { 209 return matchFactory; 210 } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) { 211 return dg; 212 } else { 213 return null; 214 } 215 } 216 217 public void bindFc(String clientItfName, Object serverItf) { 218 if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) { 219 matchFactory = (PoolMatchFactory) serverItf; 220 try { 221 updateToMinsize(null); 222 } catch (Exception e) { 223 } 224 } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) { 225 dg = (DependencyGraph) serverItf; 226 } else if ("logger".equals(clientItfName)) { 227 logger = (Logger) serverItf; 228 } 229 } 230 231 public void unbindFc(String clientItfName) { 232 if (POOL_MATCH_FACTORY_BINDING.equals(clientItfName)) { 233 matchFactory = null; 234 } else if (DEPENDENCY_GRAPH_BINDING.equals(clientItfName)) { 235 dg = null; 236 } 237 } 238 239 240 243 251 public synchronized Object getResource(Object hints) throws PoolException { 252 try { 253 return getResource(hints, null); 254 } catch (DeadLockException e) { 255 throw new PoolException(e); 257 } 258 } 259 public synchronized Object getResource(Object hints, Object user) 260 throws PoolException, DeadLockException { 261 if (!started) { 262 started = true; 263 updateToMaxsize(); 264 } 265 if (maxSize != UNLIMITED && used.size() >= maxSize) { 267 if (timeOut != 0) { 268 int vertexIdx = 0; 269 try { 270 if (user != null && dg != null) { 272 int s = users.size(); 273 for(vertexIdx=0; vertexIdx<s; vertexIdx++) { 274 Object dst = users.get(vertexIdx); 275 if (dst != null) { 276 if (!dg.addVertex(user, dst)) { 277 throw new DeadLockException("Impossible to allocate a resource: no resource is availlable and a dead lock occurs if the current thread wait a resource"); 278 } 279 } 280 } 281 } 282 if (timeOut > 0) { 284 long to = timeOut; 285 while(maxSize != UNLIMITED && used.size() >= maxSize && to > 0) { 286 long exectime = System.currentTimeMillis(); 287 wait(timeOut); 288 exectime = System.currentTimeMillis() - exectime; 289 to -= exectime; 290 } 291 } else { 292 while (maxSize != UNLIMITED && used.size() >= maxSize) { 293 wait(); 294 } 295 } 296 } catch (InterruptedException e) { 297 throw new PoolException("Pool wait has been interrupted: ", e); 298 } finally { 299 if (user != null && dg != null) { 300 for(int i=0; i<vertexIdx; i++) { 301 Object dst = users.get(i); 302 if (dst != null) { 303 dg.removeVertex(user, dst); 304 } 305 } 306 } 307 } 308 if (maxSize != UNLIMITED && used.size() >= maxSize) { 309 throw new PoolException( 310 "No more resource available in pool, time out exceeded (" 311 + timeOut + ") ! (pool max size=" + maxSize + ")"); 312 } 313 } else { 314 throw new PoolException("No more resource available in pool (max=" 315 + maxSize + ")"); 316 } 317 } 318 updateToMinsize(hints); 319 320 Object resource = null; 322 int freesize = free.size() -1; 323 for (int i = freesize; resource == null && i >=0; i--) { 324 resource = free.get(i); 325 if (matchFactory.matchResource(resource, hints)) { 326 free.remove(i); 327 if (freettl > 0) { 328 timesOfFree.remove(i); 329 } 330 if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) { 331 logger.log(BasicLevel.DEBUG, "Resource reused: '" + resource + "'."); 332 } 333 } else { 334 resource = null; 335 } 336 } 337 338 if (resource == null) { 339 resource = createResource(hints); 341 } 342 343 used.add(resource); 344 if (dg != null) { 345 users.add(user); 349 if (user != null && logger != null && logger.isLoggable(BasicLevel.DEBUG)) { 350 logger.log(BasicLevel.DEBUG, "The user '" + user 351 + "' gets the resource '" + resource +"'."); 352 } 353 } 354 return resource; 355 } 356 357 public synchronized int getSize() { 358 return free.size() + used.size(); 359 } 360 361 public synchronized int getFreeResourceNumber() { 362 return free.size(); 363 } 364 public synchronized int getUsedResourceNumber() { 365 return used.size(); 366 } 367 public synchronized Collection getUsers() { 368 return Collections.unmodifiableCollection(users); 369 } 370 371 376 public synchronized void releaseResource(Object resource) throws PoolException { 377 boolean found = false; 379 for(int i=(used.size() -1); !found && i>=0; i--) { 380 if (resource == used.get(i)) { 381 found = true; 382 used.remove(i); 383 if (dg != null) { 384 Object user = users.remove(i); 385 if (logger != null && logger.isLoggable(BasicLevel.DEBUG)) { 386 if (user == null) { 387 logger.log(BasicLevel.DEBUG, "The resource '" 388 + resource +"' is released."); 389 } else { 390 logger.log(BasicLevel.DEBUG, "The user '" + user 391 + "' releases the resource '" + resource +"'."); 392 } 393 } 394 } 395 } 396 } 397 if (!found) { 398 throw new PoolException("Release an unused resource:" + resource); 399 } 400 boolean toremove = false; 401 boolean notify = true; 402 if (maxSize != UNLIMITED 403 && (free.size() + used.size()) > maxSize) { 404 toremove = true; 405 notify = false; 406 if (logger != null && logger.isLoggable(BasicLevel.INFO)) { 407 logger.log(BasicLevel.INFO, "Released resource is destroyed (too many resources in the pool): '" + resource + "'."); 408 } 409 } else { 410 if (ttl > 0) { 411 long t = Calendar.getInstance().getTimeInMillis(); 412 t -= ((Long ) res2ttl.get(resource)).longValue(); 413 if (t > ttl) { 414 if (logger != null && logger.isLoggable(BasicLevel.INFO)) { 415 logger.log(BasicLevel.INFO, "Released resource is being destroyed (too old): '" + resource + "'."); 416 } 417 toremove = true; 418 } 420 } 421 } 422 if (toremove) { 423 if (ttl>0) { 425 res2ttl.remove(resource); 426 } 427 matchFactory.destroyResource(resource); 428 } else { 429 free.add(resource); 431 if (freettl > 0) { 432 timesOfFree.add(new Long (Calendar.getInstance().getTimeInMillis())); 433 } 434 } 435 if (notify) { 436 notify(); 438 } 439 } 440 441 442 445 449 public long getTimeout() { 450 return timeOut; 451 } 452 453 457 public int getMinSize() { 458 return minSize; 459 } 460 461 465 public int getMaxSize() { 466 return maxSize; 467 } 468 469 473 public void setTimeout(long crto) { 474 timeOut = crto; 475 } 476 477 481 public void setMinSize(int minsize) throws Exception { 482 minSize = minsize; 483 if (started) { 484 updateToMinsize(null); 485 } 486 } 487 488 492 public void setMaxSize(int maxsize) throws Exception { 493 maxSize = maxsize; 494 if (started) { 495 updateToMaxsize(); 496 } 497 } 498 499 public long getTTL() { 500 return ttl; 501 } 502 503 public void setTTL(long ttl) { 504 this.ttl = ttl; 505 } 506 507 public long getInactiveTTL() { 508 return freettl; 509 } 510 511 public void setInactiveTTL(long fttl) { 512 this.freettl = fttl; 513 } 514 } 515 | Popular Tags |