KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > slide > store > ExtendedStore


1 /*
2  * $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/store/ExtendedStore.java,v 1.18 2004/08/09 22:56:12 masonjm Exp $
3  * $Revision: 1.18 $
4  * $Date: 2004/08/09 22:56:12 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2002 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  *
22  */

23
24 package org.apache.slide.store;
25
26 import java.util.Enumeration JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Hashtable JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.Vector JavaDoc;
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 JavaDoc;
61 import javax.transaction.xa.Xid JavaDoc;
62
63 import org.apache.slide.util.logger.Logger;
64 import org.apache.slide.util.logger.TxLogger;
65
66 /**
67  * Store that allows for transactional caching of data. Takes over much modified code from StandardStore.
68  * That's why Remy is listed as author as well.
69  *
70  * @version $Revision: 1.18 $
71  */

72 public class ExtendedStore extends AbstractStore {
73
74     private static final String JavaDoc LOG_CHANNEL = ExtendedStore.class.getName();
75
76     protected static final int DEFAULT_OBJECT_GLOBAL_CACHE_SIZE = 10000;
77     protected static final String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc GLOBAL_CONTENT_CACHE_SIZE_PARAMETER = "content-cache-size";
93
94     protected static final boolean DEFAULT_ENABLE_CONTENT_CACHING = false;
95     protected static final String JavaDoc ENABLE_CONTENT_CACHING_PARAMETER = "enable-content-caching";
96
97     protected static final int DEFAULT_TX_CONTENT_CACHE_SIZE = 1000;
98     protected static final String JavaDoc TX_CONTENT_CACHE_SIZE_PARAMETER = "tx-content-cache-size";
99
100     protected static final long DEFAULT_CONTENT_CACHE_BYTES = 10000000; // 10 M
101
protected static final String JavaDoc CONTENT_CACHE_BYTES_PARAMETER = "content-cache-bytes";
102
103     protected static final long DEFAULT_TX_CONTENT_CACHE_BYTES = 1000000; // 1 M
104
protected static final String JavaDoc TX_CONTENT_CACHE_BYTES_PARAMETER = "tx-content-cache-bytes";
105
106     protected static final long DEFAULT_MAX_CONTENT_BYTES_PER_ENTRY = 50000; // 50 K
107
protected static final String JavaDoc MAX_CONTENT_BYTES_PER_ENTRY_PARAMETER = "max-content-bytes-per-entry";
108
109     protected static final String JavaDoc CACHE_MODE_PARAMETER = "cache-mode";
110     protected static final String JavaDoc CACHE_MODE_FULL = "full";
111     protected static final String JavaDoc CACHE_MODE_LOCAL = "cluster";
112     protected static final String JavaDoc CACHE_MODE_NO_GLOBAL_IN_TX = "isolation-shadow";
113     protected static final String JavaDoc CACHE_MODE_OFF = "off";
114     protected static final String JavaDoc DEFAULT_CACHE_MODE = CACHE_MODE_FULL;
115
116     protected static final int DEFAULT_TLOCK_TIMEOUT = 20000; // 20 sec
117
protected static final String JavaDoc TLOCK_TIMEOUT_PARAMETER = "tlock-timeout";
118
119     // there might be at least one active transaction branch per thread
120
protected ThreadLocal JavaDoc activeTransactionBranch = new ThreadLocal JavaDoc();
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 JavaDoc locks = new ThreadLocal JavaDoc();
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 JavaDoc suspendedLocks = new HashMap JavaDoc();
149
150     public ExtendedStore() {
151         lockManager = new GenericLockManager(1, new TxLogger(getLogger(), LOG_CHANNEL));
152     }
153     
154     public void setParameters(Hashtable JavaDoc 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 JavaDoc timeoutString = (String JavaDoc) parameters.get(TLOCK_TIMEOUT_PARAMETER);
172         if (timeoutString != null) {
173             try {
174                 timeout = Integer.parseInt(timeoutString) * 1000;
175             } catch (NumberFormatException JavaDoc 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 JavaDoc globalObjectCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_OBJECT_CACHE_SIZE_PARAMETER);
182         if (globalObjectCacheSizeString != null) {
183             try {
184                 globalObjectCacheSize = Integer.parseInt(globalObjectCacheSizeString);
185             } catch (NumberFormatException JavaDoc 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 JavaDoc globalPermissionCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_PERMISSION_CACHE_SIZE_PARAMETER);
194         if (globalPermissionCacheSizeString != null) {
195             try {
196                 globalPermissionCacheSize = Integer.parseInt(globalPermissionCacheSizeString);
197             } catch (NumberFormatException JavaDoc 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 JavaDoc globalLockCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_LOCK_CACHE_SIZE_PARAMETER);
207         if (globalLockCacheSizeString != null) {
208             try {
209                 globalLockCacheSize = Integer.parseInt(globalLockCacheSizeString);
210             } catch (NumberFormatException JavaDoc 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 JavaDoc globalDescriptorsCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_DESCRIPTORS_CACHE_SIZE_PARAMETER);
220         if (globalDescriptorsCacheSizeString != null) {
221             try {
222                 globalDescrtiptorsCacheSize = Integer.parseInt(globalDescriptorsCacheSizeString);
223             } catch (NumberFormatException JavaDoc 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 JavaDoc globalDescriptorCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_DESCRIPTOR_CACHE_SIZE_PARAMETER);
233         if (globalDescriptorCacheSizeString != null) {
234             try {
235                 globalDescrtiptorCacheSize = Integer.parseInt(globalDescriptorCacheSizeString);
236             } catch (NumberFormatException JavaDoc 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 JavaDoc enableContentCachingString = (String JavaDoc) 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 JavaDoc globalContentCacheSizeString = (String JavaDoc) parameters.get(GLOBAL_CONTENT_CACHE_SIZE_PARAMETER);
255         if (globalContentCacheSizeString != null) {
256             try {
257                 globalContentCacheSize = Integer.parseInt(globalContentCacheSizeString);
258             } catch (NumberFormatException JavaDoc 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 JavaDoc contentCacheBytesString = (String JavaDoc) parameters.get(CONTENT_CACHE_BYTES_PARAMETER);
268         if (contentCacheBytesString != null) {
269             try {
270                 contentCacheBytes = Long.parseLong(contentCacheBytesString);
271             } catch (NumberFormatException JavaDoc 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 JavaDoc txContentCacheSizeString = (String JavaDoc) parameters.get(TX_CONTENT_CACHE_SIZE_PARAMETER);
284         if (txContentCacheSizeString != null) {
285             try {
286                 txContentCacheSize = Integer.parseInt(txContentCacheSizeString);
287             } catch (NumberFormatException JavaDoc 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 JavaDoc txContentCacheBytesString = (String JavaDoc) parameters.get(TX_CONTENT_CACHE_BYTES_PARAMETER);
300         if (txContentCacheBytesString != null) {
301             try {
302                 txContentCacheBytes = Long.parseLong(txContentCacheBytesString);
303             } catch (NumberFormatException JavaDoc 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 JavaDoc maxByteSizePerEntryString = (String JavaDoc) parameters.get(MAX_CONTENT_BYTES_PER_ENTRY_PARAMETER);
316         if (maxByteSizePerEntryString != null) {
317             try {
318                 maxByteSizePerEntry = Long.parseLong(maxByteSizePerEntryString);
319             } catch (NumberFormatException JavaDoc 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 JavaDoc cacheModeString = (String JavaDoc) 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         // disable global cache if desired
364
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     /**
395      * Removes an object from all internal caches.
396      *
397      * @param key the key under which the object is stored in the caches.
398      */

399     public void removeObjectFromCache( Object JavaDoc 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         // Locks shouldn't be cached, but just in case.
413
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 JavaDoc uri)
425             throws ServiceAccessException {
426         Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
427         if (txId != null) {
428             try {
429                 GenericLock lock = (GenericLock) lockManager
430                         .atomicGetOrCreateLock(uri);
431                 if (lock.getLockLevel(txId) != 1) {
432                     Object JavaDoc 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 JavaDoc) locks.get()).add(lock);
448                     getLogger().log("Has lock: " + txId + " locks " + uri,
449                             LOG_CHANNEL, Logger.DEBUG);
450                 }
451             } catch (InterruptedException JavaDoc e) {
452                 throw new ServiceAccessException(this, new ConflictException(
453                         uri));
454             }
455         }
456     }
457
458     //
459
// overloaded content methods with caching
460
//
461

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 JavaDoc key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber();
470                 Object JavaDoc result = contentCache.get(key);
471                 if (result != null) {
472                     getLogger().log("Retrieving content at '" + key + "' from cache", LOG_CHANNEL, Logger.DEBUG);
473                     // FIXME make a copy?! how?
474
return (NodeRevisionContent) result;
475                 } else {
476                     NodeRevisionContent revisionContent = super.retrieveRevisionContent(uri, revisionDescriptor);
477                     long size = revisionDescriptor.getContentLength();
478                     // Do not add content to global cache, as this might violate repeatable read.
479
// When we reread the entry later and another thread has committed its stuff
480
// into the global cache we might get a different version on the second read.
481
contentCache.put(key, revisionContent, size);
482 // contentCache.putForRead(key, revisionContent, size);
483
// FIXME make a copy?! how?
484
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 JavaDoc 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 JavaDoc 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 JavaDoc key = uri.toString() + "_" + revisionDescriptor.getRevisionNumber();
552                 contentCache.remove(key);
553             } finally {
554                 delist(this);
555             }
556         }
557         super.removeRevisionContent(uri, revisionDescriptor);
558     }
559
560     //
561
// overloaded retrieval methods guaranteeing cache enlistment in retrieval
562
//
563

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 JavaDoc 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                     // add the link into the "linked" object if it is in the cache
609
String JavaDoc 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                     // check if the linked object is in the cache, and remove the linknode fromits link vector
629
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 JavaDoc permissionsVector = fillPermissionsCache(uri);
647                 // operate on a copy
648
Vector JavaDoc tempPermissions = (Vector JavaDoc )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 JavaDoc permissionsVector = fillPermissionsCache(uri);
663                 // operate on a copy
664
Vector JavaDoc tempPermissions = (Vector JavaDoc )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 JavaDoc value = permissionsCache.get(uri.toString());
680                 if (value != null) {
681                     permissionsCache.put(uri.toString(), new Vector JavaDoc());
682                 }
683             } finally {
684                 delist(this);
685             }
686         }
687     }
688
689     public Enumeration JavaDoc enumeratePermissions(Uri uri) throws ServiceAccessException {
690         if (securityStore.cacheResults()) {
691             if (isForceStoreEnlistment(uri)) {
692                 enlist(this);
693             }
694             try {
695                 Vector JavaDoc permissionsVector = fillPermissionsCache(uri);
696                 return ((Vector JavaDoc) 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 JavaDoc locks = fillLocksCache(uri);
713                 // operate on a copy
714
Vector JavaDoc tempLocks = (Vector JavaDoc) 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 JavaDoc value = locksCache.get(uri.toString());
729                 Vector JavaDoc locksVector = null;
730                 if (value != null) {
731                     locksVector = new Vector JavaDoc((Vector JavaDoc) 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 JavaDoc value = locksCache.get(uri.toString());
751                 Vector JavaDoc locksVector = null;
752                 if (value != null) {
753                     locksVector = new Vector JavaDoc((Vector JavaDoc) 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 JavaDoc value = locksCache.get(uri.toString());
772                 Vector JavaDoc locksVector = null;
773                 if (value != null) {
774                     locksVector = new Vector JavaDoc((Vector JavaDoc) 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 JavaDoc enumerateLocks(Uri uri) throws ServiceAccessException {
788         if (lockStore.cacheResults()) {
789             if (isForceStoreEnlistment(uri)) {
790                 enlist(this);
791             }
792             try {
793                 Vector JavaDoc locks = fillLocksCache(uri);
794                 return ((Vector JavaDoc) 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 JavaDoc 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 JavaDoc 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 JavaDoc 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     //
937
// overloaded XAResource methods for transaction support
938
//
939

940     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
941         releaseTransientLocks();
942
943         Xid JavaDoc txId = (Xid JavaDoc) 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 JavaDoc xid) throws XAException JavaDoc {
956         releaseTransientLocks();
957
958         Xid JavaDoc txId = (Xid JavaDoc) 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 JavaDoc xid, boolean onePhase) throws XAException JavaDoc {
971         releaseTransientLocks();
972
973         Xid JavaDoc txId = (Xid JavaDoc) 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 JavaDoc xid) throws XAException JavaDoc {
986         // failure is notifyed directly on transaction, so there is no need to check it here
987
return XA_OK;
988     }
989
990     // FIXME needs suspend and resume here as well!
991
public void start(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
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 JavaDoc txId = (Xid JavaDoc) XidWrapper.wrap(xid);
1001        activeTransactionBranch.set(txId);
1002        if (flags == TMNOFLAGS || flags == TMJOIN) {
1003
1004            locks.set(new HashSet JavaDoc());
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 JavaDoc xid, int flags) throws XAException JavaDoc {
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 JavaDoc txId = (Xid JavaDoc) XidWrapper.wrap(xid);
1029            suspendedLocks.put(txId, locks.get());
1030        }
1031        locks.set(null);
1032        activeTransactionBranch.set(null);
1033    }
1034
1035    //
1036

1037    public String JavaDoc toString() {
1038        return getName() + "(" + getClass().getName() + ")";
1039    }
1040
1041    protected void releaseTransientLocks() {
1042        // XXX can be the case when an external transaction took up work in another thread
1043
// no need to implement suspend and resume here as tlocks will not be used with external transactions
1044
if (locks.get() == null) return;
1045
1046        Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1047        for (Iterator JavaDoc it = ((HashSet JavaDoc)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 JavaDoc fillPermissionsCache(Uri uri) throws ServiceAccessException {
1058        Vector JavaDoc permissions = (Vector JavaDoc) permissionsCache.get(uri.toString());
1059        if (permissions != null) {
1060            return permissions;
1061        } else {
1062            permissions = new Vector JavaDoc();
1063            Enumeration JavaDoc 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 JavaDoc fillLocksCache(Uri uri) throws ServiceAccessException {
1075        Vector JavaDoc locksVector = (Vector JavaDoc) locksCache.get(uri.toString());
1076        if (locksVector != null) {
1077            return locksVector;
1078        } else {
1079            locksVector = new Vector JavaDoc();
1080            Enumeration JavaDoc 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    //
1092

1093    // have it outside ctor to make it overloadable
1094
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 JavaDoc e) {
1130            fatalError(e);
1131        } catch (RuntimeException JavaDoc re) {
1132            fatalError(re);
1133        }
1134    }
1135
1136    // could be out of memory etc.
1137
protected void fatalError(Error JavaDoc e) {
1138        getLogger().log("Fatal error: " + e, LOG_CHANNEL, Logger.CRITICAL);
1139        // XXX needed to guarantee, stack trace will be displayed
1140
getLogger().log(e, LOG_CHANNEL, Logger.CRITICAL);
1141        setRollbackOnly();
1142        throw e;
1143    }
1144
1145    // could be null pointer or any other programming error
1146
protected void fatalError(RuntimeException JavaDoc re) {
1147        getLogger().log("Fatal error: " + re, LOG_CHANNEL, Logger.CRITICAL);
1148        // XXX needed to guarantee, stack trace will be displayed
1149
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 JavaDoc name, boolean noGlobalCacheInTx) {
1163            this(new TxLRUObjectCache(globalCacheSize, getName() + "." + name, getLogger(), noGlobalCacheInTx));
1164        }
1165
1166        public Object JavaDoc get(Object JavaDoc key) {
1167            if (globalCacheOff)
1168                return null;
1169            try {
1170                Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1171                return txCache.get(txId, key);
1172            } catch (Error JavaDoc e) {
1173                fatalError(e);
1174            } catch (RuntimeException JavaDoc re) {
1175                fatalError(re);
1176            }
1177            // XXX will never be called, as fatalError will always throw a throwable, just satisfy compiler
1178
return null;
1179        }
1180
1181        public void put(Object JavaDoc key, Object JavaDoc value) {
1182            if (globalCacheOff)
1183                return;
1184            try {
1185                Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1186                txCache.put(txId, key, value);
1187            } catch (Error JavaDoc e) {
1188                fatalError(e);
1189            } catch (RuntimeException JavaDoc re) {
1190                fatalError(re);
1191            }
1192        }
1193
1194        public void remove(Object JavaDoc key) {
1195            if (globalCacheOff)
1196                return;
1197            try {
1198                Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1199                txCache.remove(txId, key);
1200                getLogger().log("Removing content at '" + key + "' from cache", LOG_CHANNEL, Logger.DEBUG);
1201            } catch (Error JavaDoc e) {
1202                fatalError(e);
1203            } catch (RuntimeException JavaDoc re) {
1204                fatalError(re);
1205            }
1206        }
1207
1208        public void remove(Object JavaDoc key, String JavaDoc delimiter) {
1209            if (globalCacheOff)
1210                return;
1211            try {
1212                Xid JavaDoc txId = (Xid JavaDoc) 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 JavaDoc e) {
1216                fatalError(e);
1217            } catch (RuntimeException JavaDoc re) {
1218                fatalError(re);
1219            }
1220        }
1221
1222        public void clear() {
1223            try {
1224                txCache.clear();
1225            } catch (Error JavaDoc e) {
1226                fatalError(e);
1227            } catch (RuntimeException JavaDoc 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        /*
1245         * Ensures that if revisionContent will be cached later, it will be accessible multiple times.
1246         * It does so by copying its input stream into a byte array. To avoid excessively large byte
1247         * arrays this is only done when revisionContent fits into the cache and will be cached later anyway.
1248         * <br>
1249         * <br>
1250         * <em>Caution</em>: This method must be called before any other method modifies revisionContent.
1251         *
1252         */

1253        public void precache(NodeRevisionContent revisionContent, long byteSize) {
1254            if (globalCacheOff)
1255                return;
1256            try {
1257                Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1258                if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(txId, byteSize)) {
1259                    // buffer stream content into byte array for multiple access
1260
revisionContent.getContentBytes();
1261                }
1262            } catch (Error JavaDoc e) {
1263                fatalError(e);
1264            } catch (RuntimeException JavaDoc re) {
1265                fatalError(re);
1266            }
1267        }
1268
1269        public void putForRead(Object JavaDoc key, NodeRevisionContent revisionContent, long byteSize) {
1270            if (globalCacheOff)
1271                return;
1272            try {
1273                if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(null, byteSize)) {
1274
1275                    // buffer stream content into byte array for multiple access
1276
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 JavaDoc e) {
1286                fatalError(e);
1287            } catch (RuntimeException JavaDoc re) {
1288                fatalError(re);
1289            }
1290        }
1291
1292        public void put(Object JavaDoc key, NodeRevisionContent revisionContent, long byteSize) {
1293            if (globalCacheOff)
1294                return;
1295            try {
1296                Xid JavaDoc txId = (Xid JavaDoc) activeTransactionBranch.get();
1297                if (((ByteSizeLimitedObjectCache) getTxCache()).canCache(txId, byteSize)) {
1298
1299                    // buffer stream content into byte array for multiple access
1300
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                    // if we can not cache it, we need to invalidate global entry upon commit
1309
getTxCache().remove(txId, key);
1310                }
1311
1312            } catch (Error JavaDoc e) {
1313                fatalError(e);
1314            } catch (RuntimeException JavaDoc re) {
1315                fatalError(re);
1316            }
1317        }
1318
1319    }
1320
1321}
1322
Popular Tags