KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > opencms > flex > CmsFlexCacheEntry


1 /*
2  * File : $Source: /usr/local/cvs/opencms/src/org/opencms/flex/CmsFlexCacheEntry.java,v $
3  * Date : $Date: 2006/03/27 14:52:35 $
4  * Version: $Revision: 1.30 $
5  *
6  * This library is part of OpenCms -
7  * the Open Source Content Mananagement System
8  *
9  * Copyright (c) 2005 Alkacon Software GmbH (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 GmbH, 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 org.opencms.flex;
33
34 import org.opencms.cache.I_CmsLruCacheObject;
35 import org.opencms.file.CmsResource;
36 import org.opencms.i18n.CmsMessageContainer;
37 import org.opencms.main.CmsLog;
38 import org.opencms.monitor.CmsMemoryMonitor;
39 import org.opencms.monitor.I_CmsMemoryMonitorable;
40
41 import java.io.IOException JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.Collections JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.List JavaDoc;
46 import java.util.Map JavaDoc;
47
48 import javax.servlet.ServletException JavaDoc;
49
50 import org.apache.commons.logging.Log;
51
52 /**
53  * Contains the contents of a cached resource.<p>
54  *
55  * It is basically a list of pre-generated output,
56  * include() calls to other resources (with request parameters) and http headers that this
57  * resource requires to be set.<p>
58  *
59  * A CmsFlexCacheEntry might also describe a redirect-call, but in this case
60  * nothing else will be cached.<p>
61  *
62  * The pre-generated output is saved in <code>byte[]</code> arrays.
63  * The include() calls are saved as Strings of the included resource name,
64  * the parameters for the calls are saved in a HashMap.
65  * The headers are saved in a HashMap.
66  * In case of a redirect, the redircet target is cached in a String.<p>
67  *
68  * The CmsFlexCacheEntry can also have an expire date value, which indicates the time
69  * that his entry will become invalid and should thus be cleared from the cache.<p>
70  *
71  * @author Alexander Kandzior
72  * @author Thomas Weckert
73  *
74  * @version $Revision: 1.30 $
75  *
76  * @since 6.0.0
77  *
78  * @see org.opencms.cache.I_CmsLruCacheObject
79  */

80 public class CmsFlexCacheEntry extends Object JavaDoc implements I_CmsLruCacheObject, I_CmsMemoryMonitorable {
81
82     /** Initial size for lists. */
83     public static final int INITIAL_CAPACITY_LISTS = 10;
84
85     /** The log object for this class. */
86     private static final Log LOG = CmsLog.getLog(CmsFlexCacheEntry.class);
87
88     /** The CacheEntry's size in bytes. */
89     private int m_byteSize;
90
91     /** Indicates if this cache entry is completed. */
92     private boolean m_completed;
93
94     /** The "expires" date for this Flex cache entry. */
95     private long m_dateExpires;
96
97     /** The "last modified" date for this Flex cache entry. */
98     private long m_dateLastModified;
99
100     /** The list of items for this resource. */
101     private List JavaDoc m_elements;
102
103     /** A Map of cached headers for this resource. */
104     private Map JavaDoc m_headers;
105
106     /** Pointer to the next cache entry in the LRU cache. */
107     private I_CmsLruCacheObject m_next;
108
109     /** Pointer to the previous cache entry in the LRU cache. */
110     private I_CmsLruCacheObject m_previous;
111
112     /** A redirection target (if redirection is set). */
113     private String JavaDoc m_redirectTarget;
114
115     /** The key under which this cache entry is stored in the variation map. */
116     private String JavaDoc m_variationKey;
117
118     /** The variation map where this cache entry is stored. */
119     private Map JavaDoc m_variationMap;
120
121     /**
122      * Constructor for class CmsFlexCacheEntry.<p>
123      *
124      * The way to use this class is to first use this empty constructor
125      * and later add data with the various add methods.
126      */

127     public CmsFlexCacheEntry() {
128
129         m_elements = new ArrayList JavaDoc(INITIAL_CAPACITY_LISTS);
130         m_dateExpires = CmsResource.DATE_EXPIRED_DEFAULT;
131         m_dateLastModified = -1;
132         // base memory footprint of this object with all referenced objects
133
m_byteSize = 1024;
134
135         setNextLruObject(null);
136         setPreviousLruObject(null);
137     }
138
139     /**
140      * Adds an array of bytes to this cache entry,
141      * this will usually be the result of some kind of output - stream.<p>
142      *
143      * @param bytes the output to save in the cache
144      */

145     public void add(byte[] bytes) {
146
147         if (m_completed) {
148             return;
149         }
150         if (m_redirectTarget == null) {
151             // Add only if not already redirected
152
m_elements.add(bytes);
153             m_byteSize += CmsMemoryMonitor.getMemorySize(bytes);
154         }
155         bytes = null;
156     }
157
158     /**
159      * Add an include - call target resource to this cache entry.<p>
160      *
161      * @param resource a name of a resource in the OpenCms VFS
162      * @param parameters a map of parameters specific to this include call
163      */

164     public void add(String JavaDoc resource, Map JavaDoc parameters) {
165
166         if (m_completed) {
167             return;
168         }
169         if (m_redirectTarget == null) {
170             // Add only if not already redirected
171
m_elements.add(resource);
172             if (parameters == null) {
173                 parameters = Collections.EMPTY_MAP;
174             }
175             m_elements.add(parameters);
176             m_byteSize += CmsMemoryMonitor.getMemorySize(resource);
177         }
178     }
179
180     /**
181      * Add a map of headers to this cache entry,
182      * which are usually collected in the class CmsFlexResponse first.<p>
183      *
184      * @param headers the map of headers to add to the entry
185      */

186     public void addHeaders(Map JavaDoc headers) {
187
188         if (m_completed) {
189             return;
190         }
191         m_headers = headers;
192
193         Iterator JavaDoc allHeaders = m_headers.keySet().iterator();
194         while (allHeaders.hasNext()) {
195             m_byteSize += CmsMemoryMonitor.getMemorySize(allHeaders.next());
196         }
197     }
198
199     /**
200      * @see org.opencms.cache.I_CmsLruCacheObject#addToLruCache()
201      */

202     public void addToLruCache() {
203
204         // do nothing here...
205
if (LOG.isDebugEnabled()) {
206             LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEENTRY_ADDED_ENTRY_1, this));
207         }
208     }
209
210     /**
211      * Completes this cache entry.<p>
212      *
213      * A completed cache entry is made "unmodifiable",
214      * so that no further data can be added and existing data can not be changed.
215      * This is to prevend the (unlikley) case that some user-written class
216      * tries to make changes to a cache entry.<p>
217      */

