1 30 31 34 package net.sf.jasperreports.engine.fill; 35 36 import java.io.IOException ; 37 import java.io.InputStream ; 38 import java.io.ObjectInputStream ; 39 import java.io.ObjectOutputStream ; 40 import java.io.OutputStream ; 41 import java.lang.ref.Reference ; 42 import java.lang.ref.ReferenceQueue ; 43 import java.lang.ref.WeakReference ; 44 import java.util.Iterator ; 45 import java.util.Map ; 46 import java.util.Map.Entry; 47 48 import net.sf.jasperreports.engine.JRConstants; 49 import net.sf.jasperreports.engine.JRRuntimeException; 50 import net.sf.jasperreports.engine.JRVirtualizable; 51 import net.sf.jasperreports.engine.JRVirtualizer; 52 53 import org.apache.commons.collections.LRUMap; 54 import org.apache.commons.collections.ReferenceMap; 55 import org.apache.commons.logging.Log; 56 import org.apache.commons.logging.LogFactory; 57 58 59 65 public abstract class JRAbstractLRUVirtualizer implements JRVirtualizer 66 { 67 private static final Log log = LogFactory.getLog(JRAbstractLRUVirtualizer.class); 68 69 protected static class CacheReference extends WeakReference 70 { 71 private final String id; 72 73 public CacheReference(JRVirtualizable o, ReferenceQueue queue) 74 { 75 super(o, queue); 76 id = o.getUID(); 77 } 78 79 public String getId() 80 { 81 return id; 82 } 83 } 84 85 89 protected class Cache 90 { 91 protected class LRUScanMap extends LRUMap 92 { 93 private static final long serialVersionUID = JRConstants.SERIAL_VERSION_UID; 94 95 public LRUScanMap(int maxSize) 96 { 97 super(maxSize); 98 } 99 100 protected void removeLRU() 101 { 102 Map.Entry entry = getFirst(); 103 boolean found = isRemovable(entry); 104 if (!found) 105 { 106 Iterator entriesIt = entrySet().iterator(); 107 entriesIt.next(); while(!found && entriesIt.hasNext()) 109 { 110 entry = (Entry) entriesIt.next(); 111 found = isRemovable(entry); 112 } 113 } 114 115 if (!found) 116 { 117 throw new JRRuntimeException("The virtualizer is used by more contexts than its in-memory cache size " + getMaximumSize()); 118 } 119 120 Object key = entry.getKey(); 121 Object value = entry.getValue(); 122 this.remove(key); 123 processRemovedLRU(key,value); 124 } 125 126 protected boolean isRemovable(Map.Entry entry) 127 { 128 JRVirtualizable value = getMapValue(entry.getValue()); 129 return value == null || !lastObjectSet.containsKey(value); 130 } 131 132 protected void processRemovedLRU(Object key, Object value) 133 { 134 JRVirtualizable o = getMapValue(value); 135 if (o != null) 136 { 137 virtualizeData(o); 138 } 139 } 140 } 141 142 private final ReferenceQueue refQueue; 143 private final LRUScanMap map; 144 145 Cache(int maxSize) 146 { 147 map = new LRUScanMap(maxSize); 148 refQueue = new ReferenceQueue (); 149 } 150 151 protected JRVirtualizable getMapValue(Object val) 152 { 153 JRVirtualizable o; 154 if (val == null) 155 { 156 o = null; 157 } 158 else 159 { 160 Reference ref = (Reference ) val; 161 if (ref.isEnqueued()) 162 { 163 o = null; 164 } 165 else 166 { 167 o = (JRVirtualizable) ref.get(); 168 } 169 } 170 return o; 171 } 172 173 protected Object toMapValue(JRVirtualizable val) 174 { 175 return val == null ? null : new CacheReference(val, refQueue); 176 } 177 178 protected void purge() 179 { 180 CacheReference ref; 181 while ((ref = (CacheReference) refQueue.poll()) != null) 182 { 183 map.remove(ref.getId()); 184 } 185 } 186 187 public JRVirtualizable get(String id) 188 { 189 purge(); 190 191 return getMapValue(map.get(id)); 192 } 193 194 public JRVirtualizable put(String id, JRVirtualizable o) 195 { 196 purge(); 197 198 return getMapValue(map.put(id, toMapValue(o))); 199 } 200 201 public JRVirtualizable remove(String id) 202 { 203 purge(); 204 205 return getMapValue(map.remove(id)); 206 } 207 208 public Iterator idIterator() 209 { 210 purge(); 211 212 final Iterator valsIt = map.values().iterator(); 213 return new Iterator () 214 { 215 public boolean hasNext() 216 { 217 return valsIt.hasNext(); 218 } 219 220 public Object next() 221 { 222 CacheReference ref = (CacheReference) valsIt.next(); 223 return ref.getId(); 224 } 225 226 public void remove() 227 { 228 valsIt.remove(); 229 } 230 }; 231 } 232 } 233 234 private final Cache pagedIn; 235 236 private final ReferenceMap pagedOut; 237 238 protected JRVirtualizable lastObject; 239 protected ReferenceMap lastObjectMap; 240 protected ReferenceMap lastObjectSet; 241 242 private boolean readOnly; 243 244 249 protected JRAbstractLRUVirtualizer(int maxSize) 250 { 251 this.pagedIn = new Cache(maxSize); 252 this.pagedOut = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.WEAK); 253 this.lastObject = null; 254 255 this.lastObjectMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.WEAK); 256 this.lastObjectSet = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD); 257 } 258 259 protected synchronized final boolean isPagedOut(String id) 260 { 261 return pagedOut.containsKey(id); 262 } 263 264 protected synchronized boolean isPagedOutAndTouch(JRVirtualizable o, String uid) 265 { 266 boolean virtualized = isPagedOut(uid); 267 if (!virtualized) 268 { 269 touch(o); 270 } 271 return virtualized; 272 } 273 274 protected final void setLastObject(JRVirtualizable o) 275 { 276 if (lastObject != o) 277 { 278 if (o != null) 279 { 280 JRVirtualizationContext context = o.getContext(); 281 Object ownerLast = lastObjectMap.get(context); 282 if (ownerLast != o) 283 { 284 if (ownerLast != null) 285 { 286 lastObjectSet.remove(ownerLast); 287 } 288 lastObjectMap.put(context, o); 289 lastObjectSet.put(o, Boolean.TRUE); 290 } 291 } 292 this.lastObject = o; 293 } 294 } 295 296 310 public void setReadOnly(boolean ro) 311 { 312 this.readOnly = ro; 313 } 314 315 316 322 public boolean isReadOnly() 323 { 324 return readOnly; 325 } 326 327 protected final boolean isReadOnly(JRVirtualizable o) 328 { 329 return readOnly || o.getContext().isReadOnly(); 330 } 331 332 public synchronized void registerObject(JRVirtualizable o) 333 { 334 setLastObject(o); 335 JRVirtualizable old = pagedIn.put(o.getUID(), o); 336 if (old != null) 337 { 338 pagedIn.put(o.getUID(), old); 339 throw new IllegalStateException ("Wrong object stored with UID \"" + o.getUID() + "\""); 340 } 341 } 342 343 public void deregisterObject(JRVirtualizable o) 344 { 345 String uid = o.getUID(); 346 347 try 349 { 350 dispose(o.getUID()); 351 } 352 catch (Exception e) 353 { 354 log.error("Error removing virtual data", e); 355 } 357 358 synchronized(this) 359 { 360 JRVirtualizable oldIn = pagedIn.remove(uid); 361 if (oldIn != null) 362 { 363 if (oldIn != o) 364 { 365 pagedIn.put(uid, oldIn); 366 throw new IllegalStateException ("Wrong object stored with UID \"" + o.getUID() + "\""); 367 } 368 } 369 else 370 { 371 Object oldOut = pagedOut.remove(uid); 372 if (oldOut != null && oldOut != o) 373 { 374 pagedOut.put(uid, oldOut); 375 throw new IllegalStateException ("Wrong object stored with UID \"" + o.getUID() + "\""); 376 } 377 } 378 379 } 382 } 383 384 public synchronized void touch(JRVirtualizable o) 385 { 386 if (this.lastObject != o) 388 { 389 setLastObject(pagedIn.get(o.getUID())); 390 } 391 } 392 393 public void requestData(JRVirtualizable o) 394 { 395 String uid = o.getUID(); 396 if (isPagedOutAndTouch(o, uid)) 397 { 398 try 400 { 401 pageIn(o); 402 } 403 catch (IOException e) 404 { 405 log.error("Error devirtualizing object", e); 406 throw new JRRuntimeException(e); 407 } 408 409 o.afterInternalization(); 410 411 synchronized (this) 412 { 413 setLastObject(o); 414 pagedOut.remove(uid); 415 pagedIn.put(uid, o); 416 } 417 } 418 } 419 420 public void clearData(JRVirtualizable o) 421 { 422 String uid = o.getUID(); 423 if (isPagedOutAndTouch(o, uid)) 424 { 425 dispose(uid); 427 428 synchronized (this) 429 { 430 pagedOut.remove(uid); 431 } 432 } 433 } 434 435 public void virtualizeData(JRVirtualizable o) 436 { 437 String uid = o.getUID(); 438 if (!isPagedOut(uid)) 439 { 440 o.beforeExternalization(); 441 442 try 444 { 445 pageOut(o); 446 } 447 catch (IOException e) 448 { 449 log.error("Error virtualizing object", e); 450 throw new JRRuntimeException(e); 451 } 452 453 o.afterExternalization(); 454 455 o.removeVirtualData(); 457 458 synchronized (this) 459 { 460 pagedOut.put(uid, o); 461 } 462 } 463 } 464 465 protected void finalize() throws Throwable 466 { 467 cleanup(); 468 469 super.finalize(); 470 } 471 472 479 protected final void writeData(JRVirtualizable o, OutputStream out) 480 throws JRRuntimeException 481 { 482 try 483 { 484 ObjectOutputStream oos = new ObjectOutputStream (out); 485 oos.writeObject(o.getIdentityData()); 486 oos.writeObject(o.getVirtualData()); 487 oos.flush(); 488 } 489 catch (IOException e) 490 { 491 log.error("Error virtualizing object", e); 492 throw new JRRuntimeException(e); 493 } 494 } 495 496 497 505 protected final void readData(JRVirtualizable o, InputStream in) 506 throws JRRuntimeException 507 { 508 try 509 { 510 ObjectInputStream ois = new ObjectInputStream (in); 511 o.setIdentityData(ois.readObject()); 512 o.setVirtualData(ois.readObject()); 513 } 514 catch (IOException e) 515 { 516 log.error("Error devirtualizing object", e); 517 throw new JRRuntimeException(e); 518 } 519 catch (ClassNotFoundException e) 520 { 521 log.error("Error devirtualizing object", e); 522 throw new JRRuntimeException(e); 523 } 524 } 525 526 protected synchronized void reset() 527 { 528 readOnly = false; 529 } 530 531 protected final void disposeAll() 532 { 533 for (Iterator it = pagedOut.keySet().iterator(); it.hasNext();) 535 { 536 String id = (String ) it.next(); 537 try 538 { 539 dispose(id); 540 it.remove(); 541 } 542 catch (Exception e) 543 { 544 log.error("Error cleaning up virtualizer.", e); 545 } 547 } 548 549 for (Iterator it = pagedIn.idIterator(); it.hasNext();) 550 { 551 String id = (String ) it.next(); 552 try 553 { 554 dispose(id); 555 it.remove(); 556 } 557 catch (Exception e) 558 { 559 log.error("Error cleaning up virtualizer.", e); 560 } 562 } 563 } 564 565 571 protected abstract void pageOut(JRVirtualizable o) throws IOException ; 572 573 574 580 protected abstract void pageIn(JRVirtualizable o) throws IOException ; 581 582 583 588 protected abstract void dispose(String virtualId); 589 } 590 | Popular Tags |