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