001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.flex; 029 030import org.opencms.loader.I_CmsResourceLoader; 031import org.opencms.main.CmsLog; 032import org.opencms.util.CmsStringUtil; 033 034import java.util.Arrays; 035import java.util.Collections; 036import java.util.HashSet; 037import java.util.Iterator; 038import java.util.List; 039import java.util.Map; 040import java.util.Set; 041 042import javax.servlet.http.HttpSession; 043 044import org.apache.commons.logging.Log; 045 046/** 047 * Key used to describe the caching behaviour of a specific resource.<p> 048 * 049 * It has a lot of variables that are directly accessed (which isn't good style, I know) 050 * to avoid method calling overhead (a cache is about speed, isn't it :).<p> 051 * 052 * @since 6.0.0 053 */ 054public class CmsFlexCacheKey { 055 056 /** Flex cache keyword: always. */ 057 private static final String CACHE_00_ALWAYS = "always"; 058 059 /** Flex cache keyword: never. */ 060 private static final String CACHE_01_NEVER = "never"; 061 062 /** Flex cache keyword: uri. */ 063 private static final String CACHE_02_URI = "uri"; 064 065 /** Flex cache keyword: user. */ 066 private static final String CACHE_03_USER = "user"; 067 068 /** Flex cache keyword: params. */ 069 private static final String CACHE_04_PARAMS = "params"; 070 071 /** Flex cache keyword: no-params. */ 072 private static final String CACHE_05_NO_PARAMS = "no-params"; 073 074 /** Flex cache keyword: timeout. */ 075 private static final String CACHE_06_TIMEOUT = "timeout"; 076 077 /** Flex cache keyword: session. */ 078 private static final String CACHE_07_SESSION = "session"; 079 080 /** Flex cache keyword: schemes. */ 081 private static final String CACHE_08_SCHEMES = "schemes"; 082 083 /** Flex cache keyword: ports. */ 084 private static final String CACHE_09_PORTS = "ports"; 085 086 /** Flex cache keyword: false. */ 087 private static final String CACHE_10_FALSE = CmsStringUtil.FALSE; 088 089 /** Flex cache keyword: parse-error. */ 090 private static final String CACHE_11_PARSE_ERROR = "parse-error"; 091 092 /** Flex cache keyword: true. */ 093 private static final String CACHE_12_TRUE = CmsStringUtil.TRUE; 094 095 /** Flex cache keyword: ip. */ 096 private static final String CACHE_13_IP = "ip"; 097 098 /** Flex cache keyword: element. */ 099 private static final String CACHE_14_ELEMENT = "element"; 100 101 /** Flex cache keyword: locale. */ 102 private static final String CACHE_15_LOCALE = "locale"; 103 104 /** Flex cache keyword: encoding. */ 105 private static final String CACHE_16_ENCODING = "encoding"; 106 107 /** Flex cache keyword: site. */ 108 private static final String CACHE_17_SITE = "site"; 109 110 /** Flex cache keyword: attrs. */ 111 private static final String CACHE_18_ATTRS = "attrs"; 112 113 /** Flex cache keyword: no-attrs. */ 114 private static final String CACHE_19_NO_ATTRS = "no-attrs"; 115 116 /** Flex cache keyword: device. */ 117 private static final String CACHE_20_DEVICE = "device"; 118 119 /** Flex cache keyword: container-element. */ 120 private static final String CACHE_21_CONTAINER_ELEMENT = "container-element"; 121 122 /** The list of keywords of the Flex cache language. */ 123 private static final List<String> CACHE_COMMANDS = Arrays.asList( 124 new String[] { 125 CACHE_00_ALWAYS, 126 CACHE_01_NEVER, 127 CACHE_02_URI, 128 CACHE_03_USER, 129 CACHE_04_PARAMS, 130 CACHE_05_NO_PARAMS, 131 CACHE_06_TIMEOUT, 132 CACHE_07_SESSION, 133 CACHE_08_SCHEMES, 134 CACHE_09_PORTS, 135 CACHE_10_FALSE, 136 CACHE_11_PARSE_ERROR, 137 CACHE_12_TRUE, 138 CACHE_13_IP, 139 CACHE_14_ELEMENT, 140 CACHE_15_LOCALE, 141 CACHE_16_ENCODING, 142 CACHE_17_SITE, 143 CACHE_18_ATTRS, 144 CACHE_19_NO_ATTRS, 145 CACHE_20_DEVICE, 146 CACHE_21_CONTAINER_ELEMENT}); 147 148 /** Marker to identify use of certain String key members (uri, ip etc.). */ 149 private static final String IS_USED = "/ /"; 150 151 /** The log object for this class. */ 152 private static final Log LOG = CmsLog.getLog(CmsFlexCacheKey.class); 153 154 /** Cache key variable: Determines if this resource can be cached alwys, never or under certain conditions. -1 = never, 0=check, 1=always. */ 155 private int m_always; 156 157 /** Cache key variable: List of attributes. */ 158 private Set<String> m_attrs; 159 160 /** Cache key variable: The current container element. */ 161 private String m_containerElement; 162 163 /** Cache key variable: The current device. */ 164 private String m_device; 165 166 /** Cache key variable: The requested element. */ 167 private String m_element; 168 169 /** Cache key variable: The requested encoding. */ 170 private String m_encoding; 171 172 /** Cache key variable: The ip address of the request. */ 173 private String m_ip; 174 175 /** Cache key variable: The requested locale. */ 176 private String m_locale; 177 178 /** Cache key variable: List of "blocking" attributes. */ 179 private Set<String> m_noattrs; 180 181 /** Cache key variable: List of "blocking" parameters. */ 182 private Set<String> m_noparams; 183 184 /** Cache key variable: List of parameters. */ 185 private Set<String> m_params; 186 187 /** Flag raised in case a key parse error occurred. */ 188 private boolean m_parseError; 189 190 /** Cache key variable: The request TCP/IP port. */ 191 private Set<Integer> m_ports; 192 193 /** The OpenCms resource that this key is used for. */ 194 private String m_resource; 195 196 /** Cache key variable: Distinguishes request schemes (http, https etc.). */ 197 private Set<String> m_schemes; 198 199 /** Cache key variable: List of session variables. */ 200 private Set<String> m_session; 201 202 /** Cache key variable: The current site root. */ 203 private String m_site; 204 205 /** Cache key variable: Timeout of the resource. */ 206 private long m_timeout; 207 208 /** Cache key variable: The uri of the original request. */ 209 private String m_uri; 210 211 /** Cache key variable: The user id. */ 212 private String m_user; 213 214 /** The cache behaviour description for the resource. */ 215 private String m_variation; 216 217 /** 218 * This constructor is used when building a cache key from set of cache directives.<p> 219 * 220 * These directives are attached to the properties of the requested resource 221 * on a property called "cache". 222 * The value of this poperty that is passed in this constructor as "cacheDirectives" 223 * is parsed to build the keys data structure.<p> 224 * 225 * In case a parsing error occures, the value of this key is set to "cache=never", 226 * and the hadParseError() flag is set to true. 227 * This is done to ensure that a valid key is always constructed with the constructor.<p> 228 * 229 * @param resourcename the full name of the resource including site root 230 * @param cacheDirectives the cache directives of the resource (value of the property "cache") 231 * @param online must be true for an online resource, false for offline resources 232 */ 233 public CmsFlexCacheKey(String resourcename, String cacheDirectives, boolean online) { 234 235 m_resource = getKeyName(resourcename, online); 236 m_variation = "never"; 237 m_always = -1; 238 m_timeout = -1; 239 if (cacheDirectives != null) { 240 parseFlexKey(cacheDirectives); 241 } 242 if (LOG.isDebugEnabled()) { 243 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_GENERATED_1, toString())); 244 } 245 } 246 247 /** 248 * Calculates the cache key name that is used as key in 249 * the first level of the FlexCache.<p> 250 * 251 * @param resourcename the full name of the resource including site root 252 * @param online must be true for an online resource, false for offline resources 253 * 254 * @return the FlexCache key name 255 */ 256 public static String getKeyName(String resourcename, boolean online) { 257 258 return resourcename.concat(online ? CmsFlexCache.CACHE_ONLINESUFFIX : CmsFlexCache.CACHE_OFFLINESUFFIX); 259 } 260 261 /** 262 * Appends a flex cache key value to the given buffer.<p> 263 * 264 * @param str the buffer to append to 265 * @param key the key to append 266 * @param value the value to append 267 */ 268 private static void appendKeyValue(StringBuffer str, String key, String value) { 269 270 str.append(key); 271 if (value == IS_USED) { 272 str.append(";"); 273 } else { 274 str.append("=("); 275 str.append(value); 276 str.append(");"); 277 } 278 } 279 280 /** 281 * This flag is used to indicate that a parse error had 282 * occurred, which can happen if the cache directives String 283 * passed to the constructor using the response is 284 * not build according to the Flex cache language syntax.<p> 285 * 286 * @return true if a parse error did occur, false otherwise 287 */ 288 public boolean hadParseError() { 289 290 return m_parseError; 291 } 292 293 /** 294 * Compares this key to the other key passed as parameter, 295 * from comparing the two keys, a variation String is constructed.<p> 296 * 297 * This method is the "heart" of the key matching process.<p> 298 * 299 * The assumtion is that this key should be the one constructed for the response, 300 * while the parameter key should have been constructed from the request.<p> 301 * 302 * A short example how this works: 303 * If the cache key is "cache=user" and the request is done from a guest user 304 * the constructed variation will be "user=(guest)".<p> 305 * 306 * @param key the key to match this key with 307 * @return null if not cachable, or the Variation String if cachable 308 */ 309 public String matchRequestKey(CmsFlexRequestKey key) { 310 311 StringBuffer str = new StringBuffer(100); 312 if (m_always < 0) { 313 if (LOG.isDebugEnabled()) { 314 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_KEYMATCH_CACHE_NEVER_0)); 315 } 316 return null; 317 } 318 319 if (LOG.isDebugEnabled()) { 320 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_KEYMATCH_CHECK_NO_PARAMS_0)); 321 } 322 if ((m_noparams != null) && (key.getParams() != null)) { 323 if ((m_noparams.size() == 0) && (key.getParams().size() > 0)) { 324 return null; 325 } 326 Iterator<String> i = key.getParams().keySet().iterator(); 327 while (i.hasNext()) { 328 if (m_noparams.contains(i.next())) { 329 return null; 330 } 331 } 332 } 333 334 if (LOG.isDebugEnabled()) { 335 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_KEYMATCH_CHECK_NO_ATTRS_0)); 336 } 337 if ((m_noattrs != null) && (key.getAttributes() != null)) { 338 if ((m_noattrs.size() == 0) && (key.getAttributes().size() > 0)) { 339 return null; 340 } 341 Iterator<String> i = key.getAttributes().keySet().iterator(); 342 while (i.hasNext()) { 343 if (m_noattrs.contains(i.next())) { 344 return null; 345 } 346 } 347 } 348 349 if (m_always > 0) { 350 if (LOG.isDebugEnabled()) { 351 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_KEYMATCH_CACHE_ALWAYS_0)); 352 } 353 str.append(CACHE_00_ALWAYS); 354 return str.toString(); 355 } 356 357 if (m_uri != null) { 358 appendKeyValue(str, CACHE_02_URI, key.getUri()); 359 } 360 361 if (m_site != null) { 362 appendKeyValue(str, CACHE_17_SITE, key.getSite()); 363 } 364 365 if (m_element != null) { 366 appendKeyValue(str, CACHE_14_ELEMENT, key.getElement()); 367 } 368 369 if (m_device != null) { 370 appendKeyValue(str, CACHE_20_DEVICE, key.getDevice()); 371 } 372 373 if (m_containerElement != null) { 374 appendKeyValue(str, CACHE_21_CONTAINER_ELEMENT, key.getContainerElement()); 375 } 376 377 if (m_locale != null) { 378 appendKeyValue(str, CACHE_15_LOCALE, key.getLocale()); 379 } 380 381 if (m_encoding != null) { 382 appendKeyValue(str, CACHE_16_ENCODING, key.getEncoding()); 383 } 384 385 if (m_ip != null) { 386 appendKeyValue(str, CACHE_13_IP, key.getIp()); 387 } 388 389 if (m_user != null) { 390 appendKeyValue(str, CACHE_03_USER, key.getUser()); 391 } 392 393 if (m_params != null) { 394 str.append(CACHE_04_PARAMS); 395 str.append("=("); 396 Map<String, String[]> keyParams = key.getParams(); 397 if (keyParams != null) { 398 if (m_params.size() > 0) { 399 // match only params listed in cache directives 400 Iterator<String> i = m_params.iterator(); 401 while (i.hasNext()) { 402 Object o = i.next(); 403 if (keyParams.containsKey(o)) { 404 str.append(o); 405 str.append("="); 406 // TODO: handle multiple occurrences of the same parameter value 407 String[] values = keyParams.get(o); 408 str.append(values[0]); 409 if (i.hasNext()) { 410 str.append(","); 411 } 412 } 413 } 414 } else { 415 // match all request params 416 Iterator<Map.Entry<String, String[]>> i = keyParams.entrySet().iterator(); 417 while (i.hasNext()) { 418 Map.Entry<String, String[]> entry = i.next(); 419 str.append(entry.getKey()); 420 str.append("="); 421 // TODO: handle multiple occurrences of the same parameter value 422 String[] values = entry.getValue(); 423 str.append(values[0]); 424 if (i.hasNext()) { 425 str.append(","); 426 } 427 } 428 } 429 } 430 str.append(");"); 431 } 432 433 if (m_attrs != null) { 434 str.append(CACHE_18_ATTRS); 435 str.append("=("); 436 Map<String, Object> keyAttrs = key.getAttributes(); 437 if (keyAttrs != null) { 438 if (m_attrs.size() > 0) { 439 // match only attributes listed in cache directives 440 Iterator<String> i = m_attrs.iterator(); 441 while (i.hasNext()) { 442 String s = i.next(); 443 if (keyAttrs.containsKey(s)) { 444 str.append(s); 445 str.append("="); 446 Object value = keyAttrs.get(s); 447 str.append(value); 448 if (i.hasNext()) { 449 str.append(","); 450 } 451 } 452 } 453 } else { 454 // match all request attributes 455 Iterator<Map.Entry<String, Object>> i = keyAttrs.entrySet().iterator(); 456 while (i.hasNext()) { 457 Map.Entry<String, Object> entry = i.next(); 458 str.append(entry.getKey()); 459 str.append("="); 460 Object value = entry.getValue(); 461 str.append(value); 462 if (i.hasNext()) { 463 str.append(","); 464 } 465 } 466 } 467 } 468 str.append(");"); 469 } 470 471 if (m_session != null) { 472 StringBuffer buf = new StringBuffer(32); 473 boolean found = false; 474 buf.append(CACHE_07_SESSION); 475 buf.append("=("); 476 HttpSession keySession = key.getSession(); 477 if (keySession != null) { 478 // match only session attributes listed in cache directives 479 Iterator<String> i = m_session.iterator(); 480 while (i.hasNext()) { 481 String name = i.next(); 482 Object val = keySession.getAttribute(name); 483 if (val != null) { 484 found = true; 485 buf.append(name); 486 buf.append("="); 487 buf.append(val); 488 if (i.hasNext()) { 489 buf.append(","); 490 } 491 } 492 } 493 } 494 if (found) { 495 buf.append(");"); 496 str.append(buf); 497 } 498 } 499 500 if (m_schemes != null) { 501 String s = key.getScheme(); 502 if ((m_schemes.size() > 0) && (!m_schemes.contains(s))) { 503 return null; 504 } 505 appendKeyValue(str, CACHE_08_SCHEMES, s); 506 } 507 508 if (m_ports != null) { 509 Integer i = key.getPort(); 510 if ((m_ports.size() > 0) && (!m_ports.contains(i))) { 511 return null; 512 } 513 str.append(CACHE_09_PORTS); 514 str.append("=("); 515 str.append(i); 516 str.append(");"); 517 } 518 519 if (m_timeout > 0) { 520 str.append(CACHE_06_TIMEOUT); 521 str.append("=("); 522 str.append(m_timeout); 523 str.append(");"); 524 } 525 526 if (str.length() > 0) { 527 return str.toString(); 528 } else { 529 return null; 530 } 531 } 532 533 /** 534 * @see java.lang.Object#toString() 535 * 536 * @return a complete String representation for this key 537 */ 538 @Override 539 public String toString() { 540 541 StringBuffer str = new StringBuffer(100); 542 543 if (m_always < 0) { 544 str.append(CACHE_01_NEVER); 545 if (m_parseError) { 546 str.append(";"); 547 str.append(CACHE_11_PARSE_ERROR); 548 } 549 return str.toString(); 550 } 551 if (m_noparams != null) { 552 // add "no-cachable" parameters 553 str.append(CACHE_05_NO_PARAMS); 554 if (m_noparams.size() == 0) { 555 str.append(";"); 556 } else { 557 str.append("=("); 558 Iterator<String> i = m_noparams.iterator(); 559 while (i.hasNext()) { 560 Object o = i.next(); 561 str.append(o); 562 if (i.hasNext()) { 563 str.append(","); 564 } 565 } 566 str.append(");"); 567 } 568 } 569 if (m_noattrs != null) { 570 // add "no-cachable" attributes 571 str.append(CACHE_19_NO_ATTRS); 572 if (m_noattrs.size() == 0) { 573 str.append(";"); 574 } else { 575 str.append("=("); 576 Iterator<String> i = m_noattrs.iterator(); 577 while (i.hasNext()) { 578 String s = i.next(); 579 str.append(s); 580 if (i.hasNext()) { 581 str.append(","); 582 } 583 } 584 str.append(");"); 585 } 586 } 587 if (m_always > 0) { 588 str.append(CACHE_00_ALWAYS); 589 if (m_parseError) { 590 str.append(";"); 591 str.append(CACHE_11_PARSE_ERROR); 592 } 593 return str.toString(); 594 } 595 if (m_uri != null) { 596 // add uri 597 appendKeyValue(str, CACHE_02_URI, m_uri); 598 } 599 if (m_site != null) { 600 // add site 601 appendKeyValue(str, CACHE_17_SITE, m_site); 602 } 603 if (m_element != null) { 604 // add element 605 appendKeyValue(str, CACHE_14_ELEMENT, m_element); 606 } 607 if (m_device != null) { 608 appendKeyValue(str, CACHE_20_DEVICE, m_device); 609 } 610 if (m_containerElement != null) { 611 appendKeyValue(str, CACHE_21_CONTAINER_ELEMENT, m_containerElement); 612 } 613 if (m_locale != null) { 614 // add locale 615 appendKeyValue(str, CACHE_15_LOCALE, m_locale); 616 } 617 if (m_encoding != null) { 618 // add encoding 619 appendKeyValue(str, CACHE_16_ENCODING, m_encoding); 620 } 621 if (m_ip != null) { 622 // add ip 623 appendKeyValue(str, CACHE_13_IP, m_ip); 624 } 625 if (m_user != null) { 626 // add user 627 appendKeyValue(str, CACHE_03_USER, m_user); 628 } 629 if (m_params != null) { 630 // add parameters 631 str.append(CACHE_04_PARAMS); 632 if (m_params.size() == 0) { 633 str.append(";"); 634 } else { 635 str.append("=("); 636 Iterator<String> i = m_params.iterator(); 637 while (i.hasNext()) { 638 Object o = i.next(); 639 if (I_CmsResourceLoader.PARAMETER_ELEMENT.equals(o)) { 640 continue; 641 } 642 str.append(o); 643 if (i.hasNext()) { 644 str.append(","); 645 } 646 } 647 str.append(");"); 648 } 649 } 650 if (m_attrs != null) { 651 // add attributes 652 str.append(CACHE_18_ATTRS); 653 if (m_attrs.size() == 0) { 654 str.append(";"); 655 } else { 656 str.append("=("); 657 Iterator<String> i = m_attrs.iterator(); 658 while (i.hasNext()) { 659 String s = i.next(); 660 str.append(s); 661 if (i.hasNext()) { 662 str.append(","); 663 } 664 } 665 str.append(");"); 666 } 667 } 668 if (m_session != null) { 669 // add session variables 670 str.append(CACHE_07_SESSION); 671 str.append("=("); 672 Iterator<String> i = m_session.iterator(); 673 while (i.hasNext()) { 674 Object o = i.next(); 675 str.append(o); 676 if (i.hasNext()) { 677 str.append(","); 678 } 679 } 680 str.append(");"); 681 } 682 if (m_timeout >= 0) { 683 // add timeout 684 str.append(CACHE_06_TIMEOUT); 685 str.append("=("); 686 str.append(m_timeout); 687 str.append(");"); 688 } 689 if (m_schemes != null) { 690 // add schemes 691 str.append(CACHE_08_SCHEMES); 692 if (m_schemes.size() == 0) { 693 str.append(";"); 694 } else { 695 str.append("=("); 696 Iterator<String> i = m_schemes.iterator(); 697 while (i.hasNext()) { 698 str.append(i.next()); 699 if (i.hasNext()) { 700 str.append(","); 701 } 702 } 703 str.append(");"); 704 } 705 } 706 if (m_ports != null) { 707 // add ports 708 str.append(CACHE_09_PORTS); 709 if (m_ports.size() == 0) { 710 str.append(";"); 711 } else { 712 str.append("=("); 713 Iterator<Integer> i = m_ports.iterator(); 714 while (i.hasNext()) { 715 str.append(i.next()); 716 if (i.hasNext()) { 717 str.append(","); 718 } 719 } 720 str.append(");"); 721 } 722 } 723 724 if (m_parseError) { 725 str.append(CACHE_11_PARSE_ERROR); 726 } 727 return str.toString(); 728 } 729 730 /** 731 * Returns the resource.<p> 732 * 733 * @return the resource 734 */ 735 protected String getResource() { 736 737 return m_resource; 738 } 739 740 /** 741 * Returns the timeout.<p> 742 * 743 * @return the timeout 744 */ 745 protected long getTimeout() { 746 747 return m_timeout; 748 } 749 750 /** 751 * Returns the variation.<p> 752 * 753 * @return the variation 754 */ 755 protected String getVariation() { 756 757 return m_variation; 758 } 759 760 /** 761 * Sets the variation.<p> 762 * 763 * @param variation the variation to set 764 */ 765 protected void setVariation(String variation) { 766 767 m_variation = variation; 768 } 769 770 /** 771 * Parse a String in the Flex cache language and construct 772 * the key data structure from this.<p> 773 * 774 * @param key the String to parse (usually read from the file property "cache") 775 */ 776 private void parseFlexKey(String key) { 777 778 List<String> tokens = CmsStringUtil.splitAsList(key, ';', false); 779 Iterator<String> i = tokens.iterator(); 780 try { 781 while (i.hasNext()) { 782 String t = i.next(); 783 String k = null; 784 String v = null; 785 int idx = t.indexOf('='); 786 if (idx >= 0) { 787 k = t.substring(0, idx).trim(); 788 if (t.length() > idx) { 789 v = t.substring(idx + 1).trim(); 790 } 791 } else { 792 k = t.trim(); 793 } 794 m_always = 0; 795 if (LOG.isDebugEnabled()) { 796 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_PARSE_FLEXKEY_3, t, k, v)); 797 } 798 switch (CACHE_COMMANDS.indexOf(k)) { 799 case 0: // always 800 case 12: // true 801 m_always = 1; 802 // continue processing (make sure we find a "never" behind "always") 803 break; 804 case 1: // never 805 case 10: // false 806 m_always = -1; 807 // no need for any further processing 808 return; 809 case 2: // uri 810 m_uri = IS_USED; // marks m_uri as being used 811 break; 812 case 3: // user 813 m_user = IS_USED; // marks m_user as being used 814 break; 815 case 4: // params 816 if (v != null) { 817 m_params = parseValueList(v); 818 } else { 819 m_params = Collections.emptySet(); 820 } 821 822 if (m_params.contains(I_CmsResourceLoader.PARAMETER_ELEMENT)) { 823 // workaround for element setting by parameter in OpenCms < 6.0 824 m_element = IS_USED; 825 m_params.remove(I_CmsResourceLoader.PARAMETER_ELEMENT); 826 if (m_params.size() == 0) { 827 m_params = null; 828 } 829 } 830 break; 831 case 5: // no-params 832 if (v != null) { 833 // no-params are present 834 m_noparams = parseValueList(v); 835 } else { 836 // never cache with parameters 837 m_noparams = Collections.emptySet(); 838 } 839 break; 840 case 6: // timeout 841 m_timeout = Integer.parseInt(v); 842 break; 843 case 7: // session 844 m_session = parseValueList(v); 845 if (m_session.size() <= 0) { 846 // session must have at last one variable set 847 m_parseError = true; 848 } 849 break; 850 case 8: // schemes 851 m_schemes = parseValueList(v); 852 break; 853 case 9: // ports 854 Set<String> ports = parseValueList(v); 855 m_ports = new HashSet<Integer>(ports.size()); 856 for (String p : ports) { 857 try { 858 m_ports.add(Integer.valueOf(p)); 859 } catch (NumberFormatException e) { 860 // ignore this number 861 } 862 } 863 break; 864 case 11: // previous parse error - ignore 865 break; 866 case 13: // ip 867 m_ip = IS_USED; // marks ip as being used 868 break; 869 case 14: // element 870 m_element = IS_USED; 871 break; 872 case 15: // locale 873 m_locale = IS_USED; 874 break; 875 case 16: // encoding 876 m_encoding = IS_USED; 877 break; 878 case 17: // site 879 m_site = IS_USED; 880 break; 881 case 18: // attrs 882 if (v != null) { 883 m_attrs = parseValueList(v); 884 } else { 885 m_attrs = null; 886 } 887 break; 888 case 19: // no-attrs 889 if (v != null) { 890 // no-attrs are present 891 m_noattrs = parseValueList(v); 892 } else { 893 // never cache with attributes 894 m_noattrs = Collections.emptySet(); 895 } 896 break; 897 case 20: // device 898 m_device = IS_USED; // marks m_device as being used 899 break; 900 case 21: // container element 901 m_containerElement = IS_USED; 902 break; 903 default: // unknown directive, throw error 904 m_parseError = true; 905 } 906 } 907 } catch (Exception e) { 908 // any Exception here indicates a parsing error 909 if (LOG.isErrorEnabled()) { 910 LOG.error(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_PARSE_ERROR_1, e.toString()), e); 911 } 912 m_parseError = true; 913 } 914 if (m_parseError) { 915 // If string is invalid set cache to "never" 916 m_always = -1; 917 } 918 } 919 920 /** 921 * A helper method for the parsing process which parses 922 * Strings like groups=(a, b, c).<p> 923 * 924 * @param value the String to parse 925 * @return a Map that contains of the parsed values, only the keyset of the Map is needed later 926 */ 927 private Set<String> parseValueList(String value) { 928 929 if (value.charAt(0) == '(') { 930 value = value.substring(1); 931 } 932 int len = value.length() - 1; 933 if (value.charAt(len) == ')') { 934 value = value.substring(0, len); 935 } 936 if (value.charAt(len - 1) == ',') { 937 value = value.substring(0, len - 1); 938 } 939 if (LOG.isDebugEnabled()) { 940 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXCACHEKEY_PARSE_VALUES_1, value)); 941 } 942 List<String> tokens = CmsStringUtil.splitAsList(value, ',', true); 943 Set<String> result = new HashSet<String>(); 944 result.addAll(tokens); 945 return result; 946 } 947}