KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb3 > entity > OptimisticJBCCache


1 package org.jboss.ejb3.entity;
2
3 import java.util.Comparator JavaDoc;
4 import java.util.HashMap JavaDoc;
5 import java.util.Iterator JavaDoc;
6 import java.util.Map JavaDoc;
7 import java.util.Set JavaDoc;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.hibernate.cache.CacheException;
12 import org.hibernate.cache.OptimisticCache;
13 import org.hibernate.cache.OptimisticCacheSource;
14 import org.jboss.cache.Fqn;
15 import org.jboss.cache.InvocationContext;
16 import org.jboss.cache.Node;
17 import org.jboss.cache.config.Option;
18 import org.jboss.cache.lock.TimeoutException;
19 import org.jboss.cache.optimistic.DataVersion;
20
21 public class OptimisticJBCCache implements OptimisticCache
22 {
23     // todo : eventually merge this with TreeCache and just add optional opt-lock support there.
24

25     private static final Log log = LogFactory.getLog( OptimisticJBCCache.class);
26
27     private static final String JavaDoc ITEM = "item";
28
29     private static final Option NONLOCKING_OPTION = new Option();
30     private static final Option FAIL_SILENT_OPTION = new Option();
31     private static final Option FAIL_SILENT_NONLOCKING_OPTION = new Option();
32     
33     static
34     {
35        FAIL_SILENT_OPTION.setFailSilently( true );
36        
37        FAIL_SILENT_NONLOCKING_OPTION.setFailSilently( true );
38        FAIL_SILENT_NONLOCKING_OPTION.setDataVersion( NonLockingDataVersion.INSTANCE );
39        NONLOCKING_OPTION.setDataVersion( NonLockingDataVersion.INSTANCE );
40     }
41     
42     private org.jboss.cache.Cache cache;
43     private final String JavaDoc regionName;
44     private final Fqn regionFqn;
45     private OptimisticCacheSource source;
46
47     public OptimisticJBCCache(org.jboss.cache.Cache cache, String JavaDoc regionName)
48     throws CacheException {
49         this.cache = cache;
50         this.regionName = regionName;
51         this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
52     }
53
54
55     // OptimisticCache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
56

57     public void setSource(OptimisticCacheSource source) {
58         this.source = source;
59     }
60
61     public void writeInsert(Object JavaDoc key, Object JavaDoc value, Object JavaDoc currentVersion) {
62         writeUpdate( key, value, currentVersion, null );
63     }
64
65     public void writeUpdate(Object JavaDoc key, Object JavaDoc value, Object JavaDoc currentVersion, Object JavaDoc previousVersion)
66     {
67        InvocationContext ctx = cache.getInvocationContext();
68        Option existing = ctx.getOptionOverrides();
69         try {
70             Option option = new Option();
71             DataVersion dv = ( source != null && source.isVersioned() )
72                              ? new DataVersionAdapter( currentVersion, previousVersion, source.getVersionComparator(), source.toString() )
73                              : NonLockingDataVersion.INSTANCE;
74             option.setDataVersion( dv );
75             
76             ctx.setOptionOverrides(option);
77             cache.put( new Fqn( regionFqn, key ), ITEM, value);
78         }
79         catch ( Exception JavaDoc e ) {
80             throw new CacheException( e );
81         }
82         finally
83         {
84            ctx.setOptionOverrides(existing);
85         }
86     }
87
88     public void writeLoad(Object JavaDoc key, Object JavaDoc value, Object JavaDoc currentVersion)
89     {
90        InvocationContext ctx = cache.getInvocationContext();
91        Option existing = ctx.getOptionOverrides();
92         try {
93            
94             ctx.setOptionOverrides(FAIL_SILENT_NONLOCKING_OPTION);
95             cache.remove( new Fqn( regionFqn, key ), "ITEM");
96
97             Option option = new Option();
98             option.setFailSilently( true );
99             DataVersion dv = ( source != null && source.isVersioned() )
100                              ? new DataVersionAdapter( currentVersion, currentVersion, source.getVersionComparator(), source.toString() )
101                              : NonLockingDataVersion.INSTANCE;
102             option.setDataVersion( dv );
103             
104             ctx = cache.getInvocationContext();
105             ctx.setOptionOverrides(option);
106             cache.put( new Fqn( regionFqn, key ), ITEM, value);
107         }
108         catch (Exception JavaDoc e) {
109             throw new CacheException(e);
110         }
111         finally
112         {
113            ctx.setOptionOverrides(existing);
114         }
115     }
116
117
118     // Cache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
119

120     public Object JavaDoc get(Object JavaDoc key) throws CacheException
121     {
122        InvocationContext ctx = cache.getInvocationContext();
123        Option existing = ctx.getOptionOverrides();
124         try {
125             
126 // ctx.setOptionOverrides(FAIL_SILENT_NONLOCKING_OPTION);
127
ctx.setOptionOverrides(FAIL_SILENT_OPTION);
128             return cache.get( new Fqn( regionFqn, key ), ITEM);
129         }
130         catch (Exception JavaDoc e) {
131             throw new CacheException(e);
132         }
133         finally
134         {
135            ctx.setOptionOverrides(existing);
136         }
137     }
138
139     public Object JavaDoc read(Object JavaDoc key) throws CacheException {
140         try {
141             return cache.get( new Fqn( regionFqn, key ), ITEM );
142         }
143         catch (Exception JavaDoc e) {
144             throw new CacheException(e);
145         }
146     }
147
148     public void update(Object JavaDoc key, Object JavaDoc value) throws CacheException
149     {
150        InvocationContext ctx = cache.getInvocationContext();
151        Option existing = ctx.getOptionOverrides();
152         try {
153             ctx.setOptionOverrides(NONLOCKING_OPTION);
154             cache.put( new Fqn( regionFqn, key ), ITEM, value );
155         }
156         catch (Exception JavaDoc e) {
157             throw new CacheException(e);
158         }
159         finally
160         {
161            ctx.setOptionOverrides(existing);
162         }
163     }
164
165     public void put(Object JavaDoc key, Object JavaDoc value) throws CacheException
166     {
167        InvocationContext ctx = cache.getInvocationContext();
168        Option existing = ctx.getOptionOverrides();
169         try {
170             log.trace( "performing put() into region [" + regionName + "]" );
171             // do the put outside the scope of the JTA txn
172
ctx.setOptionOverrides(FAIL_SILENT_NONLOCKING_OPTION);
173             cache.put( new Fqn( regionFqn, key ), ITEM, value );
174         }
175         catch (TimeoutException te) {
176             //ignore!
177
log.debug("ignoring write lock acquisition failure");
178         }
179         catch (Exception JavaDoc e) {
180             throw new CacheException(e);
181         }
182         finally
183         {
184            ctx.setOptionOverrides(existing);
185         }
186     }
187
188     public void remove(Object JavaDoc key) throws CacheException
189     {
190        InvocationContext ctx = cache.getInvocationContext();
191        Option existing = ctx.getOptionOverrides();
192         try {
193             // tree cache in optimistic mode seems to have as very difficult
194
// time with remove calls on non-existent nodes (NPEs)...
195
if ( cache.get( new Fqn( regionFqn, key ), ITEM ) != null ) {
196                 Option option = new Option();
197                 option.setDataVersion( NonLockingDataVersion.INSTANCE );
198                 ctx.setOptionOverrides(option);
199                 cache.removeNode( new Fqn( regionFqn, key ) );
200             }
201             else {
202                 log.trace( "skipping remove() call as the underlying node did not seem to exist" );
203             }
204         }
205         catch (Exception JavaDoc e) {
206             throw new CacheException(e);
207         }
208         finally
209         {
210            ctx.setOptionOverrides(existing);
211         }
212     }
213
214     public void clear() throws CacheException
215     {
216        InvocationContext ctx = cache.getInvocationContext();
217        Option existing = ctx.getOptionOverrides();
218         try {
219             Option option = new Option();
220             option.setDataVersion( NonLockingDataVersion.INSTANCE );
221             ctx.setOptionOverrides(option);
222             cache.removeNode( regionFqn );
223         }
224         catch (Exception JavaDoc e) {
225             throw new CacheException(e);
226         }
227         finally
228         {
229            ctx.setOptionOverrides(existing);
230         }
231     }
232
233     public void destroy() throws CacheException
234     {
235        InvocationContext ctx = cache.getInvocationContext();
236        Option existing = ctx.getOptionOverrides();
237         try {
238             Option option = new Option();
239             option.setCacheModeLocal( true );
240             option.setFailSilently( true );
241             option.setDataVersion( NonLockingDataVersion.INSTANCE );
242             ctx.setOptionOverrides(option);
243             cache.removeNode( regionFqn );
244         }
245         catch( Exception JavaDoc e ) {
246             throw new CacheException( e );
247         }
248         finally
249         {
250            ctx.setOptionOverrides(existing);
251         }
252     }
253
254     public void lock(Object JavaDoc key) throws CacheException {
255         throw new UnsupportedOperationException JavaDoc( "TreeCache is a fully transactional cache" + regionName );
256     }
257
258     public void unlock(Object JavaDoc key) throws CacheException {
259         throw new UnsupportedOperationException JavaDoc( "TreeCache is a fully transactional cache: " + regionName );
260     }
261
262     public long nextTimestamp() {
263         return System.currentTimeMillis() / 100;
264     }
265
266     public int getTimeout() {
267         return 600; //60 seconds
268
}
269
270     public String JavaDoc getRegionName() {
271         return regionName;
272     }
273
274     public long getSizeInMemory() {
275         return -1;
276     }
277
278     public long getElementCountInMemory() {
279         try {
280             Set JavaDoc children = getChildrenNames();
281             return children == null ? 0 : children.size();
282         }
283         catch (Exception JavaDoc e) {
284             throw new CacheException(e);
285         }
286     }
287
288     public long getElementCountOnDisk() {
289         return 0;
290     }
291
292     public Map JavaDoc toMap() {
293         try {
294             Map JavaDoc result = new HashMap JavaDoc();
295             Set JavaDoc childrenNames = getChildrenNames();
296             if (childrenNames != null) {
297                 Iterator JavaDoc iter = childrenNames.iterator();
298                 while ( iter.hasNext() ) {
299                     Object JavaDoc key = iter.next();
300                     result.put(
301                             key,
302                             cache.get( new Fqn( regionFqn, key ), ITEM )
303                         );
304                 }
305             }
306             return result;
307         }
308         catch (Exception JavaDoc e) {
309             throw new CacheException(e);
310         }
311     }
312     
313     private Set JavaDoc getChildrenNames()
314     {
315        try {
316           Node base = cache.getChild( regionFqn );
317           return base == null ? null : base.getChildrenNames();
318        }
319        catch (Exception JavaDoc e) {
320           throw new CacheException(e);
321        }
322     }
323
324     public String JavaDoc toString() {
325         return "OptimisticTreeCache(" + regionName + ')';
326     }
327
328     public static class DataVersionAdapter implements DataVersion {
329         private final Object JavaDoc currentVersion;
330         private final Object JavaDoc previousVersion;
331         private final Comparator JavaDoc versionComparator;
332         private final String JavaDoc sourceIdentifer;
333
334         public DataVersionAdapter(Object JavaDoc currentVersion, Object JavaDoc previousVersion, Comparator JavaDoc versionComparator, String JavaDoc sourceIdentifer) {
335             this.currentVersion = currentVersion;
336             this.previousVersion = previousVersion;
337             this.versionComparator = versionComparator;
338             this.sourceIdentifer = sourceIdentifer;
339             log.trace( "created " + this );
340         }
341
342         /**
343          * newerThan() call is dispatched against the DataVersion currently
344          * associated with the node; the passed dataVersion param is the
345          * DataVersion associated with the data we are trying to put into
346          * the node.
347          * <p/>
348          * we are expected to return true in the case where we (the current
349          * node DataVersion) are newer that then incoming value. Returning
350          * true here essentially means that a optimistic lock failure has
351          * occured (because conversely, the value we are trying to put into
352          * the node is "older than" the value already there...)
353          */

354         public boolean newerThan(DataVersion dataVersion) {
355             log.trace( "checking [" + this + "] against [" + dataVersion + "]" );
356             if ( dataVersion instanceof CircumventChecksDataVersion ) {
357                 log.trace( "skipping lock checks..." );
358                 return false;
359             }
360             else if ( dataVersion instanceof NonLockingDataVersion ) {
361                 // can happen because of the multiple ways Cache.remove()
362
// can be invoked :(
363
log.trace( "skipping lock checks..." );
364                 return false;
365             }
366             DataVersionAdapter other = ( DataVersionAdapter ) dataVersion;
367             if ( other.previousVersion == null ) {
368                 log.warn( "Unexpected optimistic lock check on inserting data" );
369                 // work around the "feature" where tree cache is validating the
370
// inserted node during the next transaction. no idea...
371
if ( this == dataVersion ) {
372                     log.trace( "skipping lock checks due to same DV instance" );
373                     return false;
374                 }
375             }
376             return versionComparator.compare( currentVersion, other.previousVersion ) >= 1;
377         }
378
379         public String JavaDoc toString() {
380             return super.toString() + " [current=" + currentVersion + ", previous=" + previousVersion + ", SRC=" + sourceIdentifer + "]";
381         }
382     }
383
384     /**
385      * Used in regions where no locking should ever occur. This includes query-caches,
386      * update-timestamps caches, collection caches, and entity caches where the entity
387      * is not versioned.
388      */

389     public static class NonLockingDataVersion implements DataVersion {
390         public static final DataVersion INSTANCE = new NonLockingDataVersion();
391         public boolean newerThan(DataVersion dataVersion) {
392             log.trace( "non locking lock check...");
393             return false;
394         }
395     }
396
397     /**
398      * Used to signal to a DataVersionAdapter to simply not perform any checks. This
399      * is currently needed for proper handling of remove() calls for entity cache regions
400      * (we do not know the version info...).
401      */

402     public static class CircumventChecksDataVersion implements DataVersion {
403         public static final DataVersion INSTANCE = new CircumventChecksDataVersion();
404         public boolean newerThan(DataVersion dataVersion) {
405             throw new CacheException( "optimistic locking checks should never happen on CircumventChecksDataVersion" );
406         }
407     }
408
409 }
410
Popular Tags