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