001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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 & Co. KG, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.file.CmsObject; 031import org.opencms.file.history.CmsHistoryResourceHandler; 032import org.opencms.jsp.util.CmsJspStandardContextBean; 033import org.opencms.loader.CmsJspLoader; 034import org.opencms.main.CmsEvent; 035import org.opencms.main.CmsLog; 036import org.opencms.main.I_CmsEventListener; 037import org.opencms.main.OpenCms; 038import org.opencms.security.CmsRole; 039import org.opencms.staticexport.CmsLinkManager; 040import org.opencms.util.CmsParameterEscaper; 041import org.opencms.util.CmsRequestUtil; 042 043import java.util.Arrays; 044import java.util.Collections; 045import java.util.Enumeration; 046import java.util.HashMap; 047import java.util.Iterator; 048import java.util.List; 049import java.util.Map; 050import java.util.Set; 051import java.util.Vector; 052 053import org.apache.commons.logging.Log; 054 055import com.google.common.collect.Sets; 056 057import jakarta.servlet.ServletRequest; 058import jakarta.servlet.http.HttpServletRequest; 059import jakarta.servlet.http.HttpServletRequestWrapper; 060 061/** 062 * Wrapper class for a HttpServletRequest.<p> 063 * 064 * This class wraps the standard HttpServletRequest so that it's output can be delivered to 065 * the CmsFlexCache.<p> 066 * 067 * @since 6.0.0 068 */ 069public class CmsFlexRequest extends HttpServletRequestWrapper { 070 071 /** Request parameter for FlexCache commands. */ 072 public static final String PARAMETER_FLEX = "_flex"; 073 074 /** The log object for this class. */ 075 private static final Log LOG = CmsLog.getLog(CmsFlexRequest.class); 076 077 /** JSP Loader instance. */ 078 private static CmsJspLoader m_jspLoader; 079 080 /** The max allowed recursive include number.*/ 081 private static final int MAX_INCLUDE_RECURSION = 7; 082 083 /** Map of attributes from the original request. */ 084 private Map<String, Object> m_attributes; 085 086 /** Flag to decide if this request can be cached or not. */ 087 private boolean m_canCache; 088 089 /** The CmsFlexController for this request. */ 090 private CmsFlexController m_controller; 091 092 /** Flag to force a JSP recompile. */ 093 private boolean m_doRecompile; 094 095 /** The requested resources element URI in the OpenCms VFS. */ 096 private String m_elementUri; 097 098 /** The site root of the requested resource. */ 099 private String m_elementUriSiteRoot; 100 101 /** The parameter escaper. */ 102 private CmsParameterEscaper m_escaper; 103 104 /** List of all include calls (to prevent an endless inclusion loop). */ 105 private List<String> m_includeCalls; 106 107 /** Flag to check if this request is in the online project or not. */ 108 private boolean m_isOnline; 109 110 /** The CmsFlexRequestKey for this request. */ 111 private CmsFlexRequestKey m_key; 112 113 /** Map of parameters from the original request. */ 114 private Map<String, String[]> m_parameters; 115 116 /** Stores the request URI after it was once calculated. */ 117 private String m_requestUri; 118 119 /** Stores the request URL after it was once calculated. */ 120 private StringBuffer m_requestUrl; 121 122 /** A set of keys of parameters which should be stored in a cached include even if they were not passed as additional parameters to the include call. */ 123 private Set<String> m_dynamicParameters = Sets.newHashSet(); 124 125 /** 126 * Creates a new CmsFlexRequest wrapper which is most likely the "Top" 127 * request wrapper, i.e. the wrapper that is constructed around the 128 * first "real" (not wrapped) request.<p> 129 * 130 * @param req the request to wrap 131 * @param controller the controller to use 132 */ 133 public CmsFlexRequest(HttpServletRequest req, CmsFlexController controller) { 134 135 super(req); 136 m_controller = controller; 137 CmsObject cms = m_controller.getCmsObject(); 138 m_elementUri = cms.getSitePath(m_controller.getCmsResource()); 139 m_elementUriSiteRoot = cms.getRequestContext().getSiteRoot(); 140 m_includeCalls = new Vector<String>(); 141 m_parameters = CmsRequestUtil.getParameterMap(req); 142 m_attributes = CmsRequestUtil.getAtrributeMap(req); 143 m_isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject(); 144 String[] params = req.getParameterValues(PARAMETER_FLEX); 145 boolean nocachepara = CmsHistoryResourceHandler.isHistoryRequest(req); 146 boolean dorecompile = false; 147 if (params != null) { 148 if (OpenCms.getRoleManager().hasRole(cms, CmsRole.WORKPLACE_MANAGER)) { 149 List<String> paramList = Arrays.asList(params); 150 boolean firstCall = controller.isEmptyRequestList(); 151 nocachepara |= paramList.contains("nocache"); 152 dorecompile = paramList.contains("recompile"); 153 boolean p_on = paramList.contains("online"); 154 boolean p_off = paramList.contains("offline"); 155 if (paramList.contains("purge") && firstCall) { 156 OpenCms.fireCmsEvent( 157 new CmsEvent( 158 I_CmsEventListener.EVENT_FLEX_PURGE_JSP_REPOSITORY, 159 new HashMap<String, Object>(0))); 160 OpenCms.fireCmsEvent( 161 new CmsEvent( 162 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 163 Collections.<String, Object> singletonMap( 164 "action", 165 Integer.valueOf(CmsFlexCache.CLEAR_ENTRIES)))); 166 dorecompile = false; 167 } else if ((paramList.contains("clearcache") || dorecompile) && firstCall) { 168 if (!(p_on || p_off)) { 169 OpenCms.fireCmsEvent( 170 new CmsEvent( 171 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 172 Collections.<String, Object> singletonMap( 173 "action", 174 Integer.valueOf(CmsFlexCache.CLEAR_ALL)))); 175 } else { 176 if (p_on) { 177 OpenCms.fireCmsEvent( 178 new CmsEvent( 179 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 180 Collections.<String, Object> singletonMap( 181 "action", 182 Integer.valueOf(CmsFlexCache.CLEAR_ONLINE_ALL)))); 183 } 184 if (p_off) { 185 OpenCms.fireCmsEvent( 186 new CmsEvent( 187 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 188 Collections.<String, Object> singletonMap( 189 "action", 190 Integer.valueOf(CmsFlexCache.CLEAR_OFFLINE_ALL)))); 191 } 192 } 193 } else if (paramList.contains("clearvariations") && firstCall) { 194 if (!(p_on || p_off)) { 195 OpenCms.fireCmsEvent( 196 new CmsEvent( 197 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 198 Collections.<String, Object> singletonMap( 199 "action", 200 Integer.valueOf(CmsFlexCache.CLEAR_ENTRIES)))); 201 } else { 202 if (p_on) { 203 OpenCms.fireCmsEvent( 204 new CmsEvent( 205 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 206 Collections.<String, Object> singletonMap( 207 "action", 208 Integer.valueOf(CmsFlexCache.CLEAR_ONLINE_ENTRIES)))); 209 } 210 if (p_off) { 211 OpenCms.fireCmsEvent( 212 new CmsEvent( 213 I_CmsEventListener.EVENT_FLEX_CACHE_CLEAR, 214 Collections.<String, Object> singletonMap( 215 "action", 216 Integer.valueOf(CmsFlexCache.CLEAR_OFFLINE_ENTRIES)))); 217 } 218 } 219 } 220 } 221 } 222 m_canCache = ((((m_isOnline && m_controller.getCmsCache().isEnabled()) 223 || (!m_isOnline && m_controller.getCmsCache().cacheOffline())) && !nocachepara) || dorecompile); 224 m_doRecompile = dorecompile; 225 if (LOG.isDebugEnabled()) { 226 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXREQUEST_CREATED_NEW_REQUEST_1, m_elementUri)); 227 } 228 } 229 230 /** 231 * Constructs a new wrapper layer around an (already wrapped) CmsFlexRequest.<p> 232 * 233 * @param req the request to be wrapped 234 * @param controller the controller to use 235 * @param resource the target resource that has been requested 236 */ 237 CmsFlexRequest(HttpServletRequest req, CmsFlexController controller, String resource) { 238 239 super(req); 240 m_controller = controller; 241 m_elementUri = CmsLinkManager.getAbsoluteUri(resource, m_controller.getCurrentRequest().getElementUri()); 242 m_elementUriSiteRoot = m_controller.getCurrentRequest().m_elementUriSiteRoot; 243 m_isOnline = m_controller.getCurrentRequest().isOnline(); 244 m_canCache = m_controller.getCurrentRequest().isCacheable(); 245 m_doRecompile = m_controller.getCurrentRequest().isDoRecompile(); 246 m_includeCalls = m_controller.getCurrentRequest().getCmsIncludeCalls(); 247 m_parameters = CmsRequestUtil.getParameterMap(req); 248 m_attributes = CmsRequestUtil.getAtrributeMap(req); 249 if (LOG.isDebugEnabled()) { 250 LOG.debug(Messages.get().getBundle().key(Messages.LOG_FLEXREQUEST_REUSING_FLEX_REQUEST_1, m_elementUri)); 251 } 252 } 253 254 /** 255 * Adds the specified Map to the attributes of the request, 256 * added attributes will not overwrite existing attributes in the 257 * request.<p> 258 * 259 * @param map the map to add 260 * 261 * @return the merged map of attributes 262 */ 263 public Map<String, Object> addAttributeMap(Map<String, Object> map) { 264 265 if (map == null) { 266 return m_attributes; 267 } 268 if ((m_attributes == null) || (m_attributes.size() == 0)) { 269 m_attributes = new HashMap<String, Object>(map); 270 } else { 271 Map<String, Object> attributes = new HashMap<String, Object>(); 272 attributes.putAll(m_attributes); 273 Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); 274 while (it.hasNext()) { 275 Map.Entry<String, Object> entry = it.next(); 276 String key = entry.getKey(); 277 // prevent flexcache controller to be overwritten 278 if (CmsFlexController.ATTRIBUTE_NAME.equals(key)) { 279 continue; 280 } else if (CmsJspStandardContextBean.ATTRIBUTE_NAME.equals(key)) { 281 CmsJspStandardContextBean bean = (CmsJspStandardContextBean)entry.getValue(); 282 bean.updateCmsObject(m_controller.getCmsObject()); 283 bean.updateRequestData(this); 284 } 285 attributes.put(key, entry.getValue()); 286 } 287 m_attributes = new HashMap<String, Object>(attributes); 288 } 289 290 return m_attributes; 291 } 292 293 /** 294 * Adds the specified Map to the parameters of the request, 295 * added parameters will not overwrite existing parameters in the 296 * request.<p> 297 * 298 * Remember that the value for a parameter name in 299 * a HttpRequest is a String array. If a parameter name already 300 * exists in the HttpRequest, the values will be added to the existing 301 * value array. Multiple occurrences of the same value for one 302 * parameter are also possible.<p> 303 * 304 * @param map the map to add 305 * 306 * @return the merged map of parameters 307 */ 308 public Map<String, String[]> addParameterMap(Map<String, String[]> map) { 309 310 if (map == null) { 311 return m_parameters; 312 } 313 if ((m_parameters == null) || (m_parameters.size() == 0)) { 314 m_parameters = Collections.unmodifiableMap(map); 315 } else { 316 Map<String, String[]> parameters = new HashMap<String, String[]>(); 317 parameters.putAll(m_parameters); 318 319 Iterator<Map.Entry<String, String[]>> it = map.entrySet().iterator(); 320 while (it.hasNext()) { 321 Map.Entry<String, String[]> entry = it.next(); 322 String key = entry.getKey(); 323 // Check if the parameter name (key) exists 324 if (parameters.containsKey(key)) { 325 326 String[] oldValues = parameters.get(key); 327 String[] newValues = entry.getValue(); 328 329 String[] mergeValues = new String[oldValues.length + newValues.length]; 330 System.arraycopy(newValues, 0, mergeValues, 0, newValues.length); 331 System.arraycopy(oldValues, 0, mergeValues, newValues.length, oldValues.length); 332 333 parameters.put(key, mergeValues); 334 } else { 335 // No: Add new value array 336 parameters.put(key, entry.getValue()); 337 } 338 } 339 m_parameters = Collections.unmodifiableMap(parameters); 340 } 341 342 return m_parameters; 343 } 344 345 /** 346 * Enables escaping for all parameters which are not in the list of exceptions.<p> 347 */ 348 public void enableParameterEscaping() { 349 350 if (m_escaper == null) { 351 LOG.info("Enabling parameter escaping for the current flex request"); 352 m_escaper = new CmsParameterEscaper(); 353 } 354 } 355 356 /** 357 * Return the value of the specified request attribute, if any; otherwise, 358 * return <code>null</code>.<p> 359 * 360 * @param name the name of the desired request attribute 361 * 362 * @return the value of the specified request attribute 363 * 364 * @see jakarta.servlet.ServletRequest#getAttribute(java.lang.String) 365 */ 366 @Override 367 public Object getAttribute(String name) { 368 369 Object object = m_attributes.get(name); 370 if (object == null) { 371 object = super.getAttribute(name); 372 } 373 return object; 374 } 375 376 /** 377 * Returns a <code>Map</code> of the attributes of this request.<p> 378 * 379 * @return a <code>Map</code> containing attribute names as keys 380 * and attribute values as map values 381 */ 382 public Map<String, Object> getAttributeMap() { 383 384 return m_attributes; 385 } 386 387 /** 388 * Return the names of all defined request attributes for this request.<p> 389 * 390 * @return the names of all defined request attributes for this request 391 * 392 * @see jakarta.servlet.ServletRequest#getAttributeNames 393 */ 394 @Override 395 public Enumeration<String> getAttributeNames() { 396 397 Vector<String> v = new Vector<String>(); 398 v.addAll(m_attributes.keySet()); 399 return v.elements(); 400 } 401 402 /** 403 * Gets the set of dynamic parameters.<p> 404 * 405 * Normally, when caching a JSP which includes another JSP, only the parameters given directly to the include call will be cached in the new flex cache entry's include list. 406 * But when the include call happens implicitly (e.g. for elements rendered in a cms:container tag), we can't pass it any parameters. In this case, we have to modify the parameter 407 * map of the current flex request in the JSP, and the keys for the modified parameters need to be stored in this set for the Flex cache to work correctly. 408 * 409 * @return the set of keys for the dynamic parameters 410 */ 411 public Set<String> getDynamicParameters() { 412 413 return m_dynamicParameters; 414 } 415 416 /** 417 * Returns the full element URI site root path to the resource currently processed.<p> 418 * 419 * @return the name of the resource currently processed 420 */ 421 public String getElementRootPath() { 422 423 return m_controller.getCmsObject().getRequestContext().addSiteRoot(m_elementUriSiteRoot, m_elementUri); 424 } 425 426 /** 427 * Returns the element URI of the resource currently processed, 428 * relative to the current site root.<p> 429 * 430 * This might be the name of an included resource, 431 * not necessarily the name the resource requested by the user.<p> 432 * 433 * @return the name of the resource currently processed 434 */ 435 public String getElementUri() { 436 437 return m_elementUri; 438 } 439 440 /** 441 * Return the value of the specified request parameter, if any; otherwise, 442 * return <code>null</code>.<p> 443 * 444 * If there is more than one value defined, 445 * return only the first one.<p> 446 * 447 * @param name the name of the desired request parameter 448 * 449 * @return the value of the specified request parameter 450 * 451 * @see jakarta.servlet.ServletRequest#getParameter(java.lang.String) 452 */ 453 @Override 454 public String getParameter(String name) { 455 456 String[] values = m_parameters.get(name); 457 if (values != null) { 458 if (m_escaper != null) { 459 return m_escaper.escape(name, values[0]); 460 } else { 461 return (values[0]); 462 } 463 } else { 464 return (null); 465 } 466 } 467 468 /** 469 * Gets the parameter escaper.<p> 470 * 471 * @return the parameter escaper 472 */ 473 public CmsParameterEscaper getParameterEscaper() { 474 475 return m_escaper; 476 } 477 478 /** 479 * Returns a <code>Map</code> of the parameters of this request.<p> 480 * 481 * Request parameters are extra information sent with the request. 482 * For HTTP servlets, parameters are contained in the query string 483 * or posted form data.<p> 484 * 485 * @return a <code>Map</code> containing parameter names as keys 486 * and parameter values as map values 487 * 488 * @see jakarta.servlet.ServletRequest#getParameterMap() 489 */ 490 @Override 491 public Map<String, String[]> getParameterMap() { 492 493 // NOTE: The parameters in this map are not escaped, so when escaping is enabled, 494 // its values may be different from those obtained via getParameter/getParameterValues 495 return m_parameters; 496 } 497 498 /** 499 * Return the names of all defined request parameters for this request.<p> 500 * 501 * @return the names of all defined request parameters for this request 502 * 503 * @see jakarta.servlet.ServletRequest#getParameterNames() 504 */ 505 @Override 506 public Enumeration<String> getParameterNames() { 507 508 Vector<String> v = new Vector<String>(); 509 v.addAll(m_parameters.keySet()); 510 return (v.elements()); 511 } 512 513 /** 514 * Returns the defined values for the specified request parameter, if any; 515 * otherwise, return <code>null</code>.<p> 516 * 517 * @param name Name of the desired request parameter 518 * 519 * @return the defined values for the specified request parameter, if any; 520 * <code>null</code> otherwise 521 * 522 * @see jakarta.servlet.ServletRequest#getParameterValues(java.lang.String) 523 */ 524 @Override 525 public String[] getParameterValues(String name) { 526 527 if (m_escaper != null) { 528 return m_escaper.escape(name, m_parameters.get(name)); 529 } else { 530 return m_parameters.get(name); 531 } 532 } 533 534 /** 535 * Allows requests to be dispatched to internal VFS resources or 536 * external JSP pages, overloads the standard servlet API <code>getRequestDispatcher()</code> method.<p> 537 * 538 * @param target the target for the request dispatcher 539 * 540 * @return a special RequestDispatcher that allows access to VFS resources 541 */ 542 @Override 543 public jakarta.servlet.RequestDispatcher getRequestDispatcher(String target) { 544 545 String absolutUri = CmsLinkManager.getAbsoluteUri(target, m_controller.getCurrentRequest().getElementUri()); 546 return new CmsFlexRequestDispatcher( 547 m_controller.getTopRequest().getRequestDispatcher(absolutUri), 548 absolutUri, 549 null); 550 } 551 552 /** 553 * Replacement for the standard servlet API getRequestDispatcher() method.<p> 554 * 555 * This variation is used if an external file (probably JSP) is dispatched to. 556 * This external file must have a "mirror" version, i.e. a file in the OpenCms VFS 557 * that represents the external file.<p> 558 * 559 * @param vfs_target the OpenCms file that is a "mirror" version of the external file 560 * @param ext_target the external file (outside the OpenCms VFS) 561 * 562 * @return the constructed CmsFlexRequestDispatcher 563 */ 564 public CmsFlexRequestDispatcher getRequestDispatcherToExternal(String vfs_target, String ext_target) { 565 566 return new CmsFlexRequestDispatcher( 567 m_controller.getTopRequest().getRequestDispatcher(ext_target), 568 CmsLinkManager.getAbsoluteUri(vfs_target, m_controller.getCmsObject().getRequestContext().getUri()), 569 ext_target); 570 } 571 572 /** 573 * Wraps the request URI, overloading the standard API.<p> 574 * 575 * This ensures that any wrapped request will use the "faked" 576 * target parameters. Remember that for the real request, 577 * a mixture of PathInfo and other request information is used to 578 * identify the target.<p> 579 * 580 * @return a faked URI that will point to the wrapped target in the VFS 581 * 582 * @see jakarta.servlet.http.HttpServletRequest#getRequestURI() 583 */ 584 @Override 585 public String getRequestURI() { 586 587 if (m_requestUri != null) { 588 return m_requestUri; 589 } 590 StringBuffer buf = new StringBuffer(128); 591 buf.append(OpenCms.getSystemInfo().getOpenCmsContext()); 592 buf.append(getElementUri()); 593 m_requestUri = buf.toString(); 594 return m_requestUri; 595 } 596 597 /** 598 * Wraps the request URL, overloading the standard API, 599 * the wrapped URL will always point to the currently included VFS resource.<p> 600 * 601 * @return a faked URL that will point to the included target in the VFS 602 * 603 * @see jakarta.servlet.http.HttpServletRequest#getRequestURL() 604 */ 605 @Override 606 public StringBuffer getRequestURL() { 607 608 if (m_requestUrl != null) { 609 return m_requestUrl; 610 } 611 StringBuffer buf = new StringBuffer(128); 612 buf.append(getScheme()); 613 buf.append("://"); 614 buf.append(getServerName()); 615 buf.append(":"); 616 buf.append(getServerPort()); 617 buf.append(getRequestURI()); 618 m_requestUrl = buf; 619 return m_requestUrl; 620 } 621 622 /** 623 * This is a work around for servlet containers creating a new application dispatcher 624 * instead of using our request dispatcher, so missing RFS JSP pages are not requested to 625 * OpenCms and the dispatcher is unable to load the included/forwarded JSP file.<p> 626 * 627 * @see jakarta.servlet.http.HttpServletRequestWrapper#getServletPath() 628 */ 629 @Override 630 public String getServletPath() { 631 632 // unwrap the request to prevent multiple unneeded attempts to generate missing JSP files 633 // m_controller.getTopRequest() does not return the right request here when forwarding 634 // this method is generally called exactly once per request on different servlet containers 635 // only resin calls it twice 636 ServletRequest req = getRequest(); 637 while (req instanceof CmsFlexRequest) { 638 req = ((CmsFlexRequest)req).getRequest(); 639 } 640 String servletPath = null; 641 if (req instanceof HttpServletRequest) { 642 servletPath = ((HttpServletRequest)req).getServletPath(); 643 } else { 644 servletPath = super.getServletPath(); 645 } 646 // generate missing JSP file 647 CmsJspLoader jspLoader = getJspLoader(); 648 if (jspLoader != null) { 649 jspLoader.updateJspFromRequest(servletPath, this); 650 } 651 return servletPath; 652 } 653 654 /** 655 * Checks if JSPs should always be recompiled.<p> 656 * 657 * This is useful in case directive based includes are used 658 * with <%@ include file="..." %> on a JSP. 659 * Note that this also forces the request not to be cached.<p> 660 * 661 * @return true if JSPs should be recompiled, false otherwise 662 */ 663 public boolean isDoRecompile() { 664 665 return m_doRecompile; 666 } 667 668 /** 669 * Indicates that this request belongs to an online project.<p> 670 * 671 * This is required to distinguish between online and offline 672 * resources in the cache. Since the resources have the same name, 673 * a suffix [online] or [offline] is added to distinguish the strings 674 * when building cache keys. 675 * Any resource from a request that isOnline() will be saved with 676 * the [online] suffix and vice versa.<p> 677 * 678 * Resources in the OpenCms workplace are not distinguished between 679 * online and offline but have their own suffix [workplace]. 680 * The assumption is that if you do change the workplace, this is 681 * only on true development machines so you can do the cache clearing 682 * manually if required.<p> 683 * 684 * The suffixes are used so that we have a simple String name 685 * for the resources in the cache. This makes it easy to 686 * use a standard HashMap for storage of the resources.<p> 687 * 688 * @return true if an online resource was requested, false otherwise 689 */ 690 public boolean isOnline() { 691 692 return m_isOnline; 693 } 694 695 /** 696 * @see jakarta.servlet.ServletRequestWrapper#removeAttribute(java.lang.String) 697 */ 698 @Override 699 public void removeAttribute(String name) { 700 701 m_attributes.remove(name); 702 m_controller.getTopRequest().removeAttribute(name); 703 } 704 705 /** 706 * @see jakarta.servlet.ServletRequestWrapper#setAttribute(java.lang.String, java.lang.Object) 707 */ 708 @Override 709 public void setAttribute(String name, Object value) { 710 711 m_attributes.put(name, value); 712 m_controller.getTopRequest().setAttribute(name, value); 713 } 714 715 /** 716 * Sets the specified Map as attribute map of the request.<p> 717 * 718 * The map should be immutable. 719 * This will completely replace the attribute map. 720 * Use this in combination with {@link #getAttributeMap()} and 721 * {@link #addAttributeMap(Map)} in case you want to set the old status 722 * of the attribute map after you have modified it for 723 * a specific operation.<p> 724 * 725 * @param map the map to set 726 */ 727 public void setAttributeMap(Map<String, Object> map) { 728 729 m_attributes = new HashMap<String, Object>(map); 730 } 731 732 /** 733 * Sets the set of dynamic parameters.<p> 734 * 735 * @param dynamicParams the set of dynamic parameters 736 */ 737 public void setDynamicParameters(Set<String> dynamicParams) { 738 739 if (dynamicParams == null) { 740 dynamicParams = Sets.newHashSet(); 741 } 742 m_dynamicParameters = dynamicParams; 743 } 744 745 /** 746 * Sets the specified Map as parameter map of the request.<p> 747 * 748 * The map should be immutable. 749 * This will completely replace the parameter map. 750 * Use this in combination with {@link #getParameterMap()} and 751 * {@link #addParameterMap(Map)} in case you want to set the old status 752 * of the parameter map after you have modified it for 753 * a specific operation.<p> 754 * 755 * @param map the map to set 756 */ 757 public void setParameterMap(Map<String, String[]> map) { 758 759 m_parameters = map; 760 } 761 762 /** 763 * @see java.lang.Object#toString() 764 */ 765 @Override 766 public String toString() { 767 768 // return the uri of the element requested for this request, useful in debugging 769 return m_elementUri; 770 } 771 772 /** 773 * Returns the List of include calls which will be passed to the next wrapping layer.<p> 774 * 775 * The set of include calls is maintained to detect 776 * an endless inclusion loop.<p> 777 * 778 * @return the List of include calls 779 */ 780 protected List<String> getCmsIncludeCalls() { 781 782 return m_includeCalls; 783 } 784 785 /** 786 * Returns the jsp loader instance.<p> 787 * 788 * @return the jsp loader instance 789 */ 790 protected CmsJspLoader getJspLoader() { 791 792 if (m_jspLoader == null) { 793 try { 794 m_jspLoader = (CmsJspLoader)OpenCms.getResourceManager().getLoader(CmsJspLoader.RESOURCE_LOADER_ID); 795 } catch (ArrayIndexOutOfBoundsException e) { 796 // ignore, loader not configured 797 } 798 } 799 return m_jspLoader; 800 } 801 802 /** 803 * Adds another include call to this wrapper.<p> 804 * 805 * The set of include calls is maintained to detect 806 * an endless inclusion loop.<p> 807 * 808 * @param target the target name (absolute OpenCms URI) to add 809 */ 810 void addInlucdeCall(String target) { 811 812 m_includeCalls.add(target); 813 } 814 815 /** 816 * Checks if a given target has been included earlier and exceeds the max allowed recursions.<p> 817 * 818 * The set of include calls is maintained to detect 819 * an endless inclusion loop.<p> 820 * 821 * @param target the target name (absolute OpenCms URI) to check for 822 * @return true if the target is already included, false otherwise 823 */ 824 boolean exceedsCallLimit(String target) { 825 826 if (m_includeCalls.contains(target)) { 827 int count = 0; 828 for (String call : m_includeCalls) { 829 if (call.equals(target)) { 830 count++; 831 if (count > MAX_INCLUDE_RECURSION) { 832 return true; 833 } 834 } 835 } 836 } 837 return false; 838 } 839 840 /** 841 * Returns the CmsFlexCacheKey for this request, 842 * the key will be calculated if necessary.<p> 843 * 844 * @return the CmsFlexCacheKey for this request 845 */ 846 CmsFlexRequestKey getCmsCacheKey() { 847 848 // The key for this request is only calculated if actually requested 849 if (m_key == null) { 850 m_key = new CmsFlexRequestKey(this, m_elementUri, m_isOnline); 851 } 852 return m_key; 853 } 854 855 /** 856 * This is needed to decide if this request can be cached or not.<p> 857 * 858 * Using the request to decide if caching is used or not 859 * makes it possible to set caching to false e.g. on a per-user 860 * or per-project basis.<p> 861 * 862 * @return <code>true</code> if the request is cacheable, false otherwise 863 */ 864 boolean isCacheable() { 865 866 return m_canCache; 867 } 868 869 /** 870 * Removes an include call from this wrapper.<p> 871 * 872 * The set of include calls is maintained to detect 873 * an endless inclusion loop.<p> 874 * 875 * @param target the target name (absolute OpenCms URI) to remove 876 */ 877 void removeIncludeCall(String target) { 878 879 m_includeCalls.remove(target); 880 } 881}