KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > HashtableTC


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
3  * notice. All rights reserved.
4  */

5 package java.util;
6
7 import com.tc.object.ObjectID;
8 import com.tc.object.TCObject;
9 import com.tc.object.bytecode.Clearable;
10 import com.tc.object.bytecode.Manageable;
11 import com.tc.object.bytecode.ManagerUtil;
12 import com.tc.object.bytecode.TCMap;
13 import com.tc.object.bytecode.hook.impl.Util;
14
15 import java.util.Map.Entry;
16
17 /*
18  * This class will be merged with java.lang.Hashtable in the bootjar. This hashtable can store ObjectIDs instead of
19  * Objects to save memory and transparently fault Objects as needed. It can also clear references. For General rules
20  *
21  * @see HashMapTC class
22  */

23 public class HashtableTC extends Hashtable JavaDoc implements TCMap, Manageable, Clearable {
24
25   private volatile transient TCObject $__tc_MANAGED;
26
27   public HashtableTC() {
28     super();
29   }
30
31   public HashtableTC(int initialCapacity, float loadFactor) {
32     super(initialCapacity, loadFactor);
33   }
34
35   public HashtableTC(int initialCapacity) {
36     super(initialCapacity);
37   }
38
39   public HashtableTC(Map JavaDoc arg0) {
40     super(arg0);
41   }
42
43   public synchronized void clear() {
44     if (__tc_isManaged()) {
45       ManagerUtil.checkWriteAccess(this);
46       ManagerUtil.logicalInvoke(this, "clear()V", new Object JavaDoc[0]);
47     }
48     super.clear();
49   }
50
51   public synchronized Object JavaDoc clone() {
52     if (__tc_isManaged()) {
53       Hashtable JavaDoc clone = new Hashtable JavaDoc(this);
54
55       // This call to fixTCObjectReference isn't strictly required, but if someone every changes
56
// this method to actually use any built-in clone mechanism, it will be needed -- better safe than sorry here
57
return Util.fixTCObjectReferenceOfClonedObject(this, clone);
58     }
59
60     return super.clone();
61   }
62
63   // Values that contains ObjectIDs are already wrapped, so this should be fine
64
public synchronized boolean contains(Object JavaDoc value) {
65     return super.contains(value);
66   }
67
68   // XXX:: Keys can't be ObjectIDs as of Now.
69
public synchronized boolean containsKey(Object JavaDoc key) {
70     return super.containsKey(key);
71   }
72
73   public boolean containsValue(Object JavaDoc value) {
74     return super.containsValue(value);
75   }
76
77   public synchronized boolean equals(Object JavaDoc o) {
78     return super.equals(o);
79   }
80
81   /*
82    * XXX:: This method uses getEntry instead of a get and put to avoid changing the modCount in shared mode
83    */

84   public synchronized Object JavaDoc get(Object JavaDoc key) {
85     if (__tc_isManaged()) {
86       Map.Entry JavaDoc e = getEntry(key);
87       if (e == null) return null;
88       Object JavaDoc value = e.getValue();
89       Object JavaDoc actualValue = unwrapValueIfNecessary(value);
90       if (actualValue != value) {
91         e.setValue(actualValue);
92       }
93       return actualValue;
94     } else {
95       return super.get(key);
96     }
97   }
98
99   public synchronized int hashCode() {
100     return super.hashCode();
101   }
102
103   public synchronized boolean isEmpty() {
104     return super.isEmpty();
105   }
106
107   /*
108    * This method needs to call logicalInvoke before modifying the local state to avoid inconsistency when throwing
109    * NonPortableExceptions TODO:: provide special method for the applicator
110    */

111   public synchronized Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
112     if (__tc_isManaged()) {
113       if (key == null || value == null) { throw new NullPointerException JavaDoc(); }
114       ManagerUtil.checkWriteAccess(this);
115       Entry e = getEntry(key);
116       if (e == null) {
117         // New mapping
118
ManagerUtil.logicalInvoke(this, "put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", new Object JavaDoc[] {
119             key, value });
120         // Sucks to do a second lookup !!
121
return unwrapValueIfNecessary(super.put(key, wrapValueIfNecessary(value)));
122       } else {
123         Object JavaDoc old = unwrapValueIfNecessary(e.getValue());
124         if (old != value) {
125           ManagerUtil.logicalInvoke(this, "put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", new Object JavaDoc[] {
126               e.getKey(), value });
127           e.setValue(wrapValueIfNecessary(value));
128         }
129         return old;
130       }
131     } else {
132       return super.put(key, value);
133     }
134   }
135
136   /**
137    * This method is only to be invoked from the applicator thread. This method does not need to check if the map is
138    * managed as it will always be managed when called by the applicator thread. In addition, this method does not need
139    * to be synchronized under getResolveLock() as the applicator thread is already under the scope of such
140    * synchronization.
141    */

