Source Code Cross Referenced for ImageCache.java in  » GIS » udig-1.1 » net » refractions » udig » ui » 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 » GIS » udig 1.1 » net.refractions.udig.ui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*******************************************************************************
002:         * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved.
003:         * This program and the accompanying materials are made available under the
004:         * terms of the Common Public License v1.0 which accompanies this distribution,
005:         * and is available at http://www.eclipse.org/legal/cpl-v10.html
006:         * 
007:         * Contributors: IBM Corporation - initial API and implementation
008:         ******************************************************************************/package net.refractions.udig.ui;
009:
010:        import java.lang.ref.Reference;
011:        import java.lang.ref.ReferenceQueue;
012:        import java.lang.ref.WeakReference;
013:        import java.util.ArrayList;
014:        import java.util.Collections;
015:        import java.util.HashMap;
016:        import java.util.Iterator;
017:        import java.util.List;
018:        import java.util.Map;
019:        import java.util.Set;
020:
021:        import org.eclipse.jface.resource.ImageDescriptor;
022:        import org.eclipse.swt.SWT;
023:        import org.eclipse.swt.graphics.Image;
024:        import org.eclipse.swt.widgets.Display;
025:
026:        /**
027:         * A weakly referenced cache of image descriptors to arrays of image instances
028:         * (representing normal, gray and disabled images). This is used to hold images
029:         * in memory while their descriptors are defined. When the image descriptors
030:         * become weakly referred to, the corresponding images in the array of images
031:         * will be disposed.
032:         * 
033:         * Weak references of equivalent image descriptors are mapped to the same array
034:         * of images (where equivalent descriptors are <code>equals(Object)</code>).
035:         * 
036:         * It is recommended to use this class as a singleton, since it creates a thread
037:         * for cleaning out images.
038:         * 
039:         * It is the responsibility of the user to ensure that the image descriptors are
040:         * kept around as long as the images are needed. The users of this cache should
041:         * not explicitly dispose the images.
042:         * 
043:         * Upon request of a disabled or gray image, the normal image will be created as
044:         * well (if it was not already in the cache) in order to create the disabled or
045:         * gray version of the image.
046:         * 
047:         * This cache makes no guarantees on how long the cleaning process will take, or
048:         * when exactly it will occur.
049:         * 
050:         * 
051:         * This class may be instantiated; it is not intended to be subclassed.
052:         * 
053:         * @since 3.1
054:         */
055:        public final class ImageCache {
056:
057:            /**
058:             * An equivalent set of weak references to equivalent descriptors. The
059:             * equivalence of image descriptors is determined through
060:             * <code>equals(Object)</code>.
061:             * 
062:             * @since 3.1
063:             */
064:            private static final class EquivalenceSet {
065:
066:                /**
067:                 * The equivalence set's hash code is the hash code of the first weak
068:                 * reference added to the set.
069:                 */
070:                private final int equivalenceHashCode;
071:
072:                /**
073:                 * A list of weak references to equivalent image descriptors.
074:                 */
075:                private final ArrayList imageCacheWeakReferences;
076:
077:                /**
078:                 * Create an equivalence set and add the weak reference to the list.
079:                 * 
080:                 * @param referenceToAdd
081:                 *            The weak reference to add to the list of weak references.
082:                 */
083:                private EquivalenceSet(ImageCacheWeakReference referenceToAdd) {
084:                    imageCacheWeakReferences = new ArrayList();
085:                    imageCacheWeakReferences.add(referenceToAdd);
086:                    // The equivalence hash code will be the hash code of the first
087:                    // inserted weak reference
088:                    equivalenceHashCode = referenceToAdd.getCachedHashCode();
089:                }
090:
091:                /**
092:                 * Add a weak refrence to the equivalence set. This method assumes that
093:                 * the reference to add does belong in this set.
094:                 * 
095:                 * @param referenceToAdd
096:                 *            The weak reference to add.
097:                 * @return true if the weak reference was added to the set, and false if
098:                 *         the reference already exists in the set.
099:                 */
100:                public boolean addWeakReference(
101:                        ImageCacheWeakReference referenceToAdd) {
102:                    // Only add the weak reference if it does not already exist
103:                    ImageCacheWeakReference weakReference = null;
104:                    for (Iterator i = imageCacheWeakReferences.iterator(); i
105:                            .hasNext();) {
106:                        weakReference = (ImageCacheWeakReference) i.next();
107:                        // "referenceToAdd.get()" will not be null, but
108:                        // "weakReference.get()" could be null, which is ok since we
109:                        // should add the element since its "identity" will be removed
110:                        // shortly.
111:                        if (referenceToAdd.get() == weakReference.get()) {
112:                            return false;
113:                        }
114:                    }
115:                    imageCacheWeakReferences.add(referenceToAdd);
116:                    return true;
117:                }
118:
119:                /**
120:                 * Clear the weak references in this equivalence set.
121:                 * 
122:                 */
123:                public void clear() {
124:                    ImageCacheWeakReference currentReference = null;
125:                    for (Iterator i = imageCacheWeakReferences.iterator(); i
126:                            .hasNext();) {
127:                        currentReference = (ImageCacheWeakReference) i.next();
128:                        // Cleaner thread could've have cleared the reference
129:                        if (currentReference != null) {
130:                            currentReference.clear();
131:                        }
132:                    }
133:                    imageCacheWeakReferences.clear();
134:                }
135:
136:                /*
137:                 * (non-Javadoc)
138:                 * 
139:                 * @see java.lang.Object#equals(java.lang.Object)
140:                 */
141:                public boolean equals(Object object) {
142:                    // Two sets are equivalent if their descriptors
143:                    // are "equal"
144:                    ImageDescriptor reachableDescriptor = null;
145:                    if (!(object instanceof  EquivalenceSet)) {
146:                        return false;
147:                    }
148:
149:                    // Retrieve an image descriptor in the set of weak references
150:                    // that has not been enqueued
151:                    reachableDescriptor = ((EquivalenceSet) object)
152:                            .getFirstReachableDescriptor();
153:                    if (reachableDescriptor == null) {
154:                        return false;
155:                    }
156:                    // Manipulating descriptors themselves just in case the referent
157:                    // gets cleaned by the time we reach this part.
158:                    return reachableDescriptor
159:                            .equals(getFirstReachableDescriptor());
160:
161:                }
162:
163:                /**
164:                 * Get a non-null image descriptor from the list of weak references to
165:                 * image descriptors.
166:                 * 
167:                 * @return a non null image descriptor, or null if none could be found.
168:                 */
169:                public ImageDescriptor getFirstReachableDescriptor() {
170:                    ImageDescriptor referent = null;
171:                    for (Iterator i = imageCacheWeakReferences.iterator(); i
172:                            .hasNext();) {
173:                        referent = (ImageDescriptor) ((ImageCacheWeakReference) i
174:                                .next()).get();
175:                        if (referent != null) {
176:                            // return descriptor itself. This way, we have a reference
177:                            // to it and it won't be cleared by the time we return from
178:                            // this method
179:                            return referent;
180:                        }
181:                    }
182:                    // no reachable descriptors found
183:                    return null;
184:                }
185:
186:                /**
187:                 * Return the number of items in the list of weak references.
188:                 * 
189:                 * @return the number of items in the list of weak references.
190:                 */
191:                public int getSize() {
192:                    return imageCacheWeakReferences.size();
193:                }
194:
195:                /*
196:                 * (non-Javadoc)
197:                 * 
198:                 * @see java.lang.Object#hashCode()
199:                 */
200:                public int hashCode() {
201:                    return equivalenceHashCode;
202:                }
203:
204:                /**
205:                 * Remove a hashable weak reference from the list. This method makes no
206:                 * assumptions as to whether the reference to remove belongs in this
207:                 * equivalence set or not.
208:                 * 
209:                 * @param referenceToRemove
210:                 *            The weak reference to remove.
211:                 * @return true if the reference was removed succesfully.
212:                 */
213:                public boolean removeReference(
214:                        ImageCacheWeakReference referenceToRemove) {
215:                    return imageCacheWeakReferences.remove(referenceToRemove);
216:                }
217:
218:            }
219:
220:            /**
221:             * A wrapper around the weak reference to imae descriptors in order to be
222:             * able to store the referrent's hash code since it will be null when
223:             * enqueued.
224:             * 
225:             * @since 3.1
226:             */
227:            private static final class ImageCacheWeakReference extends
228:                    WeakReference {
229:                /**
230:                 * Referent's hash code since it will not be available once the
231:                 * reference has been enqueued.
232:                 */
233:                private final int referentHashCode;
234:
235:                /**
236:                 * Creates a weak reference for an image descriptor.
237:                 * 
238:                 * @param referent
239:                 *            The image descriptor. Will not be <code>null</code>.
240:                 * @param queue
241:                 *            The reference queue.
242:                 */
243:                public ImageCacheWeakReference(Object referent,
244:                        ReferenceQueue queue) {
245:                    super (referent, queue);
246:                    referentHashCode = referent.hashCode();
247:                }
248:
249:                /**
250:                 * The referent's cached hash code value.
251:                 * 
252:                 * @return the referent's cached hash code value.
253:                 */
254:                public int getCachedHashCode() {
255:                    return referentHashCode;
256:                }
257:
258:            }
259:
260:            /**
261:             * An entry in the image map, which consists of the array of images (the
262:             * value), as well as the key. This allows to retrieve BOTH the key (the
263:             * equivalence set) and the value (the array of images) from the map
264:             * directly.
265:             * 
266:             * @since 3.1
267:             */
268:            private static final class ImageMapEntry {
269:                /**
270:                 * The array of images.
271:                 */
272:                private final Image[] entryImages;
273:
274:                /**
275:                 * The equivalence set.
276:                 */
277:                private final EquivalenceSet entrySet;
278:
279:                /**
280:                 * Create an entry that consists of the equivalence set (key) as well as
281:                 * the array of images.
282:                 * 
283:                 * @param equivalenceSet
284:                 *            The equivalence set.
285:                 * @param images
286:                 *            The array of images.
287:                 */
288:                public ImageMapEntry(EquivalenceSet equivalenceSet,
289:                        Image[] images) {
290:                    this .entrySet = equivalenceSet;
291:                    this .entryImages = images;
292:                }
293:
294:                /**
295:                 * Return the equivalence set in this entry. Should not be
296:                 * <code>null</code>.
297:                 * 
298:                 * @return the entry set.
299:                 */
300:                public EquivalenceSet getEquivalenceSet() {
301:                    return entrySet;
302:                }
303:
304:                /**
305:                 * Return the array of images in this entry. Should not be
306:                 * <code>null</code>.
307:                 * 
308:                 * @return the array of images.
309:                 */
310:                public Image[] getImages() {
311:                    return entryImages;
312:                }
313:
314:            }
315:
316:            /**
317:             * A thread for cleaning up the reference queues as the garbage collector
318:             * fills them. It takes an image map and a reference queue. When an item
319:             * appears in the reference queue, it uses it as a key to remove values from
320:             * the map. If the value is an array of images, then the defined images in
321:             * that array are is disposed. To shutdown the thread, call
322:             * <code>stopCleaning()</code>.
323:             * 
324:             * @since 3.1
325:             */
326:            private static class ReferenceCleanerThread extends Thread {
327:
328:                /**
329:                 * The number of reference cleaner threads created.
330:                 */
331:                private static int threads = 0;
332:
333:                /**
334:                 * A marker indicating that the reference cleaner thread should exit.
335:                 * This is enqueued when the thread is told to stop. Any referenced
336:                 * enqueued after the thread is told to stop will not be cleaned up.
337:                 */
338:                private final ImageCacheWeakReference endMarker;
339:
340:                /**
341:                 * A map of equivalence sets to ImageMapEntry (Image[3],
342:                 * EquivalenceSet).
343:                 */
344:                private final Map imageMap;
345:
346:                /**
347:                 * The reference queue to check.
348:                 */
349:                private final ReferenceQueue referenceQueue;
350:
351:                private final StaleImages staleImages;
352:
353:                /**
354:                 * Constructs a new instance of <code>ReferenceCleanerThread</code>.
355:                 * 
356:                 * @param referenceQueue
357:                 *            The reference queue to check for garbage.
358:                 * @param map
359:                 *            Map of equivalence sets to ImageMapEntry (Image[3],
360:                 *            EquivalenceSet).
361:                 */
362:                private ReferenceCleanerThread(final ImageCache imageCache) {
363:                    super ("Reference Cleaner: " + ++threads); //$NON-NLS-1$
364:
365:                    this .referenceQueue = imageCache.imageReferenceQueue;
366:                    this .imageMap = imageCache.imageMap;
367:                    this .endMarker = new ImageCacheWeakReference(
368:                            referenceQueue, referenceQueue);
369:                    this .staleImages = imageCache.staleImages;
370:                }
371:
372:                /**
373:                 * Remove the reference enqueued by iterating through the set of keys in
374:                 * the map.
375:                 * 
376:                 * @param currentReference
377:                 *            The current reference.
378:                 */
379:                private void removeReferenceEnqueued(
380:                        final ImageCacheWeakReference currentReference) {
381:                    EquivalenceSet currentSet = null;
382:                    Set keySet = imageMap.keySet();
383:                    Image[] images = null;
384:
385:                    // Ensure that the image map is locked until the removal of the
386:                    // reference has finished
387:                    synchronized (imageMap) {
388:                        // Traverse the set of keys to find corresponding
389:                        // equivalence set
390:                        for (Iterator i = keySet.iterator(); i.hasNext();) {
391:                            currentSet = (EquivalenceSet) i.next();
392:                            boolean removed = currentSet
393:                                    .removeReference(currentReference);
394:                            if (removed) {
395:                                // Clean up needed since the set is now empty
396:                                if (currentSet.getSize() == 0) {
397:                                    images = ((ImageMapEntry) imageMap
398:                                            .remove(currentSet)).getImages();
399:                                    if (images == null) {
400:                                        throw new NullPointerException(
401:                                                "The array of images removed from the map on clean up should not be null."); //$NON-NLS-1$
402:                                    }
403:                                }
404:                                // break out of for loop since the reference has
405:                                // been removed
406:                                break;
407:                            }
408:                        }
409:                    }
410:
411:                    // Images need disposal
412:                    if (images != null) {
413:                        staleImages.addImagesToDispose(images);
414:                        // Run async to avoid deadlock from dispose
415:                        Display display = Display.getDefault();
416:                        if (display != null) {
417:                            display.asyncExec(new Runnable() {
418:                                public void run() {
419:                                    staleImages.disposeStaleImages();
420:                                }
421:                            });
422:                        }
423:                    }
424:                }
425:
426:                /**
427:                 * Wait for new garbage. When new garbage arrives, remove it, clear it,
428:                 * and dispose of any corresponding images.
429:                 */
430:                public final void run() {
431:                    while (true) {
432:                        // Get the next reference to dispose.
433:                        Reference reference = null;
434:                        // Block until a reference becomes available in the queue
435:                        try {
436:                            reference = referenceQueue.remove();
437:                        } catch (final InterruptedException e) {
438:                            // Reference will be null.
439:                        }
440:
441:                        // Check to see if we've been told to stop.
442:                        if (reference == endMarker) {
443:                            // Clean up the image map
444:                            break;
445:                        }
446:
447:                        // Image disposal - need to traverse the set of keys, since the
448:                        // image descriptor has been cleaned. No way to directly
449:                        // retrieve the equivalence set from the map . This could be
450:                        // improved (with better search/sort).
451:                        if (reference instanceof  ImageCacheWeakReference) {
452:                            removeReferenceEnqueued((ImageCacheWeakReference) reference);
453:                        }
454:
455:                        // Clear the reference.
456:                        if (reference != null) {
457:                            reference.clear();
458:                        }
459:
460:                    }
461:                }
462:
463:                /**
464:                 * Tells this thread to stop trying to clean up. This is usually run
465:                 * when the cache is shutting down.
466:                 */
467:                private final void stopCleaning() {
468:                    endMarker.enqueue();
469:                }
470:            }
471:
472:            /**
473:             * A container class to hold a list of array of images that have been
474:             * identified as requiring disposal. This class was added to ensure that if
475:             * the image cache's dispose method is called while the cleaner thread is in
476:             * the process of cleaning images, stopping the thread will not prevent
477:             * those images from being disposed. They will be disposed by the image
478:             * cache's dispose method.
479:             * 
480:             */
481:            private static class StaleImages {
482:                /**
483:                 * List of array of images the require disposal.
484:                 */
485:                private final List staleImages;
486:
487:                /**
488:                 * Create the list of stale images.
489:                 * 
490:                 */
491:                public StaleImages() {
492:                    staleImages = Collections.synchronizedList(new ArrayList());
493:                }
494:
495:                /**
496:                 * Add the array of images to the list of images to dispose. This is
497:                 * called only from the cleaner thread.
498:                 * 
499:                 * @param images
500:                 *            The array of images.
501:                 */
502:                public void addImagesToDispose(final Image[] images) {
503:                    staleImages.add(images);
504:                }
505:
506:                /**
507:                 * Dispose images that require disposal.
508:                 * 
509:                 */
510:                public void disposeStaleImages() {
511:                    Image[] imagesToDispose = null;
512:                    // Ensure only one thread at a time accesses the stale images list
513:                    synchronized (staleImages) {
514:                        for (Iterator i = staleImages.iterator(); i.hasNext();) {
515:                            imagesToDispose = (Image[]) i.next();
516:                            for (int j = 0; j < imagesToDispose.length; j++) {
517:                                final Image image = imagesToDispose[j];
518:                                if ((image != null) && (!image.isDisposed())) {
519:                                    image.dispose();
520:                                }
521:                            }
522:                        }
523:                        staleImages.clear();
524:                    }
525:                }
526:
527:            }
528:
529:            /**
530:             * Types of images supported by the image cache.
531:             */
532:            public static final int DISABLE = 0;
533:
534:            public static final int GRAY = 1;
535:
536:            public static final int REGULAR = 2;
537:
538:            private static final int TYPES_OF_IMAGES = 3;
539:
540:            /**
541:             * The thread responsible for cleaning out images that are no longer needed.
542:             * The images in Image[3] will be cleaned if the corresponding equivalence
543:             * set contains no more weak references to image descriptor.
544:             */
545:            private final ReferenceCleanerThread imageCleaner;
546:
547:            /**
548:             * A map of equivalence sets to ImageMapEntry (Image[3], EquivalenceSet).
549:             * The equivalence set represents a list of weakly referenced image
550:             * descriptors that are equivalent ("equal"). The equivalence set will
551:             * contain no duplicate image descriptor references (check for identical
552:             * descriptors on addition using "==").
553:             */
554:            private final Map imageMap;
555:
556:            /**
557:             * A queue of references (<code>HashableWeakReference</code>) waiting to
558:             * be garbage collected. This value is never <code>null</code>. This is
559:             * the queue for <code>imageMap</code>.
560:             */
561:            private final ReferenceQueue imageReferenceQueue;
562:
563:            /**
564:             * The image to display when no image is available. This value is
565:             * <code>null</code> until it is first used, and will not get disposed
566:             * until the image cache itself is disposed.
567:             */
568:            private Image missingImage = null;
569:
570:            /**
571:             * Stale images that the cleaner thread might not have the opportunity to
572:             * dispose. The latter images will be disposed by the image cache's dispose.
573:             */
574:            private StaleImages staleImages;
575:
576:            /**
577:             * Constructs a new instance of <code>ImageCache</code>, and starts a
578:             * thread to monitor the reference queue for image clean up.
579:             */
580:            public ImageCache() {
581:                imageMap = Collections.synchronizedMap(new HashMap());
582:
583:                staleImages = new StaleImages();
584:                imageReferenceQueue = new ReferenceQueue();
585:                imageCleaner = new ReferenceCleanerThread(this );
586:                imageCleaner.start();
587:            }
588:
589:            /**
590:             * Constructs a new instance of <code>ImageCache</code>, and starts a
591:             * thread to monitor the reference queue for image clean up. If the passed
592:             * initial load capacity is negative, the image map is created with the
593:             * default <code>HashMap</code> constructor.
594:             * 
595:             * @param initialLoadCapacity
596:             *            Initial load capacity for the image hash map.
597:             */
598:            public ImageCache(final int initialLoadCapacity) {
599:                if (initialLoadCapacity < 0) {
600:                    imageMap = Collections.synchronizedMap(new HashMap());
601:                } else {
602:                    imageMap = Collections.synchronizedMap(new HashMap(
603:                            initialLoadCapacity));
604:                }
605:
606:                staleImages = new StaleImages();
607:                imageReferenceQueue = new ReferenceQueue();
608:                imageCleaner = new ReferenceCleanerThread(this );
609:                imageCleaner.start();
610:            }
611:
612:            /**
613:             * Constructs a new instance of <code>ImageCache</code>, and starts a
614:             * thread to monitor the reference queue for image clean up. If the passed
615:             * initial load capacity is negative or if the load factor is nonpositive,
616:             * the image map is created with the default <code>HashMap</code>
617:             * constructor.
618:             * 
619:             * @param initialLoadCapacity
620:             *            Initial load capacity for the image hash map.
621:             * @param loadFactor
622:             *            Load factor for the image hash map.
623:             */
624:            public ImageCache(final int initialLoadCapacity,
625:                    final float loadFactor) {
626:                if (initialLoadCapacity < 0 || loadFactor <= 0) {
627:                    imageMap = Collections.synchronizedMap(new HashMap());
628:                } else {
629:                    imageMap = Collections.synchronizedMap(new HashMap(
630:                            initialLoadCapacity, loadFactor));
631:                }
632:
633:                staleImages = new StaleImages();
634:                imageReferenceQueue = new ReferenceQueue();
635:                imageCleaner = new ReferenceCleanerThread(this );
636:                imageCleaner.start();
637:            }
638:
639:            /**
640:             * Add a new equivalence set to the imag map.
641:             * 
642:             * @param imageDescriptor
643:             *            The image descriptor.
644:             * @param temporaryKey
645:             *            The temporary key.
646:             * @param typeOfImage
647:             *            The type of image requested.
648:             * @return the requested image, or the missing image if an error occurs in
649:             *         the creation of the image.
650:             */
651:            private Image addNewEquivalenceSet(
652:                    final ImageDescriptor imageDescriptor,
653:                    EquivalenceSet equivalenceKey, int typeOfImage) {
654:
655:                // Create the array of images, as well as the regular image
656:                // since it will be need to create gray or disable
657:                final Image[] images = new Image[TYPES_OF_IMAGES];
658:                images[REGULAR] = imageDescriptor.createImage(false);
659:
660:                // If the image creation fails, returns the missing image
661:                if (images[REGULAR] == null) {
662:                    // clear the key (this will also clear the reference created)
663:                    equivalenceKey.clear();
664:                    return getMissingImage();
665:
666:                }
667:                if (typeOfImage == DISABLE) {
668:                    images[typeOfImage] = new Image(null, images[REGULAR],
669:                            SWT.IMAGE_DISABLE);
670:                } else if (typeOfImage == GRAY) {
671:                    images[typeOfImage] = new Image(null, images[REGULAR],
672:                            SWT.IMAGE_GRAY);
673:                }
674:                // Add the entry to the map
675:                final ImageMapEntry mapEntry = new ImageMapEntry(
676:                        equivalenceKey, images);
677:                imageMap.put(equivalenceKey, mapEntry);
678:                return images[typeOfImage];
679:            }
680:
681:            /**
682:             * Cleans up all images in the cache. This disposes of all of the images,
683:             * and drops references to them. This should only be called when the images
684:             * and the image cache are no longer needed (i.e.: shutdown). Note that the
685:             * image disposal is handled by the cleaner thread.
686:             */
687:            public final void dispose() {
688:                // Clean up the missing image.
689:                if ((missingImage != null) && (!missingImage.isDisposed())) {
690:                    missingImage.dispose();
691:                    missingImage = null;
692:                }
693:
694:                // Stop the image cleaner thread
695:                imageCleaner.stopCleaning();
696:                try {
697:                    imageCleaner.join();
698:                } catch (InterruptedException e) {
699:                    // Interrupted
700:                }
701:
702:                // Clear all the references in the equivalence sets and
703:                // dispose the corresponding images
704:                for (Iterator imageItr = imageMap.entrySet().iterator(); imageItr
705:                        .hasNext();) {
706:                    final Map.Entry entry = (Map.Entry) imageItr.next();
707:                    final EquivalenceSet key = (EquivalenceSet) entry.getKey();
708:                    // Dispose the images if they have been created and have
709:                    // not been disposed yet
710:                    final Image[] images = ((ImageMapEntry) entry.getValue())
711:                            .getImages();
712:                    for (int i = 0; i < images.length; i++) {
713:                        final Image image = images[i];
714:                        if ((image != null) && (!image.isDisposed())) {
715:                            image.dispose();
716:                        }
717:                    }
718:
719:                    // Clear all the references in the equivalence set
720:                    key.clear();
721:                }
722:                // Clear map
723:                imageMap.clear();
724:
725:                // Clean up the stale images that the cleaner thread might have missed
726:                staleImages.disposeStaleImages();
727:            }
728:
729:            /**
730:             * Returns the regular image for the given image descriptor. This caches the
731:             * result so that future attempts to get the image for an equivalent or
732:             * identical image descriptor will only access the cache. When all
733:             * references to equivalent image descriptors are dropped, the images
734:             * (regular, gray and disabled) will be cleaned up if they have been
735:             * created. This clean up makes no guarantees about how long or when it will
736:             * take place.
737:             * 
738:             * @param descriptor
739:             *            The image descriptor with which a regular image should be
740:             *            created; may be <code>null</code>.
741:             * @return The regular image, either newly created or from the cache. This
742:             *         value is <code>null</code> if the image descriptor passed in is
743:             *         <code>null</code>. Note that a missing image will be returned
744:             *         if a problem occurs in the creation of the image.
745:             */
746:            public final Image getImage(final ImageDescriptor imageDescriptor) {
747:                return getImage(imageDescriptor, REGULAR);
748:            }
749:
750:            /**
751:             * Returns the requested image for the given image descriptor and image
752:             * type. This caches the result so that future attempts to get the image for
753:             * an equivalent or identical image descriptor will only access the cache.
754:             * When all references to equivalent image descriptors are dropped, the
755:             * images (regular, gray and disabled) will be cleaned up if they have been
756:             * created. This clean up makes no guarantees about how long or when it will
757:             * take place.
758:             * 
759:             * @param descriptor
760:             *            The image descriptor with which the requested image should be
761:             *            created; may be <code>null</code>.
762:             * @param typeOfImage
763:             *            The type of the desired image:
764:             *            <code>ImageCache.DISABLED</code>,
765:             *            <code>ImageCache.GRAY</code> or
766:             *            <code>ImageCache.NORMAL</code>.
767:             * @return The image for the requested image type, either newly created or
768:             *         from the cache. This value is <code>null</code> if the image
769:             *         descriptor passed in is <code>null</code>, or if the image
770:             *         type is invalid. Note that a missing image will be returned if a
771:             *         problem occurs in the creation of the image.
772:             */
773:            public final Image getImage(final ImageDescriptor imageDescriptor,
774:                    final int typeOfImage) {
775:                // Invalid descriptor
776:                if (imageDescriptor == null) {
777:                    return null;
778:                }
779:                // Invalid type of image
780:                if (typeOfImage < 0 || !(typeOfImage < TYPES_OF_IMAGES)) {
781:                    return null;
782:                }
783:                // Created a temporary key to query the image map
784:                ImageCacheWeakReference referencedToAdd = new ImageCacheWeakReference(
785:                        imageDescriptor, imageReferenceQueue);
786:                EquivalenceSet temporaryKey = new EquivalenceSet(
787:                        referencedToAdd);
788:
789:                Image imageToReturn = null;
790:
791:                // Ensure that the image map is locked until the retrieving of the image
792:                // process is finished
793:                synchronized (imageMap) {
794:                    // Retrieve the corresponding entry in the map
795:                    ImageMapEntry mapEntry = (ImageMapEntry) imageMap
796:                            .get(temporaryKey);
797:                    if (mapEntry != null) {
798:                        // The entry was found, retrieve the image from cache, or
799:                        // create it if it has not been created yet
800:                        imageToReturn = getImageFromEquivalenceSet(
801:                                imageDescriptor, mapEntry, referencedToAdd,
802:                                typeOfImage);
803:                    } else {
804:                        // The entry was not found, create it.
805:                        imageToReturn = addNewEquivalenceSet(imageDescriptor,
806:                                temporaryKey, typeOfImage);
807:                    }
808:                }
809:                return imageToReturn;
810:
811:            }
812:
813:            /**
814:             * Retrieve the image from the cache, or create it if it has not been
815:             * created yet.
816:             * 
817:             * @param imageDescriptor
818:             *            The image descriptor.
819:             * @param mapEntry
820:             *            The mape entry.
821:             * @param referenceToAdd
822:             *            The weak reference to add.
823:             * @param typeOfImage
824:             *            The type of image to create.
825:             * @return the requested image, or the missing image if an error occurs in
826:             *         the creation of the image.
827:             */
828:            private Image getImageFromEquivalenceSet(
829:                    ImageDescriptor imageDescriptor, ImageMapEntry mapEntry,
830:                    ImageCacheWeakReference referenceToAdd, int typeOfImage) {
831:
832:                final Image[] images = mapEntry.getImages();
833:                final EquivalenceSet equivalenceKey = mapEntry
834:                        .getEquivalenceSet();
835:
836:                // Add the weak reference to the equivalence set
837:                boolean added = equivalenceKey.addWeakReference(referenceToAdd);
838:                if (!added) {
839:                    // The identical reference already exists in the set, clear it
840:                    referenceToAdd.clear();
841:                }
842:                // If the type of image requested is cached
843:                if (images[typeOfImage] != null) {
844:                    return images[typeOfImage];
845:                }
846:
847:                // Regular image shoudl not be null, since it gets created when the set
848:                // is created
849:                if (images[REGULAR] == null) {
850:                    throw new NullPointerException(
851:                            "The normal image from the equivalence set should not be null.");//$NON-NLS-1$
852:                }
853:
854:                if (typeOfImage == GRAY) {
855:                    images[typeOfImage] = new Image(null, images[REGULAR],
856:                            SWT.IMAGE_GRAY);
857:                } else if (typeOfImage == DISABLE) {
858:                    images[typeOfImage] = new Image(null, images[REGULAR],
859:                            SWT.IMAGE_DISABLE);
860:                }
861:                return images[typeOfImage];
862:            }
863:
864:            /**
865:             * Returns the image to display when no image can be found, or none is
866:             * specified. This image is only disposed when the cache is disposed.
867:             * 
868:             * @return The image to display for missing images. This value will never be
869:             *         <code>null</code>.
870:             */
871:            public final Image getMissingImage() {
872:                // Ensure that the missing image is not being accessed by another thread
873:                if (missingImage == null) {
874:                    missingImage = ImageDescriptor.getMissingImageDescriptor()
875:                            .createImage();
876:                }
877:
878:                return missingImage;
879:            }
880:
881:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.