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