142   public synchronized void __tc_applicator_put(Object JavaDoc key, Object JavaDoc value) {
143     if (key == null || value == null) { throw new NullPointerException JavaDoc(); }
144     super.put(key, wrapValueIfNecessary(value));
145   }
146
147   private static Object JavaDoc unwrapValueIfNecessary(Object JavaDoc value) {
148     if (value instanceof ValuesWrapper) {
149       return ((ValuesWrapper) value).getValue();
150     } else {
151       return value;
152     }
153   }
154
155   private static Object JavaDoc wrapValueIfNecessary(Object JavaDoc value) {
156     if (value instanceof ObjectID) {
157       // value cant be NULL_ID as Hashtable doesnt handle null !
158
return new ValuesWrapper(value);
159     } else {
160       return value;
161     }
162   }
163
164   public synchronized void putAll(Map JavaDoc arg0) {
165     super.putAll(arg0);
166   }
167
168   public synchronized Object JavaDoc remove(Object JavaDoc key) {
169     if (__tc_isManaged()) {
170       ManagerUtil.checkWriteAccess(this);
171       Object JavaDoc removed = unwrapValueIfNecessary(super.remove(key));
172       if (removed != null) {
173         ManagerUtil.logicalInvoke(this, "remove(Ljava/lang/Object;)Ljava/lang/Object;", new Object JavaDoc[] { key });
174       }
175       return removed;
176     } else {
177       return super.remove(key);
178     }
179   }
180
181   /**
182    * This method is only to be invoked from the applicator thread. This method does not need to check if the map is
183    * managed as it will always be managed when called by the applicator thread. In addition, this method does not need
184    * to be synchronized under getResolveLock() as the applicator thread is already under the scope of such
185    * synchronization.
186    */

187   public synchronized void __tc_applicator_remove(Object JavaDoc key) {
188     super.remove(key);
189   }
190
191   public synchronized int size() {
192     return super.size();
193   }
194
195   public synchronized String JavaDoc toString() {
196     return super.toString();
197   }
198
199   public synchronized Enumeration JavaDoc keys() {
200     return new EnumerationWrapper(super.keys());
201   }
202
203   public Set JavaDoc keySet() {
204     return new KeySetWrapper(super.keySet());
205   }
206
207   public synchronized Enumeration JavaDoc elements() {
208     return new EnumerationWrapper(super.elements());
209   }
210
211   public Set JavaDoc entrySet() {
212     return nonOverridableEntrySet();
213   }
214
215   private Set JavaDoc nonOverridableEntrySet() {
216     return new EntrySetWrapper(super.entrySet());
217   }
218
219   public Collection JavaDoc values() {
220     return new ValuesCollectionWrapper(super.values());
221   }
222
223   /**
224    * Clearable interface - called by CacheManager thru TCObjectLogical
225    */

