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