001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.main; 029 030import org.opencms.util.A_CmsModeStringEnumeration; 031import org.opencms.util.CmsFileUtil; 032import org.opencms.util.CmsStringUtil; 033 034import java.io.File; 035 036import javax.servlet.ServletContext; 037 038import org.apache.commons.logging.Log; 039 040/** 041 * Stores specific servlet container options, that might influence OpenCms behavior.<p> 042 * 043 * @since 7.0.5 044 */ 045public class CmsServletContainerSettings { 046 047 /** 048 * Enumeration class for the configuration mode.<p> 049 */ 050 public static final class CmsServletContainerCfgMode extends A_CmsModeStringEnumeration { 051 052 /** Auto configuration mode. */ 053 protected static final CmsServletContainerCfgMode MODE_AUTO = new CmsServletContainerCfgMode("auto"); 054 055 /** Manual configuration mode. */ 056 protected static final CmsServletContainerCfgMode MODE_MANUAL = new CmsServletContainerCfgMode("manual"); 057 058 /** No set configuration mode. */ 059 protected static final CmsServletContainerCfgMode MODE_NONE = new CmsServletContainerCfgMode("none"); 060 061 /** Version id required for safe serialization. */ 062 private static final long serialVersionUID = -8191582624108081577L; 063 064 /** 065 * Private constructor.<p> 066 * 067 * @param mode the remote command execution return type integer representation 068 */ 069 private CmsServletContainerCfgMode(String mode) { 070 071 super(mode); 072 } 073 074 /** 075 * Returns the parsed mode object if the string representation matches, or <code>null</code> if not.<p> 076 * 077 * @param mode the string representation to parse 078 * 079 * @return the parsed mode object 080 */ 081 public static CmsServletContainerCfgMode valueOf(String mode) { 082 083 if (mode == null) { 084 return null; 085 } 086 if (mode.equalsIgnoreCase(MODE_NONE.getMode())) { 087 return MODE_NONE; 088 } 089 if (mode.equalsIgnoreCase(MODE_MANUAL.getMode())) { 090 return MODE_MANUAL; 091 } 092 if (mode.equalsIgnoreCase(MODE_AUTO.getMode())) { 093 return MODE_AUTO; 094 } 095 return null; 096 } 097 098 /** 099 * Checks if this is the auto mode.<p> 100 * 101 * @return <code>true</code> if this is the auto mode 102 */ 103 public boolean isAuto() { 104 105 return this == MODE_AUTO; 106 } 107 108 /** 109 * Checks if this is the manual mode.<p> 110 * 111 * @return <code>true</code> if this is the manual mode 112 */ 113 public boolean isManual() { 114 115 return this == MODE_MANUAL; 116 } 117 118 /** 119 * Checks if this is the none mode.<p> 120 * 121 * @return <code>true</code> if this is the none mode 122 */ 123 public boolean isNone() { 124 125 return this == MODE_NONE; 126 } 127 } 128 129 /** String remote command execution return type. */ 130 public static final CmsServletContainerCfgMode CFG_MODE_AUTO = CmsServletContainerCfgMode.MODE_AUTO; 131 132 /** Map remote command execution return type. */ 133 public static final CmsServletContainerCfgMode CFG_MODE_MANUAL = CmsServletContainerCfgMode.MODE_MANUAL; 134 135 /** List remote command execution return type. */ 136 public static final CmsServletContainerCfgMode CFG_MODE_NONE = CmsServletContainerCfgMode.MODE_NONE; 137 138 /** The static log object for this class. */ 139 private static final Log LOG = CmsLog.getLog(CmsServletContainerSettings.class); 140 141 /** If the servlet can throw an exception if initialization fails, for instance, Weblogic and Resin have problems with the exception. */ 142 private static boolean m_servletThrowsException = true; 143 144 /** 145 * The replacement request attribute for the {@link javax.servlet.http.HttpServletRequest#getPathInfo()} method, 146 * which is needed because this method is not properly implemented in BEA WLS 9.x.<p> 147 */ 148 private static final String REQUEST_ERROR_PAGE_ATTRIBUTE_WEBLOGIC = "weblogic.servlet.errorPage"; 149 150 /** Constant name to identify GlassFish servers. */ 151 // 2.1: "Sun GlassFish Enterprise Server v2.1" 152 private static final String SERVLET_CONTAINER_GLASSFISH = "GlassFish"; 153 154 /** Constant name to identify Resin servers. */ 155 private static final String SERVLET_CONTAINER_RESIN = "Resin"; 156 157 /** Constant name to identify BEA WebLogic servers. */ 158 private static final String SERVLET_CONTAINER_WEBLOGIC = "WebLogic Server"; 159 160 /** Constant name to identify IBM Websphere servers. */ 161 private static final String SERVLET_CONTAINER_WEBSPHERE = "IBM WebSphere Application Server"; 162 163 /** The context path of the web application. */ 164 private String m_contextPath; 165 166 /** The default web application (usually "ROOT"). */ 167 private String m_defaultWebApplicationName; 168 169 /** The configuration mode. */ 170 private CmsServletContainerCfgMode m_mode = CFG_MODE_NONE; 171 172 /** The OpenCms context and servlet path, e.g. <code>/opencms/opencms</code>. */ 173 private String m_openCmsContext; 174 175 /** If the flex response has to prevent buffer flushing, for instance, Websphere does not allow to set headers afterwards, so we have to prevent it. */ 176 private boolean m_preventResponseFlush; 177 178 /** If the tags need to be released after ending, this has to be prevented when running with Resin, for example. */ 179 private boolean m_releaseTagsAfterEnd = true; 180 181 /** 182 * The request error page attribute to use if {@link javax.servlet.http.HttpServletRequest#getPathInfo()} 183 * is not working properly, like in BEA WLS 9.x. 184 */ 185 private String m_requestErrorPageAttribute; 186 187 /** The name of the servlet container running OpenCms. */ 188 private String m_servletContainerName; 189 190 /** The servlet path for the OpenCms servlet. */ 191 private String m_servletPath; 192 193 /** The web application name. */ 194 private String m_webApplicationName; 195 196 /** The OpenCms web application servlet container folder path (in the "real" file system). */ 197 private String m_webApplicationRfsPath; 198 199 /** The OpenCms web application "WEB-INF" path (in the "real" file system). */ 200 private String m_webInfRfsPath; 201 202 /** 203 * Creates a new object.<p> 204 * 205 * @param context used to find out specifics of the servlet container 206 */ 207 public CmsServletContainerSettings(ServletContext context) { 208 209 // CmsSystemInfo<init> has to call this with null (for setup) 210 if (context != null) { 211 // check for OpenCms home (base) directory path 212 String webInfRfsPath = context.getInitParameter(OpenCmsServlet.SERVLET_PARAM_OPEN_CMS_HOME); 213 if (CmsStringUtil.isEmpty(webInfRfsPath)) { 214 webInfRfsPath = CmsFileUtil.searchWebInfFolder(context.getRealPath("/")); 215 if (CmsStringUtil.isEmpty(webInfRfsPath)) { 216 throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_FOLDER_0)); 217 } 218 } 219 220 // set the default web application name 221 // read the the default name from the servlet context parameters 222 String defaultWebApplication = context.getInitParameter("DefaultWebApplication"); 223 224 // read the the OpenCms servlet mapping from the servlet context parameters 225 String servletMapping = context.getInitParameter(OpenCmsServlet.SERVLET_PARAM_OPEN_CMS_SERVLET); 226 if (servletMapping == null) { 227 throw new CmsInitException(Messages.get().container(Messages.ERR_CRITICAL_INIT_SERVLET_0)); 228 } 229 230 // read the servlet container name 231 String servletContainerName = context.getServerInfo(); 232 233 // web application context: 234 // read it from the servlet context parameters 235 // this is needed in case an application server specific deployment descriptor is used to changed the webapp context 236 String webApplicationContextFromConfig = context.getInitParameter( 237 OpenCmsServlet.SERVLET_PARAM_WEB_APPLICATION_CONTEXT); 238 String contextPath = ""; 239 if (CmsStringUtil.isEmptyOrWhitespaceOnly(webApplicationContextFromConfig)) { 240 contextPath = context.getContextPath(); 241 } else { 242 if (defaultWebApplication.equals(webApplicationContextFromConfig)) { 243 contextPath = ""; 244 } else { 245 contextPath = "/" + webApplicationContextFromConfig; 246 } 247 } 248 // init values: 249 init(webInfRfsPath, defaultWebApplication, servletMapping, servletContainerName, contextPath); 250 // finally care for the speciality of different servlet containers: 251 initContainerSpecifics(context); 252 } 253 } 254 255 /** 256 * Creates an instance based on the given values.<p> 257 * 258 * This is intended for <code>{@link CmsShell}</code> access.<p> 259 * 260 * @param webInfRfsPath the OpenCms web application "WEB-INF" path in the "real" file system) to set 261 * @param servletMapping the OpenCms servlet mapping (e.g. "/opencms/*") 262 * @param webApplicationContext the name/path of the OpenCms web application context (optional, will be calculated form the path if null) 263 * @param defaultWebApplication the default web application name (usually "ROOT") 264 * @param servletContainerName the name of the servlet container running OpenCms 265 */ 266 protected CmsServletContainerSettings( 267 String webInfRfsPath, 268 String defaultWebApplication, 269 String servletMapping, 270 String servletContainerName, 271 String webApplicationContext) { 272 273 init(webInfRfsPath, defaultWebApplication, servletMapping, servletContainerName, webApplicationContext); 274 } 275 276 /** 277 * Checks if the servlet can throw an exception if initialization fails.<p> 278 * 279 * @return <code>true</code> if the servlet can throw an exception if initialization fails 280 */ 281 public static boolean isServletThrowsException() { 282 283 return m_servletThrowsException; 284 } 285 286 /** 287 * Returns the web application context path, e.g. "" (empty String) if the web application 288 * is the default web application (usually "ROOT"), or "/opencms" if the web application 289 * is called "opencms".<p> 290 * 291 * <i>From the Java Servlet Specification v2.4:</i><br> 292 * <b>Context Path:</b> The path prefix associated with the ServletContext that this 293 * servlet is a part of. If this context is the "default" context rooted at the base of 294 * the web server's URL name space, this path will be an empty string. Otherwise, 295 * if the context is not rooted at the root of the server's name space, the path starts 296 * with a "/" character but does not end with a "/" character.<p> 297 * 298 * @return the web application context path 299 * @see #getWebApplicationName() 300 * @see #getServletPath() 301 * @see #getOpenCmsContext() 302 */ 303 public String getContextPath() { 304 305 return m_contextPath; 306 } 307 308 /** 309 * Returns the default web application name (usually "ROOT").<p> 310 * 311 * @return the default web application name 312 */ 313 public String getDefaultWebApplicationName() { 314 315 return m_defaultWebApplicationName; 316 } 317 318 /** 319 * Returns the mode.<p> 320 * 321 * @return the mode 322 */ 323 public CmsServletContainerCfgMode getMode() { 324 325 return m_mode; 326 } 327 328 /** 329 * Returns the OpenCms request context, e.g. "/opencms/opencms".<p> 330 * 331 * The OpenCms context will always start with a "/" and never have a trailing "/". 332 * The OpenCms context is identical to <code>getContexPath() + getServletPath()</code>.<p> 333 * 334 * @return the OpenCms request context, e.g. "/opencms/opencms" 335 * @see #getContextPath() 336 * @see #getServletPath() 337 */ 338 public String getOpenCmsContext() { 339 340 return m_openCmsContext; 341 } 342 343 /** 344 * Returns the request error page attribute.<p> 345 * 346 * @return the request error page attribute 347 */ 348 public String getRequestErrorPageAttribute() { 349 350 return m_requestErrorPageAttribute; 351 } 352 353 /** 354 * Returns the name of the servlet container running OpenCms.<p> 355 * 356 * @return the name of the servlet container running OpenCms 357 */ 358 public String getServletContainerName() { 359 360 return m_servletContainerName; 361 } 362 363 /** 364 * Returns the OpenCms servlet path, e.g. "/opencms".<p> 365 * 366 * <i>From the Java Servlet Specification v2.4:</i><br> 367 * <b>Servlet Path:</b> The path section that directly corresponds to the mapping 368 * which activated this request. This path starts with a?/? character except in the 369 * case where the request is matched with the ?/*? pattern, in which case it is the 370 * empty string.<p> 371 * 372 * @return the OpenCms servlet path 373 * @see #getContextPath() 374 * @see #getWebApplicationName() 375 * @see #getOpenCmsContext() 376 */ 377 public String getServletPath() { 378 379 return m_servletPath; 380 } 381 382 /** 383 * Returns the OpenCms web application name, e.g. "opencms" or "ROOT" (no leading or trailing "/").<p> 384 * 385 * The web application name is stored for informational purposes only. 386 * If you want to construct an URI, use either {@link #getContextPath()} and 387 * {@link #getServletPath()}, or for links to the OpenCms VFS use {@link #getOpenCmsContext()}.<p> 388 * 389 * @return the OpenCms web application name 390 * @see #getContextPath() 391 * @see #getServletPath() 392 * @see #getOpenCmsContext() 393 */ 394 public String getWebApplicationName() { 395 396 return m_webApplicationName; 397 } 398 399 /** 400 * Returns the OpenCms web application folder in the servlet container.<p> 401 * 402 * @return the OpenCms web application folder in the servlet container 403 */ 404 public String getWebApplicationRfsPath() { 405 406 return m_webApplicationRfsPath; 407 } 408 409 /** 410 * Returns the OpenCms web application "WEB-INF" directory path.<p> 411 * 412 * @return the OpenCms web application "WEB-INF" directory path 413 */ 414 public String getWebInfRfsPath() { 415 416 return m_webInfRfsPath; 417 } 418 419 /** 420 * Checks if the flex response has to prevent buffer flushing.<p> 421 * 422 * @return <code>true</code> if the flex response has to prevent buffer flushing 423 */ 424 public boolean isPreventResponseFlush() { 425 426 return m_preventResponseFlush; 427 } 428 429 /** 430 * Checks if the tags need to be released after ending.<p> 431 * 432 * @return <code>true</code> if the tags need to be released after ending 433 */ 434 public boolean isReleaseTagsAfterEnd() { 435 436 return m_releaseTagsAfterEnd; 437 } 438 439 /** 440 * Sets the mode from the configuration.<p> 441 * 442 * @param configValue the mode to set 443 */ 444 public void setMode(String configValue) { 445 446 m_mode = CmsServletContainerCfgMode.valueOf(configValue); 447 } 448 449 /** 450 * Sets if the flex response has to prevent buffer flushing.<p> 451 * 452 * @param preventResponseFlush the flag to set 453 */ 454 public void setPreventResponseFlush(boolean preventResponseFlush) { 455 456 m_preventResponseFlush = preventResponseFlush; 457 } 458 459 /** 460 * Sets if the tags need to be released after ending.<p> 461 * 462 * @param releaseTagsAfterEnd the flag to set 463 */ 464 public void setReleaseTagsAfterEnd(boolean releaseTagsAfterEnd) { 465 466 m_releaseTagsAfterEnd = releaseTagsAfterEnd; 467 } 468 469 /** 470 * Sets the request error page attribute.<p> 471 * 472 * @param requestErrorPageAttribute the request error page attribute to set 473 */ 474 public void setRequestErrorPageAttribute(String requestErrorPageAttribute) { 475 476 m_requestErrorPageAttribute = requestErrorPageAttribute; 477 } 478 479 /** 480 * Sets if the servlet can throw an exception if initialization fails.<p> 481 * 482 * @param servletThrowsException the flag to set 483 */ 484 public void setServletThrowsException(boolean servletThrowsException) { 485 486 m_servletThrowsException = servletThrowsException; 487 } 488 489 /** 490 * Initialization code common to both constructors.<p> 491 * 492 * While the "webapplication - mode" constructor obtains all values from the 493 * <code>{@link ServletContext}</code> the <code>{@link CmsShell}</code> constructor 494 * accepts them as arguments and passes them here. <p> 495 * 496 * @param webInfRfsPath the OpenCms web application "WEB-INF" path in the "real" file system) to set 497 * @param servletMapping the OpenCms servlet mapping (e.g. "/opencms/*") 498 * @param webApplicationContext the name/path of the OpenCms web application context (optional, will be calculated form the path if null) 499 * @param defaultWebApplication the default web application name (usually "ROOT") 500 * @param servletContainerName the name of the servlet container running OpenCms 501 * @param contextPath the context path 502 */ 503 private void init( 504 String webInfRfsPath, 505 String defaultWebApplication, 506 String servletMapping, 507 String servletContainerName, 508 String contextPath) { 509 510 // WEB-INF RFS path 511 512 webInfRfsPath = webInfRfsPath.replace('\\', '/'); 513 if (!webInfRfsPath.endsWith("/")) { 514 webInfRfsPath = webInfRfsPath + "/"; 515 } 516 m_webInfRfsPath = CmsFileUtil.normalizePath(webInfRfsPath); 517 518 // default web application 519 if (defaultWebApplication == null) { 520 defaultWebApplication = ""; 521 } 522 if (defaultWebApplication.endsWith("/")) { 523 defaultWebApplication = defaultWebApplication.substring(0, defaultWebApplication.length() - 1); 524 } 525 if (defaultWebApplication.startsWith("/")) { 526 defaultWebApplication = defaultWebApplication.substring(1); 527 } 528 m_defaultWebApplicationName = defaultWebApplication; 529 530 // servlet mapping 531 if (!servletMapping.startsWith("/")) { 532 servletMapping = "/" + servletMapping; 533 } 534 if (servletMapping.endsWith("/*")) { 535 // usually a mapping must be in the form "/opencms/*", cut off all slashes 536 servletMapping = servletMapping.substring(0, servletMapping.length() - 2); 537 } 538 m_servletPath = servletMapping; 539 540 // servlet container name 541 if (servletContainerName == null) { 542 m_servletContainerName = ""; 543 } 544 m_servletContainerName = servletContainerName; 545 546 // set the web application name 547 File path = new File(m_webInfRfsPath); 548 m_webApplicationName = path.getParentFile().getName(); 549 550 // set the context path 551 if (contextPath == null) { 552 // this should only happen during test cases 553 m_contextPath = "/" + m_webApplicationName; 554 } else { 555 m_contextPath = contextPath; 556 } 557 // set the OpenCms context 558 m_openCmsContext = m_contextPath + m_servletPath; 559 560 // set the web application rfs path 561 m_webApplicationRfsPath = path.getParentFile().getAbsolutePath(); 562 if (!m_webApplicationRfsPath.endsWith(File.separator)) { 563 m_webApplicationRfsPath += File.separator; 564 } 565 566 // fill some defaults: 567 m_releaseTagsAfterEnd = false; 568 m_requestErrorPageAttribute = null; 569 m_servletThrowsException = true; 570 m_preventResponseFlush = false; 571 } 572 573 /** 574 * Initializes these container settings with container specific settings.<p> 575 * 576 * @param context 577 * the servlet context to find out information about the servlet container 578 */ 579 private void initContainerSpecifics(ServletContext context) { 580 581 // the tags behavior 582 m_releaseTagsAfterEnd = !(m_servletContainerName.indexOf(SERVLET_CONTAINER_RESIN) > -1); 583 584 // the request error page attribute 585 if (m_servletContainerName.indexOf(SERVLET_CONTAINER_WEBLOGIC) > -1) { 586 m_requestErrorPageAttribute = REQUEST_ERROR_PAGE_ATTRIBUTE_WEBLOGIC; 587 } 588 589 // the failed initialization behavior 590 m_servletThrowsException = true; 591 m_servletThrowsException &= (m_servletContainerName.indexOf(SERVLET_CONTAINER_RESIN) < 0); 592 m_servletThrowsException &= (m_servletContainerName.indexOf(SERVLET_CONTAINER_WEBLOGIC) < 0); 593 m_servletThrowsException &= (m_servletContainerName.indexOf(SERVLET_CONTAINER_GLASSFISH) < 0); 594 595 // the flush flex response behavior 596 m_preventResponseFlush = false; 597 m_preventResponseFlush |= (m_servletContainerName.indexOf(SERVLET_CONTAINER_WEBSPHERE) > -1); 598 m_preventResponseFlush |= (m_servletContainerName.indexOf(SERVLET_CONTAINER_RESIN) > -1); 599 } 600}