Source Code Cross Referenced for WeakHashtable.java in  » Library » apache-common-Logging » org » apache » commons » logging » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » apache common Logging » org.apache.commons.logging.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2004 The Apache Software Foundation.
003:         * 
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         * 
008:         *      http://www.apache.org/licenses/LICENSE-2.0
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:
017:        package org.apache.commons.logging.impl;
018:
019:        import java.lang.ref.ReferenceQueue;
020:        import java.lang.ref.WeakReference;
021:        import java.util.*;
022:
023:        /**
024:         * <p>Implementation of <code>Hashtable</code> that uses <code>WeakReference</code>'s
025:         * to hold its keys thus allowing them to be reclaimed by the garbage collector.
026:         * The associated values are retained using strong references.</p>
027:         *
028:         * <p>This class follows the symantics of <code>Hashtable</code> as closely as
029:         * possible. It therefore does not accept null values or keys.</p>
030:         *
031:         * <p><strong>Note:</strong>
032:         * This is <em>not</em> intended to be a general purpose hash table replacement.
033:         * This implementation is also tuned towards a particular purpose: for use as a replacement
034:         * for <code>Hashtable</code> in <code>LogFactory</code>. This application requires
035:         * good liveliness for <code>get</code> and <code>put</code>. Various tradeoffs
036:         * have been made with this in mind.
037:         * </p>
038:         * <p>
039:         * <strong>Usage:</strong> typical use case is as a drop-in replacement 
040:         * for the <code>Hashtable</code> used in <code>LogFactory</code> for J2EE enviroments
041:         * running 1.3+ JVMs. Use of this class <i>in most cases</i> (see below) will
042:         * allow classloaders to be collected by the garbage collector without the need 
043:         * to call {@link org.apache.commons.logging.LogFactory#release(ClassLoader) LogFactory.release(ClassLoader)}.
044:         * </p>
045:         *
046:         * <p><code>org.apache.commons.logging.LogFactory</code> checks whether this class
047:         * can be supported by the current JVM, and if so then uses it to store
048:         * references to the <code>LogFactory</code> implementationd it loads 
049:         * (rather than using a standard Hashtable instance). 
050:         * Having this class used instead of <code>Hashtable</code> solves
051:         * certain issues related to dynamic reloading of applications in J2EE-style
052:         * environments. However this class requires java 1.3 or later (due to its use
053:         * of <code>java.lang.ref.WeakReference</code> and associates).
054:         * And by the way, this extends <code>Hashtable</code> rather than <code>HashMap</code>
055:         * for backwards compatibility reasons. See the documentation
056:         * for method <code>LogFactory.createFactoryStore</code> for more details.</p>
057:         *
058:         * <p>The reason all this is necessary is due to a issue which
059:         * arises during hot deploy in a J2EE-like containers. 
060:         * Each component running in the container owns one or more classloaders; when
061:         * the component loads a LogFactory instance via the component classloader
062:         * a reference to it gets stored in the static LogFactory.factories member,
063:         * keyed by the component's classloader so different components don't
064:         * stomp on each other. When the component is later unloaded, the container
065:         * sets the component's classloader to null with the intent that all the 
066:         * component's classes get garbage-collected. However there's still a
067:         * reference to the component's classloader from a key in the "global"
068:         * <code>LogFactory</code>'s factories member! If <code>LogFactory.release()</code>
069:         * is called whenever component is unloaded, the classloaders will be correctly
070:         * garbage collected; this <i>should</i> be done by any container that 
071:         * bundles commons-logging by default. However, holding the classloader
072:         * references weakly ensures that the classloader will be garbage collected
073:         * without the container performing this step. </p>
074:         *
075:         * <p>
076:         * <strong>Limitations:</strong>
077:         * There is still one (unusual) scenario in which a component will not 
078:         * be correctly unloaded without an explicit release. Though weak references
079:         * are used for its keys, it is necessary to use strong references for its values.
080:         * </p>
081:         * 
082:         * <p> If the abstract class <code>LogFactory</code> is 
083:         * loaded by the container classloader but a subclass of 
084:         * <code>LogFactory</code> [LogFactory1] is loaded by the component's 
085:         * classloader and an instance stored in the static map associated with the
086:         * base LogFactory class, then there is a strong reference from the LogFactory
087:         * class to the LogFactory1 instance (as normal) and a strong reference from
088:         * the LogFactory1 instance to the component classloader via
089:         * <code>getClass().getClassLoader()</code>. This chain of references will prevent 
090:         * collection of the child classloader.</p>
091:         *
092:         * <p>
093:         * Such a situation occurs when the commons-logging.jar is
094:         * loaded by a parent classloader (e.g. a server level classloader in a
095:         * servlet container) and a custom <code>LogFactory</code> implementation is
096:         * loaded by a child classloader (e.g. a web app classloader).</p>
097:         * 
098:         * <p>To avoid this scenario, ensure
099:         * that any custom LogFactory subclass is loaded by the same classloader as 
100:         * the base <code>LogFactory</code>. Creating custom LogFactory subclasses is,
101:         * however, rare. The standard LogFactoryImpl class should be sufficient
102:         * for most or all users.</p>
103:         *
104:         *
105:         * @author Brian Stansberry
106:         * 
107:         * @since 1.1
108:         */
109:        public final class WeakHashtable extends Hashtable {
110:
111:            /** 
112:             * The maximum number of times put() or remove() can be called before
113:             * the map will be purged of all cleared entries.
114:             */
115:            private static final int MAX_CHANGES_BEFORE_PURGE = 100;
116:
117:            /** 
118:             * The maximum number of times put() or remove() can be called before
119:             * the map will be purged of one cleared entry.
120:             */
121:            private static final int PARTIAL_PURGE_COUNT = 10;
122:
123:            /* ReferenceQueue we check for gc'd keys */
124:            private ReferenceQueue queue = new ReferenceQueue();
125:            /* Counter used to control how often we purge gc'd entries */
126:            private int changeCount = 0;
127:
128:            /**
129:             * Constructs a WeakHashtable with the Hashtable default
130:             * capacity and load factor.
131:             */
132:            public WeakHashtable() {
133:            }
134:
135:            /**
136:             *@see Hashtable
137:             */
138:            public boolean containsKey(Object key) {
139:                // purge should not be required
140:                Referenced referenced = new Referenced(key);
141:                return super .containsKey(referenced);
142:            }
143:
144:            /**
145:             *@see Hashtable
146:             */
147:            public Enumeration elements() {
148:                purge();
149:                return super .elements();
150:            }
151:
152:            /**
153:             *@see Hashtable
154:             */
155:            public Set entrySet() {
156:                purge();
157:                Set referencedEntries = super .entrySet();
158:                Set unreferencedEntries = new HashSet();
159:                for (Iterator it = referencedEntries.iterator(); it.hasNext();) {
160:                    Map.Entry entry = (Map.Entry) it.next();
161:                    Referenced referencedKey = (Referenced) entry.getKey();
162:                    Object key = referencedKey.getValue();
163:                    Object value = entry.getValue();
164:                    if (key != null) {
165:                        Entry dereferencedEntry = new Entry(key, value);
166:                        unreferencedEntries.add(dereferencedEntry);
167:                    }
168:                }
169:                return unreferencedEntries;
170:            }
171:
172:            /**
173:             *@see Hashtable
174:             */
175:            public Object get(Object key) {
176:                // for performance reasons, no purge
177:                Referenced referenceKey = new Referenced(key);
178:                return super .get(referenceKey);
179:            }
180:
181:            /**
182:             *@see Hashtable
183:             */
184:            public Enumeration keys() {
185:                purge();
186:                final Enumeration enumer = super .keys();
187:                return new Enumeration() {
188:                    public boolean hasMoreElements() {
189:                        return enumer.hasMoreElements();
190:                    }
191:
192:                    public Object nextElement() {
193:                        Referenced nextReference = (Referenced) enumer
194:                                .nextElement();
195:                        return nextReference.getValue();
196:                    }
197:                };
198:            }
199:
200:            /**
201:             *@see Hashtable
202:             */
203:            public Set keySet() {
204:                purge();
205:                Set referencedKeys = super .keySet();
206:                Set unreferencedKeys = new HashSet();
207:                for (Iterator it = referencedKeys.iterator(); it.hasNext();) {
208:                    Referenced referenceKey = (Referenced) it.next();
209:                    Object keyValue = referenceKey.getValue();
210:                    if (keyValue != null) {
211:                        unreferencedKeys.add(keyValue);
212:                    }
213:                }
214:                return unreferencedKeys;
215:            }
216:
217:            /**
218:             *@see Hashtable
219:             */
220:            public Object put(Object key, Object value) {
221:                // check for nulls, ensuring symantics match superclass
222:                if (key == null) {
223:                    throw new NullPointerException("Null keys are not allowed");
224:                }
225:                if (value == null) {
226:                    throw new NullPointerException(
227:                            "Null values are not allowed");
228:                }
229:
230:                // for performance reasons, only purge every 
231:                // MAX_CHANGES_BEFORE_PURGE times
232:                if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
233:                    purge();
234:                    changeCount = 0;
235:                }
236:                // do a partial purge more often
237:                else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) {
238:                    purgeOne();
239:                }
240:
241:                Object result = null;
242:                Referenced keyRef = new Referenced(key, queue);
243:                return super .put(keyRef, value);
244:            }
245:
246:            /**
247:             *@see Hashtable
248:             */
249:            public void putAll(Map t) {
250:                if (t != null) {
251:                    Set entrySet = t.entrySet();
252:                    for (Iterator it = entrySet.iterator(); it.hasNext();) {
253:                        Map.Entry entry = (Map.Entry) it.next();
254:                        put(entry.getKey(), entry.getValue());
255:                    }
256:                }
257:            }
258:
259:            /**
260:             *@see Hashtable
261:             */
262:            public Collection values() {
263:                purge();
264:                return super .values();
265:            }
266:
267:            /**
268:             *@see Hashtable
269:             */
270:            public Object remove(Object key) {
271:                // for performance reasons, only purge every 
272:                // MAX_CHANGES_BEFORE_PURGE times
273:                if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) {
274:                    purge();
275:                    changeCount = 0;
276:                }
277:                // do a partial purge more often
278:                else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) {
279:                    purgeOne();
280:                }
281:                return super .remove(new Referenced(key));
282:            }
283:
284:            /**
285:             *@see Hashtable
286:             */
287:            public boolean isEmpty() {
288:                purge();
289:                return super .isEmpty();
290:            }
291:
292:            /**
293:             *@see Hashtable
294:             */
295:            public int size() {
296:                purge();
297:                return super .size();
298:            }
299:
300:            /**
301:             *@see Hashtable
302:             */
303:            public String toString() {
304:                purge();
305:                return super .toString();
306:            }
307:
308:            /**
309:             * @see Hashtable
310:             */
311:            protected void rehash() {
312:                // purge here to save the effort of rehashing dead entries
313:                purge();
314:                super .rehash();
315:            }
316:
317:            /**
318:             * Purges all entries whose wrapped keys
319:             * have been garbage collected.
320:             */
321:            private void purge() {
322:                synchronized (queue) {
323:                    WeakKey key;
324:                    while ((key = (WeakKey) queue.poll()) != null) {
325:                        super .remove(key.getReferenced());
326:                    }
327:                }
328:            }
329:
330:            /**
331:             * Purges one entry whose wrapped key 
332:             * has been garbage collected.
333:             */
334:            private void purgeOne() {
335:
336:                synchronized (queue) {
337:                    WeakKey key = (WeakKey) queue.poll();
338:                    if (key != null) {
339:                        super .remove(key.getReferenced());
340:                    }
341:                }
342:            }
343:
344:            /** Entry implementation */
345:            private final static class Entry implements  Map.Entry {
346:
347:                private final Object key;
348:                private final Object value;
349:
350:                private Entry(Object key, Object value) {
351:                    this .key = key;
352:                    this .value = value;
353:                }
354:
355:                public boolean equals(Object o) {
356:                    boolean result = false;
357:                    if (o != null && o instanceof  Map.Entry) {
358:                        Map.Entry entry = (Map.Entry) o;
359:                        result = (getKey() == null ? entry.getKey() == null
360:                                : getKey().equals(entry.getKey()))
361:                                && (getValue() == null ? entry.getValue() == null
362:                                        : getValue().equals(entry.getValue()));
363:                    }
364:                    return result;
365:                }
366:
367:                public int hashCode() {
368:
369:                    return (getKey() == null ? 0 : getKey().hashCode())
370:                            ^ (getValue() == null ? 0 : getValue().hashCode());
371:                }
372:
373:                public Object setValue(Object value) {
374:                    throw new UnsupportedOperationException(
375:                            "Entry.setValue is not supported.");
376:                }
377:
378:                public Object getValue() {
379:                    return value;
380:                }
381:
382:                public Object getKey() {
383:                    return key;
384:                }
385:            }
386:
387:            /** Wrapper giving correct symantics for equals and hashcode */
388:            private final static class Referenced {
389:
390:                private final WeakReference reference;
391:                private final int hashCode;
392:
393:                /**
394:                 * 
395:                 * @throws NullPointerException if referant is <code>null</code>
396:                 */
397:                private Referenced(Object referant) {
398:                    reference = new WeakReference(referant);
399:                    // Calc a permanent hashCode so calls to Hashtable.remove()
400:                    // work if the WeakReference has been cleared
401:                    hashCode = referant.hashCode();
402:                }
403:
404:                /**
405:                 * 
406:                 * @throws NullPointerException if key is <code>null</code>
407:                 */
408:                private Referenced(Object key, ReferenceQueue queue) {
409:                    reference = new WeakKey(key, queue, this );
410:                    // Calc a permanent hashCode so calls to Hashtable.remove()
411:                    // work if the WeakReference has been cleared
412:                    hashCode = key.hashCode();
413:
414:                }
415:
416:                public int hashCode() {
417:                    return hashCode;
418:                }
419:
420:                private Object getValue() {
421:                    return reference.get();
422:                }
423:
424:                public boolean equals(Object o) {
425:                    boolean result = false;
426:                    if (o instanceof  Referenced) {
427:                        Referenced otherKey = (Referenced) o;
428:                        Object this KeyValue = getValue();
429:                        Object otherKeyValue = otherKey.getValue();
430:                        if (this KeyValue == null) {
431:                            result = (otherKeyValue == null);
432:
433:                            // Since our hashcode was calculated from the original
434:                            // non-null referant, the above check breaks the 
435:                            // hashcode/equals contract, as two cleared Referenced
436:                            // objects could test equal but have different hashcodes.
437:                            // We can reduce (not eliminate) the chance of this
438:                            // happening by comparing hashcodes.
439:                            if (result == true) {
440:                                result = (this .hashCode() == otherKey
441:                                        .hashCode());
442:                            }
443:                            // In any case, as our c'tor does not allow null referants
444:                            // and Hashtable does not do equality checks between 
445:                            // existing keys, normal hashtable operations should never 
446:                            // result in an equals comparison between null referants
447:                        } else {
448:                            result = this KeyValue.equals(otherKeyValue);
449:                        }
450:                    }
451:                    return result;
452:                }
453:            }
454:
455:            /**
456:             * WeakReference subclass that holds a hard reference to an
457:             * associated <code>value</code> and also makes accessible
458:             * the Referenced object holding it.
459:             */
460:            private final static class WeakKey extends WeakReference {
461:
462:                private final Referenced referenced;
463:
464:                private WeakKey(Object key, ReferenceQueue queue,
465:                        Referenced referenced) {
466:                    super (key, queue);
467:                    this .referenced = referenced;
468:                }
469:
470:                private Referenced getReferenced() {
471:                    return referenced;
472:                }
473:            }
474:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.