KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > internal > identitymaps > IdentityMap


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.internal.identitymaps;
23
24 import java.util.*;
25 import java.io.*;
26 import oracle.toplink.essentials.internal.helper.*;
27
28 /**
29  * <p><b>Purpose</b>: Caches objects, and allows their retrieval by their primary key.
30  * <p><b>Responsibilities</b>:<ul>
31  * <li> Store CacheKeys containing objects and possibly writeLockValues
32  * <li> Insert & retrieve objects from the cache
33  * <li> Allow retrieval and modification of writeLockValue for a cached object.
34  * </ul>
35  * @see CacheKey
36  * @since TOPLink/Java 1.0
37  */

38 public abstract class IdentityMap implements Serializable, Cloneable JavaDoc {
39
40     /** The innitial or maximum size of the cache depending upon the concrete implementation */
41     protected int maxSize;
42
43     /** Used to optimize get through avoiding recreation of the cache key each time. */
44     protected CacheKey searchKey;
45
46     /**
47      * Instantiate an new IdentityMap with it's maximum size.<p>
48      * <b>NOTE</b>: Subclasses may provide different behaviour for maxSize.
49      * @param anInteger is the maximum size to be allocated for the recevier.
50     */

51     public IdentityMap(int size) {
52         maxSize = size;
53         searchKey = new CacheKey(new Vector(1), null, null);
54     }
55
56     /**
57      * Acquire the deferred lock
58      */

59     public CacheKey acquireDeferredLock(Vector primaryKey) {
60         //check if the key is already in the hashtable
61
CacheKey key = null;
62
63         //cache key should not be changed in other threads during the lock acquire operation
64
synchronized (this) {
65             // bug 3094912 get must be synchronized as well
66
key = getCacheKey(primaryKey);
67             if (key == null) {
68                 //create a chachKey and lock the object
69
CacheKey cacheKey = createCacheKey(primaryKey, null, null);
70                 cacheKey.acquireDeferredLock();
71                 put(cacheKey);
72                 return cacheKey;
73             }
74         }
75
76         // code removed as key will never be null here, either one will be found or one created
77
key.acquireDeferredLock();
78
79         return key;
80     }
81
82     /**
83      * Set an exclusive lock on an object in the IdentityMap. This is provided so that when the object is being read from the database
84      * the reader can lock the object while it builds and caches the new object. This will prevent other threads
85      * from accessing this objects but will not stop other threads from inserting other objects into this IdentityMap.
86      */

87     public CacheKey acquireLock(Vector primaryKey, boolean forMerge) {
88         //check if the key is already in the hashtable
89
CacheKey key = null;
90
91         //cache key should not be changed in other threads during the lock acquire operation
92
synchronized (this) {
93             // bug 3094912 get must be synchronized as well
94
key = getCacheKey(primaryKey);
95             if (key == null) {
96                 //create a chachKey and lock the object
97
CacheKey cacheKey = createCacheKey(primaryKey, null, null);
98                 cacheKey.acquire(forMerge);
99                 put(cacheKey);
100                 return cacheKey;
101             }
102         }
103
104         // code removed as key will never be null here, either one will be found or one created
105
key.acquire();
106
107         return key;
108     }
109
110     /**
111      * INTERNAL:
112      * Used to print all the Locks in every identity map in this session.
113      * The output of this method will go to log passed in as a parameter.
114      */

115     public abstract void collectLocks(HashMap threadList);
116
117     /**
118      * Set an exclusive lock on an object in the IdentityMap. This is provided so that when the object is being read from the database
119      * the reader can lock the object while it builds and caches the new object. This will prevent other threads
120      * from accessing this objects but will not stop other threads from inserting other objects into this IdentityMap.
121      */

122     public CacheKey acquireLockNoWait(Vector primaryKey, boolean forMerge) {
123         //check if the key is already in the hashtable
124
CacheKey key = null;
125
126         //cache key should not be changed in other threads during the lock acquire operation
127
synchronized (this) {
128             key = getCacheKey(primaryKey);
129             if (key == null) {
130                 //create a chachKey and lock the object
131
CacheKey cacheKey = createCacheKey(primaryKey, null, null);
132                 cacheKey.acquire(forMerge);
133                 put(cacheKey);
134                 return cacheKey;
135             }
136         }
137
138         //find the key in the hashtable, lock the object
139
if (key != null) {
140             //couldn't acquire the key so do not return it
141
if (!key.acquireNoWait(forMerge)) {
142                 key = null;
143             }
144         }
145
146         return key;
147     }
148
149     /**
150      * INTERNAL:
151      * Find the cachekey for the provided primary key and place a readlock on it.
152      * This will allow multiple users to read the same object but prevent writes to
153      * the object while the read lock is held.
154      */

155     public CacheKey acquireReadLockOnCacheKey(Vector primaryKey) {
156         //check if the key is already in the hashtable
157
CacheKey key = null;
158
159         //cache key should not be changed in other threads during the lock acquire operation
160
synchronized (this) {
161             key = getCacheKey(primaryKey);
162             if (key == null) {
163                 //create a chachKey and lock the object
164
CacheKey cacheKey = createCacheKey(primaryKey, null, null);
165
166                 //lets create one but not put it in the cache, as we are only reading
167
// should not be writing to the identitymap
168
cacheKey.acquireReadLock();
169                 return cacheKey;
170             }
171         }
172
173         key.acquireReadLock();
174
175         return key;
176     }
177
178     /**
179      * INTERNAL:
180      * Find the cachekey for the provided primary key and place a readlock on it.
181      * This will allow multiple users to read the same object but prevent writes to
182      * the object while the read lock is held.
183      * If no readlock can be acquired then do not wait but return null.
184      */

185     public CacheKey acquireReadLockOnCacheKeyNoWait(Vector primaryKey) {
186         //check if the key is already in the hashtable
187
CacheKey key = null;
188
189         //cache key should not be changed in other threads during the lock acquire operation
190
synchronized (this) {
191             key = getCacheKey(primaryKey);
192             if (key == null) {
193                 //create a chachKey and lock the object
194
CacheKey cacheKey = createCacheKey(primaryKey, null, null);
195                 cacheKey.acquireReadLock();
196
197                 //lets create one but not put it in the cache, as we are only reading
198
// should not be writing to the identitymap
199
return cacheKey;
200             }
201         }
202
203         //find the key in the hashtable, lock the object
204
if (key != null) {
205             //couldn't acquire the key so do not return it
206
if (!key.acquireReadLockNoWait()) {
207                 key = null;
208             }
209         }
210
211         return key;
212     }
213
214     /**
215      * INTERNAL:
216      * Clones itself.
217      */

218     public Object JavaDoc clone() {
219         Object JavaDoc object = null;
220
221         try {
222             object = super.clone();
223         } catch (Exception JavaDoc e) {
224             ;
225         }
226
227         return object;
228     }
229
230     /**
231      * Return true if an object is indexed in the recevier at the primary key &lt;aVector&gt;
232      * @param aVector is the primary key for the object to search for.
233      */

234     public boolean containsKey(Vector primaryKey) {
235         CacheKey wrapper = getCacheKeyWithReadLock(primaryKey);
236
237         if (wrapper == null) {
238             return false;
239         } else {
240             return true;
241         }
242     }
243
244     public CacheKey createCacheKey(Vector primaryKey, Object JavaDoc object, Object JavaDoc writeLockValue) {
245         return createCacheKey(primaryKey, object, writeLockValue, 0);
246     }
247
248     public CacheKey createCacheKey(Vector primaryKey, Object JavaDoc object, Object JavaDoc writeLockValue, long readTime) {
249         return new CacheKey(primaryKey, object, writeLockValue, readTime);
250     }
251
252     /**
253      * Allow for the cache to be iterated on.
254      */

255     public abstract Enumeration elements();
256
257     /**
258      * Return the object cached in the identity map or null if it could not be found.
259      */

260     public Object JavaDoc get(Vector primaryKey) {
261         CacheKey cacheKey = getCacheKeyWithReadLock(primaryKey);
262
263         if (cacheKey == null) {
264             return null;
265         }
266         return cacheKey.getObject();
267     }
268
269     /**
270      * Get the cache key (with object) for the primary key.
271      * This reuses the same instance of cache key (searchKey) for all of the get to improve performance.
272      */

273     protected CacheKey getCacheKey(Vector primaryKey) {
274         CacheKey key = null;
275
276         synchronized (this) {
277             getSearchKey().setKey(primaryKey);
278             key = getCacheKey(getSearchKey());
279         }
280
281         return key;
282     }
283
284     /**
285      * Return the cache key (with object) matching the cache key wrapper of the primary key.
286      */

287     protected abstract CacheKey getCacheKey(CacheKey cacheKey);
288
289     /**
290      * Get the cache key (with object) for the primary key with read lock.
291      */

292     protected CacheKey getCacheKeyWithReadLock(Vector primaryKey) {
293         CacheKey key = getCacheKey(primaryKey);
294
295         if (key != null) {
296             key.acquireReadLock();
297             key.releaseReadLock();
298         }
299
300         return key;
301     }
302
303     /**
304      * INTERNAL:
305      * Returns the class which should be used as an identity map. For JDK1.1.x
306      * FullIdentityMap is the default, for JDK1.2 it is SoftCacheWeakIdentityMap.
307      *
308      * @return java.lang.Class
309      */

310     public static Class JavaDoc getDefaultIdentityMapClass() {
311         return ClassConstants.SoftCacheWeakIdentityMap_Class;
312     }
313
314     /**
315      * @return The maxSize for the IdentityMap (NOTE: some subclasses may use this differently).
316      */

317     public int getMaxSize() {
318         if (maxSize == -1) {
319             maxSize = 100;
320         }
321         return maxSize;
322     }
323
324     protected CacheKey getSearchKey() {
325         return searchKey;
326     }
327
328     /**
329      * Return the number of objects in the receiver.
330      */

331     public abstract int getSize();
332
333     /**
334      * Return the number of actual objects of type myClass in the IdentityMap.
335      * Recurse = true will include subclasses of myClass in the count.
336      */

337     public abstract int getSize(Class JavaDoc myClass, boolean recurse);
338
339     /**
340      * Get the wrapper object from the cache key associated with the given primary key,
341      * this is used for EJB.
342      */

343     public Object JavaDoc getWrapper(Vector primaryKey) {
344         CacheKey cacheKey = getCacheKeyWithReadLock(primaryKey);
345
346         if (cacheKey == null) {
347             return null;
348         } else {
349             return cacheKey.getWrapper();
350         }
351     }
352
353     /**
354      * Get the write lock value from the cache key associated to the primarykey
355      */

356     public Object JavaDoc getWriteLockValue(Vector primaryKey) {
357         CacheKey cacheKey = getCacheKeyWithReadLock(primaryKey);
358
359         if (cacheKey == null) {
360             return null;
361         } else {
362             return cacheKey.getWriteLockValue();
363         }
364     }
365
366     /**
367      * Initialize the newly allocated instance of this class. This method must be called in order for
368      * the IdentityMap to be functional.
369      * @param anInteger is the maximum size to be allocated for the recevier.
370      */

371     public void initialize(int size) {
372         setMaxSize(size);
373     }
374
375     /**
376      * Allow for the cache keys to be iterated on.
377      */

378     public abstract Enumeration keys();
379
380     /**
381      * Store the object in the cache at its primary key.
382      * @param primaryKey is the primary key for the object.
383      * @param object is the domain object to cache.
384      * @param writeLockValue is the current write lock value of object, if null the version is ignored.
385      * @param readTime the read time of the object to be stored in the cache
386      */

387     public abstract CacheKey put(Vector primaryKey, Object JavaDoc object, Object JavaDoc writeLockValue, long readTime);
388
389     /**
390      * Store the object in the cache with the cache key.
391      * Should be overide by the sub-class
392      */

393     protected abstract void put(CacheKey cacheKey);
394
395     /**
396      * Remove the primary key from the cache.
397      */

398     public Object JavaDoc remove(Vector primaryKey) {
399         CacheKey key = getCacheKey(primaryKey);
400         return remove(key);
401     }
402
403     /**
404      * Remove the cache key from the cache.
405      */

406     public abstract Object JavaDoc remove(CacheKey cacheKey);
407
408     /**
409      * Set the maximum size for the recevier.
410      * @param anInteger is the new maximum size.
411      */

412     protected void setMaxSize(int size) {
413         maxSize = size;
414     }
415
416     /**
417      * INTERNAL:
418      * This method will be used to update the max cache size, any objects exceeding the max cache size will
419      * be remove from the cache. Please note that this does not remove the object from the identityMap, except in
420      * the case of the CacheIdentityMap.
421      */

422     public synchronized void updateMaxSize(int maxSize) {
423         setMaxSize(maxSize);
424     }
425
426     protected void setSearchKey(CacheKey searchKey) {
427         this.searchKey = searchKey;
428     }
429
430     /**
431      * Update the wrapper object the cache key associated with the given primary key,
432      * this is used for EJB.
433      */

434     public void setWrapper(Vector primaryKey, Object JavaDoc wrapper) {
435         CacheKey cacheKey = getCacheKey(primaryKey);
436
437         if (cacheKey != null) {
438             cacheKey.setWrapper(wrapper);
439         }
440     }
441
442     /**
443      * Update the write lock value of the cache key associated with the given primary key,
444      */

445     public void setWriteLockValue(Vector primaryKey, Object JavaDoc writeLockValue) {
446         CacheKey cacheKey = getCacheKey(primaryKey);
447
448         if (cacheKey != null) {
449             //lock/release the cache key during the lock value updating
450
cacheKey.acquire();
451             cacheKey.setWriteLockValue(writeLockValue);
452             cacheKey.release();
453         }
454     }
455
456     public String JavaDoc toString() {
457         return oracle.toplink.essentials.internal.helper.Helper.getShortClassName(getClass()) + "[" + getSize() + "]";
458     }
459
460     /**
461      * This is used to notify the identity map of a locked keys modification to allow updating of weak refs.
462      */

463     public void updateCacheKey(CacheKey cacheKey) {
464         return;
465     }
466 }
467
Popular Tags