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