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