218     public void complete() {
219
220         m_completed = true;
221         // Prevent changing of the cached lists
222
if (m_headers != null) {
223             m_headers = Collections.unmodifiableMap(m_headers);
224         }
225         if (m_elements != null) {
226             m_elements = Collections.unmodifiableList(m_elements);
227         }
228         if (LOG.isDebugEnabled()) {
229             LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEENTRY_ENTRY_COMPLETED_1, toString()));
230         }
231     }
232
233     /**
234      * Returns the list of data entries of this cache entry.<p>
235      *
236      * Data entries are byte arrays representing some kind of ouput
237      * or Strings representing include calls to other resources.
238      *
239      * @return the list of data elements of this cache entry
240      */

241     public List JavaDoc elements() {
242
243         return m_elements;
244     }
245
246     /**
247      * Returns the expiration date of this cache entry,
248      * this is set to the time when the entry becomes invalid.<p>
249      *
250      * @return the expiration date value for this resource
251      */

252     public long getDateExpires() {
253
254         return m_dateExpires;
255     }
256
257     /**
258      * Returns the "last modified" date for this Flex cache entry.<p>
259      *
260      * @return the "last modified" date for this Flex cache entry
261      */

262     public long getDateLastModified() {
263
264         return m_dateLastModified;
265     }
266
267     /**
268      * @see org.opencms.cache.I_CmsLruCacheObject#getLruCacheCosts()
269      */

270     public int getLruCacheCosts() {
271
272         return m_byteSize;
273     }
274
275     /**
276      * @see org.opencms.monitor.I_CmsMemoryMonitorable#getMemorySize()
277      */

278     public int getMemorySize() {
279
280         return getLruCacheCosts();
281     }
282
283     /**
284      * @see org.opencms.cache.I_CmsLruCacheObject#getNextLruObject()
285      */

286     public I_CmsLruCacheObject getNextLruObject() {
287
288         return m_next;
289     }
290
291     /**
292      * @see org.opencms.cache.I_CmsLruCacheObject#getPreviousLruObject()
293      */

294     public I_CmsLruCacheObject getPreviousLruObject() {
295
296         return m_previous;
297     }
298
299     /**
300      * @see org.opencms.cache.I_CmsLruCacheObject#getValue()
301      */

302     public Object JavaDoc getValue() {
303
304         return m_elements;
305     }
306
307     /**
308      * @see org.opencms.cache.I_CmsLruCacheObject#removeFromLruCache()
309      */

