Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/opencms/flex/cache/CmsFlexCache.java


1   /*
2    * File   : $Source: /usr/local/cvs/opencms/src/com/opencms/flex/cache/Attic/CmsFlexCache.java,v $
3    * Date   : $Date: 2003/03/31 16:49:19 $
4    * Version: $Revision: 1.17 $
5    *
6    * This library is part of OpenCms -
7    * the Open Source Content Mananagement System
8    *
9    * Copyright (C) 2002 - 2003 Alkacon Software (http://www.alkacon.com)
10   *
11   * This library is free software; you can redistribute it and/or
12   * modify it under the terms of the GNU Lesser General Public
13   * License as published by the Free Software Foundation; either
14   * version 2.1 of the License, or (at your option) any later version.
15   *
16   * This library is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19   * Lesser General Public License for more details.
20   *
21   * For further information about Alkacon Software, please see the
22   * company website: http://www.alkacon.com
23   *
24   * For further information about OpenCms, please see the
25   * project website: http://www.opencms.org
26   * 
27   * You should have received a copy of the GNU Lesser General Public
28   * License along with this library; if not, write to the Free Software
29   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30   */
31  
32  package com.opencms.flex.cache;
33  
34  import com.opencms.boot.I_CmsLogChannels;
35  import com.opencms.core.A_OpenCms;
36  import com.opencms.file.CmsObject;
37  import com.opencms.flex.util.CmsFlexLruCache;
38  import com.opencms.flex.util.CmsLruHashMap;
39  import com.opencms.flex.util.I_CmsFlexLruCacheObject;
40  
41  import java.io.File;
42  import java.util.HashMap;
43  import java.util.Map;
44  
45  /**
46   * This class implements the FlexCache.<p>
47   *
48   * The data structure used is a two-level hashtable.
49   * This is optimized for the structure of the keys that are used to describe the
50   * caching behaviour of the entries.
51   * The first hash-level is calculated from the resource name, i.e. the
52   * name of the resource as it is referred to in the VFS of OpenCms.
53   * A suffix [online] or [offline] is appended to te resource name
54   * to distinguish between the online and offline projects of OpenCms.
55   * The second hash-level is calculated from the cache-key of the resource,
56   * which also is a String representing the specifc variation of the cached entry.<p>
57   *
58   * Entries in the first level of the cache are of type CmsFlexCacheVariation,
59   * which is a sub-class of CmsFlexCache.
60   * This class is a simple data type that contains of a Map of CmsFlexCacheEntries,
61   * with variations - Strings as keys.<p>
62   *
63   * Here's a short summary of used terms:
64   * <ul>
65   * <li><b>key:</b>
66   * A combination of a resource name and a variation.
67   * The data structure used is CmsFlexCacheKey.
68   * <li><b>resource:</b>
69   * A String with the resource name and an appended [online] of [offline] suffix.
70   * <li><b>variation:</b>
71   * A String describing a variation of a cached entry in the CmsFlexCache language.
72   * <li><b>entry:</b>
73   * A CmsFlexCacheEntry data structure which is describes a cached OpenCms resource.
74   * For every entry a key is saved which contains the resource name and the variation.
75   * </ul>
76   *
77   * Currenty the whole cache is flushed if something is published.
78   * Implement partial cache flushing, i.e. remove only changed elements at publish
79   * or change event (in case of offline resources).<p>
80   *
81   * @author Alexander Kandzior (a.kandzior@alkacon.com)
82   * @author Thomas Weckert (t.weckert@alkacon.com)
83   * 
84   * @version $Revision: 1.17 $
85   * 
86   * @see com.opencms.flex.cache.CmsFlexCacheKey
87   * @see com.opencms.flex.cache.CmsFlexCacheEntry
88   * @see com.opencms.flex.util.CmsFlexLruCache
89   * @see com.opencms.flex.util.I_CmsFlexLruCacheObject
90   */
91  public class CmsFlexCache extends java.lang.Object implements com.opencms.flex.I_CmsEventListener {
92      
93      /** Initial Cache size, this should be a power of 2 because of the Java collections implementation */
94      public static final int C_INITIAL_CAPACITY_CACHE = 512;
95      // Some prime numbers: 127 257 509 1021 2039 4099 8191
96      
97      /** Initial size for variation lists, should be a power of 2 */
98      public static final int C_INITIAL_CAPACITY_VARIATIONS = 8;
99      // Some prime numbers: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71
100     
101     /** Suffix to append to online cache entries */
102     public static String C_CACHE_ONLINESUFFIX = " [online]";
103     
104     /** Suffix to append to online cache entries */
105     public static String C_CACHE_OFFLINESUFFIX = " [offline]";
106     
107     /** Hashmap to store the Entries for fast lookup */
108     private java.util.Map m_resourceMap;
109     
110     /** Counter for the size */
111     private int m_size;
112     
113     /** Indicates if the cache is enabled or not */
114     private boolean m_enabled;
115     
116     /** Indicates if offline resources should be cached or not */
117     private boolean m_cacheOffline;
118     
119     /** Debug switch */
120     private static final int DEBUG = 0;
121     
122     /** Static ints to trigger clearcache events */
123     public static final int C_CLEAR_ALL = 0;
124     public static final int C_CLEAR_ENTRIES = 1;
125     public static final int C_CLEAR_ONLINE_ALL = 2;
126     public static final int C_CLEAR_ONLINE_ENTRIES = 3;
127     public static final int C_CLEAR_OFFLINE_ALL = 4;
128     public static final int C_CLEAR_OFFLINE_ENTRIES = 5;
129     
130     /** The LRU cache to organize the cached entries. */
131     private CmsFlexLruCache m_EntryLruCache;
132     
133     /** The LRU cache to organize the cached resources. */
134     private CmsFlexLruCache m_VariationCache;
135     
136     
137     /**
138      * Constructor for class CmsFlexCache.<p>
139      *
140      * The parameter "enabled" is used to control if the cache is
141      * actually on or off. Even if you don't need the cache, you still
142      * have to create an instance of it with enabled=false.
143      * This is because you need some of the FlexCache data structures
144      * for JSP inclusion buffering.<p>
145      *
146      * @param openCms the OpenCms instance
147      */
148     public CmsFlexCache( com.opencms.core.OpenCms openCms ) {
149         source.org.apache.java.util.Configurations opencmsProperties = openCms.getConfiguration();
150         m_enabled = opencmsProperties.getBoolean( "flex.cache.enabled", true );
151         m_cacheOffline = opencmsProperties.getBoolean( "flex.cache.offline", true );
152         
153         boolean forceGC = opencmsProperties.getBoolean( "flex.cache.forceGC", false );
154         int maxCacheBytes = opencmsProperties.getInteger( "flex.cache.maxCacheBytes", 2000000 );
155         int avgCacheBytes = opencmsProperties.getInteger( "flex.cache.avgCacheBytes", 1500000 );
156         int maxEntryBytes = opencmsProperties.getInteger( "flex.cache.maxEntryBytes", 400000 );  
157         int maxVariations = opencmsProperties.getInteger( "flex.cache.maxEntries", 4000 );
158         int maxKeys = opencmsProperties.getInteger( "flex.cache.maxKeys", 4000 );
159      
160         this.m_EntryLruCache = new CmsFlexLruCache( maxCacheBytes, avgCacheBytes, maxEntryBytes, forceGC );             
161         this.m_VariationCache = new CmsFlexLruCache( maxVariations, (int)(maxVariations*0.75), -1, false );
162         
163         if (m_enabled) {
164             this.m_resourceMap = java.util.Collections.synchronizedMap( new CmsLruHashMap(CmsFlexCache.C_INITIAL_CAPACITY_CACHE,maxKeys) );     
165             //this.m_resourceMap = java.util.Collections.synchronizedMap( new HashMap(CmsFlexCache.C_INITIAL_CAPACITY_CACHE) );
166             A_OpenCms.addCmsEventListener(this);
167         }
168         
169         // make the flex cache available to other classes through the runtime properties
170         openCms.setRuntimeProperty( com.opencms.flex.I_CmsResourceLoader.C_LOADER_CACHENAME, this );
171         
172         if (DEBUG > 0) System.err.println("FlexCache: Initializing with parameters enabled=" + m_enabled + " cacheOffline=" + m_cacheOffline);
173     }
174     
175     /**
176      * Clears the cache for finalization.<p>
177      */
178     protected void finalize() throws java.lang.Throwable {
179         this.clear();
180         
181         this.m_EntryLruCache = null;
182         this.m_VariationCache = null;
183         this.m_resourceMap = null;
184         this.m_resourceMap = null;
185         
186         super.finalize();
187     }    
188     
189     /**
190      * Indicates if the cache is enabled (i.e. actually
191      * caching entries) or not.<p>
192      *
193      * @return true if the cache is enabled, false if not
194      */
195     public boolean isEnabled() {
196         return m_enabled;
197     }
198     
199     /**
200      * Indicates if offline project resources are cached.<p>
201      *
202      * @return true if offline projects are cached, false if not
203      */
204     public boolean cacheOffline() {
205         return m_cacheOffline;
206     }
207     
208     /**
209      * Clears all entries and all keys in the cache, online or offline.<p>
210      *
211      * Only users with administrator permissions are allowed
212      * to perform this operation.<p>
213      *
214      * @param cms the CmsObject used for user authorization
215      */
216     private void clear(CmsObject cms) {
217         if (! isEnabled()) return;
218         if (! isAdmin(cms)) return;
219         if (DEBUG > 0) System.err.println("FlexCache: Clearing complete cache");
220         clear();
221     }
222     
223     /**
224      * Clears all entries in the cache, online or offline.
225      * The keys are not cleared.<p>
226      *
227      * Only users with administrator permissions are allowed
228      * to perform this operation.<p>
229      *
230      * @param cms the CmsObject used for user authorization
231      */
232     private synchronized void clearEntries(CmsObject cms) {
233         if (! isEnabled()) return;
234         if (! isAdmin(cms)) return;
235         if (DEBUG > 0) System.err.println("FlexCache: Clearing all entries");
236         java.util.Iterator i = m_resourceMap.keySet().iterator();
237         while (i.hasNext()) {
238             CmsFlexCacheVariation v = (CmsFlexCacheVariation)m_resourceMap.get(i.next());
239             java.util.Iterator allEntries = v.map.values().iterator();
240             while (allEntries.hasNext()) {
241                 I_CmsFlexLruCacheObject nextObject = (I_CmsFlexLruCacheObject)allEntries.next();
242                 allEntries.remove();
243                 this.m_EntryLruCache.remove( nextObject );
244             }
245             v.map = java.util.Collections.synchronizedMap(new HashMap(C_INITIAL_CAPACITY_VARIATIONS));
246         }
247         m_size = 0;
248     }
249     
250     /**
251      * Clears all entries and all keys from offline projects in the cache.
252      * Cached resources from the online project are not touched.<p>
253      *
254      * Only users with administrator permissions are allowed
255      * to perform this operation.<p>
256      *
257      * @param cms the CmsObject used for user authorization
258      */
259     private void clearOffline(CmsObject cms) {
260         if (! isEnabled()) return;
261         if (! isAdmin(cms)) return;
262         if (DEBUG > 0) System.err.println("FlexCache: Clearing offline keys & entries");
263         clearOneHalf(C_CACHE_OFFLINESUFFIX, false);
264     }
265     
266     /**
267      * Clears all entries from offline projects in the cache.
268      * The keys from the offline projects are not cleared.
269      * Cached resources from the online project are not touched.<p>
270      *
271      * Only users with administrator permissions are allowed
272      * to perform this operation.<p>
273      *
274      * @param cms the CmsObject used for user authorization
275      */
276     private void clearOfflineEntries(CmsObject cms) {
277         if (! isEnabled()) return;
278         if (! isAdmin(cms)) return;
279         if (DEBUG > 0) System.err.println("FlexCache: Clearing offline entries");
280         clearOneHalf(C_CACHE_OFFLINESUFFIX, true);
281     }
282     
283     /**
284      * Clears all entries and all keys from the online project in the cache.
285      * Cached resources from the offline projects are not touched.<p>
286      *
287      * Only users with administrator permissions are allowed
288      * to perform this operation.<p>
289      *
290      * @param cms the CmsObject used for user authorization
291      */
292     private void clearOnline(CmsObject cms) {
293         if (! isEnabled()) return;
294         if (! isAdmin(cms)) return;
295         if (DEBUG > 0) System.err.println("FlexCache: Clearing online keys & entries");
296         clearOneHalf(C_CACHE_ONLINESUFFIX, false);
297     }
298     
299     /**
300      * Clears all entries from the online project in the cache.
301      * The keys from the online project are not cleared.
302      * Cached resources from the offline projects are not touched.<p>
303      *
304      * Only users with administrator permissions are allowed
305      * to perform this operation.<p>
306      *
307      * @param cms the CmsObject used for user authorization
308      */
309     private void clearOnlineEntries(CmsObject cms) {
310         if (! isEnabled()) return;
311         if (! isAdmin(cms)) return;
312         if (DEBUG > 0) System.err.println("FlexCache: Clearing online entries");
313         clearOneHalf(C_CACHE_ONLINESUFFIX, true);
314     }
315     
316     /**
317      * This method purges the JSP repository dirs,
318      * i.e. it deletes all JSP files that OpenCms has written to the
319      * real FS.<p>
320      * 
321      * Obviously this method must be used with caution.
322      * Purpose of this method is to allow
323      * a complete purge of all JSP pages on a machine after
324      * a major update of JSP templates was made.<p>
325      *
326      * @param cms the CmsObject used for user authorization
327      */
328     private synchronized void purgeJspRepository(CmsObject cms) {
329         if (!isAdmin(cms) && !cms.getRequestContext().isEventControlled()) return;
330         if (DEBUG > 0) System.err.println("FlexCache.purgeJspRepository() purging JSP repositories!");
331 
332         File d;
333         d = new java.io.File(com.opencms.flex.CmsJspLoader.getJspRepository() + "online" + java.io.File.separator);
334         purgeDirectory(d);
335 
336         d = new java.io.File(com.opencms.flex.CmsJspLoader.getJspRepository() + "offline" + java.io.File.separator);
337         purgeDirectory(d);
338          
339         clear();
340         if (I_CmsLogChannels.C_LOGGING && A_OpenCms.isLogging(I_CmsLogChannels.C_OPENCMS_INFO)) 
341             A_OpenCms.log(I_CmsLogChannels.C_OPENCMS_INFO, "JSP repository purged - purgeJspRepository() called");
342     }
343     
344     /**
345      * Deletes a directory in the file system and all subfolders of the directory.<p>
346      * 
347      * @param d the directory to delete
348      */
349     private void purgeDirectory(File d) {
350         if (d.canRead() && d.isDirectory()) {
351             java.io.File files[] = d.listFiles();
352             if (DEBUG > 0) {
353                 System.err.println("FlexCache.purgeDirectory() Deleting directory = " + d.getAbsolutePath());
354                 System.err.println("FlexCache.purgeDirectory() Files in directory = " + files.length);
355             }                 
356             for (int i = 0; i<files.length; i++) {
357                 File f = files[i];
358                 if (f.isDirectory()) {
359                     purgeDirectory(f);
360                 }
361                 if (f.canWrite()) {
362                     f.delete();
363                 } else if (DEBUG > 0) {
364                     System.err.println("FlexCache.purgeDirectory() could not delete file = " + f);
365                 }
366             }
367         } else if (DEBUG > 0) {
368             System.err.println("FlexCache.purgeDirectory() could not access directory: " + d);
369             System.err.println("FlexCache.purgeDirectory() d.canWrite() = " + d.canWrite());
370             System.err.println("FlexCache.purgeDirectory() d.canWrite() = " + d.canWrite());
371             System.err.println("FlexCache.purgeDirectory() d.isDirectory() = " + d.isDirectory());
372             
373         }        
374     }
375     
376     /**
377      * Returns a set of all cached resource names.
378      * Usefull if you want to show a list of all cached resources,
379      * like on the FlexCache administration page.<p>
380      *
381      * Only users with administrator permissions are allowed
382      * to perform this operation.<p>
383      *
384      * @param cms the CmsObject used for user authorization
385      * @return a Set of cached resource names (which are of type String)
386      */
387     public java.util.Set getCachedResources(CmsObject cms) {
388         if (! isEnabled()) return null;
389         if (! isAdmin(cms)) return null;
390         return m_resourceMap.keySet();
391     }
392     
393     /**
394      * Returns all variations in the cache for a given resource name.
395      * The variations are of type String.<p>
396      * 
397      * Usefull if you want to show a list of all cached entry - variations,
398      * like on the FlexCache administration page.<p>
399      *
400      * Only users with administrator permissions are allowed
401      * to perform this operation.<p>
402      *
403      * @param key the resource name for which to look up the variations for
404      * @param cms the CmsObject used for user authorization
405      * @return a Set of cached variations (which are of type String)
406      */
407     public java.util.Set getCachedVariations(String key, CmsObject cms) {
408         if (! isEnabled()) return null;
409         if (! isAdmin(cms)) return null;
410         Object o = m_resourceMap.get(key);
411         if (o != null) {
412             CmsFlexCacheVariation v = (CmsFlexCacheVariation)o;
413             this.m_VariationCache.touch( (I_CmsFlexLruCacheObject)o );
414             return v.map.keySet();
415         }
416         return null;
417     }
418     
419     /**
420      * Returns the CmsFlexCacheKey data structure for a given
421      * key (i.e. resource name).<p>
422      * 
423      * Usefull if you want to show the cache key for a resources,
424      * like on the FlexCache administration page.<p>
425      *
426      * Only users with administrator permissions are allowed
427      * to perform this operation.<p>
428      *
429      * @param key the resource name for which to look up the variation for
430      * @param cms the CmsObject used for user authorization
431      * @return the CmsFlexCacheKey data structure found for the resource
432      */
433     public CmsFlexCacheKey getCachedKey(String key, CmsObject cms) {
434         if (! isEnabled()) return null;
435         if (! isAdmin(cms)) return null;
436         Object o = m_resourceMap.get(key);
437         if (o != null) {
438             CmsFlexCacheVariation v = (CmsFlexCacheVariation)o;
439             this.m_VariationCache.touch( (I_CmsFlexLruCacheObject)o );
440             return v.key;
441         }
442         return null;
443     }
444     
445     /**
446      * Returns the total number of entries in the cache.<p>
447      *
448      * @return the number of entries in the cache
449      */
450     public int size() {
451         return this.m_EntryLruCache.size();
452     }
453     
454     /**
455      * Returns the total number of cached resource keys.
456      *
457      * @return the number of resource keys in the cache
458      */
459     public int keySize() {
460         if (! isEnabled()) return 0;
461         return m_resourceMap.size();
462     }
463     
464     /**
465      * This method checks if a given key
466      * is already contained in the cache.<p>
467      *
468      * @return true if key is in the cache, false otherwise
469      * @param key the key to look for
470      */
471     boolean containsKey(CmsFlexCacheKey key) {
472         if (! isEnabled()) return false;
473         return (get(key) != null);
474     }
475     
476     /**
477      * Implements the CmsEvent interface,
478      * the FlexCache uses the events to clear itself in case a project is published.<p>
479      *
480      * @param event CmsEvent that has occurred
481      */
482     public void cmsEvent(com.opencms.flex.CmsEvent event) {
483         if (! isEnabled()) return;
484         
485         switch (event.getType()) {
486             case com.opencms.flex.I_CmsEventListener.EVENT_PUBLISH_PROJECT:
487             case com.opencms.flex.I_CmsEventListener.EVENT_CLEAR_CACHES:
488                 if (DEBUG > 0) System.err.println("FlexCache: Recieved event, clearing cache!");
489                 clear();
490                 break;
491             case com.opencms.flex.I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY:
492                 if (DEBUG > 0) System.err.println("FlexCache: Recieved event, purging JSP repository!");
493                 purgeJspRepository(event.getCmsObject());
494                 break;
495             case com.opencms.flex.I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR:
496                 if (DEBUG > 0) System.err.println("FlexCache: Recieved event, clearing part of cache!");
497                 java.util.Map m = event.getData();
498                 if (m == null) break;
499                 Integer it = null;
500                 try {
501                     it = (Integer)m.get("action");
502                 } catch (Exception e) {}
503                 if (it == null) break;
504                 int i = it.intValue();
505                 switch (i) {
506                     case C_CLEAR_ALL:
507                         clear(event.getCmsObject());
508                         break;
509                     case C_CLEAR_ENTRIES:
510                         clearEntries(event.getCmsObject());
511                         break;
512                     case C_CLEAR_ONLINE_ALL:
513                         clearOnline(event.getCmsObject());
514                         break;
515                     case C_CLEAR_ONLINE_ENTRIES:
516                         clearOnlineEntries(event.getCmsObject());
517                         break;
518                     case C_CLEAR_OFFLINE_ALL:
519                         clearOffline(event.getCmsObject());
520                         break;
521                     case C_CLEAR_OFFLINE_ENTRIES:
522                         clearOfflineEntries(event.getCmsObject());
523                         break;
524                 }
525         }
526     }
527     
528     /**
529      * Looks up a specific entry in the cache.<p>
530      * 
531      * In case a found entry has a timeout set, it will be checked upon lookup.
532      * In case the timeout of the entry has been reached, it will be removed from
533      * the cache (and null will be returend in this case).<p>
534      *
535      * @param key The key to look for in the cache
536      * @return the entry found for the key, or null if key is not in the cache
537      */
538     CmsFlexCacheEntry get(CmsFlexCacheKey key) {
539         if (! isEnabled()) return null;
540         if (DEBUG > 0) System.err.println("FlexCache: Trying to get entry for resource " + key.Resource);
541         Object o = m_resourceMap.get(key.Resource);
542         if (o != null) {
543             CmsFlexCacheVariation v = (CmsFlexCacheVariation)o;
544             String variation = v.key.matchRequestKey(key);
545             
546             this.m_VariationCache.touch( (I_CmsFlexLruCacheObject)o );
547             
548             if (DEBUG > 0) {
549                 if (variation != null) {
550                     CmsFlexCacheEntry e = (CmsFlexCacheEntry)v.map.get(variation);
551                     if (e != null) {
552                         System.err.println("FlexCache: Found entry for variation " + variation);
553                     } else {
554                         System.err.println("FlexCache: Did not find entry for variation " + variation);
555                     }
556                 } else {
557                     System.err.println("FlexCache: Found nothing because resource is not cachable for this request!");
558                 }
559             }
560             if (variation == null) return null;
561             if (v.key.m_timeout < 0) {
562                 // No timeout for this resource is specified
563                 return (CmsFlexCacheEntry)v.map.get(variation);
564             } else {
565                 // Check for possible timeout of entry
566                 CmsFlexCacheEntry e = (CmsFlexCacheEntry)v.map.get(variation);
567                 if (e == null) return null;
568                 if (DEBUG > 1) System.err.println("FlexCache: Checking timeout for resource " + key.Resource);
569                 if (e.getTimeout() < key.m_timeout) {
570                     if (DEBUG > 1) System.err.println("FlexCache: Resource has reached timeout, removing from cache!");
571                     this.m_EntryLruCache.remove( (I_CmsFlexLruCacheObject)e );
572                     return null;
573                 }
574                 if (DEBUG > 1) System.err.println("FlexCache: Resource timeout not reached!");
575                 return e;
576             }
577         } else if (DEBUG > 0) {
578             System.err.println("FlexCache: Did not find any entry for resource" );
579             return null;
580         } else return null;
581     }
582     
583     /**
584      * Returns the CmsFlexCacheKey data structure for a given resource name.<p>
585      *
586      * @param resource the resource name for which to look up the key for
587      * @return the CmsFlexCacheKey data structure found for the resource
588      */
589     CmsFlexCacheKey getKey(String resource) {
590         if (! isEnabled()) return null;
591         Object o = m_resourceMap.get(resource);
592         if (o != null) {
593             if (DEBUG > 1) System.err.println("FlexCache: Found pre-calculated key for resource " + resource);
594             this.m_VariationCache.touch( (I_CmsFlexLruCacheObject)o );
595             return ((CmsFlexCacheVariation)o).key;
596         } else {
597             if (DEBUG > 1) System.err.println("FlexCache: Did not find pre-calculated key for resource " + resource);
598             return null;
599         }
600     }
601     
602     /**
603      * Adds a key with a new, empty variation map to the cache.<p>
604      *
605      * @param key the key to add to the cache.
606      */
607     void putKey(CmsFlexCacheKey key) {
608         if (! isEnabled()) return;
609         Object o = m_resourceMap.get(key.Resource);
610         if (o == null) {
611             // No variation map for this resource yet, so create one
612             CmsFlexCacheVariation variationMap = new CmsFlexCacheVariation( key );
613             m_resourceMap.put( key.Resource, variationMap );
614             this.m_VariationCache.add( (I_CmsFlexLruCacheObject)variationMap );
615             if (DEBUG > 1) System.err.println("FlexCache: Added pre-calculated key for resource " + key.Resource);
616         }
617         // If != null the key is already in the cache, so we just do nothing
618     }
619     
620     /**
621      * This method adds new entries to the cache.<p>
622      *
623      * The key describes the conditions under which the value can be cached.
624      * Usually the key belongs to the response.
625      * The variation describes the conditions under which the
626      * entry was created. This is usually calculated from the request.
627      * If the variation is != null, the entry is cachable.<p>
628      *
629      * @param key the key for the new value entry. Usually calculated from the response
630      * @param entry the CmsFlexCacheEntry to store in the cache
631      * @param variation the pre-calculated variation for the entry
632      * @return true if the value was added to the cache, false otherwise
633      */
634     boolean put(CmsFlexCacheKey key, CmsFlexCacheEntry entry, String variation) {
635         if (! isEnabled()) return false;
636         if (DEBUG > 1) System.err.println("FlexCache: Trying to add entry for resource " + key.Resource);
637         if (variation != null) {
638             // This is a cachable result
639             key.Variation = variation;
640             if (DEBUG > 1) System.err.println("FlexCache: Adding entry for resource " + key.Resource + " with variation:" + key.Variation);
641             put(key, entry);
642             // Note that duplicates are NOT checked, it it assumed that this is done beforehand,
643             // while checking if the entry is already in the cache or not.
644             return true;
645         } else {
646             // Result is not cachable
647             if (DEBUG > 1) System.err.println("FlexCache: Nothing added because resource is not cachable for this request!");
648             return false;
649         }
650     }
651     
652     /**
653      * Removes an entry from the cache.<p>
654      *
655      * @param key the key which describes the entry to remove from the cache
656      */
657     void remove(CmsFlexCacheKey key) {
658         if (! isEnabled()) return;
659         Object o = m_resourceMap.get(key.Resource);
660         if (o != null) {
661             //Object old = ((HashMap)o).remove(key.Variation);
662             Object old = ((HashMap)o).get(key.Variation);
663             if (old != null) {
664                 this.getEntryLruCache().remove( (I_CmsFlexLruCacheObject)old );
665             }
666         };
667     }
668     
669     /**
670      * Checks if the cache is empty or if at last one element is contained.<p>
671      *
672      * @return true if the cache is empty, false otherwise
673      */
674     boolean isEmpty() {
675         if (! isEnabled()) return true;
676         return m_resourceMap.isEmpty();
677     }
678     
679     /**
680      * Emptys the cache completely.<p>
681      */
682     private synchronized void clear() {
683         if (! isEnabled()) return;
684         
685         m_resourceMap.clear();
686         m_resourceMap = java.util.Collections.synchronizedMap(new CmsLruHashMap(C_INITIAL_CAPACITY_CACHE));
687         
688         m_size = 0;
689         
690         this.m_EntryLruCache.clear();
691         this.m_VariationCache.clear();
692         
693         if (I_CmsLogChannels.C_LOGGING && A_OpenCms.isLogging(I_CmsLogChannels.C_FLEX_CACHE)) 
694             A_OpenCms.log(I_CmsLogChannels.C_FLEX_CACHE, "[FlexCache] Complete cache cleared - clear() called" );
695     }
696     
697     /**
698      * Save a value to the cache.<p>
699      *
700      * @param key the key under shich the value is saved
701      * @param value the value to save in the cache
702      */
703     private void put( CmsFlexCacheKey key, CmsFlexCacheEntry theCacheEntry ) {
704         Object o = m_resourceMap.get(key.Resource);
705         if (key.m_timeout > 0) theCacheEntry.setTimeout(key.m_timeout * 60000);
706         if (o != null) {
707             // We already have a variation map for this resource
708             java.util.Map m = ((CmsFlexCacheVariation)o).map;
709             boolean wasAdded = true;
710             if (! m.containsKey(key.Variation)) {
711                 wasAdded = this.m_EntryLruCache.add( (I_CmsFlexLruCacheObject)theCacheEntry );
712             }
713             else {
714                 wasAdded = this.m_EntryLruCache.touch( (I_CmsFlexLruCacheObject)theCacheEntry );
715             }
716             
717             if (wasAdded) {
718                 theCacheEntry.setVariationData( key.Variation, m );
719                 m.put(key.Variation, theCacheEntry);
720                 this.m_VariationCache.touch( (I_CmsFlexLruCacheObject)o );
721             }
722         } else {
723             // No variation map for this resource yet, so create one
724             CmsFlexCacheVariation list = new CmsFlexCacheVariation(key);
725 
726             boolean wasAdded = this.m_EntryLruCache.add( (I_CmsFlexLruCacheObject)theCacheEntry );
727             
728             if (wasAdded) {
729                 theCacheEntry.setVariationData( key.Variation, list.map );
730                 list.map.put(key.Variation, theCacheEntry);
731                 m_resourceMap.put(key.Resource, list);
732                 this.m_VariationCache.add( (I_CmsFlexLruCacheObject)list );
733             }
734         }
735         
736         if (DEBUG > 0) System.err.println("FlexCache: Entry "  + m_size + " added for resource " + key.Resource + " with variation " + key.Variation);
737         if (DEBUG > 2) System.err.println("FlexCache: Entry added was:\n" + theCacheEntry.toString() );
738     }
739     
740     /**
741      * Internal method to determine if a user has Administration permissions.<p>
742      */
743     private boolean isAdmin(CmsObject cms) {
744         boolean result;
745         try {
746             result = cms.getRequestContext().isAdmin();
747         } catch (Exception e) {
748             result = false;
749         }
750         return result;
751     }
752     
753 
754     /**
755      * Internal method to perform cache clearance.<p>
756      * 
757      * It clears "one half" of the cache, i.e. either
758      * the online or the offline parts.
759      * A parameter is used to indicate if only
760      * the entries or keys and entries are to be cleared.<p>
761      * 
762      * @param suffix used to distinguish between "[Online]" and "[Offline]" entries
763      * @param entriesOnly if <code>true</code>, only entries will be cleared, otherwise
764      *         the entries and the keys will be cleared
765      */    
766     private synchronized void clearOneHalf(String suffix, boolean entriesOnly) {
767         java.util.Set keys = new java.util.HashSet(m_resourceMap.keySet());
768         java.util.Iterator i = keys.iterator();
769         while (i.hasNext()) {
770             String s = (String)i.next();
771             if (s.endsWith(suffix)) {
772                 CmsFlexCacheVariation v = (CmsFlexCacheVariation)m_resourceMap.get(s);
773                 if (entriesOnly) {
774                     // Clear only entry
775                     m_size -= v.map.size();
776                     java.util.Iterator allEntries = v.map.values().iterator();
777                     while (allEntries.hasNext()) {
778                         I_CmsFlexLruCacheObject nextObject = (I_CmsFlexLruCacheObject)allEntries.next();
779                         allEntries.remove();
780                         this.m_EntryLruCache.remove( nextObject );
781                     }
782                     v.map = java.util.Collections.synchronizedMap(new HashMap(C_INITIAL_CAPACITY_VARIATIONS));
783                 } else {
784                     // Clear key and entry
785                     m_size -= v.map.size();
786                     java.util.Iterator allEntries = v.map.values().iterator();
787                     while (allEntries.hasNext()) {
788                         I_CmsFlexLruCacheObject nextObject = (I_CmsFlexLruCacheObject)allEntries.next();
789                         allEntries.remove();
790                         this.m_EntryLruCache.remove( nextObject );
791                     }
792                     
793                     this.m_VariationCache.remove( (I_CmsFlexLruCacheObject)v );
794                     
795                     v.map = null;
796                     v.key = null;
797                     m_resourceMap.remove(s);
798                 }
799             }
800         }
801         if (I_CmsLogChannels.C_LOGGING && A_OpenCms.isLogging(I_CmsLogChannels.C_FLEX_CACHE)) 
802             A_OpenCms.log(I_CmsLogChannels.C_FLEX_CACHE, "[FlexCache] Part of the FlexCache cleared - clearOneHalf(" + suffix + ", " + entriesOnly + ") called" );
803     }
804     
805     /**
806      * Returns the LRU cache where the CacheEntries are cached.<p>
807      *
808      * @return the LRU cache where the CacheEntries are cached
809      */
810     public CmsFlexLruCache getEntryLruCache() {
811         return this.m_EntryLruCache;
812     }
813         
814     /**
815      * A simple data container class for the FlexCache variations.<p>
816      * 
817      * @see com.opencms.flex.cache.CmsFlexCache
818      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject
819      * @author Alexander Kandzior (a.kandzior@alkacon.com)
820      * @author Thomas Weckert (t.weckert@alkacon.com)
821      * @version $Revision: 1.17 $ 
822      */
823     class CmsFlexCacheVariation extends Object implements com.opencms.flex.util.I_CmsFlexLruCacheObject {
824         
825         /** Pointer to the next cache entry in the LRU cache */
826         private I_CmsFlexLruCacheObject m_Next;
827         
828         /** Pointer to the previous cache entry in the LRU cache. */
829         private I_CmsFlexLruCacheObject m_Previous;        
830         
831         /** The key belonging to the resource */
832         public CmsFlexCacheKey key;
833         
834         /** Maps variations to CmsFlexCacheEntries */
835         public Map map;
836         
837         /** Internal debug switch */
838         private static final int DEBUG = 0;
839                 
840         /**
841          * Generates a new instance of CmsFlexCacheVariation.<p>
842          *
843          * @param theKey The (resource) key to contruct this variation list for
844          */
845         public CmsFlexCacheVariation(CmsFlexCacheKey theKey ) {
846             this.key = theKey;
847             this.map = java.util.Collections.synchronizedMap( new HashMap(CmsFlexCache.C_INITIAL_CAPACITY_VARIATIONS) );
848         }
849         
850         // implementation of the com.opencms.flex.util.I_CmsFlexLruCacheObject interface methods
851         
852         /**
853          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#setNextLruObject(I_CmsFlexLruCacheObject)
854          */
855         public void setNextLruObject( I_CmsFlexLruCacheObject theNextEntry ) {
856             this.m_Next = theNextEntry;
857         }
858         
859         /**
860          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getNextLruObject()
861          */
862         public I_CmsFlexLruCacheObject getNextLruObject() {
863             return this.m_Next;
864         }
865         
866         /**
867          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#setPreviousLruObject(I_CmsFlexLruCacheObject)
868          */
869         public void setPreviousLruObject( I_CmsFlexLruCacheObject thePreviousEntry ) {
870             this.m_Previous = thePreviousEntry;
871         }
872         
873         /**
874          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getPreviousLruObject()
875          */
876         public I_CmsFlexLruCacheObject getPreviousLruObject() {
877             return this.m_Previous;
878         }  
879         
880         /**
881          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#addToLruCache()
882          */
883         public void addToLruCache() {
884             // NOOP
885             if (DEBUG>0) System.out.println( "Added resource " + this.key.Resource + " to the LRU cache" );
886         }
887         
888         /**
889          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#removeFromLruCache()
890          */
891         public void removeFromLruCache() {
892             // NOOP            
893             if (DEBUG>0) System.out.println( "Removed resource " + this.key.Resource + " from the LRU cache" );
894         }
895         
896         /**
897          * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getLruCacheCosts()
898          */
899         public int getLruCacheCosts() {
900             return this.map.size();
901         }     
902     }    
903 }
904