Source Code Cross Referenced for MemCache.java in  » ERP-CRM-Financial » sakai » org » sakaiproject » memory » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

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


0001:        /**********************************************************************************
0002:         * $URL: https://source.sakaiproject.org/svn/memory/tags/sakai_2-4-1/memory-impl/impl/src/java/org/sakaiproject/memory/impl/MemCache.java $
0003:         * $Id: MemCache.java 12712 2006-07-24 04:09:14Z ggolden@umich.edu $
0004:         ***********************************************************************************
0005:         *
0006:         * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
0007:         * 
0008:         * Licensed under the Educational Community License, Version 1.0 (the "License"); 
0009:         * you may not use this file except in compliance with the License. 
0010:         * You may obtain a copy of the License at
0011:         * 
0012:         *      http://www.opensource.org/licenses/ecl1.php
0013:         * 
0014:         * Unless required by applicable law or agreed to in writing, software 
0015:         * distributed under the License is distributed on an "AS IS" BASIS, 
0016:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0017:         * See the License for the specific language governing permissions and 
0018:         * limitations under the License.
0019:         *
0020:         **********************************************************************************/package org.sakaiproject.memory.impl;
0021:
0022:        import java.lang.ref.SoftReference;
0023:        import java.util.HashSet;
0024:        import java.util.Iterator;
0025:        import java.util.List;
0026:        import java.util.Map;
0027:        import java.util.Observable;
0028:        import java.util.Observer;
0029:        import java.util.Set;
0030:        import java.util.Vector;
0031:
0032:        import org.apache.commons.logging.Log;
0033:        import org.apache.commons.logging.LogFactory;
0034:        import org.sakaiproject.component.cover.ComponentManager;
0035:        import org.sakaiproject.event.api.Event;
0036:        import org.sakaiproject.event.api.EventTrackingService;
0037:        import org.sakaiproject.memory.api.Cache;
0038:        import org.sakaiproject.memory.api.CacheRefresher;
0039:        import org.sakaiproject.memory.api.DerivedCache;
0040:
0041:        import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
0042:
0043:        /**
0044:         * <p>
0045:         * A Cache of objects with keys with a limited lifespan.
0046:         * </p>
0047:         * <p>
0048:         * When the object expires, the cache calls upon a CacheRefresher to update the key's value. The update is done in a separate thread.
0049:         * </p>
0050:         */
0051:        public class MemCache implements  Cache, Runnable, Observer {
0052:            /** Our logger. */
0053:            private static Log M_log = LogFactory.getLog(MemCache.class);
0054:
0055:            /** Map holding cached entries. */
0056:            protected Map m_map = null;
0057:
0058:            /** The object that will deal with expired entries. */
0059:            protected CacheRefresher m_refresher = null;
0060:
0061:            /** The string that all resources in this cache will start with. */
0062:            protected String m_resourcePattern = null;
0063:
0064:            /** The number of seconds to sleep between expiration checks. */
0065:            protected long m_refresherSleep = 60;
0066:
0067:            /** If true, we are disabled. */
0068:            protected boolean m_disabled = false;
0069:
0070:            /** If true, we have all the entries that there are in the cache. */
0071:            protected boolean m_complete = false;
0072:
0073:            /** Alternate isComplete, based on patterns. */
0074:            protected Set m_partiallyComplete = new HashSet();
0075:
0076:            /** If true, we are going to hold any events we see in the m_heldEvents list for later processing. */
0077:            protected boolean m_holdEventProcessing = false;
0078:
0079:            /** The events we are holding for later processing. */
0080:            protected List m_heldEvents = new Vector();
0081:
0082:            /** Constructor injected memory service. */
0083:            protected BasicMemoryService m_memoryService = null;
0084:
0085:            /** Constructor injected event tracking service. */
0086:            protected EventTrackingService m_eventTrackingService = null;
0087:
0088:            /** If true, we do soft references, else we do hard ones. */
0089:            protected boolean m_softRefs = true;
0090:
0091:            /** Count of access requests. */
0092:            protected long m_getCount = 0;
0093:
0094:            /** Count of access requests satisfied with a cached entry. */
0095:            protected long m_hitCount = 0;
0096:
0097:            /** Count of things put into the cache. */
0098:            protected long m_putCount = 0;
0099:
0100:            /** My (optional) DerivedCache. */
0101:            protected DerivedCache m_derivedCache = null;
0102:
0103:            /**
0104:             * The cache entry. Holds a time stamped payload.
0105:             */
0106:            protected class CacheEntry extends SoftReference {
0107:                /** currentTimeMillis when this expires. */
0108:                protected long m_expires = 0;
0109:
0110:                /** The time (seconds) to keep this cached (0 means don't exipre). */
0111:                protected int m_duration = 0;
0112:
0113:                /** Set if our payload is supposed to be null. */
0114:                protected boolean m_nullPayload = false;
0115:
0116:                /** Hard reference to the payload, if needed. */
0117:                protected Object m_hardPayload = null;
0118:
0119:                /**
0120:                 * Construct to cache the payload for the duration.
0121:                 * 
0122:                 * @param payload
0123:                 *        The thing to cache.
0124:                 * @param duration
0125:                 *        The time (seconds) to keep this cached.
0126:                 */
0127:                public CacheEntry(Object payload, int duration) {
0128:                    // put the payload into the soft reference
0129:                    super (payload);
0130:
0131:                    // if we are not doing soft refs, make the hard ref and clear the soft
0132:                    if (!m_softRefs) {
0133:                        this .clear();
0134:                        m_hardPayload = payload;
0135:                    }
0136:
0137:                    // is it supposed to be null?
0138:                    m_nullPayload = (payload == null);
0139:
0140:                    m_duration = duration;
0141:                    reset();
0142:
0143:                } // CacheEntry
0144:
0145:                /**
0146:                 * Access the hard payload directly.
0147:                 * @return The hard payload.
0148:                 */
0149:                public Object getHardPayload() {
0150:                    return m_hardPayload;
0151:                }
0152:
0153:                /**
0154:                 * Get the cached object.
0155:                 * 
0156:                 * @param key
0157:                 *        The key for this entry (if null, we won't try to refresh if missing)
0158:                 * @return The cached object.
0159:                 */
0160:                public Object getPayload(Object key) {
0161:                    // if we hold null, this is easy
0162:                    if (m_nullPayload) {
0163:                        return null;
0164:                    }
0165:
0166:                    // for our hard, not soft, option
0167:                    if (!m_softRefs) {
0168:                        return m_hardPayload;
0169:                    }
0170:
0171:                    // get the payload
0172:                    Object payload = this .get();
0173:
0174:                    // if it has been garbage collected, and we can, refresh it
0175:                    if (payload == null) {
0176:                        if ((m_refresher != null) && (key != null)) {
0177:                            // ask the refresher for the value
0178:                            payload = m_refresher.refresh(key, null, null);
0179:
0180:                            if (m_memoryService.getCacheLogging()) {
0181:                                M_log.info("cache miss: refreshing: key: "
0182:                                        + key + " new payload: " + payload);
0183:                            }
0184:
0185:                            // store this new value
0186:                            put(key, payload, m_duration);
0187:                        } else {
0188:                            if (m_memoryService.getCacheLogging()) {
0189:                                M_log.info("cache miss: no refresh: key: "
0190:                                        + key);
0191:                            }
0192:                        }
0193:                    }
0194:
0195:                    // TODO: stash hard ref in the current LRU...
0196:
0197:                    return payload;
0198:                }
0199:
0200:                /**
0201:                 * Check for expiration.
0202:                 * 
0203:                 * @return true if expired, false if still good.
0204:                 */
0205:                public boolean hasExpired() {
0206:                    return ((m_duration > 0) ? (System.currentTimeMillis() > m_expires)
0207:                            : false);
0208:                }
0209:
0210:                /**
0211:                 * Access the duration.
0212:                 * 
0213:                 * @return The time (seconds) before the entry expires.
0214:                 */
0215:                public int getDuration() {
0216:                    return m_duration;
0217:                }
0218:
0219:                /**
0220:                 * If we have a duration, reset our expiration time.
0221:                 */
0222:                public void reset() {
0223:                    if (m_duration > 0)
0224:                        m_expires = System.currentTimeMillis()
0225:                                + (m_duration * 1000);
0226:                }
0227:
0228:            } // CacheEntry
0229:
0230:            /**
0231:             * Construct the Cache. No automatic refresh handling.
0232:             */
0233:            public MemCache(BasicMemoryService memoryService,
0234:                    EventTrackingService eventTrackingService) {
0235:                // inject our dependencies
0236:                m_memoryService = memoryService;
0237:                m_eventTrackingService = eventTrackingService;
0238:
0239:                m_map = new ConcurrentReaderHashMap();
0240:
0241:                // register as a cacher
0242:                m_memoryService.registerCacher(this );
0243:            }
0244:
0245:            /**
0246:             * Construct the Cache. Attempts to keep complete on Event notification by calling the refresher.
0247:             * 
0248:             * @param refresher
0249:             *        The object that will handle refreshing of event notified modified or added entries.
0250:             * @param pattern
0251:             *        The "startsWith()" string for all resources that may be in this cache - if null, don't watch events for updates.
0252:             */
0253:            public MemCache(BasicMemoryService memoryService,
0254:                    EventTrackingService eventTrackingService,
0255:                    CacheRefresher refresher, String pattern) {
0256:                this (memoryService, eventTrackingService);
0257:                m_refresher = refresher;
0258:                m_resourcePattern = pattern;
0259:
0260:                // register to get events - first, before others
0261:                if (pattern != null) {
0262:                    m_eventTrackingService.addPriorityObserver(this );
0263:                }
0264:            }
0265:
0266:            /**
0267:             * Construct the Cache. Automatic refresh handling if refresher is not null.
0268:             * 
0269:             * @param refresher
0270:             *        The object that will handle refreshing of expired entries.
0271:             * @param sleep
0272:             *        The number of seconds to sleep between expiration checks.
0273:             */
0274:            public MemCache(BasicMemoryService memoryService,
0275:                    EventTrackingService eventTrackingService,
0276:                    CacheRefresher refresher, long sleep) {
0277:                this (memoryService, eventTrackingService);
0278:                m_refresherSleep = sleep;
0279:
0280:                if (refresher != null) {
0281:                    m_refresher = refresher;
0282:
0283:                    // start the expiration thread
0284:                    start();
0285:                }
0286:            }
0287:
0288:            /**
0289:             * Construct the Cache. Event scanning if pattern not null - will expire entries.
0290:             * 
0291:             * @param sleep
0292:             *        The number of seconds to sleep between expiration checks.
0293:             * @param pattern
0294:             *        The "startsWith()" string for all resources that may be in this cache - if null, don't watch events for expiration.
0295:             */
0296:            public MemCache(BasicMemoryService memoryService,
0297:                    EventTrackingService eventTrackingService, long sleep,
0298:                    String pattern) {
0299:                this (memoryService, eventTrackingService);
0300:                m_refresherSleep = sleep;
0301:                m_resourcePattern = pattern;
0302:
0303:                // start the expiration thread
0304:                start();
0305:
0306:                // register to get events - first, before others
0307:                if (pattern != null) {
0308:                    m_eventTrackingService.addPriorityObserver(this );
0309:                }
0310:            }
0311:
0312:            /**
0313:             * Clean up.
0314:             */
0315:            public void destroy() {
0316:                clear();
0317:
0318:                // if we are not in a global shutdown
0319:                if (!ComponentManager.hasBeenClosed()) {
0320:                    // remove my registration
0321:                    m_memoryService.unregisterCacher(this );
0322:
0323:                    // remove my event notification registration
0324:                    m_eventTrackingService.deleteObserver(this );
0325:                }
0326:
0327:                // stop our expiration thread (if any)
0328:                stop();
0329:            }
0330:
0331:            /**
0332:             * {@inheritDoc}
0333:             */
0334:            public void attachDerivedCache(DerivedCache cache) {
0335:                // Note: only one is supported
0336:                if (cache == null) {
0337:                    m_derivedCache = null;
0338:                } else {
0339:                    if (m_derivedCache != null) {
0340:                        M_log.warn("attachDerivedCache - already got one!");
0341:                    } else {
0342:                        m_derivedCache = cache;
0343:                    }
0344:                }
0345:            }
0346:
0347:            /**
0348:             * Cache an object
0349:             * 
0350:             * @param key
0351:             *        The key with which to find the object.
0352:             * @param payload
0353:             *        The object to cache.
0354:             * @param duration
0355:             *        The time to cache the object (seconds).
0356:             */
0357:            public void put(Object key, Object payload, int duration) {
0358:                if (disabled())
0359:                    return;
0360:
0361:                m_map.put(key, new CacheEntry(payload, duration));
0362:
0363:                m_putCount++;
0364:
0365:                if (m_derivedCache != null)
0366:                    m_derivedCache.notifyCachePut(key, payload);
0367:            }
0368:
0369:            /**
0370:             * Cache an object - don't automatically exipire it.
0371:             * 
0372:             * @param key
0373:             *        The key with which to find the object.
0374:             * @param payload
0375:             *        The object to cache.
0376:             * @param duration
0377:             *        The time to cache the object (seconds).
0378:             */
0379:            public void put(Object key, Object payload) {
0380:                put(key, payload, 0);
0381:            }
0382:
0383:            /**
0384:             * Test for an entry in the cache - expired or not.
0385:             * 
0386:             * @param key
0387:             *        The cache key.
0388:             * @return true if the key maps to a cache entry, false if not.
0389:             */
0390:            public boolean containsKeyExpiredOrNot(Object key) {
0391:                if (disabled())
0392:                    return false;
0393:
0394:                // is it there?
0395:                boolean rv = m_map.containsKey(key);
0396:
0397:                m_getCount++;
0398:                if (rv) {
0399:                    m_hitCount++;
0400:                }
0401:
0402:                return rv;
0403:
0404:            } // containsKeyExpiredOrNot
0405:
0406:            /**
0407:             * Test for a non expired entry in the cache.
0408:             * 
0409:             * @param key
0410:             *        The cache key.
0411:             * @return true if the key maps to a non-expired cache entry, false if not.
0412:             */
0413:            public boolean containsKey(Object key) {
0414:                if (disabled())
0415:                    return false;
0416:
0417:                m_getCount++;
0418:
0419:                // is it there?
0420:                CacheEntry entry = (CacheEntry) m_map.get(key);
0421:                if (entry != null) {
0422:                    // has it expired?
0423:                    if (entry.hasExpired()) {
0424:                        // if so, remove it
0425:                        remove(key);
0426:                        return false;
0427:                    }
0428:                    m_hitCount++;
0429:                    return true;
0430:                }
0431:
0432:                return false;
0433:
0434:            } // containsKey
0435:
0436:            /**
0437:             * Expire this object.
0438:             * 
0439:             * @param key
0440:             *        The cache key.
0441:             */
0442:            public void expire(Object key) {
0443:                if (disabled())
0444:                    return;
0445:
0446:                // remove it
0447:                remove(key);
0448:
0449:            } // expire
0450:
0451:            /**
0452:             * Get the entry, or null if not there (expired entries are returned, too).
0453:             * 
0454:             * @param key
0455:             *        The cache key.
0456:             * @return The payload, or null if the payload is null, the key is not found. (Note: use containsKey() to remove this ambiguity).
0457:             */
0458:            public Object getExpiredOrNot(Object key) {
0459:                if (disabled())
0460:                    return null;
0461:
0462:                // is it there?
0463:                CacheEntry entry = (CacheEntry) m_map.get(key);
0464:                if (entry != null) {
0465:                    return entry.getPayload(key);
0466:                }
0467:
0468:                return null;
0469:
0470:            } // getExpiredOrNot
0471:
0472:            /**
0473:             * Get the non expired entry, or null if not there (or expired)
0474:             * 
0475:             * @param key
0476:             *        The cache key.
0477:             * @return The payload, or null if the payload is null, the key is not found, or the entry has expired (Note: use containsKey() to remove this ambiguity).
0478:             */
0479:            public Object get(Object key) {
0480:                if (disabled())
0481:                    return null;
0482:
0483:                // get it if there
0484:                CacheEntry entry = (CacheEntry) m_map.get(key);
0485:                if (entry != null) {
0486:                    // has it expired?
0487:                    if (entry.hasExpired()) {
0488:                        // if so, remove it
0489:                        remove(key);
0490:                        return null;
0491:                    }
0492:                    return entry.getPayload(key);
0493:                }
0494:
0495:                return null;
0496:
0497:            } // get
0498:
0499:            /**
0500:             * Get all the non-expired non-null entries.
0501:             * 
0502:             * @return all the non-expired non-null entries, or an empty list if none.
0503:             */
0504:            public List getAll() {
0505:                List rv = new Vector();
0506:
0507:                if (disabled())
0508:                    return rv;
0509:                if (m_map.isEmpty())
0510:                    return rv;
0511:
0512:                // for each entry in the cache
0513:                for (Iterator iKeys = m_map.entrySet().iterator(); iKeys
0514:                        .hasNext();) {
0515:                    Map.Entry e = (Map.Entry) iKeys.next();
0516:                    CacheEntry entry = (CacheEntry) e.getValue();
0517:
0518:                    // skip expired
0519:                    if (entry.hasExpired())
0520:                        continue;
0521:
0522:                    Object payload = entry.getPayload(e.getKey());
0523:
0524:                    // skip nulls
0525:                    if (payload == null)
0526:                        continue;
0527:
0528:                    // skip inappropriate types
0529:                    // if ((type != null) && (!(type.isInstance(payload)))) continue;
0530:
0531:                    // filter out those not matching the filter
0532:                    // if ((filter != null) && (((String) keys[i]).startsWith(filter))) continue;
0533:
0534:                    // we'll take it
0535:                    rv.add(payload);
0536:                }
0537:
0538:                return rv;
0539:
0540:            } // getAll
0541:
0542:            /**
0543:             * Get all the non-expired non-null entries that are in the specified reference path. Note: only works with String keys.
0544:             * 
0545:             * @param path
0546:             *        The reference path.
0547:             * @return all the non-expired non-null entries, or an empty list if none.
0548:             */
0549:            public List getAll(String path) {
0550:                List rv = new Vector();
0551:
0552:                if (disabled())
0553:                    return rv;
0554:                if (m_map.isEmpty())
0555:                    return rv;
0556:
0557:                // for each entry in the cache
0558:                for (Iterator iKeys = m_map.entrySet().iterator(); iKeys
0559:                        .hasNext();) {
0560:                    Map.Entry e = (Map.Entry) iKeys.next();
0561:                    CacheEntry entry = (CacheEntry) e.getValue();
0562:
0563:                    // skip expired
0564:                    if (entry.hasExpired())
0565:                        continue;
0566:
0567:                    Object payload = entry.getPayload(e.getKey());
0568:
0569:                    // skip nulls
0570:                    if (payload == null)
0571:                        continue;
0572:
0573:                    // take only if keys start with path, and have no SEPARATOR following other than at the end %%%
0574:                    String keyPath = referencePath((String) e.getKey());
0575:                    if (!keyPath.equals(path))
0576:                        continue;
0577:
0578:                    // we'll take it
0579:                    rv.add(payload);
0580:                }
0581:
0582:                return rv;
0583:
0584:            } // getAll
0585:
0586:            /**
0587:             * Get all the keys
0588:             * 
0589:             * @return The List of key values (Object).
0590:             */
0591:            public List getKeys() {
0592:                List rv = new Vector();
0593:                rv.addAll(m_map.keySet());
0594:                return rv;
0595:
0596:            } // getKeys
0597:
0598:            /**
0599:             * Get all the keys, eache modified to remove the resourcePattern prefix. Note: only works with String keys.
0600:             * 
0601:             * @return The List of keys converted from references to ids (String).
0602:             */
0603:            public List getIds() {
0604:                List rv = new Vector();
0605:
0606:                for (Iterator it = m_map.keySet().iterator(); it.hasNext();) {
0607:                    String key = (String) it.next();
0608:                    int i = key.indexOf(m_resourcePattern);
0609:                    if (i != -1)
0610:                        key = key.substring(i + m_resourcePattern.length());
0611:                    rv.add(key);
0612:                }
0613:
0614:                return rv;
0615:
0616:            } // getKeys
0617:
0618:            /**
0619:             * Clear all entries.
0620:             */
0621:            public void clear() {
0622:                m_map.clear();
0623:                m_complete = false;
0624:                m_partiallyComplete.clear();
0625:                m_getCount = 0;
0626:                m_hitCount = 0;
0627:                m_putCount = 0;
0628:
0629:                if (m_derivedCache != null)
0630:                    m_derivedCache.notifyCacheClear();
0631:
0632:            } // clear
0633:
0634:            /**
0635:             * Remove this entry from the cache.
0636:             * 
0637:             * @param key
0638:             *        The cache key.
0639:             */
0640:            public void remove(Object key) {
0641:                if (disabled())
0642:                    return;
0643:
0644:                CacheEntry entry = (CacheEntry) m_map.remove(key);
0645:
0646:                if (m_derivedCache != null) {
0647:                    Object old = null;
0648:                    if (entry != null) {
0649:                        old = entry.getHardPayload();
0650:                    }
0651:
0652:                    m_derivedCache.notifyCacheRemove(key, old);
0653:                }
0654:
0655:            } // remove
0656:
0657:            /**
0658:             * Disable the cache.
0659:             */
0660:            public void disable() {
0661:                m_disabled = true;
0662:                m_eventTrackingService.deleteObserver(this );
0663:                clear();
0664:
0665:            } // disable
0666:
0667:            /**
0668:             * Enable the cache.
0669:             */
0670:            public void enable() {
0671:                m_disabled = false;
0672:
0673:                if (m_resourcePattern != null) {
0674:                    m_eventTrackingService.addPriorityObserver(this );
0675:                }
0676:
0677:            } // enable
0678:
0679:            /**
0680:             * Is the cache disabled?
0681:             * 
0682:             * @return true if the cache is disabled, false if it is enabled.
0683:             */
0684:            public boolean disabled() {
0685:                return m_disabled;
0686:
0687:            } // disabled
0688:
0689:            /**
0690:             * Are we complete?
0691:             * 
0692:             * @return true if we have all the possible entries cached, false if not.
0693:             */
0694:            public boolean isComplete() {
0695:                if (disabled())
0696:                    return false;
0697:
0698:                return m_complete;
0699:
0700:            } // isComplete
0701:
0702:            /**
0703:             * Set the cache to be complete, containing all possible entries.
0704:             */
0705:            public void setComplete() {
0706:                if (disabled())
0707:                    return;
0708:
0709:                m_complete = true;
0710:
0711:            } // isComplete
0712:
0713:            /**
0714:             * Are we complete for one level of the reference hierarchy?
0715:             * 
0716:             * @param path
0717:             *        The reference to the completion level.
0718:             * @return true if we have all the possible entries cached, false if not.
0719:             */
0720:            public boolean isComplete(String path) {
0721:                return m_partiallyComplete.contains(path);
0722:
0723:            } // isComplete
0724:
0725:            /**
0726:             * Set the cache to be complete for one level of the reference hierarchy.
0727:             * 
0728:             * @param path
0729:             *        The reference to the completion level.
0730:             */
0731:            public void setComplete(String path) {
0732:                m_partiallyComplete.add(path);
0733:
0734:            } // setComplete
0735:
0736:            /**
0737:             * Set the cache to hold events for later processing to assure an atomic "complete" load.
0738:             */
0739:            public void holdEvents() {
0740:                m_holdEventProcessing = true;
0741:
0742:            } // holdEvents
0743:
0744:            /**
0745:             * Restore normal event processing in the cache, and process any held events now.
0746:             */
0747:            public void processEvents() {
0748:                m_holdEventProcessing = false;
0749:
0750:                for (int i = 0; i < m_heldEvents.size(); i++) {
0751:                    Event event = (Event) m_heldEvents.get(i);
0752:                    continueUpdate(event);
0753:                }
0754:
0755:                m_heldEvents.clear();
0756:
0757:            } // holdEvents
0758:
0759:            /**********************************************************************************************************************************************************************************************************************************************************
0760:             * Cacher implementation
0761:             *********************************************************************************************************************************************************************************************************************************************************/
0762:
0763:            /**
0764:             * Clear out as much as possible anything cached; re-sync any cache that is needed to be kept.
0765:             */
0766:            public void resetCache() {
0767:                clear();
0768:
0769:            } // resetCache
0770:
0771:            /**
0772:             * Return the size of the cacher - indicating how much memory in use.
0773:             * 
0774:             * @return The size of the cacher.
0775:             */
0776:            public long getSize() {
0777:                return m_map.size();
0778:            }
0779:
0780:            /**
0781:             * Return a description of the cacher.
0782:             * 
0783:             * @return The cacher's description.
0784:             */
0785:            public String getDescription() {
0786:                StringBuffer buf = new StringBuffer();
0787:                buf.append("MemCache");
0788:                if (m_softRefs) {
0789:                    buf.append(" soft");
0790:                }
0791:                if (m_disabled) {
0792:                    buf.append(" disabled");
0793:                }
0794:                if (m_complete) {
0795:                    buf.append(" complete");
0796:                }
0797:                if (m_resourcePattern != null) {
0798:                    buf.append(" " + m_resourcePattern);
0799:                }
0800:                if (m_refresher != null) {
0801:                    buf.append(" " + m_refresher.toString());
0802:                }
0803:                if (m_thread != null) {
0804:                    buf.append(" thread_sleep: " + m_refresherSleep);
0805:                }
0806:                if (m_partiallyComplete.size() > 0) {
0807:                    buf.append(" partially_complete[");
0808:                    for (Iterator i = m_partiallyComplete.iterator(); i
0809:                            .hasNext();) {
0810:                        buf.append(" " + i.next());
0811:                    }
0812:                    buf.append("]");
0813:                }
0814:
0815:                buf.append("  puts:"
0816:                        + m_putCount
0817:                        + "  gets:"
0818:                        + m_getCount
0819:                        + "  hits:"
0820:                        + m_hitCount
0821:                        + "  hit%:"
0822:                        + ((m_getCount > 0) ? ""
0823:                                + ((100l * m_hitCount) / m_getCount) : "n/a"));
0824:
0825:                return buf.toString();
0826:            }
0827:
0828:            /**********************************************************************************************************************************************************************************************************************************************************
0829:             * Runnable implementation
0830:             *********************************************************************************************************************************************************************************************************************************************************/
0831:
0832:            /** The thread which runs the expiration check. */
0833:            protected Thread m_thread = null;
0834:
0835:            /** My thread's quit flag. */
0836:            protected boolean m_threadStop = false;
0837:
0838:            /**
0839:             * Start the expiration thread.
0840:             */
0841:            protected void start() {
0842:                m_threadStop = false;
0843:
0844:                m_thread = new Thread(this , getClass().getName());
0845:                m_thread.setDaemon(true);
0846:                m_thread.setPriority(Thread.MIN_PRIORITY + 2);
0847:                m_thread.start();
0848:
0849:            } // start
0850:
0851:            /**
0852:             * Stop the expiration thread.
0853:             */
0854:            protected void stop() {
0855:                if (m_thread == null)
0856:                    return;
0857:
0858:                // signal the thread to stop
0859:                m_threadStop = true;
0860:
0861:                // wake up the thread
0862:                m_thread.interrupt();
0863:
0864:                m_thread = null;
0865:
0866:            } // stop
0867:
0868:            /**
0869:             * Run the expiration thread.
0870:             */
0871:            public void run() {
0872:                // since we might be running while the component manager is still being created and populated, such as at server
0873:                // startup, wait here for a complete component manager
0874:                ComponentManager.waitTillConfigured();
0875:
0876:                // loop till told to stop
0877:                while ((!m_threadStop)
0878:                        && (!Thread.currentThread().isInterrupted())) {
0879:                    long startTime = 0;
0880:                    try {
0881:                        if (M_log.isDebugEnabled()) {
0882:                            startTime = System.currentTimeMillis();
0883:                            M_log.debug(this  + ".checking ...");
0884:                        }
0885:
0886:                        // collect keys of expired entries in the cache
0887:                        List expired = new Vector();
0888:                        for (Iterator iKeys = m_map.entrySet().iterator(); iKeys
0889:                                .hasNext();) {
0890:                            Map.Entry e = (Map.Entry) iKeys.next();
0891:                            String key = (String) e.getKey();
0892:                            CacheEntry entry = (CacheEntry) e.getValue();
0893:
0894:                            // if it has expired
0895:                            if (entry.hasExpired()) {
0896:                                expired.add(key);
0897:                            }
0898:                        }
0899:
0900:                        // if we have a refresher, for each expired, try to refresh
0901:                        if (m_refresher != null) {
0902:                            for (Iterator iKeys = expired.iterator(); iKeys
0903:                                    .hasNext();) {
0904:                                String key = (String) iKeys.next();
0905:                                CacheEntry entry = (CacheEntry) m_map.get(key);
0906:                                if (entry != null) {
0907:                                    Object newValue = m_refresher.refresh(key,
0908:                                            entry.getPayload(null), null);
0909:
0910:                                    remove(key);
0911:
0912:                                    // if the response is not null, replace and rejuvinate
0913:                                    if (newValue != null) {
0914:                                        put(key, newValue, entry.getDuration());
0915:                                    }
0916:                                }
0917:                            }
0918:                        }
0919:
0920:                        // if no refresher, for each expired, remove
0921:                        else {
0922:                            for (Iterator iKeys = expired.iterator(); iKeys
0923:                                    .hasNext();) {
0924:                                String key = (String) iKeys.next();
0925:                                remove(key);
0926:                            }
0927:                        }
0928:                    } catch (Throwable e) {
0929:                        M_log.warn(this  + ": exception: ", e);
0930:                    }
0931:
0932:                    if (M_log.isDebugEnabled()) {
0933:                        M_log.debug(this  + ".done. Time: "
0934:                                + (System.currentTimeMillis() - startTime));
0935:                    }
0936:
0937:                    // take a small nap
0938:                    try {
0939:                        Thread.sleep(m_refresherSleep * 1000);
0940:                    } catch (Exception ignore) {
0941:                    }
0942:
0943:                } // while
0944:
0945:            } // run
0946:
0947:            /**********************************************************************************************************************************************************************************************************************************************************
0948:             * Observer implementation
0949:             *********************************************************************************************************************************************************************************************************************************************************/
0950:
0951:            /**
0952:             * This method is called whenever the observed object is changed. An application calls an <tt>Observable</tt> object's <code>notifyObservers</code> method to have all the object's observers notified of the change. default implementation is to
0953:             * cause the courier service to deliver to the interface controlled by my controller. Extensions can override.
0954:             * 
0955:             * @param o
0956:             *        the observable object.
0957:             * @param arg
0958:             *        an argument passed to the <code>notifyObservers</code> method.
0959:             */
0960:            public void update(Observable o, Object arg) {
0961:                if (disabled())
0962:                    return;
0963:
0964:                // arg is Event
0965:                if (!(arg instanceof  Event))
0966:                    return;
0967:                Event event = (Event) arg;
0968:
0969:                // if this is just a read, not a modify event, we can ignore it
0970:                if (!event.getModify())
0971:                    return;
0972:
0973:                String key = event.getResource();
0974:
0975:                // if this resource is not in my pattern of resources, we can ignore it
0976:                if (!key.startsWith(m_resourcePattern))
0977:                    return;
0978:
0979:                // if we are holding event processing
0980:                if (m_holdEventProcessing) {
0981:                    m_heldEvents.add(event);
0982:                    return;
0983:                }
0984:
0985:                continueUpdate(event);
0986:
0987:            } // update
0988:
0989:            /**
0990:             * Complete the update, given an event that we know we need to act upon.
0991:             * 
0992:             * @param event
0993:             *        The event to process.
0994:             */
0995:            protected void continueUpdate(Event event) {
0996:                String key = event.getResource();
0997:
0998:                if (M_log.isDebugEnabled())
0999:                    M_log.debug(this  + ".update() [" + m_resourcePattern
1000:                            + "] resource: " + key + " event: "
1001:                            + event.getEvent());
1002:
1003:                // do we have this in our cache?
1004:                Object oldValue = get(key);
1005:                if (m_map.containsKey(key)) {
1006:                    // invalidate our copy
1007:                    remove(key);
1008:                }
1009:
1010:                // if we are being complete, we need to get this cached.
1011:                if (m_complete) {
1012:                    // we can only get it cached if we have a refresher
1013:                    if (m_refresher != null) {
1014:                        // ask the refresher for the value
1015:                        Object value = m_refresher
1016:                                .refresh(key, oldValue, event);
1017:                        if (value != null) {
1018:                            put(key, value);
1019:                        }
1020:                    } else {
1021:                        // we can no longer claim to be complete
1022:                        m_complete = false;
1023:                    }
1024:                }
1025:
1026:                // if we are partially complete
1027:                else if (!m_partiallyComplete.isEmpty()) {
1028:                    // what is the reference path that this key lives within?
1029:                    String path = referencePath(key);
1030:
1031:                    // if we are partially complete for this path
1032:                    if (m_partiallyComplete.contains(path)) {
1033:                        // we can only get it cached if we have a refresher
1034:                        if (m_refresher != null) {
1035:                            // ask the refresher for the value
1036:                            Object value = m_refresher.refresh(key, oldValue,
1037:                                    event);
1038:                            if (value != null) {
1039:                                put(key, value);
1040:                            }
1041:                        } else {
1042:                            // we can no longer claim to be complete for this path
1043:                            m_partiallyComplete.remove(path);
1044:                        }
1045:                    }
1046:                }
1047:
1048:            } // continueUpdate
1049:
1050:            /**
1051:             * Compute the reference path (i.e. the container) for a given reference.
1052:             * 
1053:             * @param ref
1054:             *        The reference string.
1055:             * @return The reference root for the given reference.
1056:             */
1057:            protected String referencePath(String ref) {
1058:                String path = null;
1059:
1060:                // Note: there may be a trailing separator
1061:                int pos = ref.lastIndexOf("/", ref.length() - 2);
1062:
1063:                // if no separators are found, place it even before the root!
1064:                if (pos == -1) {
1065:                    path = "";
1066:                }
1067:
1068:                // use the string up to and including that last separator
1069:                else {
1070:                    path = ref.substring(0, pos + 1);
1071:                }
1072:
1073:                return path;
1074:
1075:            } // referencePath
1076:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.