Source Code Cross Referenced for SunTileCache.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » com » sun » media » jai » util » 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 » 6.0 JDK Modules » Java Advanced Imaging » com.sun.media.jai.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: SunTileCache.java,v $
0003:         *
0004:         * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
0005:         *
0006:         * Use is subject to license terms.
0007:         *
0008:         * $Revision: 1.2 $
0009:         * $Date: 2005/11/15 01:50:59 $
0010:         * $State: Exp $
0011:         */
0012:        package com.sun.media.jai.util;
0013:
0014:        import java.awt.RenderingHints;
0015:        import java.util.Collections;
0016:        import java.util.Comparator;
0017:        import java.util.ConcurrentModificationException;
0018:        import java.util.Iterator;
0019:        import java.util.Observable;
0020:        import java.util.Vector;
0021:        import java.util.Enumeration;
0022:        import java.util.Hashtable;
0023:        import java.util.SortedSet;
0024:        import java.util.TreeSet;
0025:        import java.awt.Point;
0026:        import java.awt.image.Raster;
0027:        import java.awt.image.RenderedImage;
0028:        import javax.media.jai.EnumeratedParameter;
0029:        import javax.media.jai.TileCache;
0030:        import javax.media.jai.util.ImagingListener;
0031:
0032:        /**
0033:         * This is Sun Microsystems' reference implementation of the
0034:         * <code>javax.media.jai.TileCache</code> interface.  It provides a
0035:         * central location for images to cache computed tiles, and is used as
0036:         * the default tile cache mechanism when no other tile cache objects
0037:         * are specified.
0038:         *
0039:         * <p> In this implementation, the cache size is limited by the memory
0040:         * capacity, which may be set at construction time or using the
0041:         * <code>setMemoryCapacity(long)</code> method.  The tile capacity
0042:         * is not used.  Different images may have very different tile sizes.
0043:         * Therefore, the memory usage for a specific tile capacity may vary
0044:         * greatly depends on the type of images involved.  In fact, the tile
0045:         * capacity is rather meaningless.
0046:         *
0047:         * @see javax.media.jai.TileCache
0048:         *
0049:         */
0050:
0051:        //
0052:        // NOTE: code is inlined for performance reasons
0053:        //
0054:        public final class SunTileCache extends Observable implements 
0055:                TileCache, CacheDiagnostics {
0056:
0057:            /** The default memory capacity of the cache (16 MB). */
0058:            private static final long DEFAULT_MEMORY_CAPACITY = 16L * 1024L * 1024L;
0059:
0060:            /** The default hashtable capacity (heuristic) */
0061:            private static final int DEFAULT_HASHTABLE_CAPACITY = 1009; // prime number
0062:
0063:            /** The hashtable load factor */
0064:            private static final float LOAD_FACTOR = 0.5F;
0065:
0066:            /**
0067:             * The tile cache.
0068:             * A Hashtable is used to cache the tiles.  The "key" is a 
0069:             * <code>Object</code> determined based on tile owner's UID if any or
0070:             * hashCode if the UID doesn't exist, and tile index.  The
0071:             * "value" is a SunCachedTile.
0072:             */
0073:            private Hashtable cache;
0074:
0075:            /**
0076:             * Sorted (Tree) Set used with tile metrics.
0077:             * Adds another level of metrics used to determine
0078:             * which tiles are removed during memoryControl().
0079:             */
0080:            private SortedSet cacheSortedSet;
0081:
0082:            /** The memory capacity of the cache. */
0083:            private long memoryCapacity;
0084:
0085:            /** The amount of memory currently being used by the cache. */
0086:            private long memoryUsage = 0;
0087:
0088:            /** The amount of memory to keep after memory control */
0089:            private float memoryThreshold = 0.75F;
0090:
0091:            /** A indicator for tile access time. */
0092:            private long timeStamp = 0;
0093:
0094:            /** Custom comparator used to determine tile cost or
0095:             *  priority ordering in the tile cache.
0096:             */
0097:            private Comparator comparator = null;
0098:
0099:            /** Pointer to the first (newest) tile of the linked SunCachedTile list. */
0100:            private SunCachedTile first = null;
0101:
0102:            /** Pointer to the last (oldest) tile of the linked SunCachedTile list. */
0103:            private SunCachedTile last = null;
0104:
0105:            /** Tile count used for diagnostics */
0106:            private long tileCount = 0;
0107:
0108:            /** Cache hit count */
0109:            private long hitCount = 0;
0110:
0111:            /** Cache miss count */
0112:            private long missCount = 0;
0113:
0114:            /** Diagnostics enable/disable */
0115:            private boolean diagnostics = false;
0116:
0117:            // diagnostic actions
0118:            // !!! If actions are changed in any way (removal, modification, addition)
0119:            // then the getCachedTileActions() method below should be changed to match.
0120:            private static final int ADD = 0;
0121:            private static final int REMOVE = 1;
0122:            private static final int REMOVE_FROM_FLUSH = 2;
0123:            private static final int REMOVE_FROM_MEMCON = 3;
0124:            private static final int UPDATE_FROM_ADD = 4;
0125:            private static final int UPDATE_FROM_GETTILE = 5;
0126:            private static final int ABOUT_TO_REMOVE = 6;
0127:
0128:            /**
0129:             * Returns an array of <code>EnumeratedParameter</code>s corresponding
0130:             * to the numeric values returned by the <code>getAction()</code>
0131:             * method of the <code>CachedTile</code> implementation used by
0132:             * <code>SunTileCache</code>.  The "name" of each
0133:             * <code>EnumeratedParameter</code> provides a brief string
0134:             * describing the numeric action value.
0135:             */
0136:            public static EnumeratedParameter[] getCachedTileActions() {
0137:                return new EnumeratedParameter[] {
0138:                        new EnumeratedParameter("add", ADD),
0139:                        new EnumeratedParameter("remove", REMOVE),
0140:                        new EnumeratedParameter("remove_by_flush",
0141:                                REMOVE_FROM_FLUSH),
0142:                        new EnumeratedParameter("remove_by_memorycontrol",
0143:                                REMOVE_FROM_MEMCON),
0144:                        new EnumeratedParameter("timestamp_update_by_add",
0145:                                UPDATE_FROM_ADD),
0146:                        new EnumeratedParameter("timestamp_update_by_gettile",
0147:                                UPDATE_FROM_GETTILE),
0148:                        new EnumeratedParameter("preremove", ABOUT_TO_REMOVE) };
0149:            }
0150:
0151:            /**
0152:             * No args constructor. Use the DEFAULT_MEMORY_CAPACITY of 16 Megs.
0153:             */
0154:            public SunTileCache() {
0155:                this (DEFAULT_MEMORY_CAPACITY);
0156:            }
0157:
0158:            /**
0159:             * Constructor.  The memory capacity should be explicitly specified.
0160:             *
0161:             * @param memoryCapacity  The maximum cache memory size in bytes.
0162:             *
0163:             * @throws IllegalArgumentException  If <code>memoryCapacity</code>
0164:             *         is less than 0.
0165:             */
0166:            public SunTileCache(long memoryCapacity) {
0167:                if (memoryCapacity < 0) {
0168:                    throw new IllegalArgumentException(JaiI18N
0169:                            .getString("SunTileCache"));
0170:                }
0171:
0172:                this .memoryCapacity = memoryCapacity;
0173:
0174:                // try to get a prime number (more efficient?)
0175:                // lower values of LOAD_FACTOR increase speed, decrease space efficiency
0176:                cache = new Hashtable(DEFAULT_HASHTABLE_CAPACITY, LOAD_FACTOR);
0177:            }
0178:
0179:            /**
0180:             * Adds a tile to the cache.
0181:             *
0182:             * <p> If the specified tile is already in the cache, it will not be
0183:             * cached again.  If by adding this tile, the cache exceeds the memory
0184:             * capacity, older tiles in the cache are removed to keep the cache
0185:             * memory usage under the specified limit.
0186:             *
0187:             * @param owner            The image the tile blongs to.
0188:             * @param tileX            The tile's X index within the image.
0189:             * @param tileY            The tile's Y index within the image.
0190:             * @param tile             The tile to be cached.
0191:             */
0192:            public void add(RenderedImage owner, int tileX, int tileY,
0193:                    Raster tile) {
0194:                add(owner, tileX, tileY, tile, null);
0195:            }
0196:
0197:            /**
0198:             * Adds a tile to the cache with an associated tile compute cost.
0199:             *
0200:             * <p> If the specified tile is already in the cache, it will not be
0201:             * cached again.  If by adding this tile, the cache exceeds the memory
0202:             * capacity, older tiles in the cache are removed to keep the cache
0203:             * memory usage under the specified limit.
0204:             *
0205:             * @param owner            The image the tile blongs to.
0206:             * @param tileX            The tile's X index within the image.
0207:             * @param tileY            The tile's Y index within the image.
0208:             * @param tile             The tile to be cached.
0209:             * @param tileCacheMetric  Metric for prioritizing tiles
0210:             */
0211:            public synchronized void add(RenderedImage owner, int tileX,
0212:                    int tileY, Raster tile, Object tileCacheMetric) {
0213:
0214:                if (memoryCapacity == 0) {
0215:                    return;
0216:                }
0217:
0218:                // This tile is not in the cache; create a new SunCachedTile.
0219:                // else just update. (code inlined for performance).
0220:                Object key = SunCachedTile.hashKey(owner, tileX, tileY);
0221:                SunCachedTile ct = (SunCachedTile) cache.get(key);
0222:
0223:                if (ct != null) {
0224:                    // tile is cached, inlines update()
0225:                    ct.timeStamp = timeStamp++;
0226:
0227:                    if (ct != first) {
0228:                        // Bring this tile to the beginning of the list.
0229:                        if (ct == last) {
0230:                            last = ct.previous;
0231:                            last.next = null;
0232:                        } else {
0233:                            ct.previous.next = ct.next;
0234:                            ct.next.previous = ct.previous;
0235:                        }
0236:
0237:                        ct.previous = null;
0238:                        ct.next = first;
0239:
0240:                        first.previous = ct;
0241:                        first = ct;
0242:                    }
0243:
0244:                    hitCount++;
0245:
0246:                    if (diagnostics) {
0247:                        ct.action = UPDATE_FROM_ADD;
0248:                        setChanged();
0249:                        notifyObservers(ct);
0250:                    }
0251:                } else {
0252:                    // create a new tile
0253:                    ct = new SunCachedTile(owner, tileX, tileY, tile,
0254:                            tileCacheMetric);
0255:
0256:                    // Don't cache tile if adding it would provoke memoryControl()
0257:                    // which would in turn only end up removing the tile.
0258:                    if (memoryUsage + ct.memorySize > memoryCapacity
0259:                            && ct.memorySize > (long) (memoryCapacity * memoryThreshold)) {
0260:                        return;
0261:                    }
0262:
0263:                    ct.timeStamp = timeStamp++;
0264:                    ct.previous = null;
0265:                    ct.next = first;
0266:
0267:                    if (first == null && last == null) {
0268:                        first = ct;
0269:                        last = ct;
0270:                    } else {
0271:                        first.previous = ct;
0272:                        first = ct; // put this tile at the top of the list
0273:                    }
0274:
0275:                    // add to tile cache
0276:                    if (cache.put(ct.key, ct) == null) {
0277:                        memoryUsage += ct.memorySize;
0278:                        tileCount++;
0279:                        //missCount++;  Not necessary?
0280:
0281:                        if (cacheSortedSet != null) {
0282:                            cacheSortedSet.add(ct);
0283:                        }
0284:
0285:                        if (diagnostics) {
0286:                            ct.action = ADD;
0287:                            setChanged();
0288:                            notifyObservers(ct);
0289:                        }
0290:                    }
0291:
0292:                    // Bring memory usage down to memoryThreshold % of memory capacity.
0293:                    if (memoryUsage > memoryCapacity) {
0294:                        memoryControl();
0295:                    }
0296:                }
0297:            }
0298:
0299:            /**
0300:             * Removes a tile from the cache.
0301:             *
0302:             * <p> If the specified tile is not in the cache, this method
0303:             * does nothing.
0304:             */
0305:            public synchronized void remove(RenderedImage owner, int tileX,
0306:                    int tileY) {
0307:
0308:                if (memoryCapacity == 0) {
0309:                    return;
0310:                }
0311:
0312:                Object key = SunCachedTile.hashKey(owner, tileX, tileY);
0313:                SunCachedTile ct = (SunCachedTile) cache.get(key);
0314:
0315:                if (ct != null) {
0316:                    // Notify observers that a tile is about to be removed.
0317:                    // It is possible that the tile will be removed from the
0318:                    // cache before the observers get notified.  This should
0319:                    // be ok, since a hard reference to the tile will be
0320:                    // kept for the observers, so the garbage collector won't
0321:                    // remove the tile until the observers release it.
0322:                    ct.action = ABOUT_TO_REMOVE;
0323:                    setChanged();
0324:                    notifyObservers(ct);
0325:
0326:                    ct = (SunCachedTile) cache.remove(key);
0327:
0328:                    // recalculate memoryUsage only if tile is actually removed
0329:                    if (ct != null) {
0330:                        memoryUsage -= ct.memorySize;
0331:                        tileCount--;
0332:
0333:                        if (cacheSortedSet != null) {
0334:                            cacheSortedSet.remove(ct);
0335:                        }
0336:
0337:                        if (ct == first) {
0338:                            if (ct == last) {
0339:                                first = null; // only one tile in the list
0340:                                last = null;
0341:                            } else {
0342:                                first = ct.next;
0343:                                first.previous = null;
0344:                            }
0345:                        } else if (ct == last) {
0346:                            last = ct.previous;
0347:                            last.next = null;
0348:                        } else {
0349:                            ct.previous.next = ct.next;
0350:                            ct.next.previous = ct.previous;
0351:                        }
0352:
0353:                        // Notify observers that a tile has been removed.
0354:                        // If the core's hard references go away, the
0355:                        // soft references will be garbage collected.
0356:                        // Usually, by the time the observers are notified
0357:                        // the ct owner and tile are nulled by the GC, so
0358:                        // we can't really tell which op was removed
0359:                        // This occurs when OpImage's finalize method is
0360:                        // invoked.  This code works ok when remove is
0361:                        // called directly. (by flush() for example).
0362:                        // If the soft references are GC'd, the timeStamp
0363:                        // will no longer be contiguous, it will be
0364:                        // unique, so this is ok.
0365:                        if (diagnostics) {
0366:                            ct.action = REMOVE;
0367:                            setChanged();
0368:                            notifyObservers(ct);
0369:                        }
0370:
0371:                        ct.previous = null;
0372:                        ct.next = null;
0373:                        ct = null;
0374:                    }
0375:                }
0376:            }
0377:
0378:            /**
0379:             * Retrieves a tile from the cache.
0380:             *
0381:             * <p> If the specified tile is not in the cache, this method
0382:             * returns <code>null</code>.  If the specified tile is in the
0383:             * cache, its last-access time is updated.
0384:             *
0385:             * @param owner  The image the tile blongs to.
0386:             * @param tileX  The tile's X index within the image.
0387:             * @param tileY  The tile's Y index within the image.
0388:             */
0389:            public synchronized Raster getTile(RenderedImage owner, int tileX,
0390:                    int tileY) {
0391:
0392:                Raster tile = null;
0393:
0394:                if (memoryCapacity == 0) {
0395:                    return null;
0396:                }
0397:
0398:                Object key = SunCachedTile.hashKey(owner, tileX, tileY);
0399:                SunCachedTile ct = (SunCachedTile) cache.get(key);
0400:
0401:                if (ct == null) {
0402:                    missCount++;
0403:                } else { // found tile in cache
0404:                    tile = (Raster) ct.getTile();
0405:
0406:                    // Update last-access time. (update() inlined for performance)
0407:                    ct.timeStamp = timeStamp++;
0408:
0409:                    if (ct != first) {
0410:                        // Bring this tile to the beginning of the list.
0411:                        if (ct == last) {
0412:                            last = ct.previous;
0413:                            last.next = null;
0414:                        } else {
0415:                            ct.previous.next = ct.next;
0416:                            ct.next.previous = ct.previous;
0417:                        }
0418:
0419:                        ct.previous = null;
0420:                        ct.next = first;
0421:
0422:                        first.previous = ct;
0423:                        first = ct;
0424:                    }
0425:
0426:                    hitCount++;
0427:
0428:                    if (diagnostics) {
0429:                        ct.action = UPDATE_FROM_GETTILE;
0430:                        setChanged();
0431:                        notifyObservers(ct);
0432:                    }
0433:                }
0434:
0435:                return tile;
0436:            }
0437:
0438:            /**
0439:             * Retrieves a contiguous array of all tiles in the cache which are
0440:             * owned by the specified image.  May be <code>null</code> if there
0441:             * were no tiles in the cache.  The array contains no null entries.
0442:             *
0443:             * @param owner The <code>RenderedImage</code> to which the tiles belong.
0444:             * @return An array of all tiles owned by the specified image or
0445:             *         <code>null</code> if there are none currently in the cache.
0446:             */
0447:            public synchronized Raster[] getTiles(RenderedImage owner) {
0448:                Raster[] tiles = null;
0449:
0450:                if (memoryCapacity == 0) {
0451:                    return null;
0452:                }
0453:
0454:                int size = Math.min(
0455:                        owner.getNumXTiles() * owner.getNumYTiles(),
0456:                        (int) tileCount);
0457:
0458:                if (size > 0) {
0459:                    int minTx = owner.getMinTileX();
0460:                    int minTy = owner.getMinTileY();
0461:                    int maxTx = minTx + owner.getNumXTiles();
0462:                    int maxTy = minTy + owner.getNumYTiles();
0463:
0464:                    // arbitrarily set a temporary vector size
0465:                    Vector temp = new Vector(10, 20);
0466:
0467:                    for (int y = minTy; y < maxTy; y++) {
0468:                        for (int x = minTx; x < maxTx; x++) {
0469:                            // inline this method
0470:                            //Raster raster = getTile(owner, x, y);
0471:                            //************************
0472:                            Raster raster = null;
0473:                            Object key = SunCachedTile.hashKey(owner, x, y);
0474:                            SunCachedTile ct = (SunCachedTile) cache.get(key);
0475:
0476:                            if (ct == null) {
0477:                                raster = null;
0478:                                missCount++;
0479:                            } else { // found tile in cache
0480:                                raster = (Raster) ct.getTile();
0481:
0482:                                // Update last-access time. (update() inlined for performance)
0483:                                ct.timeStamp = timeStamp++;
0484:
0485:                                if (ct != first) {
0486:                                    // Bring this tile to the beginning of the list.
0487:                                    if (ct == last) {
0488:                                        last = ct.previous;
0489:                                        last.next = null;
0490:                                    } else {
0491:                                        ct.previous.next = ct.next;
0492:                                        ct.next.previous = ct.previous;
0493:                                    }
0494:
0495:                                    ct.previous = null;
0496:                                    ct.next = first;
0497:
0498:                                    first.previous = ct;
0499:                                    first = ct;
0500:                                }
0501:
0502:                                hitCount++;
0503:
0504:                                if (diagnostics) {
0505:                                    ct.action = UPDATE_FROM_GETTILE;
0506:                                    setChanged();
0507:                                    notifyObservers(ct);
0508:                                }
0509:                            }
0510:                            //************************
0511:
0512:                            if (raster != null) {
0513:                                temp.add(raster);
0514:                            }
0515:                        }
0516:                    }
0517:
0518:                    int tmpsize = temp.size();
0519:                    if (tmpsize > 0) {
0520:                        tiles = (Raster[]) temp.toArray(new Raster[tmpsize]);
0521:                    }
0522:                }
0523:
0524:                return tiles;
0525:            }
0526:
0527:            /**
0528:             * Removes all the tiles that belong to a <code>RenderedImage</code>
0529:             * from the cache.
0530:             *
0531:             * @param owner  The image whose tiles are to be removed from the cache.
0532:             */
0533:            public void removeTiles(RenderedImage owner) {
0534:                if (memoryCapacity > 0) {
0535:                    int minTx = owner.getMinTileX();
0536:                    int minTy = owner.getMinTileY();
0537:                    int maxTx = minTx + owner.getNumXTiles();
0538:                    int maxTy = minTy + owner.getNumYTiles();
0539:
0540:                    for (int y = minTy; y < maxTy; y++) {
0541:                        for (int x = minTx; x < maxTx; x++) {
0542:                            remove(owner, x, y);
0543:                        }
0544:                    }
0545:                }
0546:            }
0547:
0548:            /**
0549:             * Adds an array of tiles to the tile cache.
0550:             *
0551:             * @param owner The <code>RenderedImage</code> that the tile belongs to.
0552:             * @param tileIndices An array of <code>Point</code>s containing the
0553:             *        <code>tileX</code> and <code>tileY</code> indices for each tile.
0554:             * @param tiles The array of tile <code>Raster</code>s containing tile data.
0555:             * @param tileCacheMetric Object which provides an ordering metric
0556:             *        associated with the <code>RenderedImage</code> owner.
0557:             * @since 1.1
0558:             */
0559:            public synchronized void addTiles(RenderedImage owner,
0560:                    Point[] tileIndices, Raster[] tiles, Object tileCacheMetric) {
0561:
0562:                if (memoryCapacity == 0) {
0563:                    return;
0564:                }
0565:
0566:                // this just inlines the add routine (no sync overhead for each call).
0567:                for (int i = 0; i < tileIndices.length; i++) {
0568:                    int tileX = tileIndices[i].x;
0569:                    int tileY = tileIndices[i].y;
0570:                    Raster tile = tiles[i];
0571:
0572:                    Object key = SunCachedTile.hashKey(owner, tileX, tileY);
0573:                    SunCachedTile ct = (SunCachedTile) cache.get(key);
0574:
0575:                    if (ct != null) {
0576:                        // tile is cached, inlines update()
0577:                        ct.timeStamp = timeStamp++;
0578:
0579:                        if (ct != first) {
0580:                            // Bring this tile to the beginning of the list.
0581:                            if (ct == last) {
0582:                                last = ct.previous;
0583:                                last.next = null;
0584:                            } else {
0585:                                ct.previous.next = ct.next;
0586:                                ct.next.previous = ct.previous;
0587:                            }
0588:
0589:                            ct.previous = null;
0590:                            ct.next = first;
0591:
0592:                            first.previous = ct;
0593:                            first = ct;
0594:                        }
0595:
0596:                        hitCount++;
0597:
0598:                        if (diagnostics) {
0599:                            ct.action = UPDATE_FROM_ADD;
0600:                            setChanged();
0601:                            notifyObservers(ct);
0602:                        }
0603:                    } else {
0604:                        // create a new tile
0605:                        ct = new SunCachedTile(owner, tileX, tileY, tile,
0606:                                tileCacheMetric);
0607:
0608:                        // Don't cache tile if adding it would provoke memoryControl()
0609:                        // which would in turn only end up removing the tile.
0610:                        if (memoryUsage + ct.memorySize > memoryCapacity
0611:                                && ct.memorySize > (long) (memoryCapacity * memoryThreshold)) {
0612:                            return;
0613:                        }
0614:
0615:                        ct.timeStamp = timeStamp++;
0616:                        ct.previous = null;
0617:                        ct.next = first;
0618:
0619:                        if (first == null && last == null) {
0620:                            first = ct;
0621:                            last = ct;
0622:                        } else {
0623:                            first.previous = ct;
0624:                            first = ct; // put this tile at the top of the list
0625:                        }
0626:
0627:                        // add to tile cache
0628:                        if (cache.put(ct.key, ct) == null) {
0629:                            memoryUsage += ct.memorySize;
0630:                            tileCount++;
0631:                            //missCount++;  Not necessary?
0632:
0633:                            if (cacheSortedSet != null) {
0634:                                cacheSortedSet.add(ct);
0635:                            }
0636:
0637:                            if (diagnostics) {
0638:                                ct.action = ADD;
0639:                                setChanged();
0640:                                notifyObservers(ct);
0641:                            }
0642:                        }
0643:
0644:                        // Bring memory usage down to memoryThreshold % of memory capacity.
0645:                        if (memoryUsage > memoryCapacity) {
0646:                            memoryControl();
0647:                        }
0648:                    }
0649:                }
0650:            }
0651:
0652:            /**
0653:             * Returns an array of tile <code>Raster</code>s from the cache.
0654:             * Any or all of the elements of the returned array may be <code>null</code>
0655:             * if the corresponding tile is not in the cache.
0656:             *
0657:             * @param owner The <code>RenderedImage</code> that the tile belongs to.
0658:             * @param tileIndices  An array of <code>Point</code>s containing the
0659:             *        <code>tileX</code> and <code>tileY</code> indices for each tile.
0660:             * @since 1.1
0661:             */
0662:            public synchronized Raster[] getTiles(RenderedImage owner,
0663:                    Point[] tileIndices) {
0664:
0665:                if (memoryCapacity == 0) {
0666:                    return null;
0667:                }
0668:
0669:                Raster[] tiles = new Raster[tileIndices.length];
0670:
0671:                for (int i = 0; i < tiles.length; i++) {
0672:                    int tileX = tileIndices[i].x;
0673:                    int tileY = tileIndices[i].y;
0674:
0675:                    Object key = SunCachedTile.hashKey(owner, tileX, tileY);
0676:                    SunCachedTile ct = (SunCachedTile) cache.get(key);
0677:
0678:                    if (ct == null) {
0679:                        tiles[i] = null;
0680:                        missCount++;
0681:                    } else { // found tile in cache
0682:                        tiles[i] = (Raster) ct.getTile();
0683:
0684:                        // Update last-access time. (update() inlined for performance)
0685:                        ct.timeStamp = timeStamp++;
0686:
0687:                        if (ct != first) {
0688:                            // Bring this tile to the beginning of the list.
0689:                            if (ct == last) {
0690:                                last = ct.previous;
0691:                                last.next = null;
0692:                            } else {
0693:                                ct.previous.next = ct.next;
0694:                                ct.next.previous = ct.previous;
0695:                            }
0696:
0697:                            ct.previous = null;
0698:                            ct.next = first;
0699:
0700:                            first.previous = ct;
0701:                            first = ct;
0702:                        }
0703:
0704:                        hitCount++;
0705:
0706:                        if (diagnostics) {
0707:                            ct.action = UPDATE_FROM_GETTILE;
0708:                            setChanged();
0709:                            notifyObservers(ct);
0710:                        }
0711:                    }
0712:                }
0713:
0714:                return tiles;
0715:            }
0716:
0717:            /** Removes -ALL- tiles from the cache. */
0718:            public synchronized void flush() {
0719:                //
0720:                // It is necessary to clear all the elements
0721:                // from the old cache in order to remove dangling
0722:                // references, due to the linked list.  In other
0723:                // words, it is possible to reache the object
0724:                // through 2 paths so the object does not
0725:                // become weakly reachable until the reference
0726:                // to it in the hash map is null. It is not enough
0727:                // to just set the object to null.
0728:                //
0729:                Enumeration keys = cache.keys(); // all keys in Hashtable
0730:
0731:                // reset counters before diagnostics
0732:                hitCount = 0;
0733:                missCount = 0;
0734:
0735:                while (keys.hasMoreElements()) {
0736:                    Object key = keys.nextElement();
0737:                    SunCachedTile ct = (SunCachedTile) cache.remove(key);
0738:
0739:                    // recalculate memoryUsage only if tile is actually removed
0740:                    if (ct != null) {
0741:                        memoryUsage -= ct.memorySize;
0742:                        tileCount--;
0743:
0744:                        if (ct == first) {
0745:                            if (ct == last) {
0746:                                first = null; // only one tile in the list
0747:                                last = null;
0748:                            } else {
0749:                                first = ct.next;
0750:                                first.previous = null;
0751:                            }
0752:                        } else if (ct == last) {
0753:                            last = ct.previous;
0754:                            last.next = null;
0755:                        } else {
0756:                            ct.previous.next = ct.next;
0757:                            ct.next.previous = ct.previous;
0758:                        }
0759:
0760:                        ct.previous = null;
0761:                        ct.next = null;
0762:
0763:                        // diagnostics
0764:                        if (diagnostics) {
0765:                            ct.action = REMOVE_FROM_FLUSH;
0766:                            setChanged();
0767:                            notifyObservers(ct);
0768:                        }
0769:                    }
0770:                }
0771:
0772:                if (memoryCapacity > 0) {
0773:                    cache = new Hashtable(DEFAULT_HASHTABLE_CAPACITY,
0774:                            LOAD_FACTOR);
0775:                }
0776:
0777:                if (cacheSortedSet != null) {
0778:                    cacheSortedSet.clear();
0779:                    cacheSortedSet = Collections
0780:                            .synchronizedSortedSet(new TreeSet(comparator));
0781:                }
0782:
0783:                // force reset after diagnostics
0784:                tileCount = 0;
0785:                timeStamp = 0;
0786:                memoryUsage = 0;
0787:
0788:                // no System.gc() here, it's too slow and may occur anyway.
0789:            }
0790:
0791:            /**
0792:             * Returns the cache's tile capacity.
0793:             *
0794:             * <p> This implementation of <code>TileCache</code> does not use
0795:             * the tile capacity.  This method always returns 0.
0796:             */
0797:            public int getTileCapacity() {
0798:                return 0;
0799:            }
0800:
0801:            /**
0802:             * Sets the cache's tile capacity to the desired number of tiles.
0803:             *
0804:             * <p> This implementation of <code>TileCache</code> does not use
0805:             * the tile capacity.  The cache size is limited by the memory
0806:             * capacity only.  This method does nothing and has no effect on
0807:             * the cache.
0808:             *
0809:             * @param tileCapacity  The desired tile capacity for this cache
0810:             *        in number of tiles.
0811:             */
0812:            public void setTileCapacity(int tileCapacity) {
0813:            }
0814:
0815:            /** Returns the cache's memory capacity in bytes. */
0816:            public long getMemoryCapacity() {
0817:                return memoryCapacity;
0818:            }
0819:
0820:            /**
0821:             * Sets the cache's memory capacity to the desired number of bytes.
0822:             * If the new memory capacity is smaller than the amount of memory
0823:             * currently being used by this cache, tiles are removed from the
0824:             * cache until the memory usage is less than the specified memory
0825:             * capacity.
0826:             *
0827:             * @param memoryCapacity  The desired memory capacity for this cache
0828:             *        in bytes.
0829:             *
0830:             * @throws IllegalArgumentException  If <code>memoryCapacity</code>
0831:             *         is less than 0.
0832:             */
0833:            public void setMemoryCapacity(long memoryCapacity) {
0834:                if (memoryCapacity < 0) {
0835:                    throw new IllegalArgumentException(JaiI18N
0836:                            .getString("SunTileCache"));
0837:                } else if (memoryCapacity == 0) {
0838:                    flush();
0839:                }
0840:
0841:                this .memoryCapacity = memoryCapacity;
0842:
0843:                if (memoryUsage > memoryCapacity) {
0844:                    memoryControl();
0845:                }
0846:            }
0847:
0848:            /** Enable Tile Monitoring and Diagnostics */
0849:            public void enableDiagnostics() {
0850:                diagnostics = true;
0851:            }
0852:
0853:            /** Turn off diagnostic notification */
0854:            public void disableDiagnostics() {
0855:                diagnostics = false;
0856:            }
0857:
0858:            public long getCacheTileCount() {
0859:                return tileCount;
0860:            }
0861:
0862:            public long getCacheMemoryUsed() {
0863:                return memoryUsage;
0864:            }
0865:
0866:            public long getCacheHitCount() {
0867:                return hitCount;
0868:            }
0869:
0870:            public long getCacheMissCount() {
0871:                return missCount;
0872:            }
0873:
0874:            /**
0875:             * Reset hit and miss counters.
0876:             *
0877:             * @since 1.1
0878:             */
0879:            public void resetCounts() {
0880:                hitCount = 0;
0881:                missCount = 0;
0882:            }
0883:
0884:            /**
0885:             * Set the memory threshold value.
0886:             *
0887:             * @since 1.1
0888:             */
0889:            public void setMemoryThreshold(float mt) {
0890:                if (mt < 0.0F || mt > 1.0F) {
0891:                    throw new IllegalArgumentException(JaiI18N
0892:                            .getString("SunTileCache"));
0893:                } else {
0894:                    memoryThreshold = mt;
0895:                    memoryControl();
0896:                }
0897:            }
0898:
0899:            /**
0900:             * Returns the current <code>memoryThreshold</code>.
0901:             *
0902:             * @since 1.1
0903:             */
0904:            public float getMemoryThreshold() {
0905:                return memoryThreshold;
0906:            }
0907:
0908:            /** Returns a string representation of the class object. */
0909:            public String toString() {
0910:                return getClass().getName() + "@"
0911:                        + Integer.toHexString(hashCode())
0912:                        + ": memoryCapacity = "
0913:                        + Long.toHexString(memoryCapacity) + " memoryUsage = "
0914:                        + Long.toHexString(memoryUsage) + " #tilesInCache = "
0915:                        + Integer.toString(cache.size());
0916:            }
0917:
0918:            /** Returns the <code>Object</code> that represents the actual cache. */
0919:            public Object getCachedObject() {
0920:                return cache;
0921:            }
0922:
0923:            /**
0924:             * Removes tiles from the cache based on their last-access time
0925:             * (old to new) until the memory usage is memoryThreshold % of that of the
0926:             * memory capacity.
0927:             */
0928:            public synchronized void memoryControl() {
0929:                if (cacheSortedSet == null) {
0930:                    standard_memory_control();
0931:                } else {
0932:                    custom_memory_control();
0933:                }
0934:            }
0935:
0936:            // time stamp based memory control (LRU)
0937:            private final void standard_memory_control() {
0938:                long limit = (long) (memoryCapacity * memoryThreshold);
0939:
0940:                while (memoryUsage > limit && last != null) {
0941:                    SunCachedTile ct = (SunCachedTile) cache.get(last.key);
0942:
0943:                    if (ct != null) {
0944:                        ct = (SunCachedTile) cache.remove(last.key);
0945:
0946:                        memoryUsage -= last.memorySize;
0947:                        tileCount--;
0948:
0949:                        last = last.previous;
0950:
0951:                        if (last != null) {
0952:                            last.next.previous = null;
0953:                            last.next = null;
0954:                        } else {
0955:                            first = null;
0956:                        }
0957:
0958:                        // diagnostics
0959:                        if (diagnostics) {
0960:                            ct.action = REMOVE_FROM_MEMCON;
0961:                            setChanged();
0962:                            notifyObservers(ct);
0963:                        }
0964:                    }
0965:                }
0966:            }
0967:
0968:            // comparator based memory control (TreeSet)
0969:            private final void custom_memory_control() {
0970:                long limit = (long) (memoryCapacity * memoryThreshold);
0971:                Iterator iter = cacheSortedSet.iterator();
0972:                SunCachedTile ct;
0973:
0974:                while (iter.hasNext() && (memoryUsage > limit)) {
0975:                    ct = (SunCachedTile) iter.next();
0976:
0977:                    memoryUsage -= ct.memorySize;
0978:                    tileCount--;
0979:
0980:                    // remove from sorted set
0981:                    try {
0982:                        iter.remove();
0983:                    } catch (ConcurrentModificationException e) {
0984:                        ImagingListener listener = ImageUtil
0985:                                .getImagingListener((RenderingHints) null);
0986:                        listener.errorOccurred(JaiI18N
0987:                                .getString("SunTileCache0"), e, this , false);
0988:                        //                e.printStackTrace();
0989:                    }
0990:
0991:                    // remove tile from the linked list
0992:                    if (ct == first) {
0993:                        if (ct == last) {
0994:                            first = null;
0995:                            last = null;
0996:                        } else {
0997:                            first = ct.next;
0998:
0999:                            if (first != null) {
1000:                                first.previous = null;
1001:                                first.next = ct.next.next;
1002:                            }
1003:                        }
1004:                    } else if (ct == last) {
1005:                        last = ct.previous;
1006:
1007:                        if (last != null) {
1008:                            last.next = null;
1009:                            last.previous = ct.previous.previous;
1010:                        }
1011:                    } else {
1012:                        SunCachedTile ptr = first.next;
1013:
1014:                        while (ptr != null) {
1015:
1016:                            if (ptr == ct) {
1017:                                if (ptr.previous != null) {
1018:                                    ptr.previous.next = ptr.next;
1019:                                }
1020:
1021:                                if (ptr.next != null) {
1022:                                    ptr.next.previous = ptr.previous;
1023:                                }
1024:
1025:                                break;
1026:                            }
1027:
1028:                            ptr = ptr.next;
1029:                        }
1030:                    }
1031:
1032:                    // remove reference in the hashtable
1033:                    cache.remove(ct.key);
1034:
1035:                    // diagnostics
1036:                    if (diagnostics) {
1037:                        ct.action = REMOVE_FROM_MEMCON;
1038:                        setChanged();
1039:                        notifyObservers(ct);
1040:                    }
1041:                }
1042:
1043:                // If the custom memory control didn't release sufficient
1044:                // number of tiles to satisfy the memory limit, fallback
1045:                // to the standard memory controller.
1046:                if (memoryUsage > limit) {
1047:                    standard_memory_control();
1048:                }
1049:            }
1050:
1051:            /**
1052:             *  The <code>Comparator</code> is used to produce an
1053:             *  ordered list of tiles based on a user defined
1054:             *  compute cost or priority metric.  This determines
1055:             *  which tiles are subject to "ordered" removal
1056:             *  during a memory control operation.
1057:             *
1058:             *  @since 1.1
1059:             */
1060:            public synchronized void setTileComparator(Comparator c) {
1061:                comparator = c;
1062:
1063:                if (comparator == null) {
1064:                    // turn of comparator
1065:                    if (cacheSortedSet != null) {
1066:                        cacheSortedSet.clear();
1067:                        cacheSortedSet = null;
1068:                    }
1069:                } else {
1070:                    // copy tiles from hashtable to sorted tree set
1071:                    cacheSortedSet = Collections
1072:                            .synchronizedSortedSet(new TreeSet(comparator));
1073:
1074:                    Enumeration keys = cache.keys();
1075:
1076:                    while (keys.hasMoreElements()) {
1077:                        Object key = keys.nextElement();
1078:                        Object ct = cache.get(key);
1079:                        cacheSortedSet.add(ct);
1080:                    }
1081:                }
1082:            }
1083:
1084:            /**
1085:             * Return the current comparator
1086:             *
1087:             * @since 1.1
1088:             */
1089:            public Comparator getTileComparator() {
1090:                return comparator;
1091:            }
1092:
1093:            // test
1094:            public void dump() {
1095:
1096:                System.out.println("first = " + first);
1097:                System.out.println("last  = " + last);
1098:
1099:                Iterator iter = cacheSortedSet.iterator();
1100:                int k = 0;
1101:
1102:                while (iter.hasNext()) {
1103:                    SunCachedTile ct = (SunCachedTile) iter.next();
1104:                    System.out.println(k++);
1105:                    System.out.println(ct);
1106:                }
1107:            }
1108:
1109:            void sendExceptionToListener(String message, Exception e) {
1110:                ImagingListener listener = ImageUtil
1111:                        .getImagingListener((RenderingHints) null);
1112:                listener.errorOccurred(message, e, this , false);
1113:            }
1114:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.