310     public void removeFromLruCache() {
311
312         if ((m_variationMap != null) && (m_variationKey != null)) {
313             m_variationMap.remove(m_variationKey);
314         }
315         if (LOG.isDebugEnabled()) {
316             LOG.debug(Messages.get().getBundle().key(
317                 Messages.LOG_FLEXCACHEENTRY_REMOVED_ENTRY_FOR_VARIATION_1,
318                 m_variationKey));
319         }
320         clear();
321     }
322
323     /**
324      * Processing method for this cached entry.<p>
325      *
326      * If this method is called, it delivers the contents of
327      * the cached entry to the given request / response.
328      * This includes calls to all included resources.<p>
329      *
330      * @param req the request from the client
331      * @param res the server response
332      * @throws CmsFlexCacheException is thrown when problems writing to the response output-stream occur
333      * @throws ServletException might be thrown from call to RequestDispatcher.include()
334      * @throws IOException might be thrown from call to RequestDispatcher.include() or from Response.sendRedirect()
335      */

336     public void service(CmsFlexRequest req, CmsFlexResponse res)
337     throws CmsFlexCacheException, ServletException JavaDoc, IOException JavaDoc {
338
339         if (!m_completed) {
340             return;
341         }
342
343         if (m_redirectTarget != null) {
344             res.setOnlyBuffering(false);
345             // redirect the response, no further output required
346
res.sendRedirect(m_redirectTarget);
347         } else {
348             // process cached headers first
349
CmsFlexResponse.processHeaders(m_headers, res);
350             // check if this cache entry is a "leaf" (i.e. no further includes)
351
boolean hasNoSubElements = ((m_elements != null) && (m_elements.size() == 1));
352             // write output to stream and process all included elements
353
for (int i = 0; i < m_elements.size(); i++) {
354                 Object JavaDoc o = m_elements.get(i);
355                 if (o instanceof String JavaDoc) {
356                     // handle cached parameters
357
i++;
358                     Map JavaDoc map = (Map JavaDoc)m_elements.get(i);
359                     Map JavaDoc oldMap = null;
360                     if (map.size() > 0) {
361                         oldMap = req.getParameterMap();
362                         req.addParameterMap(map);
363                     }
364                     // do the include call
365
req.getRequestDispatcher((String JavaDoc)o).include(req, res);
366                     // reset parameters if neccessary
367
if (oldMap != null) {
368                         req.setParameterMap(oldMap);
369                     }
370                 } else {
371                     try {
372                         res.writeToOutputStream((byte[])o, hasNoSubElements);
373                     } catch (IOException JavaDoc e) {
374
375                         CmsMessageContainer message = Messages.get().container(
376                             Messages.LOG_FLEXCACHEKEY_NOT_FOUND_1,
377                             getClass().getName());
378                         if (LOG.isDebugEnabled()) {
379                             LOG.debug(message.key());
380                         }
381
382                         throw new CmsFlexCacheException(message, e);
383                     }
384                 }
385             }
386         }
387     }
388
389     /**
390      * Sets the expiration date of this Flex cache entry exactly to the
391      * given time.<p>
392      *
393      * @param dateExpires the time to expire this cache entry
394      */

395     public synchronized void setDateExpires(long dateExpires) {
396
397         m_dateExpires = dateExpires;
398         if (LOG.isDebugEnabled()) {
399             long now = System.currentTimeMillis();
400             LOG.debug(Messages.get().getBundle().key(
401                 Messages.LOG_FLEXCACHEENTRY_SET_EXPIRATION_DATE_3,
402                 new Long JavaDoc(m_dateExpires),
403                 new Long JavaDoc(now),
404                 new Long JavaDoc(m_dateExpires - now)));
405         }
406     }
407
408     /**
409      * Sets an expiration date for this cache entry to the next timeout,
410      * which indicates the time this entry becomes invalid.<p>
411      *
412      * The timeout parameter represents the minute - intervall in which the cache entry
413      * is to be cleared.
414      * The intervall always starts at 0.00h.
415      * A value of 60 would indicate that this entry will reach it's expiration date at the beginning of the next
416      * full hour, a timeout of 20 would indicate that the entry is invalidated at x.00, x.20 and x.40 of every hour etc.<p>
417      *
418      * @param timeout the timeout value to be set
419      */

420     public void setDateExpiresToNextTimeout(long timeout) {
421
422         if (timeout < 0 || !m_completed) {
423             return;
424         }
425
426         long now = System.currentTimeMillis();
427         long daytime = now % 86400000;
428         long timeoutMinutes = timeout * 60000;
429         setDateExpires(now - (daytime % timeoutMinutes) + timeoutMinutes);
430     }
431
432     /**
433      * Sets the "last modified" date for this Flex cache entry with the given value.<p>
434      *
435      * @param dateLastModified the value to set for the "last modified" date
436      */

