1 23 24 package org.apache.slide.store; 25 26 import java.util.Enumeration ; 27 import java.util.HashMap ; 28 import java.util.HashSet ; 29 import java.util.Hashtable ; 30 import java.util.Iterator ; 31 import java.util.Map ; 32 import java.util.Vector ; 33 34 import org.apache.commons.transaction.locking.GenericLock; 35 import org.apache.commons.transaction.locking.GenericLockManager; 36 import org.apache.commons.transaction.util.xa.XidWrapper; 37 import org.apache.slide.common.ServiceAccessException; 38 import org.apache.slide.common.ServiceParameterErrorException; 39 import org.apache.slide.common.ServiceParameterMissingException; 40 import org.apache.slide.common.Uri; 41 import org.apache.slide.content.NodeRevisionContent; 42 import org.apache.slide.content.NodeRevisionDescriptor; 43 import org.apache.slide.content.NodeRevisionDescriptors; 44 import org.apache.slide.content.NodeRevisionNumber; 45 import org.apache.slide.content.RevisionAlreadyExistException; 46 import org.apache.slide.content.RevisionDescriptorNotFoundException; 47 import org.apache.slide.content.RevisionNotFoundException; 48 import org.apache.slide.lock.LockTokenNotFoundException; 49 import org.apache.slide.lock.NodeLock; 50 import org.apache.slide.macro.ConflictException; 51 import org.apache.slide.security.NodePermission; 52 import org.apache.slide.structure.LinkNode; 53 import org.apache.slide.structure.ObjectAlreadyExistsException; 54 import org.apache.slide.structure.ObjectNode; 55 import org.apache.slide.structure.ObjectNotFoundException; 56 import org.apache.slide.util.ByteSizeLimitedObjectCache; 57 import org.apache.slide.util.ObjectCache; 58 import org.apache.slide.util.TxLRUObjectCache; 59 60 import javax.transaction.xa.XAException ; 61 import javax.transaction.xa.Xid ; 62 63 import org.apache.slide.util.logger.Logger; 64 import org.apache.slide.util.logger.TxLogger; 65 66 72 public class ExtendedStore extends AbstractStore { 73 74 private static final String LOG_CHANNEL = ExtendedStore.class.getName(); 75 76 protected static final int DEFAULT_OBJECT_GLOBAL_CACHE_SIZE = 10000; 77 protected static final String GLOBAL_OBJECT_CACHE_SIZE_PARAMETER = "object-cache-size"; 78 79 protected static final int DEFAULT_GLOBAL_PERMISSION_CACHE_SIZE = 10000; 80 protected static final String GLOBAL_PERMISSION_CACHE_SIZE_PARAMETER = "permission-cache-size"; 81 82 protected static final int DEFAULT_GLOBAL_LOCK_CACHE_SIZE = 100; 83 protected static final String GLOBAL_LOCK_CACHE_SIZE_PARAMETER = "lock-cache-size"; 84 85 protected static final int DEFAULT_GLOBAL_DESCRIPTORS_CACHE_SIZE = 10000; 86 protected static final String GLOBAL_DESCRIPTORS_CACHE_SIZE_PARAMETER = "descriptors-cache-size"; 87 88 protected static final int DEFAULT_GLOBAL_DESCRIPTOR_CACHE_SIZE = 10000; 89 protected static final String GLOBAL_DESCRIPTOR_CACHE_SIZE_PARAMETER = "descriptor-cache-size"; 90 91 protected static final int DEFAULT_GLOBAL_CONTENT_CACHE_SIZE = 10000; 92 protected static final String GLOBAL_CONTENT_CACHE_SIZE_PARAMETER = "content-cache-size"; 93 94 protected static final boolean DEFAULT_ENABLE_CONTENT_CACHING = false; 95 protected static final String ENABLE_CONTENT_CACHING_PARAMETER = "enable-content-caching"; 96 97 protected static final int DEFAULT_TX_CONTENT_CACHE_SIZE = 1000; 98 protected static final String TX_CONTENT_CACHE_SIZE_PARAMETER = "tx-content-cache-size"; 99 100 protected static final long DEFAULT_CONTENT_CACHE_BYTES = 10000000; protected static final String CONTENT_CACHE_BYTES_PARAMETER = "content-cache-bytes"; 102 103 protected static final long DEFAULT_TX_CONTENT_CACHE_BYTES = 1000000; protected static final String TX_CONTENT_CACHE_BYTES_PARAMETER = "tx-content-cache-bytes"; 105 106 protected static final long DEFAULT_MAX_CONTENT_BYTES_PER_ENTRY = 50000; protected static final String MAX_CONTENT_BYTES_PER_ENTRY_PARAMETER = "max-content-bytes-per-entry"; 108 109 protected static final String CACHE_MODE_PARAMETER = "cache-mode"; 110 protected static final String CACHE_MODE_FULL = "full"; 111 protected static final String CACHE_MODE_LOCAL = "cluster"; 112 protected static final String CACHE_MODE_NO_GLOBAL_IN_TX = "isolation-shadow"; 113 protected static final String CACHE_MODE_OFF = "off"; 114 protected static final String DEFAULT_CACHE_MODE = CACHE_MODE_FULL; 115 116 protected static final int DEFAULT_TLOCK_TIMEOUT = 20000; protected static final String TLOCK_TIMEOUT_PARAMETER = "tlock-timeout"; 118 119 protected ThreadLocal activeTransactionBranch = new ThreadLocal (); 121 122 protected TxContentCacheWrapper contentCache; 123 protected TxCacheWrapper objectsCache; 124 protected TxCacheWrapper permissionsCache; 125 protected TxCacheWrapper locksCache; 126 protected TxCacheWrapper descriptorsCache; 127 protected TxCacheWrapper descriptorCache; 128 129 protected GenericLockManager lockManager; 130 protected ThreadLocal locks = new ThreadLocal (); 131 protected long timeout; 132 133 protected boolean globalCacheOff; 134 135 int globalObjectCacheSize; 136 int globalPermissionCacheSize; 137 int globalLockCacheSize; 138 int globalDescrtiptorsCacheSize; 139 int globalDescrtiptorCacheSize; 140 boolean contentCachingEnabled; 141 int globalContentCacheSize; 142 long contentCacheBytes; 143 int txContentCacheSize; 144 long txContentCacheBytes; 145 long maxByteSizePerEntry; 146 boolean noGlobalCacheInTx; 147 148 private Map suspendedLocks = new HashMap (); 149 150 public ExtendedStore() { 151 lockManager = new GenericLockManager(1, new TxLogger(getLogger(), LOG_CHANNEL)); 152 } 153 154 public void setParameters(Hashtable parameters) 155 throws ServiceParameterErrorException, ServiceParameterMissingException { 156 super.setParameters(parameters); 157 158 globalObjectCacheSize = DEFAULT_OBJECT_GLOBAL_CACHE_SIZE; 159 globalPermissionCacheSize = DEFAULT_GLOBAL_PERMISSION_CACHE_SIZE; 160 globalLockCacheSize = DEFAULT_GLOBAL_LOCK_CACHE_SIZE; 161 globalDescrtiptorsCacheSize = DEFAULT_GLOBAL_DESCRIPTORS_CACHE_SIZE; 162 globalDescrtiptorCacheSize = DEFAULT_GLOBAL_DESCRIPTOR_CACHE_SIZE; 163 contentCachingEnabled = DEFAULT_ENABLE_CONTENT_CACHING; 164 globalContentCacheSize = DEFAULT_GLOBAL_CONTENT_CACHE_SIZE; 165 contentCacheBytes = DEFAULT_CONTENT_CACHE_BYTES; 166 txContentCacheSize = DEFAULT_TX_CONTENT_CACHE_SIZE; 167 txContentCacheBytes = DEFAULT_TX_CONTENT_CACHE_BYTES; 168 maxByteSizePerEntry = DEFAULT_MAX_CONTENT_BYTES_PER_ENTRY; 169 170 timeout = DEFAULT_TLOCK_TIMEOUT; 171 String timeoutString = (String ) parameters.get(TLOCK_TIMEOUT_PARAMETER); 172 if (timeoutString != null) { 173 try { 174 timeout = Integer.parseInt(timeoutString) * 1000; 175 } catch (NumberFormatException nfe) { 176 getLogger().log("TLock timeout must be integer! Using default value", LOG_CHANNEL, Logger.WARNING); 177 } 178 } 179 getLogger().log("Setting TLock timeout for store " + getName() + " to " + timeout / 1000 + " seconds", Logger.INFO); 180 181 String globalObjectCacheSizeString = (String ) parameters.get(GLOBAL_OBJECT_CACHE_SIZE_PARAMETER); 182 if (globalObjectCacheSizeString != null) { 183 try { 184 globalObjectCacheSize = Integer.parseInt(globalObjectCacheSizeString); 185 } catch (NumberFormatException nfe) { 186 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 187 } 188 } 189 getLogger().log( 190 "Setting object cache size for store " + getName() + " to " + globalObjectCacheSize, 191 Logger.INFO); 192 193 String globalPermissionCacheSizeString = (String ) parameters.get(GLOBAL_PERMISSION_CACHE_SIZE_PARAMETER); 194 if (globalPermissionCacheSizeString != null) { 195 try { 196 globalPermissionCacheSize = Integer.parseInt(globalPermissionCacheSizeString); 197 } catch (NumberFormatException nfe) { 198 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 199 } 200 } 201 getLogger().log( 202 "Setting permission cache size for store " + getName() + " to " + globalPermissionCacheSize, 203 LOG_CHANNEL, 204 Logger.INFO); 205 206 String globalLockCacheSizeString = (String ) parameters.get(GLOBAL_LOCK_CACHE_SIZE_PARAMETER); 207 if (globalLockCacheSizeString != null) { 208 try { 209 globalLockCacheSize = Integer.parseInt(globalLockCacheSizeString); 210 } catch (NumberFormatException nfe) { 211 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 212 } 213 } 214 getLogger().log( 215 "Setting lock cache size for store " + getName() + " to " + globalLockCacheSize, 216 LOG_CHANNEL, 217 Logger.INFO); 218 219 String globalDescriptorsCacheSizeString = (String ) parameters.get(GLOBAL_DESCRIPTORS_CACHE_SIZE_PARAMETER); 220 if (globalDescriptorsCacheSizeString != null) { 221 try { 222 globalDescrtiptorsCacheSize = Integer.parseInt(globalDescriptorsCacheSizeString); 223 } catch (NumberFormatException nfe) { 224 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 225 } 226 } 227 getLogger().log( 228 "Setting descriptors cache size for store " + getName() + " to " + globalDescrtiptorsCacheSize, 229 LOG_CHANNEL, 230 Logger.INFO); 231 232 String globalDescriptorCacheSizeString = (String ) parameters.get(GLOBAL_DESCRIPTOR_CACHE_SIZE_PARAMETER); 233 if (globalDescriptorCacheSizeString != null) { 234 try { 235 globalDescrtiptorCacheSize = Integer.parseInt(globalDescriptorCacheSizeString); 236 } catch (NumberFormatException nfe) { 237 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 238 } 239 } 240 getLogger().log( 241 "Setting descriptor cache size for store " + getName() + " to " + globalDescrtiptorCacheSize, 242 LOG_CHANNEL, 243 Logger.INFO); 244 245 String enableContentCachingString = (String ) parameters.get(ENABLE_CONTENT_CACHING_PARAMETER); 246 if (enableContentCachingString != null) { 247 contentCachingEnabled = Boolean.valueOf(enableContentCachingString).booleanValue(); 248 } 249 getLogger().log( 250 "Setting content caching for store " + getName() + " to " + contentCachingEnabled, 251 LOG_CHANNEL, 252 Logger.INFO); 253 254 String globalContentCacheSizeString = (String ) parameters.get(GLOBAL_CONTENT_CACHE_SIZE_PARAMETER); 255 if (globalContentCacheSizeString != null) { 256 try { 257 globalContentCacheSize = Integer.parseInt(globalContentCacheSizeString); 258 } catch (NumberFormatException nfe) { 259 getLogger().log("Cache size must be an integer! Using default size", LOG_CHANNEL, Logger.WARNING); 260 } 261 } 262 getLogger().log( 263 "Setting content cache size for store " + getName() + " to " + globalContentCacheSize, 264 LOG_CHANNEL, 265 Logger.INFO); 266 267 String contentCacheBytesString = (String ) parameters.get(CONTENT_CACHE_BYTES_PARAMETER); 268 if (contentCacheBytesString != null) { 269 try { 270 contentCacheBytes = Long.parseLong(contentCacheBytesString); 271 } catch (NumberFormatException nfe) { 272 getLogger().log( 273 "Content cache byte size must be an integer! Using default size", 274 LOG_CHANNEL, 275 Logger.WARNING); 276 } 277 } 278 getLogger().log( 279 "Setting content cache byte size for store " + getName() + " to " + contentCacheBytes, 280 LOG_CHANNEL, 281 Logger.INFO); 282 283 String txContentCacheSizeString = (String ) parameters.get(TX_CONTENT_CACHE_SIZE_PARAMETER); 284 if (txContentCacheSizeString != null) { 285 try { 286 txContentCacheSize = Integer.parseInt(txContentCacheSizeString); 287 } catch (NumberFormatException nfe) { 288 getLogger().log( 289 "Content transaction cache size must be an integer! Using default size", 290 LOG_CHANNEL, 291 Logger.WARNING); 292 } 293 } 294 getLogger().log( 295 "Setting transaction content cache size for store " + getName() + " to " + txContentCacheSize, 296 LOG_CHANNEL, 297 Logger.INFO); 298 299 String txContentCacheBytesString = (String ) parameters.get(TX_CONTENT_CACHE_BYTES_PARAMETER); 300 if (txContentCacheBytesString != null) { 301 try { 302 txContentCacheBytes = Long.parseLong(txContentCacheBytesString); 303 } catch (NumberFormatException nfe) { 304 getLogger().log( 305 "Transaction content cache byte size must be an integer! Using default size", 306 LOG_CHANNEL, 307 Logger.WARNING); 308 } 309 } 310 getLogger().log( 311 "Setting transaction content cache byte size for store " + getName() + " to " + txContentCacheBytes, 312 LOG_CHANNEL, 313 Logger.INFO); 314 315 String maxByteSizePerEntryString = (String ) parameters.get(MAX_CONTENT_BYTES_PER_ENTRY_PARAMETER); 316 if (maxByteSizePerEntryString != null) { 317 try { 318 maxByteSizePerEntry = Long.parseLong(maxByteSizePerEntryString); 319 } catch (NumberFormatException nfe) { 320 getLogger().log( 321 "Maximum byte size for content cache entry must be an integer! Using default size", 322 LOG_CHANNEL, 323 Logger.WARNING); 324 } 325 } 326 getLogger().log( 327 "Setting maximum byte size for content cache entry for store " + getName() + " to " + maxByteSizePerEntry, 328 LOG_CHANNEL, 329 Logger.INFO); 330 331 String cacheModeString = (String ) parameters.get(CACHE_MODE_PARAMETER); 332 if (cacheModeString == null) cacheModeString = DEFAULT_CACHE_MODE; 333 cacheModeString = cacheModeString.trim(); 334 335 boolean noGlobalCache; 336 if (cacheModeString.equals(CACHE_MODE_FULL)) { 337 noGlobalCache = false; 338 globalCacheOff = false; 339 noGlobalCacheInTx = false; 340 getLogger().log("Enabling full caching causing low isolation", LOG_CHANNEL, Logger.INFO); 341 } else if (cacheModeString.equals(CACHE_MODE_LOCAL)) { 342 noGlobalCache = true; 343 globalCacheOff = false; 344 noGlobalCacheInTx = false; 345 getLogger().log("Disabling global cache to shadow store isolation and allow for clustering", LOG_CHANNEL, Logger.INFO); 346 } else if (cacheModeString.equals(CACHE_MODE_NO_GLOBAL_IN_TX)) { 347 globalCacheOff = false; 348 noGlobalCache = false; 349 noGlobalCacheInTx = true; 350 getLogger().log("Disabling global cache inside transactions to shadow store isolation", LOG_CHANNEL, Logger.INFO); 351 } else if (cacheModeString.equals(CACHE_MODE_OFF)) { 352 globalCacheOff = true; 353 noGlobalCache = true; 354 noGlobalCacheInTx = true; 355 getLogger().log("Disabling cache completely", LOG_CHANNEL, Logger.INFO); 356 } else { 357 noGlobalCache = false; 358 globalCacheOff = false; 359 noGlobalCacheInTx = false; 360 getLogger().log("Unknown cache mode "+cacheModeString+" Using full mode instead...", LOG_CHANNEL, Logger.WARNING); 361 } 362 363 if (noGlobalCache) { 365 globalObjectCacheSize = -1; 366 globalPermissionCacheSize = -1; 367 globalLockCacheSize = -1; 368 globalDescrtiptorsCacheSize = -1; 369 globalDescrtiptorCacheSize = -1; 370 contentCachingEnabled = false; 371 } 372 373 init( 374 globalObjectCacheSize, 375 globalPermissionCacheSize, 376 globalLockCacheSize, 377 globalDescrtiptorsCacheSize, 378 globalDescrtiptorCacheSize, 379 contentCachingEnabled, 380 globalContentCacheSize, 381 contentCacheBytes, 382 txContentCacheSize, 383 txContentCacheBytes, 384 maxByteSizePerEntry, 385 noGlobalCacheInTx); 386 } 387 388 public void resetCache() { 389 init(globalObjectCacheSize, globalPermissionCacheSize, globalLockCacheSize, globalDescrtiptorsCacheSize, 390 globalDescrtiptorCacheSize, contentCachingEnabled, globalContentCacheSize, contentCacheBytes, 391 txContentCacheSize, txContentCacheBytes, maxByteSizePerEntry, noGlobalCacheInTx); 392 } 393 394 399 public void removeObjectFromCache( Object key ) { 400 getLogger().log( "Removing " + key + " from cache.", 401 LOG_CHANNEL, 402 Logger.DEBUG ); 403 if ( contentStore.cacheResults() && contentCachingEnabled ) { 404 contentCache.remove( key.toString(), "_" ); 405 } 406 if ( nodeStore.cacheResults() ) { 407 objectsCache.remove( key.toString() ); 408 } 409 if ( securityStore.cacheResults() ) { 410 permissionsCache.remove( key.toString() ); 411 } 412 if ( lockStore.cacheResults() ) { 414 locksCache.remove( key.toString() ); 415 } 416 if ( revisionDescriptorsStore.cacheResults() ) { 417 descriptorsCache.remove( key.toString() ); 418 } 419 if ( revisionDescriptorStore.cacheResults() ) { 420 descriptorCache.remove( key.toString(), "-" ); 421 } 422 } 423 424 public void exclusiveTransientLock(String uri) 425 throws ServiceAccessException { 426 Xid txId = (Xid ) activeTransactionBranch.get(); 427 if (txId != null) { 428 try { 429 GenericLock lock = (GenericLock) lockManager 430 .atomicGetOrCreateLock(uri); 431 if (lock.getLockLevel(txId) != 1) { 432 Object owner = lock.getOwner(); 433 getLogger() 434 .log( 435 "Try lock: " 436 + txId 437 + " tries " 438 + uri 439 + (owner != null ? " ---> " 440 + owner.toString() 441 + " has it" : ""), 442 LOG_CHANNEL, Logger.DEBUG); 443 if (!lock.acquire(txId, 1, true, true, timeout)) { 444 throw new ServiceAccessException(this, 445 new ConflictException(uri)); 446 } 447 ((HashSet ) locks.get()).add(lock); 448 getLogger().log("Has lock: " + txId + " locks " + uri, 449 LOG_CHANNEL, Logger.DEBUG); 450 } 451 } catch (InterruptedException e) { 452 throw new ServiceAccessException(this, new ConflictException( 453 uri)); 454 } 455 } 456 } 457 458 462 public NodeRevisionContent retrieveRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor) 463 throws ServiceAccessException, RevisionNotFoundException { 464 if (contentStore.cacheResults() && contentCache != null) { 465 if (isForceStoreEnlistment(uri)) { 466 enlist(this); 467 } 468 try { 469 String key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber(); 470 Object result = contentCache.get(key); 471 if (result != null) { 472 getLogger().log("Retrieving content at '" + key + "' from cache", LOG_CHANNEL, Logger.DEBUG); 473 return (NodeRevisionContent) result; 475 } else { 476 NodeRevisionContent revisionContent = super.retrieveRevisionContent(uri, revisionDescriptor); 477 long size = revisionDescriptor.getContentLength(); 478 contentCache.put(key, revisionContent, size); 482 return revisionContent; 485 } 486 } finally { 487 if (isForceStoreEnlistment(uri)) { 488 delist(this); 489 } 490 } 491 } else { 492 return super.retrieveRevisionContent(uri, revisionDescriptor); 493 } 494 } 495 496 public void createRevisionContent( 497 Uri uri, 498 NodeRevisionDescriptor revisionDescriptor, 499 NodeRevisionContent revisionContent) 500 throws ServiceAccessException, RevisionAlreadyExistException { 501 502 long size = -1L; 503 if (contentStore.cacheResults() && contentCache != null) { 504 size = revisionDescriptor.getContentLength(); 505 contentCache.precache(revisionContent, size); 506 } 507 508 super.createRevisionContent(uri, revisionDescriptor, revisionContent); 509 510 if (contentStore.cacheResults() && contentCache != null) { 511 enlist(this); 512 try { 513 String key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber(); 514 contentCache.put(key, revisionContent, size); 515 } finally { 516 delist(this); 517 } 518 } 519 } 520 521 public void storeRevisionContent( 522 Uri uri, 523 NodeRevisionDescriptor revisionDescriptor, 524 NodeRevisionContent revisionContent) 525 throws ServiceAccessException, RevisionNotFoundException { 526 527 long size = -1L; 528 if (contentStore.cacheResults() && contentCache != null) { 529 size = revisionDescriptor.getContentLength(); 530 contentCache.precache(revisionContent, size); 531 } 532 533 super.storeRevisionContent(uri, revisionDescriptor, revisionContent); 534 535 if (contentStore.cacheResults() && contentCache != null) { 536 enlist(this); 537 try { 538 String key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber(); 539 contentCache.put(key, revisionContent, size); 540 } finally { 541 delist(this); 542 } 543 } 544 } 545 546 public void removeRevisionContent(Uri uri, NodeRevisionDescriptor revisionDescriptor) 547 throws ServiceAccessException { 548 if (contentStore.cacheResults() && contentCache != null) { 549 enlist(this); 550 try { 551 String key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber(); 552 contentCache.remove(key); 553 } finally { 554 delist(this); 555 } 556 } 557 super.removeRevisionContent(uri, revisionDescriptor); 558 } 559 560 564 public ObjectNode retrieveObject(Uri uri) throws ServiceAccessException, ObjectNotFoundException { 565 if (nodeStore.cacheResults()) { 566 if (isForceStoreEnlistment(uri)) { 567 enlist(this); 568 } 569 try { 570 Object tempObject = objectsCache.get(uri.toString()); 571 if (tempObject != null) { 572 return ((ObjectNode) tempObject).cloneObject(); 573 } else { 574 ObjectNode objectNode = super.retrieveObject(uri); 575 objectNode.validate(uri.toString()); 576 objectsCache.put(uri.toString(), objectNode); 577 return objectNode.cloneObject(); 578 } 579 } finally { 580 if (isForceStoreEnlistment(uri)) { 581 delist(this); 582 } 583 } 584 } else { 585 return super.retrieveObject(uri); 586 } 587 } 588 589 public void storeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { 590 super.storeObject(uri, object); 591 if (nodeStore.cacheResults()) { 592 enlist(this); 593 try { 594 objectsCache.put(uri.toString(), object.cloneObject()); 595 } finally { 596 delist(this); 597 } 598 } 599 } 600 601 public void createObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectAlreadyExistsException { 602 super.createObject(uri, object); 603 if (nodeStore.cacheResults()) { 604 enlist(this); 605 try { 606 607 if (object instanceof LinkNode) { 608 String linkedUri = ((LinkNode) object).getLinkedUri(); 610 ObjectNode linkedObject = (ObjectNode) objectsCache.get(linkedUri); 611 if (linkedObject != null) { 612 linkedObject.addLink((LinkNode)object); 613 } 614 } 615 objectsCache.put(uri.toString(), object.cloneObject()); 616 } finally { 617 delist(this); 618 } 619 } 620 } 621 622 public void removeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { 623 super.removeObject(uri, object); 624 if (nodeStore.cacheResults()) { 625 enlist(this); 626 try { 627 if (object instanceof LinkNode) { 628 ObjectNode linkedObject = (ObjectNode) objectsCache.get(((LinkNode)object).getLinkedUri()); 630 if (linkedObject !=null) { 631 linkedObject.removeLink((LinkNode) object); 632 } 633 } 634 objectsCache.remove(uri.toString()); 635 } finally { 636 delist(this); 637 } 638 } 639 } 640 641 public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException { 642 super.grantPermission(uri, permission); 643 if (securityStore.cacheResults()) { 644 enlist(this); 645 try { 646 Vector permissionsVector = fillPermissionsCache(uri); 647 Vector tempPermissions = (Vector )permissionsVector.clone(); 649 tempPermissions.addElement(permission); 650 permissionsCache.put(uri.toString(), tempPermissions); 651 } finally { 652 delist(this); 653 } 654 } 655 } 656 657 public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException { 658 super.revokePermission(uri, permission); 659 if (securityStore.cacheResults()) { 660 enlist(this); 661 try { 662 Vector permissionsVector = fillPermissionsCache(uri); 663 Vector tempPermissions = (Vector )permissionsVector.clone(); 665 tempPermissions.removeElement(permission); 666 permissionsCache.put(uri.toString(), tempPermissions); 667 } finally { 668 delist(this); 669 } 670 671 } 672 } 673 674 public void revokePermissions(Uri uri) throws ServiceAccessException { 675 super.revokePermissions(uri); 676 if (securityStore.cacheResults()) { 677 enlist(this); 678 try { 679 Object value = permissionsCache.get(uri.toString()); 680 if (value != null) { 681 permissionsCache.put(uri.toString(), new Vector ()); 682 } 683 } finally { 684 delist(this); 685 } 686 } 687 } 688 689 public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException { 690 if (securityStore.cacheResults()) { 691 if (isForceStoreEnlistment(uri)) { 692 enlist(this); 693 } 694 try { 695 Vector permissionsVector = fillPermissionsCache(uri); 696 return ((Vector ) permissionsVector.clone()).elements(); 697 } finally { 698 if (isForceStoreEnlistment(uri)) { 699 delist(this); 700 } 701 } 702 } else { 703 return super.enumeratePermissions(uri); 704 } 705 } 706 707 public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException { 708 super.putLock(uri, lock); 709 if (lockStore.cacheResults()) { 710 enlist(this); 711 try { 712 Vector locks = fillLocksCache(uri); 713 Vector tempLocks = (Vector ) locks.clone(); 715 tempLocks.addElement(lock.cloneObject()); 716 locksCache.put(uri.toString(), tempLocks); 717 } finally { 718 delist(this); 719 } 720 } 721 } 722 723 public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 724 super.renewLock(uri, lock); 725 if (lockStore.cacheResults()) { 726 enlist(this); 727 try { 728 Object value = locksCache.get(uri.toString()); 729 Vector locksVector = null; 730 if (value != null) { 731 locksVector = new Vector ((Vector ) value); 732 boolean wasPresent = locksVector.removeElement(lock); 733 if (!wasPresent) { 734 throw new LockTokenNotFoundException(lock); 735 } 736 locksVector.addElement(lock.cloneObject()); 737 locksCache.put(uri.toString(), locksVector); 738 } 739 } finally { 740 delist(this); 741 } 742 } 743 } 744 745 public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 746 super.removeLock(uri, lock); 747 if (lockStore.cacheResults()) { 748 enlist(this); 749 try { 750 Object value = locksCache.get(uri.toString()); 751 Vector locksVector = null; 752 if (value != null) { 753 locksVector = new Vector ((Vector ) value); 754 boolean wasPresent = locksVector.removeElement(lock); 755 if (!wasPresent) { 756 throw new LockTokenNotFoundException(lock); 757 } 758 locksCache.put(uri.toString(), locksVector); 759 } 760 } finally { 761 delist(this); 762 } 763 } 764 } 765 766 public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { 767 super.killLock(uri, lock); 768 if (lockStore.cacheResults()) { 769 enlist(this); 770 try { 771 Object value = locksCache.get(uri.toString()); 772 Vector locksVector = null; 773 if (value != null) { 774 locksVector = new Vector ((Vector ) value); 775 boolean wasPresent = locksVector.removeElement(lock); 776 if (!wasPresent) { 777 throw new LockTokenNotFoundException(lock); 778 } 779 locksCache.put(uri.toString(), locksVector); 780 } 781 } finally { 782 delist(this); 783 } 784 } 785 } 786 787 public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException { 788 if (lockStore.cacheResults()) { 789 if (isForceStoreEnlistment(uri)) { 790 enlist(this); 791 } 792 try { 793 Vector locks = fillLocksCache(uri); 794 return ((Vector ) locks.clone()).elements(); 795 } finally { 796 if (isForceStoreEnlistment(uri)) { 797 delist(this); 798 } 799 } 800 } else { 801 return super.enumerateLocks(uri); 802 } 803 } 804 805 public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri) 806 throws ServiceAccessException, RevisionDescriptorNotFoundException { 807 if (revisionDescriptorsStore.cacheResults()) { 808 if (isForceStoreEnlistment(uri)) { 809 enlist(this); 810 } 811 try { 812 Object tempObject = descriptorsCache.get(uri.toString()); 813 if (tempObject != null) { 814 return ((NodeRevisionDescriptors) tempObject).cloneObject(); 815 } else { 816 NodeRevisionDescriptors revisionDescriptors = super.retrieveRevisionDescriptors(uri); 817 descriptorsCache.put(uri.toString(), revisionDescriptors); 818 revisionDescriptors.validate(uri.toString()); 819 return revisionDescriptors.cloneObject(); 820 } 821 } finally { 822 if (isForceStoreEnlistment(uri)) { 823 delist(this); 824 } 825 } 826 } else { 827 return super.retrieveRevisionDescriptors(uri); 828 } 829 } 830 831 public void createRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) 832 throws ServiceAccessException { 833 super.createRevisionDescriptors(uri, revisionDescriptors); 834 if (revisionDescriptorsStore.cacheResults()) { 835 enlist(this); 836 try { 837 descriptorsCache.put(uri.toString(), revisionDescriptors.cloneObject()); 838 } finally { 839 delist(this); 840 } 841 } 842 } 843 844 public void storeRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) 845 throws ServiceAccessException, RevisionDescriptorNotFoundException { 846 super.storeRevisionDescriptors(uri, revisionDescriptors); 847 if (revisionDescriptorsStore.cacheResults()) { 848 enlist(this); 849 try { 850 descriptorsCache.put(uri.toString(), revisionDescriptors.cloneObject()); 851 } finally { 852 delist(this); 853 } 854 } 855 } 856 857 public void removeRevisionDescriptors(Uri uri) throws ServiceAccessException { 858 if (revisionDescriptorsStore.cacheResults()) { 859 enlist(this); 860 try { 861 descriptorsCache.remove(uri.toString()); 862 } finally { 863 delist(this); 864 } 865 } 866 super.removeRevisionDescriptors(uri); 867 } 868 869 public NodeRevisionDescriptor retrieveRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber) 870 throws ServiceAccessException, RevisionDescriptorNotFoundException { 871 if (revisionDescriptorStore.cacheResults()) { 872 if (isForceStoreEnlistment(uri)) { 873 enlist(this); 874 } 875 try { 876 Object result = descriptorCache.get(uri + "-" + revisionNumber); 877 if (result != null) { 878 return ((NodeRevisionDescriptor) result).cloneObject(); 879 } else { 880 NodeRevisionDescriptor revisionDescriptor = super.retrieveRevisionDescriptor(uri, revisionNumber); 881 revisionDescriptor.validate(); 882 descriptorCache.put(uri + "-" + revisionNumber, revisionDescriptor); 883 return revisionDescriptor.cloneObject(); 884 } 885 } finally { 886 if (isForceStoreEnlistment(uri)) { 887 delist(this); 888 } 889 } 890 } else { 891 return super.retrieveRevisionDescriptor(uri, revisionNumber); 892 } 893 } 894 895 public void createRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) 896 throws ServiceAccessException { 897 super.createRevisionDescriptor(uri, revisionDescriptor); 898 if (revisionDescriptorStore.cacheResults()) { 899 enlist(this); 900 try { 901 descriptorCache.put( 902 uri + "-" + revisionDescriptor.getRevisionNumber(), 903 revisionDescriptor.cloneObject()); 904 } finally { 905 delist(this); 906 } 907 } 908 } 909 910 public void storeRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) 911 throws ServiceAccessException, RevisionDescriptorNotFoundException { 912 super.storeRevisionDescriptor(uri, revisionDescriptor); 913 if (revisionDescriptorStore.cacheResults()) { 914 enlist(this); 915 try { 916 String key = uri + "-" + revisionDescriptor.getRevisionNumber(); 917 descriptorCache.put(key, revisionDescriptor.cloneObject()); 918 } finally { 919 delist(this); 920 } 921 } 922 } 923 924 public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber number) throws ServiceAccessException { 925 super.removeRevisionDescriptor(uri, number); 926 if (revisionDescriptorStore.cacheResults()) { 927 enlist(this); 928 try { 929 descriptorCache.remove(uri + "-" + number); 930 } finally { 931 delist(this); 932 } 933 } 934 } 935 936 940 public void forget(Xid xid) throws XAException { 941 releaseTransientLocks(); 942 943 Xid txId = (Xid ) XidWrapper.wrap(xid); 944 activeTransactionBranch.set(null); 945 946 objectsCache.getTxCache().forget(txId); 947 permissionsCache.getTxCache().forget(txId); 948 locksCache.getTxCache().forget(txId); 949 descriptorsCache.getTxCache().forget(txId); 950 descriptorCache.getTxCache().forget(txId); 951 if (contentCache != null) 952 contentCache.getTxCache().forget(txId); 953 } 954 955 public void rollback(Xid xid) throws XAException { 956 releaseTransientLocks(); 957 958 Xid txId = (Xid ) XidWrapper.wrap(xid); 959 activeTransactionBranch.set(null); 960 961 objectsCache.getTxCache().rollback(txId); 962 permissionsCache.getTxCache().rollback(txId); 963 locksCache.getTxCache().rollback(txId); 964 descriptorsCache.getTxCache().rollback(txId); 965 descriptorCache.getTxCache().rollback(txId); 966 if (contentCache != null) 967 contentCache.getTxCache().rollback(txId); 968 } 969 970 public void commit(Xid xid, boolean onePhase) throws XAException { 971 releaseTransientLocks(); 972 973 Xid txId = (Xid ) XidWrapper.wrap(xid); 974 activeTransactionBranch.set(null); 975 976 objectsCache.getTxCache().commit(txId); 977 permissionsCache.getTxCache().commit(txId); 978 locksCache.getTxCache().commit(txId); 979 descriptorsCache.getTxCache().commit(txId); 980 descriptorCache.getTxCache().commit(txId); 981 if (contentCache != null) 982 contentCache.getTxCache().commit(txId); 983 } 984 985 public int prepare(Xid xid) throws XAException { 986 return XA_OK; 988 } 989 990 public void start(Xid xid, int flags) throws XAException { 992 getLogger().log( 993 "Thread " 994 + Thread.currentThread() 995 + (flags == TMNOFLAGS ? " starts" 996 : flags == TMJOIN ? " joins" : " resumes") 997 + " work on behalf of transaction branch " + xid, 998 LOG_CHANNEL, Logger.DEBUG); 999 1000 Xid txId = (Xid ) XidWrapper.wrap(xid); 1001 activeTransactionBranch.set(txId); 1002 if (flags == TMNOFLAGS || flags == TMJOIN) { 1003 1004 locks.set(new HashSet ()); 1005 1006 objectsCache.getTxCache().start(txId); 1007 permissionsCache.getTxCache().start(txId); 1008 locksCache.getTxCache().start(txId); 1009 descriptorsCache.getTxCache().start(txId); 1010 descriptorCache.getTxCache().start(txId); 1011 if (contentCache != null) 1012 contentCache.getTxCache().start(txId); 1013 } else { 1014 locks.set(suspendedLocks.remove(txId)); 1015 } 1016 } 1017 1018 public void end(Xid xid, int flags) throws XAException { 1019 getLogger().log( 1020 "Thread " 1021 + Thread.currentThread() 1022 + (flags == TMSUSPEND ? " suspends" 1023 : flags == TMFAIL ? " fails" : " ends") 1024 + " work on behalf of transaction branch " + xid, 1025 LOG_CHANNEL, Logger.DEBUG); 1026 1027 if (flags == TMSUSPEND) { 1028 Xid txId = (Xid ) XidWrapper.wrap(xid); 1029 suspendedLocks.put(txId, locks.get()); 1030 } 1031 locks.set(null); 1032 activeTransactionBranch.set(null); 1033 } 1034 1035 1037 public String toString() { 1038 return getName() + "(" + getClass().getName() + ")"; 1039 } 1040 1041 protected void releaseTransientLocks() { 1042 if (locks.get() == null) return; 1045 1046 Xid txId = (Xid ) activeTransactionBranch.get(); 1047 for (Iterator it = ((HashSet )locks.get()).iterator(); it.hasNext();) { 1048 GenericLock lock = (GenericLock) it.next(); 1049 lock.release(txId); 1050 getLogger().log( 1051 "Release lock: " + txId + " released " + lock.getResourceId().toString(), 1052 LOG_CHANNEL, 1053 Logger.DEBUG); 1054 } 1055 } 1056 1057 protected Vector fillPermissionsCache(Uri uri) throws ServiceAccessException { 1058 Vector permissions = (Vector ) permissionsCache.get(uri.toString()); 1059 if (permissions != null) { 1060 return permissions; 1061 } else { 1062 permissions = new Vector (); 1063 Enumeration permissionsList = super.enumeratePermissions(uri); 1064 while (permissionsList.hasMoreElements()) { 1065 NodePermission tempPermission = (NodePermission) permissionsList.nextElement(); 1066 tempPermission.validate(uri.toString()); 1067 permissions.addElement(tempPermission); 1068 } 1069 permissionsCache.put(uri.toString(), permissions); 1070 return permissions; 1071 } 1072 } 1073 1074 protected Vector fillLocksCache(Uri uri) throws ServiceAccessException { 1075 Vector locksVector = (Vector ) locksCache.get(uri.toString()); 1076 if (locksVector != null) { 1077 return locksVector; 1078 } else { 1079 locksVector = new Vector (); 1080 Enumeration lockList = super.enumerateLocks(uri); 1081 while (lockList.hasMoreElements()) { 1082 NodeLock tempLock = (NodeLock) lockList.nextElement(); 1083 tempLock.validate(uri.toString()); 1084 locksVector.addElement(tempLock); 1085 } 1086 locksCache.put(uri.toString(), locksVector); 1087 return locksVector; 1088 } 1089 } 1090 1091 1093 protected void init( 1095 int globalObjectCacheSize, 1096 int globalPermissionCacheSize, 1097 int globalLockCacheSize, 1098 int globalDescrtiptorsCacheSize, 1099 int globalDescrtiptorCacheSize, 1100 boolean contentCachingEnabled, 1101 int globalContentCacheSize, 1102 long contentCacheBytes, 1103 int txContentCacheSize, 1104 long txContentCacheBytes, 1105 long maxByteSizePerEntry, 1106 boolean noGlobalCacheInTx) { 1107 try { 1108 objectsCache = new TxCacheWrapper(globalObjectCacheSize, "object", noGlobalCacheInTx); 1109 permissionsCache = new TxCacheWrapper(globalPermissionCacheSize, "permission", noGlobalCacheInTx); 1110 locksCache = new TxCacheWrapper(globalLockCacheSize, "lock", noGlobalCacheInTx); 1111 descriptorsCache = new TxCacheWrapper(globalDescrtiptorsCacheSize, "descriptors", noGlobalCacheInTx); 1112 descriptorCache = new TxCacheWrapper(globalDescrtiptorCacheSize, "descriptor", noGlobalCacheInTx); 1113 1114 if (contentCachingEnabled) { 1115 contentCache = 1116 new TxContentCacheWrapper( 1117 new ByteSizeLimitedObjectCache( 1118 globalContentCacheSize, 1119 txContentCacheSize, 1120 contentCacheBytes, 1121 txContentCacheBytes, 1122 maxByteSizePerEntry, 1123 getName() + ".content", 1124 getLogger(), 1125 noGlobalCacheInTx)); 1126 } else { 1127 contentCache = null; 1128 } 1129 } catch (Error e) { 1130 fatalError(e); 1131 } catch (RuntimeException re) { 1132 fatalError(re); 1133 } 1134 } 1135 1136 protected void fatalError(Error e) { 1138 getLogger().log("Fatal error: " + e, LOG_CHANNEL, Logger.CRITICAL); 1139 getLogger().log(e, LOG_CHANNEL, Logger.CRITICAL); 1141 setRollbackOnly(); 1142 throw e; 1143 } 1144 1145 protected void fatalError(RuntimeException re) { 1147 getLogger().log("Fatal error: " + re, LOG_CHANNEL, Logger.CRITICAL); 1148 getLogger().log(re, LOG_CHANNEL, Logger.CRITICAL); 1150 setRollbackOnly(); 1151 throw re; 1152 } 1153 1154 protected class TxCacheWrapper implements ObjectCache { 1155 1156 private TxLRUObjectCache txCache; 1157 1158 public TxCacheWrapper(TxLRUObjectCache txCache) { 1159 this.txCache = txCache; 1160 } 1161 1162 public TxCacheWrapper(int globalCacheSize, String name, boolean noGlobalCacheInTx) { 1163 this(new TxLRUObjectCache(globalCacheSize, getName() + "." + name, getLogger(), noGlobalCacheInTx)); 1164 } 1165 1166 public Object get(Object key) { 1167 if (globalCacheOff) 1168 return null; 1169 try { 1170 Xid txId = (Xid ) activeTransactionBranch.get(); 1171 return txCache.get(txId, key); 1172 } catch (Error e) { 1173 fatalError(e); 1174 } catch (RuntimeException re) { 1175 fatalError(re); 1176 } 1177 return null; 1179 } 1180 1181 public void put(Object key, Object value) { 1182 if (globalCacheOff) 1183 return; 1184 try { 1185 Xid txId = (Xid ) activeTransactionBranch.get(); 1186 txCache.put(txId, key, value); 1187 } catch (Error e) { 1188 fatalError(e); 1189 } catch (RuntimeException re) { 1190 fatalError(re); 1191 } 1192 } 1193 1194 public void remove(Object key) { 1195 if (globalCacheOff) 1196 return; 1197 try { 1198 Xid txId = (Xid ) activeTransactionBranch.get(); 1199 txCache.remove(txId, key); 1200 getLogger().log("Removing content at '" + key + "' from cache", LOG_CHANNEL, Logger.DEBUG); 1201 } catch (Error e) { 1202 fatalError(e); 1203 } catch (RuntimeException re) { 1204 fatalError(re); 1205 } 1206 } 1207 1208 public void remove(Object key, String delimiter) { 1209 if (globalCacheOff) 1210 return; 1211 try { 1212 Xid txId = (Xid ) activeTransactionBranch.get(); 1213 txCache.remove(txId, key, delimiter); 1214 getLogger().log("Removing content at '" + key + "' with delimeter '" + delimiter + "' from cache", LOG_CHANNEL, Logger.DEBUG); 1215 } catch (Error e) { 1216 fatalError(e); 1217 } catch (RuntimeException re) { 1218 fatalError(re); 1219 } 1220 } 1221 1222 public void clear() { 1223 try { 1224 txCache.clear(); 1225 } catch (Error e) { 1226 fatalError(e); 1227 } catch (RuntimeException re) { 1228 fatalError(re); 1229 } 1230 } 1231 1232 public TxLRUObjectCache getTxCache() { 1233 return txCache; 1234 } 1235 1236 } 1237 1238 protected class TxContentCacheWrapper extends TxCacheWrapper { 1239 1240 public TxContentCacheWrapper(ByteSizeLimitedObjectCache txCache) { 1241 super(txCache); 1242 } 1243 1244 1253 public void precache(NodeRevisionContent revisionContent, long byteSize) { 1254 if (globalCacheOff) 1255 return; 1256 try { 1257 Xid txId = (Xid ) activeTransactionBranch.get(); 1258 if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(txId, byteSize)) { 1259 revisionContent.getContentBytes(); 1261 } 1262 } catch (Error e) { 1263 fatalError(e); 1264 } catch (RuntimeException re) { 1265 fatalError(re); 1266 } 1267 } 1268 1269 public void putForRead(Object key, NodeRevisionContent revisionContent, long byteSize) { 1270 if (globalCacheOff) 1271 return; 1272 try { 1273 if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(null, byteSize)) { 1274 1275 revisionContent.getContentBytes(); 1277 1278 ((ByteSizeLimitedObjectCache) getTxCache()).put(null, key, revisionContent, byteSize); 1279 getLogger().log( 1280 "Globally caching content at '" + key + "' with " + byteSize + " bytes", 1281 LOG_CHANNEL, 1282 Logger.DEBUG); 1283 } 1284 1285 } catch (Error e) { 1286 fatalError(e); 1287 } catch (RuntimeException re) { 1288 fatalError(re); 1289 } 1290 } 1291 1292 public void put(Object key, NodeRevisionContent revisionContent, long byteSize) { 1293 if (globalCacheOff) 1294 return; 1295 try { 1296 Xid txId = (Xid ) activeTransactionBranch.get(); 1297 if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(txId, byteSize)) { 1298 1299 revisionContent.getContentBytes(); 1301 1302 ((ByteSizeLimitedObjectCache) getTxCache()).put(txId, key, revisionContent, byteSize); 1303 getLogger().log( 1304 "Caching content at '" + key + "' with " + byteSize + " bytes", 1305 LOG_CHANNEL, 1306 Logger.DEBUG); 1307 } else { 1308 getTxCache().remove(txId, key); 1310 } 1311 1312 } catch (Error e) { 1313 fatalError(e); 1314 } catch (RuntimeException re) { 1315 fatalError(re); 1316 } 1317 } 1318 1319 } 1320 1321} 1322 | Popular Tags |