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

Quick Search    Search Deep

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


1   /*
2    * File   : $Source: /usr/local/cvs/opencms/src/com/opencms/flex/cache/Attic/CmsFlexCacheKey.java,v $
3    * Date   : $Date: 2003/05/13 13:18:20 $
4    * Version: $Revision: 1.7.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.file.CmsObject;
35  
36  import java.util.Iterator;
37  
38  import javax.servlet.ServletRequest;
39  
40  /**
41   * Implements the CmsFlexCacheKey,
42   * which is a key used to describe the caching behaviour
43   * of a specific resource.<p>
44   *
45   * It has a lot of "public" variables (which isn't good style, I know)
46   * to avoid method calling overhead (a cache is about speed, isn't it :).<p>
47   *
48   * @author Alexander Kandzior (a.kandzior@alkacon.com)
49   * @version $Revision: 1.7.2.1 $
50   */
51  public class CmsFlexCacheKey {
52      
53      /** The OpenCms resource that this key is used for. */    
54      public String Resource = null;
55      
56      /** The cache behaviour description for the resource. */    
57      public String Variation = null;
58  
59      /** Cache key variable: Determines if this resource can be cached alwys, never or under certain conditions. -1 = never, 0=check, 1=always */
60      public int m_always = -1; // 
61      
62      /** Cache key variable: The uri of the original request */
63      public String m_uri = null;
64      
65      /** Cache key variable: The user id */
66      public int m_user = -1;
67      
68      /** Cache key variable: List of groups */
69      public java.util.Set m_groups = null;
70  
71      /** Cache key variable: List of parameters */
72      public java.util.Map m_params = null;
73      
74      /** Cache key variable: List of "blocking" parameters */
75      public java.util.Set m_noparams = null;
76      
77      /** Cache key variable: Timeout of the resource */
78      public long m_timeout = -1;
79      
80      /** Cache key variable: Determines if the resource sould be always cleared at publish time */
81      public boolean m_publish = false;
82          
83      /** Cache key variable: Distinguishes request schemes (http, https etc.) */
84      public java.util.Set m_schemes = null;
85      
86      /** Cache key variable: The request TCP/IP port */
87      public java.util.Set m_ports = null;
88  
89      /** The list of keywords of the Flex cache language */
90      private java.util.List cacheCmds = java.util.Arrays.asList(new String[] {
91          "always", "never", "uri", "user", "groups", "params", "no-params", "timeout", "publish-clear", "schemes", "ports", "false", "parse-error", "true"} );
92      //   0         1        2      3       4         5         6            7          8                9          10       11       12             13
93      
94      /** Flag used to determine if this key is from a request or not */
95      private boolean m_isRequest;
96      
97      /** Flag raised in case a key parse error occured */
98      private boolean m_parseError = false;
99      
100     /** Debugging flag */
101     private static final boolean DEBUG = false;
102     
103     /**
104      * This constructor is used when building a cache key from a request.<p>
105      * 
106      * The request contains several data items that are neccessary to construct
107      * the output. These items are e.g. the Query-String, the requested resource,
108      * the current time etc. etc.
109      * All required items are saved in the constructed cache - key.<p>
110      *
111      * @param target the requested resource in the OpenCms VFS
112      * @param online must be true for an online resource, false for offline resources
113      * @param request the request to construct the key for
114      */    
115     public CmsFlexCacheKey(ServletRequest request, String target, boolean online) {
116                 
117         Resource = getKeyName(target, online);     
118         Variation = "never";
119                        
120         m_isRequest = true;
121         // Fetch the cms from the request
122         CmsObject cms = ((CmsFlexController)request.getAttribute(CmsFlexController.ATTRIBUTE_NAME)).getCmsObject();        
123         // Get the top-level file name / uri
124         // m_uri = request.getCmsFile().getAbsolutePath();
125         m_uri = cms.getRequestContext().getUri();
126         // Fetch user from the current cms
127         m_user = cms.getRequestContext().currentUser().getId();        
128         // Fetch group. Must have unique names, so the String is ok
129         m_groups = java.util.Collections.singleton(cms.getRequestContext().currentGroup().getName().toLowerCase());
130         // Get the params
131         m_params = request.getParameterMap();
132         if (m_params.size() == 0) m_params = null;
133         // No-params are null for a request key
134         m_noparams = null;
135         // Save the request time 
136         m_timeout = System.currentTimeMillis();
137         // publish-clear is not related to the request
138         m_publish = false;
139         // alwalys is not related to the request 
140         m_always = 0;
141         // Save the request scheme
142         m_schemes = java.util.Collections.singleton(request.getScheme().toLowerCase());
143         // Save the request port
144         m_ports = java.util.Collections.singleton(new Integer(request.getServerPort()));
145         if (DEBUG) System.err.println("Creating CmsFlexCacheKey for Request:\n" + this.toString());        
146     }
147     
148     /**
149      * This constructor is used when building a cache key from set of cache directives.<p>
150      * 
151      * These directives are attached to the properties of the requested resource 
152      * on a property called "cache". 
153      * The value of this poperty that is passed in this constructor as "cacheDirectives" 
154      * is parsed to build the keys data structure.<p>
155      *
156      * In case a parsing error occures, the value of this key is set to "cache=never", 
157      * and the hadParseError() flag is set to true. 
158      * This is done to ensure that a valid key is always constructed with the constructor.<p>
159      *
160      * @param target the requested resource
161      * @param cacheDirectives the cache directives of the resource (value of the property "cache")
162      * @param online must be true for an online resource, false for offline resources
163      */        
164     public CmsFlexCacheKey(String target, String cacheDirectives, boolean online) {
165         Resource = getKeyName(target, online);     
166         Variation = "never";
167         m_isRequest = false;
168         if (cacheDirectives != null) parseFlexKey(cacheDirectives);
169         if (DEBUG) System.err.println("CmsFlexCacheKey for response generated:\n" + this.toString());
170     }
171     
172     /**
173      * Calculates the cache key name that is used as key in 
174      * the first level of the FlexCache.<p>
175      *
176      * @param name the name of the resource
177      * @param online must be true for an online resource, false for offline resources
178      * @return fhe FlexCache key name
179      */
180     public static String getKeyName(String name, boolean online) {
181         return name + (online?CmsFlexCache.C_CACHE_ONLINESUFFIX:CmsFlexCache.C_CACHE_OFFLINESUFFIX);             
182     }
183     
184     /**
185      * This flag is used to indicate that a parse error had
186      * occured, which can happen if the cache directives String
187      * passed to the constructor using the response is
188      * not build according to the Flex cache language syntax.<p>
189      * 
190      * @return true if a parse error did occur, false otherwise
191      */    
192     public boolean hadParseError() {
193         return m_parseError;
194     }
195         
196      /**
197       * Compares this key to the other key passed as parameter,
198       * from comparing the two keys, a variation String is constructed.<p>
199       * 
200       * This method is the "heart" of the key matching process.<p>
201       *
202       * The assumtion is that this key should be the one constructed for the response, 
203       * while the parameter key should have been constructed from the request.<p>
204       *
205       * A short example how this works:
206       * If the resource key is "cache=groups" and the request is done from a guest user
207       * (which always belongs to the default group "guests"),
208       * the constructed variation will be "groups=(guests)".<p>
209       * 
210       * @param key the key to match this key with
211       * @return null if not cachable, or the Variation String if cachable
212       */
213     public String matchRequestKey(CmsFlexCacheKey key) {
214         
215         StringBuffer str = new StringBuffer(100);
216         if (m_always < 0) {
217             if (DEBUG) System.err.println("keymatch: cache=never");
218             return null;
219         } 
220                
221         if (DEBUG) System.err.println("keymatch: Checking no-params");
222         if ((m_noparams != null) && (key.m_params != null)) {
223             if ((m_noparams.size() == 0) && (key.m_params.size() > 0)) return null;
224             Iterator i = key.m_params.keySet().iterator();
225             while (i.hasNext()) {
226                 if (m_noparams.contains(i.next())) return null;
227             }
228         }
229 
230         if (m_always > 0) {
231             if (DEBUG) System.err.println("keymatch: cache=always");
232             str.append("always");
233             return str.toString();
234         }
235         
236         if (DEBUG) System.err.println("keymatch: Checking groups");
237         if (m_groups != null) {
238             String g = (String)key.m_groups.iterator().next();
239             if (DEBUG) System.err.println("keymatch: Request group is " + g);
240             if ((m_groups.size() > 0) && ! m_groups.contains(g)) return null;
241             str.append("groups=(");
242             str.append(g);
243             str.append(");");
244         }
245         
246         if (m_uri != null) {
247             str.append("uri=(");
248             str.append(key.m_uri);
249             str.append(");");
250         }
251         
252         if (m_user > 0) {
253             str.append("user=(");
254             str.append(key.m_user);
255             str.append(");");
256         }
257         
258         if (m_params != null) {
259             str.append("params=(");
260             if (key.m_params != null) {
261                 if (m_params.size() > 0) {
262                     // Match only params listed in cache directives
263                     Iterator i = m_params.keySet().iterator();            
264                     while (i.hasNext()) {
265                         Object o = i.next();
266                         if (key.m_params.containsKey(o)) {
267                             str.append(o);
268                             str.append("=");
269                             // TODO: handle multiple occurences of the same parameter value
270                             String[] values = (String[])key.m_params.get(o);
271                             str.append(values[0]);
272                             if (i.hasNext()) str.append(",");
273                         }
274                     }
275                 } else {
276                     // Match all request params
277                     Iterator i = key.m_params.keySet().iterator();            
278                     while (i.hasNext()) {
279                         Object o = i.next();
280                         str.append(o);
281                         str.append("=");
282                         // TODO: handle multiple occurences of the same parameter value
283                         String[] values = (String[])key.m_params.get(o);
284                         str.append(values[0]);
285                         if (i.hasNext()) str.append(",");
286                     }                    
287                 }
288             }
289             str.append(")");
290         }
291         
292         if (m_schemes != null) {
293             String s = (String)key.m_schemes.iterator().next();
294             if ((m_schemes.size() > 0) && (! m_schemes.contains(s.toLowerCase()))) return null;
295             str.append("schemes=(");
296             str.append(s);
297             str.append(");");
298         }
299         
300         if (m_ports != null) {
301             Integer i = (Integer)key.m_ports.iterator().next();
302             if ((m_ports.size() > 0) && (! m_ports.contains(i))) return null;
303             str.append("ports=(");
304             str.append(i);
305             str.append(");");
306         }
307         
308         if (m_timeout > 0) {
309             str.append("timeout=(");
310             str.append(m_timeout);
311             str.append(");");
312         }
313         
314         return str.toString();
315     }
316     
317     /** 
318      * @see java.lang.Object#toString()
319      *
320      * @return a complete String representation for this key
321      */
322     public String toString() {
323         StringBuffer str = new StringBuffer(100);        
324 
325         if (m_always < 0) {
326             str.append("never"); 
327             if (m_parseError) {
328                 str.append(";parse-error");
329             }            
330             return str.toString();
331         }
332         if (m_noparams != null) {
333             // Add "no-cachable" parameters
334             if (m_noparams.size() == 0) {
335                 str.append("no-params;");
336             } else {
337                 str.append("no-params=(");
338                 Iterator i = m_noparams.iterator();
339                 while (i.hasNext()) {
340                     Object o = i.next();
341                     str.append(o);
342                     if (i.hasNext()) str.append(",");
343                 }                      
344                 str.append(");");
345             }
346         }        
347         if (m_always > 0) {
348             str.append("always");
349             if (m_parseError) {
350                 str.append(";parse-error");
351             }            
352             return str.toString();
353         }
354         if (m_uri != null) {
355             if (m_uri.equals("uri")) {
356                 str.append("uri;");
357             } else {
358                 str.append("uri=(");
359                 str.append(m_uri);
360                 str.append(");");
361             }
362         }
363         if (m_user >= 0) {
364             // Add user data
365             if (m_user == Integer.MAX_VALUE) {
366                 str.append("user;");
367             } else {
368                 str.append("user=(");
369                 str.append(m_user);
370                 str.append(");");
371             }
372         }
373         if (m_groups != null) {
374             // Add group data
375             if (m_groups.size() == 0) {
376                 str.append("groups;");
377             } else {
378                 str.append("groups=(");
379                 Iterator i = m_groups.iterator();
380                 while (i.hasNext()) {
381                     str.append(i.next());
382                     if (i.hasNext()) str.append(",");
383                 }
384                 str.append(");");
385             }
386         }               
387         if (m_params != null) {
388             // Add parameters
389             if (m_params.size() == 0) {
390                 str.append("params;");
391             } else {
392                 str.append("params=(");
393                 Iterator i = m_params.keySet().iterator();
394                 while (i.hasNext()) {
395                     Object o = i.next();
396                     str.append(o);
397                     try {
398                         // TODO: handle multiple occurences of the same parameter value
399                         String param[] = (String[])m_params.get(o);
400                         if (! "&?&".equals(param[0])) {
401                             str.append("=");
402                             str.append(param[0]);
403                         }
404                     } catch(Exception e) {                        
405                         if (DEBUG) System.err.println("Exception! o=" + o + "  Exception is " + e );
406                     }
407                     if (i.hasNext()) str.append(",");
408                 }            
409                 str.append(");");
410             }
411         }
412         if (m_timeout >= 0) {
413             // Add timeout 
414             str.append("timeout=(");
415             str.append(m_timeout);
416             str.append(");");
417         }
418         if (m_publish) {
419             // Add publish parameters
420             str.append("publish-clear;");
421         }
422         if (m_schemes != null) {
423             // Add schemes
424             if (m_schemes.size() == 0) {
425                 str.append("schemes;");
426             } else {
427                 str.append("schemes=(");
428                 Iterator i = m_schemes.iterator();
429                 while (i.hasNext()) {
430                     str.append(i.next());
431                     if (i.hasNext()) str.append(",");
432                 }          
433                 str.append(");");
434             }
435         }
436         if (m_ports != null) {
437             // Add ports
438             if (m_ports.size() == 0) {
439                 str.append("ports;");
440             } else {
441                 str.append("ports=(");
442                 Iterator i = m_ports.iterator();
443                 while (i.hasNext()) {
444                     str.append(i.next());
445                     if (i.hasNext()) str.append(",");
446                 } 
447                 str.append(");");            
448             }
449         }        
450         
451         if (m_parseError) {
452             str.append("parse-error;");
453         }
454         return str.toString();
455     }
456     
457     /**
458      * Parse a String in the Flex cache language and construct 
459      * the key data structure from this.<p>
460      *
461      * @param key the String to parse (usually read from the file property "cache")
462      */    
463     private void parseFlexKey(String key) {
464         java.util.StringTokenizer toker = new java.util.StringTokenizer(key,";");
465         try {
466             while (toker.hasMoreElements()) {
467                 String t = toker.nextToken();
468                 String k = null; 
469                 String v = null;
470                 int idx = t.indexOf("=");
471                 if (idx >= 0) {
472                     k = t.substring(0, idx).trim();
473                     if (t.length() > idx) v = t.substring(idx+1).trim();
474                 } else {
475                     k = t.trim();
476                 }
477                 m_always = 0;
478                 if (DEBUG) System.err.println("Parsing token:" + t + " key=" + k + " value=" + v);
479                 switch (cacheCmds.indexOf(k)) {
480                     case 0: // always
481                     case 13:                    
482                         m_always = 1;
483                         // Continue processing (make sure we find a "never" behind "always")
484                         break;
485                     case 1: // never
486                     case 11:
487                         m_always = -1;
488                         // No need for any further processing
489                         return;
490                     case 2: // uri
491                         m_uri = "uri";
492                         // being != null is enough
493                         break;
494                     case 3: // user
495                         m_user = Integer.MAX_VALUE;
496                         // being > 0 is enough
497                         break;
498                     case 4: // groups
499                         if (v != null) {
500                             // A list of groups is present
501                             m_groups = parseValueMap(v).keySet();
502                         } else {
503                             // Cache all groups
504                             m_groups = new java.util.HashSet(0);
505                         }
506                         break;
507                     case 5: // params
508                         m_params = parseValueMap(v);
509                         break;
510                     case 6: // no-params
511                         if (v != null) {
512                             // No-params are present
513                             m_noparams = parseValueMap(v).keySet();
514                         } else {
515                             // Never cache with parameters
516                             m_noparams = new java.util.HashSet(0);
517                         }
518                         break;
519                     case 7: // timeout
520                         m_timeout = Integer.parseInt(v);
521                         break;
522                     case 8: // publish
523                         m_publish = true;
524                         break;
525                     case 9: // schemes
526                         m_schemes = parseValueMap(v).keySet();
527                         break;
528                     case 10: // ports
529                         m_ports = parseValueMap(v).keySet();
530                         break;
531                     case 12: // previous parse error - ignore
532                         break;
533                     default: // unknown directive, throw error
534                         m_parseError = true;
535                 }      
536             }
537         } catch (Exception e) {
538             // Any Exception here indicates a parsing error
539             if (DEBUG) System.err.println("----- Error in key parsing: " + e.toString());
540             m_parseError = true;
541         }
542         if (m_parseError) {
543             // If string is invalid set cache to "never"
544             m_always = -1;
545         }
546     }
547 
548     /** 
549      * A helper method for the parsing process which parses
550      * Strings like groups=(a, b, c).<p>
551      *
552      * @param value the String to parse 
553      * @return a Map that contains of the parsed values, only the keyset of the Map is needed later
554      */    
555     private java.util.Map parseValueMap(String value) {
556         if (value.charAt(0) == '(') value = value.substring(1);
557         int len;
558         if (value.charAt(len = (value.length()-1)) == ')') value = value.substring(0, len);
559         if (value.charAt(len-1) == ',') value = value.substring(0, len-1);
560         if (DEBUG) System.err.println("Parsing map: " + value);
561         java.util.StringTokenizer toker = new java.util.StringTokenizer(value, ",");
562         java.util.Map result = new java.util.HashMap();
563         while (toker.hasMoreTokens()) {
564             result.put(toker.nextToken().trim(), new String[] { "&?&" } );
565         }
566         return result;
567     }
568     
569 }