437     public void setDateLastModified(long dateLastModified) {
438
439         m_dateLastModified = dateLastModified;
440     }
441
442     /**
443      * Sets the "last modified" date for this Flex cache entry by using the last passed timeout value.<p>
444      *
445      * If a cache entry uses the timeout feature, it becomes invalid every time the timeout interval
446      * passes. Thus the "last modified" date is the time the last timeout passed.<p>
447      *
448      * @param timeout the timeout value to use to calculate the date last modified
449      */

450     public void setDateLastModifiedToPreviousTimeout(long timeout) {
451
452         long now = System.currentTimeMillis();
453         long daytime = now % 86400000;
454         long timeoutMinutes = timeout * 60000;
455         setDateLastModified(now - (daytime % timeoutMinutes));
456     }
457
458     /**
459      * @see org.opencms.cache.I_CmsLruCacheObject#setNextLruObject(org.opencms.cache.I_CmsLruCacheObject)
460      */

461     public void setNextLruObject(I_CmsLruCacheObject theNextEntry) {
462
463         m_next = theNextEntry;
464     }
465
466     /**
467      * @see org.opencms.cache.I_CmsLruCacheObject#setPreviousLruObject(org.opencms.cache.I_CmsLruCacheObject)
468      */

469     public void setPreviousLruObject(I_CmsLruCacheObject thePreviousEntry) {
470
471         m_previous = thePreviousEntry;
472     }
473
474     /**
475      * Set a redirect target for this cache entry.<p>
476      *
477      * <b>Important:</b>
478      * When a redirect target is set, all saved data is thrown away,
479      * and new data will not be saved in the cache entry.
480      * This is so since with a redirect nothing will be displayed
481      * in the browser anyway, so there is no point in saving the data.<p>
482      *
483      * @param target The redirect target (must be a valid URL).
484      */

485     public void setRedirect(String JavaDoc target) {
486
487         if (m_completed) {
488             return;
489         }
490         m_redirectTarget = target;
491         m_byteSize = 512 + CmsMemoryMonitor.getMemorySize(target);
492         // If we have a redirect we don't need any other output or headers
493
m_elements = null;
494         m_headers = null;
495     }
496
497     /**
498      * Stores a backward reference to the map and key where this cache entry is stored.
499      *
500      * This is required for the FlexCache.<p>
501      *
502      * @param theVariationKey the variation key
503      * @param theVariationMap the variation map
504      */

505     public void setVariationData(String JavaDoc theVariationKey, Map JavaDoc theVariationMap) {
506
507         m_variationKey = theVariationKey;
508         m_variationMap = theVariationMap;
509     }
510
511     /**
512      * @see java.lang.Object#toString()
513      *
514      * @return a basic String representation of this CmsFlexCache entry
515      */

516     public String JavaDoc toString() {
517
518         String JavaDoc str = null;
519         if (m_redirectTarget == null) {
520             str = "CmsFlexCacheEntry [" + m_elements.size() + " Elements/" + getLruCacheCosts() + " bytes]\n";
521             Iterator JavaDoc i = m_elements.iterator();
522             int count = 0;
523             while (i.hasNext()) {
524                 count++;
525                 Object JavaDoc o = i.next();
526                 if (o instanceof String JavaDoc) {
527                     str += "" + count + " - <cms:include target=" + o + ">\n";
528                 } else if (o instanceof byte[]) {
529                     str += "" + count + " - <![CDATA[" + new String JavaDoc((byte[])o) + "]]>\n";
530                 } else {
531                     str += "<!--[" + o.toString() + "]-->";
532                 }
533             }
534         } else {
535             str = "CmsFlexCacheEntry [Redirect to target=" + m_redirectTarget + "]";
536         }
537         return str;
538     }
539
540     /**
541      * Finalize this instance.<p>
542      *
543      * @see java.lang.Object#finalize()
544      */

545     protected void finalize() throws Throwable JavaDoc {
546
547         try {
548             clear();
549         } catch (Throwable JavaDoc t) {
550             // ignore
551
}
552         super.finalize();
553     }
554
555     /**
556      * Clears the elements and headers HashMaps.<p>
557      */

558     private void clear() {
559
560         // the maps have been made immutable, so we just can set them to null
561
m_elements = null;
562         m_headers = null;
563         // also remove references to other objects
564
m_variationKey = null;
565         m_variationMap = null;
566     }
567 }
568
Popular Tags