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