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

Quick Search    Search Deep

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


1   /*
2    * File   : $Source: /usr/local/cvs/opencms/src/com/opencms/flex/cache/Attic/CmsFlexCacheEntry.java,v $
3    * Date   : $Date: 2003/05/13 13:18:20 $
4    * Version: $Revision: 1.9.2.1 $
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.flex.util.I_CmsFlexLruCacheObject;
35  
36  import java.util.Iterator;
37  import java.util.Map;
38  
39  /**
40   * Contains the contents of a cached resource.<p>
41   * 
42   * It is basically a list of pre-generated output,
43   * include() calls to other resources (with request parameters) and http headers that this 
44   * resource requires to be set.<p>
45   *
46   * A CmsFlexCacheEntry might also describe a redirect-call, but in this case
47   * nothing else will be cached.<p>
48   *
49   * The pre-generated output is saved in <code>byte[]</code> arrays.
50   * The include() calls are saved as Strings of the included resource name, 
51   * the parameters for the calls are saved in a HashMap.
52   * The headers are saved in a HashMap.
53   * In case of a redirect, the redircet target is cached in a String.<p>
54   *
55   * The CmsFlexCacheEntry can also have a timeout value, which indicates the time 
56   * that his entry will become invalid and should thus be cleared from the cache.<p>
57   *
58   * @author  Alexander Kandzior (a.kandzior@alkacon.com)
59   * @author Thomas Weckert (t.weckert@alkacon.com)
60   * @see com.opencms.flex.util.I_CmsFlexLruCacheObject
61   * @version $Revision: 1.9.2.1 $
62   */
63  public class CmsFlexCacheEntry extends Object implements I_CmsFlexLruCacheObject {
64      
65      /** Initial size for lists */
66      public static final int C_INITIAL_CAPACITY_LISTS = 11;
67      // Alternatives: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71    
68      
69      /** The list of items for this resource */
70      private java.util.List m_elements;
71      
72      /** A Map of cached headers for this resource */
73      private java.util.Map m_headers;
74    
75      /** A redirection target (if redirection is set) */
76      private String m_redirectTarget;
77      
78      /** Debug switch */
79      private static final int DEBUG = 0;
80      
81      /** Age for timeout */
82      private long m_timeout = -1;
83      
84      /** Indicates if this cache entry is completed */
85      private boolean m_completed = false;      
86      
87      /** The CacheEntry's size in kBytes */
88      private int m_byteSize;
89      
90      /** Pointer to the next cache entry in the LRU cache */
91      private I_CmsFlexLruCacheObject m_Next;
92      
93      /** Pointer to the previous cache entry in the LRU cache. */
94      private I_CmsFlexLruCacheObject m_Previous;
95      
96      /** The variation map where this cache entry is stored. */
97      private Map m_VariationMap;
98      
99      /** The key under which this cache entry is stored in the variation map. */
100     private String m_VariationKey;
101     
102     /** Static counter to give each entry a unique ID. */
103     private static int ID_COUNTER = 0;
104     
105     /** The internal ID of this cache entry. */
106     private int ID;
107     
108     /** 
109      * Constructor for class CmsFlexCacheEntry.<p>
110      * 
111      * The way to use this class is to first use this empty constructor 
112      * and later add data with the various add methods.
113      */
114     public CmsFlexCacheEntry() {
115         m_elements = new java.util.ArrayList(C_INITIAL_CAPACITY_LISTS);
116         m_redirectTarget = null;
117         m_headers = null;
118         m_byteSize = 0;
119         
120         this.setNextLruObject( null );
121         this.setPreviousLruObject( null );
122         
123         this.ID = CmsFlexCacheEntry.ID_COUNTER++;
124     }
125     
126     /** 
127      * Adds an array of bytes to this cache entry,
128      * this will usually be the result of some kind of output - stream.<p>
129      *
130      * @param bytes the output to save in the cache
131      */    
132     public void add(byte[] bytes) {
133         if (m_completed) return;
134         if (m_redirectTarget == null) {
135             // Add only if not already redirected
136             m_elements.add(bytes);
137             m_byteSize += bytes.length;
138         }
139     }
140     
141     /** 
142      * Add an include - call target resource to this cache entry.<p>
143      *
144      * @param resource a name of a resource in the OpenCms VFS
145      * @param parameters a map of parameters specific to this include call
146      */    
147     public void add(String resource, java.util.Map paramters) {
148         if (m_completed) return;
149         if (m_redirectTarget == null) {
150             // Add only if not already redirected
151             m_elements.add(resource);
152             if (paramters == null) paramters = java.util.Collections.EMPTY_MAP;
153             m_elements.add(paramters);
154             m_byteSize += resource.getBytes().length;
155         }
156     }
157     
158     /** 
159      * Add a map of headers to this cache entry,
160      * which are usually collected in the class CmsFlexResponse first.<p>
161      *
162      * @param headers the map of headers to add to the entry 
163      */
164     public void addHeaders(java.util.Map headers) {
165         if (m_completed) return;
166         m_headers = headers;
167         
168         Iterator allHeaders = m_headers.keySet().iterator();
169         while (allHeaders.hasNext()) {
170             this.m_byteSize += ((String)allHeaders.next()).getBytes().length;
171         }
172     }
173     
174     /** 
175      * Set a redirect target for this cache entry.<p>
176      *
177      * <b>Important:</b>
178      * When a redirect target is set, all saved data is thrown away,
179      * and new data will not be saved in the cache entry.
180      * This is so since with a redirect nothing will be displayed
181      * in the browser anyway, so there is no point in saving the data.<p>
182      * 
183      * @param target The redirect target (must be a valid URL).
184      */    
185     public void setRedirect(String target) {
186         if (m_completed) return;
187         m_redirectTarget = target;
188         this.m_byteSize = target.getBytes().length;
189         // If we have a redirect we don't need any other output or headers
190         m_elements = null;
191         m_headers = null;
192     }
193     
194     /**
195      * Returns the list of data entries of this cache entry.<p>
196      * 
197      * Data entries are byte arrays representing some kind of ouput
198      * or Strings representing include calls to other resources.
199      *
200      * @return the list of data elements of this cache entry
201      */    
202     public java.util.List elements() {
203         return m_elements;
204     }
205 
206     /** 
207      * Processing method for this cached entry.<p>
208      *
209      * If this method is called, it delivers the contents of
210      * the cached entry to the given request / response.
211      * This includes calls to all included resources.<p>
212      *
213      * @param req the request from the client
214      * @param res the server response
215      * @throws CmsException is thrown when problems writing to the response output-stream occur
216      * @throws ServletException might be thrown from call to RequestDispatcher.include()
217      * @throws IOException might be thrown from call to RequestDispatcher.include() or from Response.sendRedirect()
218      */
219     public void service(CmsFlexRequest req, CmsFlexResponse res) 
220     throws com.opencms.core.CmsException, javax.servlet.ServletException, java.io.IOException {
221         if (!m_completed) return;
222 
223         if (m_redirectTarget != null) {
224             res.setOnlyBuffering(false);
225             // Redirect the response, no further output required
226             res.sendRedirect(m_redirectTarget);
227         } else {      
228             // Process cached headers first
229             CmsFlexResponse.processHeaders(m_headers, res);
230             // Check if this cache entry is a "leaf" (i.e. no further includes)            
231             boolean hasNoSubElements = ((m_elements != null) && (m_elements.size() == 1));            
232             // Write output to stream and process all included elements
233             java.util.Iterator i = m_elements.iterator();
234             while (i.hasNext()) {
235                 Object o = i.next();
236                 if (o instanceof String) {                    
237                     // Handle cached parameters
238                     java.util.Map map = (java.util.Map)i.next();                    
239                     java.util.Map oldMap = null;
240                     if (map.size() > 0) {
241                         oldMap = req.getParameterMap();
242                         req.addParameterMap(map);
243                     }
244                     // Do the include call
245                     req.getRequestDispatcher((String)o).include(req, res);
246                     // Reset parameters if neccessary
247                     if (oldMap != null) req.setParameterMap(oldMap);
248                 } else {
249                     try {
250                         res.writeToOutputStream((byte[])o, hasNoSubElements);
251                     } catch (java.io.IOException e) {
252                         String err = this.getClass().getName() + ": Could not write to response OutputStream. ";
253                         if (DEBUG > 0) System.err.println(err);
254                         throw new com.opencms.core.CmsException(err + "\n" + e, e);
255                     }
256                 }
257             }
258         }
259     }
260     
261     /** 
262      * Returns the timeout - value of this cache entry,
263      * this is set to the time when the entry becomes invalid.
264      *
265      * @return the timeout value for this resource
266      */ 
267     public long getTimeout() {
268         return m_timeout;
269     }
270     
271     /**
272      * Sets a timeout value to this cache entry,
273      * which indicates the time this entry becomes invalid.<p>
274      *
275      * The timeout parameter represents the minute - intervall in which the cache entry
276      * is to be cleared. 
277      * The intervall always starts at 0.00h. 
278      * A value of 60 would indicate that this entry will reach it's timeout at the beginning of the next 
279      * 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>
280      *
281      * @param timeout the timeout value to be set
282      */
283     public synchronized void setTimeout(long timeout) {
284         if (timeout < 0 || ! m_completed) return;
285         
286         long now = System.currentTimeMillis();
287         long daytime = now % 86400000;
288         m_timeout = now - (daytime % timeout) + timeout;
289         if (DEBUG > 2) System.err.println("FlexCacheEntry: New entry timeout=" + m_timeout + " now=" + now + " remaining=" + (m_timeout - now) );
290     } 
291     
292     /**
293      * Completes this cache entry.<p>
294      * 
295      * A completed cache entry is made "unmodifiable",
296      * so that no further data can be added and existing data can not be changed.
297      * This is to prevend the (unlikley) case that some user-written class 
298      * tries to make changes to a cache entry.<p>
299      */
300     public void complete() {        
301         m_completed = true;
302         // Prevent changing of the cached lists
303         if (m_headers != null) {
304             m_headers = java.util.Collections.unmodifiableMap(m_headers);
305         }
306         if (m_elements != null) {
307             m_elements = java.util.Collections.unmodifiableList(m_elements);
308         }
309         if (DEBUG > 1) System.err.println("CmsFlexCacheEntry: New entry completed:\n" + this.toString());
310     }
311     
312     /** 
313      * @see java.lang.Object#toString()
314      *
315      * @return a basic String representation of this CmsFlexCache entry
316      */
317     public String toString() {
318         String str = null;
319         if (m_redirectTarget == null) {
320             str = "CmsFlexCacheEntry [" + m_elements.size() + " Elements/" + this.getLruCacheCosts() + " bytes]\n";
321             java.util.Iterator i = m_elements.iterator();
322             int count = 0;
323             while (i.hasNext()) {
324                 count++;
325                 Object o = i.next();
326                 if (o instanceof String) {
327                     str += "" + count + " - <cms:include target=" + o + ">\n";
328                 } else {
329                     str += "" + count + " - <![CDATA[" + new String((byte[])o) + "]]>\n";
330                 }
331             }
332         } else {
333             str = "CmsFlexCacheEntry [Redirect to target=" + m_redirectTarget + "]";
334         }
335         return str;
336     }   
337     
338     /**
339      * Stores a backward reference to the map and key where this cache entry is stored.
340      * 
341      * This is required for the FlexCache.<p>
342      *
343      * @param theVariationKey the variation key
344      * @param theVariationMap the variation map
345      */
346     public void setVariationData( String theVariationKey, Map theVariationMap ) {
347         this.m_VariationKey = theVariationKey;
348         this.m_VariationMap = theVariationMap;
349     }
350     
351     // implementation of the com.opencms.flex.util.I_CmsFlexLruCacheObject interface methods
352     
353     /**
354      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#setNextLruObject(com.opencms.flex.util.I_CmsFlexLruCacheObject)
355      */
356     public void setNextLruObject( I_CmsFlexLruCacheObject theNextEntry ) {
357         this.m_Next = theNextEntry;
358     }
359     
360     /**
361      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getNextLruObject()
362      */
363     public I_CmsFlexLruCacheObject getNextLruObject() {
364         return this.m_Next;
365     }
366     
367     /**
368      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#setPreviousLruObject(com.opencms.flex.util.I_CmsFlexLruCacheObject)
369      */
370     public void setPreviousLruObject( I_CmsFlexLruCacheObject thePreviousEntry ) {
371         this.m_Previous = thePreviousEntry;
372     }
373     
374     /**
375      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getPreviousLruObject()
376      */
377     public I_CmsFlexLruCacheObject getPreviousLruObject() {
378         return this.m_Previous;
379     }  
380     
381     /**
382      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#addToLruCache()
383      */
384     public void addToLruCache() {
385         // do nothing here...
386         if (DEBUG>0) System.out.println( "Added cache entry with ID: " + this.ID + " to the LRU cache" );
387     }
388     
389     /**
390      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#removeFromLruCache()
391      */
392     public void removeFromLruCache() {
393         if (m_VariationMap!=null && this.m_VariationKey!=null) {
394             this.m_VariationMap.remove( this.m_VariationKey );
395             if (DEBUG>0) System.err.println( "Removed cache entry with ID: " + this.ID + " from the LRU cache" );
396         }
397     }
398     
399     /**
400      * @see com.opencms.flex.util.I_CmsFlexLruCacheObject#getLruCacheCosts()
401      */
402     public int getLruCacheCosts() {
403         return m_byteSize;
404     }
405     
406     // methods to clean-up/finalize the object instance
407     
408     /**
409      * Finalize this instance.<p>
410      *
411      * @see java.lang.Object#finalize()
412      */
413     protected void finalize() throws java.lang.Throwable {
414         if (DEBUG>0) System.err.println( "Finalizing cache entry with ID: " + this.ID );
415         
416         this.clear();
417         
418         this.m_elements = null;
419         this.m_headers = null;
420         
421         this.m_VariationKey = null;
422         this.m_VariationMap = null;        
423         
424         this.setNextLruObject( null );
425         this.setPreviousLruObject( null );
426         
427         this.m_byteSize = 0;  
428         
429         super.finalize();      
430     }
431     
432     /**
433      * Clears the elements and headers HashMaps.<p>
434      */
435     private void clear() {
436         m_elements.clear();
437         m_headers.clear();
438     }
439 }