226   public synchronized int clearReferences(int toClear) {
227     if (!__tc_isManaged()) { throw new AssertionError JavaDoc("clearReferences() called on Unmanaged Map"); }
228     int cleared = 0;
229     for (Iterator JavaDoc i = super.entrySet().iterator(); i.hasNext() && toClear > cleared;) {
230       Map.Entry JavaDoc e = (Map.Entry JavaDoc) i.next();
231       if (e.getValue() instanceof Manageable) {
232         Manageable m = (Manageable) e.getValue();
233         TCObject tcObject = m.__tc_managed();
234         if (tcObject != null && !tcObject.recentlyAccessed()) {
235           e.setValue(wrapValueIfNecessary(tcObject.getObjectID()));
236           cleared++;
237         }
238       }
239     }
240     return cleared;
241   }
242
243   public void __tc_managed(TCObject tcObject) {
244     $__tc_MANAGED = tcObject;
245   }
246
247   public TCObject __tc_managed() {
248     return $__tc_MANAGED;
249   }
250
251   public boolean __tc_isManaged() {
252     // TCObject tcManaged = $__tc_MANAGED;
253
// return (tcManaged != null && (tcManaged instanceof TCObjectPhysical || tcManaged instanceof TCObjectLogical));
254
return $__tc_MANAGED != null;
255   }
256
257   protected Map.Entry JavaDoc getEntry(Object JavaDoc key) {
258     // This method is imstrumented during bootjar creation into the vanila (which gets tainted) java.util.Hashtable.
259
// This is needed
260
// so that we can easily get access to the Original Key on put without a traversal or proxy Keys.
261
throw new RuntimeException JavaDoc("This should never execute ! Check BootJarTool");
262   }
263
264   private static class ValuesWrapper {
265
266     private Object JavaDoc value;
267
268     public ValuesWrapper(Object JavaDoc value) {
269       this.value = value;
270     }
271
272     public boolean equals(Object JavaDoc obj) {
273       return getValue().equals(obj);
274     }
275
276     Object JavaDoc getValue() {
277       if (value instanceof ObjectID) {
278         value = ManagerUtil.lookupObject((ObjectID) value);
279       }
280       return value;
281     }
282
283     public int hashCode() {
284       return getValue().hashCode();
285     }
286
287     public String JavaDoc toString() {
288       return getValue().toString();
289     }
290   }
291
292   private class EntryWrapper implements Map.Entry JavaDoc {
293
294     private final Entry entry;
295
296     public EntryWrapper(Entry entry) {
297       this.entry = entry;
298     }
299
300     public boolean equals(Object JavaDoc o) {
301       if (__tc_isManaged()) {
302         synchronized (HashtableTC.this) {
303           return entry.equals(o);
304         }
305       } else {
306         return entry.equals(o);
307       }
308     }
309
310     public Object JavaDoc getKey() {
311       if (__tc_isManaged()) {
312         synchronized (HashtableTC.this) {
313           return entry.getKey();
314         }
315       } else {
316         return entry.getKey();
317       }
318     }
319
320     public Object JavaDoc getValue() {
321       if (__tc_isManaged()) {
322         synchronized (HashtableTC.this) {
323           return unwrapValueIfNecessary(entry.getValue());
324         }
325       } else {
326         return entry.getValue();
327       }
328     }
329
330     public int hashCode() {
331       if (__tc_isManaged()) {
332         synchronized (HashtableTC.this) {
333           return entry.hashCode();
334         }
335       } else {
336         return entry.hashCode();
337       }
338     }
339
340     public Object JavaDoc setValue(Object JavaDoc value) {
341       if (__tc_isManaged()) {
342         synchronized (HashtableTC.this) {
343           // This check is done to solve the chicken and egg problem. Should I modify the local copy or the remote copy
344
// ? (both has error checks that we want to take place before any modification is probagated
345
if (value == null) throw new NullPointerException JavaDoc();
346           ManagerUtil.checkWriteAccess(HashtableTC.this);
347           ManagerUtil.logicalInvoke(HashtableTC.this, "put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
348                                     new Object JavaDoc[] { getKey(), value });
349           return unwrapValueIfNecessary(entry.setValue(value));
350         }
351       } else {
352         return entry.setValue(value);
353       }
354     }
355   }
356
357   private class EntrySetWrapper extends AbstractSet JavaDoc {
358
359     private final Set JavaDoc entrySet;
360
361     public EntrySetWrapper(Set JavaDoc entrySet) {
362       this.entrySet = entrySet;
363     }
364
365     public boolean add(Object JavaDoc arg0) {
366       return entrySet.add(arg0);
367     }
368
369     public void clear() {
370       // XXX:: Calls Hashtable.clear()
371
entrySet.clear();
372     }
373
374     public boolean contains(Object JavaDoc o) {
375       return entrySet.contains(o);
376     }
377
378     public Iterator JavaDoc iterator() {
379       return new EntriesIterator(entrySet.iterator());
380     }
381
382     public boolean remove(Object JavaDoc o) {
383       if (__tc_isManaged()) {
384         synchronized (HashtableTC.this) {
385           ManagerUtil.checkWriteAccess(HashtableTC.this);
386           if (entrySet.remove(o)) {
387             ManagerUtil.logicalInvoke(HashtableTC.this, "remove(Ljava/lang/Object;)Ljava/lang/Object;",
388                                       new Object JavaDoc[] { ((Map.Entry JavaDoc) o).getKey() });
389             return true;
390           }
391           return false;
392         }
393       } else {
394         return entrySet.remove(o);
395       }
396     }
397
398     public int size() {
399       return entrySet.size();
400     }
401   }
402
403   private class KeySetWrapper extends AbstractSet JavaDoc {
404
405     private final Set JavaDoc keys;
406
407     public KeySetWrapper(Set JavaDoc keys) {
408       this.keys = keys;
409     }
410
411     public void clear() {
412       keys.clear();
413     }
414
415     public boolean contains(Object JavaDoc o) {
416       return keys.contains(o);
417     }
418
419     public Iterator JavaDoc iterator() {
420       return new KeysIterator(nonOverridableEntrySet().iterator());
421     }
422
423     // XXX:: Calls Hashtable.remove();
424
public boolean remove(Object JavaDoc o) {
425       return keys.remove(o);
426     }
427
428     public int size() {
429       return keys.size();
430     }
431
432   }
433
434   private class ValuesCollectionWrapper extends AbstractCollection JavaDoc {
435
436     private final Collection JavaDoc values;
437
438     public ValuesCollectionWrapper(Collection JavaDoc values) {
439       this.values = values;
440     }
441
442     // XXX:: Calls Hashtable.clear();
443
public void clear() {
444       values.clear();
445     }
446
447     // XXX:: Calls Hashtable.containsValue();
448
public boolean contains(Object JavaDoc o) {
449       return values.contains(o);
450     }
451
452     public Iterator JavaDoc iterator() {
453       return new ValuesIterator(nonOverridableEntrySet().iterator());
454     }
455
456     public int size() {
457       return values.size();
458     }
459
460   }
461
462   // Hashtable Iterator doesnt synchronize access to the table !!
463
private class EntriesIterator implements Iterator JavaDoc {
464
465     private final Iterator JavaDoc entries;
466     private Map.Entry JavaDoc currentEntry;
467
468     public EntriesIterator(Iterator JavaDoc entries) {
469       this.entries = entries;
470     }
471
472     public boolean hasNext() {
473       if (__tc_isManaged()) {
474         synchronized (HashtableTC.this) {
475           return entries.hasNext();
476         }
477       } else {
478         return entries.hasNext();
479       }
480     }
481
482     public Object JavaDoc next() {
483       return new EntryWrapper(currentEntry = nextEntry());
484     }
485
486     protected Map.Entry JavaDoc nextEntry() {
487       if (__tc_isManaged()) {
488         synchronized (HashtableTC.this) {
489           return (Map.Entry JavaDoc) entries.next();
490         }
491       } else {
492         return (Map.Entry JavaDoc) entries.next();
493       }
494     }
495
496     public void remove() {
497       if (__tc_isManaged()) {
498         synchronized (HashtableTC.this) {
499           ManagerUtil.checkWriteAccess(HashtableTC.this);
500           entries.remove();
501           ManagerUtil.logicalInvoke(HashtableTC.this, "remove(Ljava/lang/Object;)Ljava/lang/Object;",
502                                     new Object JavaDoc[] { currentEntry.getKey() });
503         }
504       } else {
505         entries.remove();
506       }
507     }
508   }
509
510   private class KeysIterator extends EntriesIterator {
511
512     public KeysIterator(Iterator JavaDoc entries) {
513       super(entries);
514     }
515
516     public Object JavaDoc next() {
517       Map.Entry JavaDoc e = (Map.Entry JavaDoc) super.next();
518       return e.getKey();
519     }
520   }
521
522   private class ValuesIterator extends EntriesIterator {
523
524     public ValuesIterator(Iterator JavaDoc entries) {
525       super(entries);
526     }
527
528     public Object JavaDoc next() {
529       Map.Entry JavaDoc e = (Map.Entry JavaDoc) super.next();
530       return e.getValue();
531     }
532   }
533
534   private class EnumerationWrapper implements Enumeration JavaDoc {
535
536     private final Enumeration JavaDoc enumeration;
537
538     public EnumerationWrapper(Enumeration JavaDoc enumeration) {
539       this.enumeration = enumeration;
540     }
541
542     public boolean hasMoreElements() {
543       if (__tc_isManaged()) {
544         synchronized (HashtableTC.this) {
545           return enumeration.hasMoreElements();
546         }
547       } else {
548         return enumeration.hasMoreElements();
549       }
550     }
551
552     public Object JavaDoc nextElement() {
553       if (__tc_isManaged()) {
554         synchronized (HashtableTC.this) {
555           // XXX:: This is done for both keys and values, for keys it has no effect
556
return unwrapValueIfNecessary(enumeration.nextElement());
557         }
558       } else {
559         return enumeration.nextElement();
560       }
561     }
562   }
563 }
564
Popular Tags