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