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.file; 029 030import org.opencms.gwt.shared.CmsGwtConstants; 031import org.opencms.main.CmsIllegalArgumentException; 032import org.opencms.main.OpenCms; 033import org.opencms.security.CmsOrganizationalUnit; 034import org.opencms.site.CmsSiteMatcher; 035import org.opencms.util.CmsResourceTranslator; 036import org.opencms.util.CmsUUID; 037import org.opencms.workplace.CmsWorkplace; 038 039import java.util.Hashtable; 040import java.util.Locale; 041import java.util.Map; 042 043/** 044 * Stores the information about the current users OpenCms context, 045 * for example the requested URI, the current project, the selected site and more.<p> 046 * 047 * @since 6.0.0 048 */ 049public final class CmsRequestContext { 050 051 /** Request context attribute for the ADE context path (should be a root path). */ 052 public static final String ATTRIBUTE_ADE_CONTEXT_PATH = CmsRequestContext.class.getName() + ".ADE_CONTEXT_PATH"; 053 054 /** Request context attribute for indicating that an editor is currently open. */ 055 public static final String ATTRIBUTE_EDITOR = CmsRequestContext.class.getName() + ".ATTRIBUTE_EDITOR"; 056 057 /** Request context attribute for indicating we want full links generated for HTML fields. */ 058 public static final String ATTRIBUTE_FULLLINKS = CmsRequestContext.class.getName() + ".ATTRIBUTE_FULLLINKS"; 059 060 /** Request context attribute for indicating the model file for a create resource operation. */ 061 public static final String ATTRIBUTE_MODEL = CmsRequestContext.class.getName() + ".ATTRIBUTE_MODEL"; 062 063 /** Request context attribute for indicating content locale for a create resource operation. */ 064 public static final String ATTRIBUTE_NEW_RESOURCE_LOCALE = CmsRequestContext.class.getName() 065 + ".NEW_RESOURCE_LOCALE"; 066 067 /** A map for storing (optional) request context attributes. */ 068 private Map<String, Object> m_attributeMap; 069 070 /** The current project. */ 071 private CmsProject m_currentProject; 072 073 /** The detail content resource (possibly null). */ 074 private CmsResource m_detailResource; 075 076 /** Directory name translator. */ 077 private CmsResourceTranslator m_directoryTranslator; 078 079 /** Current encoding. */ 080 private String m_encoding; 081 082 /** File name translator. */ 083 private CmsResourceTranslator m_fileTranslator; 084 085 /** Flag to control whether links should be absolute even if we're linking to the current site. */ 086 private boolean m_forceAbsoluteLinks; 087 088 /** The secure request flag. */ 089 private boolean m_isSecureRequest; 090 091 /** The locale used by this request context. */ 092 private Locale m_locale; 093 094 /** The fully qualified name of the organizational unit for this request. */ 095 private String m_ouFqn; 096 097 /** The remote ip address. */ 098 private String m_remoteAddr; 099 100 /** the matcher for the current request, that is the host part of the URI from the original http request. */ 101 private CmsSiteMatcher m_requestMatcher; 102 103 /** The current request time. */ 104 private long m_requestTime; 105 106 /** The name of the root, e.g. /site_a/vfs. */ 107 private String m_siteRoot; 108 109 /** Flag to indicate that this context should not update the user session. */ 110 private boolean m_updateSession; 111 112 /** The URI for getUri() in case it is "overwritten". */ 113 private String m_uri; 114 115 /** The current user. */ 116 private CmsUser m_user; 117 118 /** 119 * Constructs a new request context.<p> 120 * 121 * @param user the current user 122 * @param project the current project 123 * @param requestedUri the requested OpenCms VFS URI 124 * @param requestMatcher the matcher for the current request, that is the host part of the URI from the original http request 125 * @param siteRoot the users current site root 126 * @param isSecureRequest true if this is a secure request 127 * @param locale the users current locale 128 * @param encoding the encoding to use for this request 129 * @param remoteAddr the remote IP address of the user 130 * @param requestTime the time of the request (used for resource publication / expiration date) 131 * @param directoryTranslator the directory translator 132 * @param fileTranslator the file translator 133 * @param ouFqn the fully qualified name of the organizational unit 134 * @param forceAbsoluteLinks if true, links should be generated with a server prefix even if we're linking to the current site 135 */ 136 public CmsRequestContext( 137 CmsUser user, 138 CmsProject project, 139 String requestedUri, 140 CmsSiteMatcher requestMatcher, 141 String siteRoot, 142 boolean isSecureRequest, 143 Locale locale, 144 String encoding, 145 String remoteAddr, 146 long requestTime, 147 CmsResourceTranslator directoryTranslator, 148 CmsResourceTranslator fileTranslator, 149 String ouFqn, 150 boolean forceAbsoluteLinks) { 151 152 m_updateSession = true; 153 m_user = user; 154 m_currentProject = project; 155 m_uri = requestedUri; 156 m_requestMatcher = requestMatcher; 157 m_isSecureRequest = isSecureRequest; 158 setSiteRoot(siteRoot); 159 m_locale = locale; 160 m_encoding = encoding; 161 m_remoteAddr = remoteAddr; 162 m_requestTime = requestTime; 163 m_directoryTranslator = directoryTranslator; 164 m_fileTranslator = fileTranslator; 165 setOuFqn(ouFqn); 166 m_forceAbsoluteLinks = forceAbsoluteLinks; 167 } 168 169 /** 170 * Returns the adjusted site root for a resource using the provided site root as a base.<p> 171 * 172 * Usually, this would be the site root for the current site. 173 * However, if a resource from the <code>/system/</code> folder is requested, 174 * this will be the empty String.<p> 175 * 176 * @param siteRoot the site root of the current site 177 * @param resourcename the resource name to get the adjusted site root for 178 * 179 * @return the adjusted site root for the resource 180 */ 181 public static String getAdjustedSiteRoot(String siteRoot, String resourcename) { 182 183 if (resourcename.startsWith(CmsWorkplace.VFS_PATH_SYSTEM) 184 || OpenCms.getSiteManager().startsWithShared(resourcename) 185 || (resourcename.startsWith(CmsWorkplace.VFS_PATH_SITES) && !resourcename.startsWith(siteRoot))) { 186 return ""; 187 } else { 188 return siteRoot; 189 } 190 } 191 192 /** 193 * Adds the current site root of this context to the given resource name, 194 * and also translates the resource name with the configured the directory translator.<p> 195 * 196 * @param resourcename the resource name 197 * @return the translated resource name including site root 198 * @see #addSiteRoot(String, String) 199 */ 200 public String addSiteRoot(String resourcename) { 201 202 return addSiteRoot(m_siteRoot, resourcename); 203 } 204 205 /** 206 * Adds the given site root of this context to the given resource name, 207 * taking into account special folders like "/system" where no site root must be added, 208 * and also translates the resource name with the configured the directory translator.<p> 209 * 210 * @param siteRoot the site root to add 211 * @param resourcename the resource name 212 * @return the translated resource name including site root 213 */ 214 public String addSiteRoot(String siteRoot, String resourcename) { 215 216 if ((resourcename == null) || (siteRoot == null)) { 217 return null; 218 } 219 siteRoot = getAdjustedSiteRoot(siteRoot, resourcename); 220 StringBuffer result = new StringBuffer(128); 221 result.append(siteRoot); 222 if (((siteRoot.length() == 0) || (siteRoot.charAt(siteRoot.length() - 1) != '/')) 223 && ((resourcename.length() == 0) || (resourcename.charAt(0) != '/'))) { 224 // add slash between site root and resource if required 225 result.append('/'); 226 } 227 result.append(resourcename); 228 return m_directoryTranslator.translateResource(result.toString()); 229 } 230 231 /** 232 * Returns the current project of the current user. 233 * 234 * @return the current project of the current user 235 * 236 * @deprecated use {@link #getCurrentProject()} instead 237 */ 238 @Deprecated 239 public CmsProject currentProject() { 240 241 return getCurrentProject(); 242 } 243 244 /** 245 * Returns the current user object.<p> 246 * 247 * @return the current user object 248 * 249 * @deprecated use {@link #getCurrentUser()} instead 250 */ 251 @Deprecated 252 public CmsUser currentUser() { 253 254 return getCurrentUser(); 255 } 256 257 /** 258 * Returns the adjusted site root for a resource this context current site root.<p> 259 * 260 * @param resourcename the resource name to get the adjusted site root for 261 * 262 * @return the adjusted site root for the resource 263 * 264 * @see #getAdjustedSiteRoot(String, String) 265 */ 266 public String getAdjustedSiteRoot(String resourcename) { 267 268 return getAdjustedSiteRoot(m_siteRoot, resourcename); 269 } 270 271 /** 272 * Gets the value of an attribute from the OpenCms request context attribute list.<p> 273 * 274 * @param attributeName the attribute name 275 * @return Object the attribute value, or <code>null</code> if the attribute was not found 276 */ 277 public Object getAttribute(String attributeName) { 278 279 if (m_attributeMap == null) { 280 return null; 281 } 282 return m_attributeMap.get(attributeName); 283 } 284 285 /** 286 * Returns the current project of the current user. 287 * 288 * @return the current project of the current user 289 */ 290 public CmsProject getCurrentProject() { 291 292 return m_currentProject; 293 } 294 295 /** 296 * Returns the current user object.<p> 297 * 298 * @return the current user object 299 */ 300 public CmsUser getCurrentUser() { 301 302 return m_user; 303 } 304 305 /** 306 * Gets the detail content structure id (or null if no detail content has been loaded).<p> 307 * 308 * @return the detail content id 309 */ 310 public CmsUUID getDetailContentId() { 311 312 if (m_detailResource == null) { 313 return null; 314 } 315 return m_detailResource.getStructureId(); 316 } 317 318 /** 319 * Gets the detail content resource (or null if no detail content has been loaded).<p> 320 * 321 * @return the detail content resource 322 */ 323 public CmsResource getDetailResource() { 324 325 return m_detailResource; 326 } 327 328 /** 329 * Returns the directory name translator this context was initialized with.<p> 330 * 331 * The directory translator is used to translate old VFS path information 332 * to a new location. Example: <code>/bodys/index.html --> /system/bodies/</code>.<p> 333 * 334 * @return the directory name translator this context was initialized with 335 */ 336 public CmsResourceTranslator getDirectoryTranslator() { 337 338 return m_directoryTranslator; 339 } 340 341 /** 342 * Returns the current content encoding to be used in HTTP response.<p> 343 * 344 * @return the encoding 345 */ 346 public String getEncoding() { 347 348 return m_encoding; 349 } 350 351 /** 352 * Returns the file name translator this context was initialized with.<p> 353 * 354 * The file name translator is used to translate filenames from uploaded files 355 * to valid OpenCms filenames. Example: <code>Wüste Wörter.doc --> Wueste_Woerter.doc</code>.<p> 356 * 357 * @return the file name translator this context was initialized with 358 */ 359 public CmsResourceTranslator getFileTranslator() { 360 361 return m_fileTranslator; 362 } 363 364 /** 365 * Gets the name of the parent folder of the requested file.<p> 366 * 367 * @return the name of the parent folder of the requested file 368 */ 369 public String getFolderUri() { 370 371 return CmsResource.getFolderPath(m_uri); 372 } 373 374 /** 375 * Returns the locale used by this request context.<p> 376 * 377 * In normal operation, the request context locale is initialized using 378 * {@link org.opencms.i18n.I_CmsLocaleHandler#getI18nInfo(javax.servlet.http.HttpServletRequest, CmsUser, CmsProject, String)} 379 * depending on the requested resource URI.<p> 380 * 381 * @return the locale used by this request context 382 * 383 * @see org.opencms.i18n.I_CmsLocaleHandler#getI18nInfo(javax.servlet.http.HttpServletRequest, CmsUser, CmsProject, String) 384 * @see org.opencms.i18n.CmsLocaleManager#getDefaultLocale(CmsObject, String) 385 */ 386 public Locale getLocale() { 387 388 return m_locale; 389 } 390 391 /** 392 * Returns the fully qualified name of the organizational unit.<p> 393 * 394 * @return the fully qualified name of the organizational unit 395 */ 396 public String getOuFqn() { 397 398 return m_ouFqn; 399 } 400 401 /** 402 * Returns the remote ip address.<p> 403 * 404 * @return the remote ip address as string 405 */ 406 public String getRemoteAddress() { 407 408 return m_remoteAddr; 409 } 410 411 /** 412 * Returns the matcher for the current request, that is the host part of the URI from the original http request.<p> 413 * 414 * @return the matcher for the current request, that is the host part of the URI from the original http request 415 */ 416 public CmsSiteMatcher getRequestMatcher() { 417 418 return m_requestMatcher; 419 } 420 421 /** 422 * Returns the current request time.<p> 423 * 424 * @return the current request time 425 */ 426 public long getRequestTime() { 427 428 return m_requestTime; 429 } 430 431 /** 432 * Returns this request contexts uri extended with the current site root path.<p> 433 * 434 * @return this request contexts uri extended with the current site root path 435 * 436 * @see #getUri() 437 * @see #addSiteRoot(String) 438 */ 439 public String getRootUri() { 440 441 return addSiteRoot(m_siteRoot, m_uri); 442 } 443 444 /** 445 * Adjusts the absolute resource root path for the current site.<p> 446 * 447 * The full root path of a resource is always available using 448 * <code>{@link CmsResource#getRootPath()}</code>. From this name this method cuts 449 * of the current site root using 450 * <code>{@link CmsRequestContext#removeSiteRoot(String)}</code>.<p> 451 * 452 * If the resource root path does not start with the current site root, 453 * it is left untouched.<p> 454 * 455 * @param resource the resource to get the adjusted site root path for 456 * 457 * @return the absolute resource path adjusted for the current site 458 * 459 * @see #removeSiteRoot(String) 460 * @see CmsResource#getRootPath() 461 * @see CmsObject#getSitePath(CmsResource) 462 */ 463 public String getSitePath(CmsResource resource) { 464 465 return removeSiteRoot(resource.getRootPath()); 466 } 467 468 /** 469 * Returns the current root directory in the virtual file system.<p> 470 * 471 * @return the current root directory in the virtual file system 472 */ 473 public String getSiteRoot() { 474 475 return m_siteRoot; 476 } 477 478 /** 479 * Returns the OpenCms VFS URI of the requested resource.<p> 480 * 481 * @return the OpenCms VFS URI of the requested resource 482 */ 483 public String getUri() { 484 485 return m_uri; 486 } 487 488 /** 489 * Returns true if links to the current site should be generated as absolute links, i.e. with a server prefix. 490 * 491 * @return true if links to the current site should be absolute 492 */ 493 public boolean isForceAbsoluteLinks() { 494 495 return m_forceAbsoluteLinks; 496 } 497 498 /** 499 * Checks if we are currently either in the Online project or the 'direct edit disabled' mode. 500 * 501 * @return true if we are online or in 'direct edit enabled' mode 502 */ 503 public boolean isOnlineOrEditDisabled() { 504 505 if (getCurrentProject().isOnlineProject()) { 506 return true; 507 } 508 Object directEdit = getAttribute(CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT); 509 if (Boolean.TRUE.equals(directEdit)) { 510 return true; 511 } 512 return false; 513 } 514 515 /** 516 * Returns true if this is a secure request.<p> 517 * 518 * @return true if this is secure 519 */ 520 public boolean isSecureRequest() { 521 522 return m_isSecureRequest; 523 } 524 525 /** 526 * Check if this request context will update the session.<p> 527 * 528 * This is used mainly for CmsReports that continue to use the 529 * users context, even after the http request is already finished.<p> 530 * 531 * @return true if this request context will update the session, false otherwise 532 */ 533 public boolean isUpdateSessionEnabled() { 534 535 return m_updateSession; 536 } 537 538 /** 539 * Removes an attribute from the request context.<p> 540 * 541 * @param key the name of the attribute to remove 542 * 543 * @return the removed attribute, or <code>null</code> if no attribute was set with this name 544 */ 545 public Object removeAttribute(String key) { 546 547 if (m_attributeMap != null) { 548 return m_attributeMap.remove(key); 549 } 550 return null; 551 } 552 553 /** 554 * Removes the current site root prefix from the absolute path in the resource name, 555 * that is adjusts the resource name for the current site root.<p> 556 * 557 * If the resource name does not start with the current site root, 558 * it is left untouched.<p> 559 * 560 * @param resourcename the resource name 561 * 562 * @return the resource name adjusted for the current site root 563 * 564 * @see #getSitePath(CmsResource) 565 */ 566 public String removeSiteRoot(String resourcename) { 567 568 String siteRoot = getAdjustedSiteRoot(m_siteRoot, resourcename); 569 if ((siteRoot == m_siteRoot) 570 && resourcename.startsWith(siteRoot) 571 && ((resourcename.length() == siteRoot.length()) || (resourcename.charAt(siteRoot.length()) == '/'))) { 572 resourcename = resourcename.substring(siteRoot.length()); 573 } 574 if (resourcename.length() == 0) { 575 // input was a site root folder without trailing slash 576 resourcename = "/"; 577 } 578 return resourcename; 579 } 580 581 /** 582 * Sets an attribute in the request context.<p> 583 * 584 * @param key the attribute name 585 * @param value the attribute value 586 */ 587 public void setAttribute(String key, Object value) { 588 589 if (m_attributeMap == null) { 590 // hash table is still the most efficient form of a synchronized Map 591 m_attributeMap = new Hashtable<String, Object>(); 592 } 593 m_attributeMap.put(key, value); 594 } 595 596 /** 597 * Sets the current project for the user.<p> 598 * 599 * @param project the project to be set as current project 600 * 601 * @return the CmsProject instance 602 */ 603 public CmsProject setCurrentProject(CmsProject project) { 604 605 if (project != null) { 606 m_currentProject = project; 607 } 608 return m_currentProject; 609 } 610 611 /** 612 * Sets the detail content resource.<p> 613 * 614 * @param detailResource the detail content resource 615 */ 616 public void setDetailResource(CmsResource detailResource) { 617 618 m_detailResource = detailResource; 619 } 620 621 /** 622 * Sets the current content encoding to be used in HTTP response.<p> 623 * 624 * @param encoding the encoding 625 */ 626 public void setEncoding(String encoding) { 627 628 m_encoding = encoding; 629 } 630 631 /** 632 * Enables/disables link generation with full server prefix for the current site. 633 * 634 * @param forceAbsoluteLinks true if links to the current site should be generated with server prefix 635 */ 636 public void setForceAbsoluteLinks(boolean forceAbsoluteLinks) { 637 638 m_forceAbsoluteLinks = forceAbsoluteLinks; 639 } 640 641 /** 642 * Sets the locale used by this request context.<p> 643 * 644 * @param locale the locale to set 645 * 646 * @see #getLocale() for more information about how the locale is set in normal operation 647 */ 648 public void setLocale(Locale locale) { 649 650 m_locale = locale; 651 } 652 653 /** 654 * Sets the organizational unit fully qualified name.<p> 655 * 656 * @param ouFqn the organizational unit fully qualified name 657 */ 658 public void setOuFqn(String ouFqn) { 659 660 String userOu = CmsOrganizationalUnit.getParentFqn(m_user.getName()); 661 if (ouFqn != null) { 662 if (ouFqn.startsWith(userOu) 663 || (ouFqn.startsWith(CmsOrganizationalUnit.SEPARATOR) && ouFqn.substring(1).startsWith(userOu))) { 664 m_ouFqn = ouFqn; 665 } else { 666 throw new CmsIllegalArgumentException( 667 Messages.get().container(Messages.ERR_BAD_ORGUNIT_2, ouFqn, userOu)); 668 } 669 } else { 670 m_ouFqn = userOu; 671 } 672 m_ouFqn = CmsOrganizationalUnit.removeLeadingSeparator(m_ouFqn); 673 } 674 675 /** 676 * Sets the current request time.<p> 677 * 678 * @param time the request time 679 */ 680 public void setRequestTime(long time) { 681 682 m_requestTime = time; 683 } 684 685 /** 686 * Sets the 'secure request' status.<p> 687 * 688 * @param secureRequest the new value 689 */ 690 public void setSecureRequest(boolean secureRequest) { 691 692 m_isSecureRequest = secureRequest; 693 } 694 695 /** 696 * Sets the current root directory in the virtual file system.<p> 697 * 698 * @param root the name of the new root directory 699 */ 700 public void setSiteRoot(String root) { 701 702 // site roots must never end with a "/" 703 if (root.endsWith("/")) { 704 m_siteRoot = root.substring(0, root.length() - 1); 705 } else { 706 m_siteRoot = root; 707 } 708 } 709 710 /** 711 * Mark this request context to update the session or not.<p> 712 * 713 * @param value true if this request context will update the session, false otherwise 714 */ 715 public void setUpdateSessionEnabled(boolean value) { 716 717 m_updateSession = value; 718 } 719 720 /** 721 * Set the requested resource OpenCms VFS URI, that is the value returned by {@link #getUri()}.<p> 722 * 723 * Use this with caution! Many things (caches etc.) depend on this value. 724 * If you change this value, better make sure that you change it only temporarily 725 * and reset it in a <code>try { // do something // } finally { // reset URI // }</code> statement.<p> 726 * 727 * @param value the value to set the Uri to, must be a complete OpenCms path name like /system/workplace/style.css 728 */ 729 public void setUri(String value) { 730 731 m_uri = value; 732 } 733 734 /** 735 * Switches the user in the context, required after a login.<p> 736 * 737 * @param user the new user to use 738 * @param project the new users current project 739 * @param ouFqn the organizational unit 740 */ 741 protected void switchUser(CmsUser user, CmsProject project, String ouFqn) { 742 743 m_user = user; 744 m_currentProject = project; 745 setOuFqn(ouFqn); 746 } 747}