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