KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > applications > media > cache > URLCache


1 /*
2  
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5  
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8  
9  */

10 package org.mmbase.applications.media.cache;
11
12 import org.mmbase.cache.Cache;
13 import org.mmbase.util.logging.Logger;
14 import org.mmbase.util.logging.Logging;
15 import org.mmbase.module.core.*;
16
17 import java.util.*;
18
19 /**
20  * A cache for URLS requested in the MediaFragment builder.
21  * This cache can easily be extended in such a way it can cache more requests.
22  *
23  * @author Rob Vermeulen (VPRO)
24  * @author Michiel Meeuwissen (NOS)
25  */

26 public class URLCache extends Cache {
27     private static int cacheSize = 4 * 1024; // Max size of the node cache
28
private static URLCache cache;
29     private static Logger log = Logging.getLoggerInstance(URLCache.class);
30     
31     private CacheExpire cacheExpire = new CacheExpire();
32     private Observer observer = new Observer();
33     
34     public static URLCache getCache() {
35         return cache;
36     }
37     
38     static {
39         cache = new URLCache(cacheSize);
40         putCache(cache);
41     }
42
43     /**
44      * creates a key based of the media fragment number and the user information
45      * @param mediaFragment fragment to be cached
46      * @param info user information to be cached
47      * @return key to be cached
48      */

49     static public String JavaDoc toKey(MMObjectNode mediaFragment, Map info) {
50         
51         StringBuffer JavaDoc toKey = new StringBuffer JavaDoc("MediaFragmentNumber=").append(mediaFragment.getNumber());
52         Iterator infoItems = info.entrySet().iterator();
53         while (infoItems.hasNext()) {
54             Map.Entry entry = (Map.Entry)infoItems.next();
55             toKey.append(',').append(entry.getKey()).append('=').append(entry.getValue());
56         }
57         if (log.isDebugEnabled()) {
58             log.debug("Generated key=" + toKey);
59         }
60         return toKey.toString();
61     }
62     
63     /**
64      * put an entry in the cache
65      * @param key cache key
66      * @param result cache result
67      * @param objects the objects that can invalidate the cache
68      */

69     public synchronized void put(String JavaDoc key, String JavaDoc result, Set objects) {
70         cache.put(key, result);
71         log.debug("Adding to cache, key="+key);
72         if(objects!=null) {
73             cacheExpire.put(objects,key);
74         } else {
75             log.debug("No objects are specified to expire the cache entries");
76         }
77     }
78
79     public void clear() {
80         super.clear();
81         cacheExpire.clear();
82     }
83     
84     /**
85      * Invalidates cache entries based on the node that changes
86      * @param nodeNumber number of node that changes
87      */

88     public synchronized void nodeChange(String JavaDoc nodeNumber) {
89         log.debug("Node changed, number="+nodeNumber);
90         cacheExpire.remove(nodeNumber);
91     }
92     
93     public String JavaDoc getName() {
94         return "MediaURLS";
95     }
96     public String JavaDoc getDescription() {
97         return "This cache contains the evaluated urls of media fragments (with user information)";
98     }
99     
100     /**
101      * Creates the Cache
102      */

103     private URLCache(int size) {
104         super(size);
105     }
106     
107     /**
108      * Contains information about which objects are used to create a certain cache entry.
109      * If an object changes it is a good idea to assume that the cache entry is invalid.
110      */

111     class CacheExpire {
112         private Cache objectNumber2Keys = new Cache(10000) {
113             public String JavaDoc getName() { return "Media objectnumber-to-keys cache"; }
114             public String JavaDoc getDescription() { return "Contains information about which objects are used to create a certain cache entry."; }
115         };
116
117         public CacheExpire() {
118             Cache.putCache(objectNumber2Keys);
119         }
120
121         public void clear() {
122             objectNumber2Keys.clear();
123         }
124         
125         /**
126          * add objects that were needed for the creation of a cache entry
127          * @param obj A vector with object numbers (Strings).
128          * @param key The key of the cache entry to invalidate if an object changes.
129          */

130         private void put(Set obj, String JavaDoc key) {
131             for(Iterator objects = obj.iterator();objects.hasNext();) {
132                 put((MMObjectNode)objects.next(), key);
133             }
134         }
135         
136         /**
137          * add object that was needed for the creation of a cache entry
138          * @param obj A object number.
139          * @param key The key of the cache entry to invalidate if an object changes.
140          */

141         private void put(MMObjectNode node, String JavaDoc key) {
142             if(node==null) {
143                 return;
144             }
145             Vector keyList = null;
146             String JavaDoc objectNumber = ""+node.getNumber();
147             if(objectNumber2Keys.containsKey(objectNumber)) {
148                 keyList = (Vector)objectNumber2Keys.get(objectNumber);
149             } else {
150                 keyList = new Vector(20);
151                 objectNumber2Keys.put(objectNumber,keyList);
152             }
153             keyList.add(key);
154             observer.put(node);
155         }
156         
157         /**
158          * remove all entries form the cache that are invalidated by the change of the object.
159          */

160         private void remove(String JavaDoc nodeNumber) {
161             if(objectNumber2Keys.containsKey(nodeNumber)) {
162                 Vector keyList = (Vector)objectNumber2Keys.get(nodeNumber);
163                 for(Iterator items = keyList.iterator(); items.hasNext();) {
164                     String JavaDoc key = (String JavaDoc)items.next();
165                     cache.remove(key);
166                     log.debug("Flusing key from cache, key="+key);
167                 }
168             }
169         }
170     }
171     
172     /**
173      * this observer will listen to all builders that are used while creating cache entries.
174      * if an object changes (that is used during the creation of the cache entrie) that specific
175      * cache entrie will be flushed.
176      */

177     private class Observer implements MMBaseObserver {
178         private Set observingBuilders = new HashSet(); // the builders in which 'this' was registered already.
179

180         Observer() {
181         }
182         
183         /**
184          * start listning to node changes of this builder
185          */

186         private void addToObservingBuilder(MMObjectBuilder builder) {
187             log.debug("Adding observer for builder = "+builder.getTableName());
188             builder.addLocalObserver(this);
189             builder.addRemoteObserver(this);
190             observingBuilders.add(builder.getTableName());
191         }
192         
193         /**
194          * makes sure that the observer will listen to the builder of this node
195          */

196         synchronized void put(MMObjectNode node) {
197             MMObjectBuilder bul = node.getBuilder();
198             if (!observingBuilders.contains(bul.getTableName())) {
199                 addToObservingBuilder(bul);
200             }
201         }
202         
203         /**
204          * If something changes this function is called, and the observer multilevel cache entries are removed.
205          */

206         protected boolean nodeChanged(String JavaDoc machine, String JavaDoc number, String JavaDoc builder, String JavaDoc ctype) {
207             // d=delete, c=create
208
if (ctype.equals("d") || ctype.equals("c")) {
209                 log.debug("Recieved a change, object number = "+number);
210                 nodeChange(number);
211             }
212             return true;
213         }
214         
215         // javadoc inherited (from MMBaseObserver)
216
public boolean nodeRemoteChanged(String JavaDoc machine, String JavaDoc number,String JavaDoc builder,String JavaDoc ctype) {
217             return nodeChanged(machine, number, builder, ctype);
218         }
219         
220         // javadoc inherited (from MMBaseObserver)
221
public boolean nodeLocalChanged(String JavaDoc machine, String JavaDoc number, String JavaDoc builder, String JavaDoc ctype) {
222             return nodeChanged(machine, number, builder, ctype);
223         }
224     }
225 }
226
Popular Tags