com.sun.enterprise.web.VirtualServer Maven / Gradle / Ivy
Show all versions of payara-embedded-all Show documentation
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2016] [Payara Foundation]
package com.sun.enterprise.web;
import com.sun.enterprise.config.serverbeans.ApplicationRef;
import com.sun.enterprise.config.serverbeans.Applications;
import com.sun.enterprise.config.serverbeans.AuthRealm;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.ConfigBeansUtilities;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.HttpService;
import com.sun.enterprise.config.serverbeans.SecurityService;
import com.sun.enterprise.config.serverbeans.ServerTags;
import com.sun.enterprise.deploy.shared.ArchiveFactory;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.security.web.GlassFishSingleSignOn;
import com.sun.enterprise.server.logging.GFFileHandler;
import com.sun.enterprise.util.StringUtils;
import com.sun.enterprise.v3.common.PlainTextActionReporter;
import com.sun.enterprise.v3.services.impl.GrizzlyProxy;
import com.sun.enterprise.v3.services.impl.GrizzlyService;
import com.sun.enterprise.web.logger.CatalinaLogger;
import com.sun.enterprise.web.logger.FileLoggerHandler;
import com.sun.enterprise.web.logger.FileLoggerHandlerFactory;
import com.sun.enterprise.web.pluggable.WebContainerFeatureFactory;
import com.sun.enterprise.web.session.SessionCookieConfig;
import com.sun.web.security.RealmAdapter;
import java.io.File;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.catalina.*;
import org.apache.catalina.authenticator.AuthenticatorBase;
import org.apache.catalina.authenticator.SingleSignOn;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
import org.apache.catalina.deploy.ErrorPage;
import org.apache.catalina.valves.RemoteAddrValve;
import org.apache.catalina.valves.RemoteHostValve;
import org.glassfish.api.ActionReport;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.deployment.DeployCommandParameters;
import org.glassfish.api.deployment.OpsParams;
import org.glassfish.api.deployment.UndeployCommandParameters;
import org.glassfish.api.deployment.archive.ArchiveHandler;
import org.glassfish.api.deployment.archive.ReadableArchive;
import org.glassfish.deployment.common.ApplicationConfigInfo;
import org.glassfish.deployment.common.DeploymentContextImpl;
import org.glassfish.deployment.common.DeploymentUtils;
import org.glassfish.embeddable.GlassFishException;
import org.glassfish.embeddable.web.ConfigException;
import org.glassfish.embeddable.web.Context;
import org.glassfish.embeddable.web.WebListener;
import org.glassfish.embeddable.web.config.VirtualServerConfig;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.Connection;
import org.glassfish.grizzly.ConnectionProbe;
import org.glassfish.grizzly.config.GenericGrizzlyListener;
import org.glassfish.grizzly.config.dom.NetworkListener;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.http.HttpCodecFilter;
import org.glassfish.grizzly.http.HttpPacket;
import org.glassfish.grizzly.http.HttpProbe;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.HttpResponsePacket;
import org.glassfish.grizzly.http.util.HttpStatus;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.internal.api.Globals;
import org.glassfish.internal.api.ServerContext;
import org.glassfish.internal.data.ApplicationInfo;
import org.glassfish.internal.data.ApplicationRegistry;
import org.glassfish.internal.deployment.Deployment;
import org.glassfish.internal.deployment.ExtendedDeploymentContext;
import org.glassfish.logging.annotation.LogMessageInfo;
import org.glassfish.web.admin.monitor.RequestProbeProvider;
import org.glassfish.web.deployment.archivist.WebArchivist;
import org.glassfish.web.deployment.descriptor.WebBundleDescriptorImpl;
import org.glassfish.web.loader.WebappClassLoader;
import org.glassfish.web.valve.GlassFishValve;
import org.jvnet.hk2.config.Transaction;
import org.jvnet.hk2.config.TransactionFailure;
import org.jvnet.hk2.config.types.Property;
import org.w3c.dom.*;
/**
* Standard implementation of a virtual server (aka virtual host) in
* the iPlanet Application Server.
*/
public class VirtualServer extends StandardHost
implements org.glassfish.embeddable.web.VirtualServer {
private static final String STATE = "state";
private static final String SSO_MAX_IDLE ="sso-max-inactive-seconds";
private static final String SSO_REAP_INTERVAL ="sso-reap-interval-seconds";
private static final String SSO_COOKIE_SECURE ="sso-cookie-secure";
private static final String DISABLED = "disabled";
private static final String OFF = "off";
private static final String ON = "on";
/**
* The logger to use for logging this virtual server
*/
private static final Logger DEFAULT_LOGGER = WebContainer.logger;
/**
* The resource bundle containing the message strings for _logger.
*/
protected static final ResourceBundle rb = DEFAULT_LOGGER.getResourceBundle();
@LogMessageInfo(
message = "The web module {0} has been designated as the default-web-module for virtual server {1}",
level = "FINE")
public static final String VS_DEFAULT_WEB_MODULE = "AS-WEB-GLUE-00135";
@LogMessageInfo(
message = "Error looking up the configuration information of the default-web-module {0} for virtual server {1}",
level = "SEVERE",
cause = "The web module specified is either not found or disabled or does not specify this virtual server, " +
"or there was an error loading its deployment descriptors",
action = "Verify if the virtual server's default web module is valid")
public static final String VS_DEFAULT_WEB_MODULE_NOT_FOUND = "AS-WEB-GLUE-00136";
@LogMessageInfo(
message = "The default-web-module {0} is either disabled or does not specify virtual server {1}",
level = "SEVERE",
cause = "The default web module is disabled or does not specify virtual server",
action = "Verify if the default web module is enabled and specify virtual server")
public static final String VS_DEFAULT_WEB_MODULE_DISABLED = "AS-WEB-GLUE-00137";
@LogMessageInfo(
message = "Virtual server {0} has invalid authentication realm {1}",
level = "SEVERE",
cause = "The realm {1} could not be found",
action = "Verify if the realm {1} exits for virtual server {0}")
public static final String INVALID_AUTH_REALM = "AS-WEB-GLUE-00138";
@LogMessageInfo(
message = "Invalid sso-cookie-secure configuration {0} for virtual server {1}",
level = "INFO")
public static final String INVALID_SSO_COOKIE_SECURE = "AS-WEB-GLUE-00139";
@LogMessageInfo(
message = "Realm {0} is not an instance of {1}, and will be ignored",
level = "SEVERE",
cause = "The realm {0} is either NULL or is not an instance of {1}",
action = "Verify if the realm {0} is an instance of {1}")
public static final String IGNORE_INVALID_REALM = "AS-WEB-GLUE-00140";
@LogMessageInfo(
message = "Virtual server {0} has a property with missing name or value",
level = "WARNING")
public static final String NULL_VIRTUAL_SERVER_PROPERTY = "AS-WEB-GLUE-00141";
@LogMessageInfo(
message = "Invalid redirect property value {0} for virtual server {1}: More than one {2} component",
level = "WARNING")
public static final String REDIRECT_MULTIPLE_ELEMENT = "AS-WEB-GLUE-00142";
@LogMessageInfo(
message = "Invalid redirect property value {0} for virtual server {1}: Missing url or url-prefix component",
level = "WARNING")
public static final String REDIRECT_MISSING_URL_OR_URL_PREFIX = "AS-WEB-GLUE-00143";
@LogMessageInfo(
message = "Invalid redirect property value {0} for virtual server {1}: Both url and url-prefix specified",
level = "WARNING")
public static final String REDIRECT_BOTH_URL_AND_URL_PREFIX = "AS-WEB-GLUE-00144";
@LogMessageInfo(
message = "Invalid redirect property value {0} for virtual server {1}: escape must be equal to yes or no",
level = "WARNING")
public static final String REDIRECT_INVALID_ESCAPE = "AS-WEB-GLUE-00145";
@LogMessageInfo(
message = "Invalid send-error property value {0} for virtual server {1}: More than one {2} component",
level = "WARNING")
public static final String SEND_ERROR_MULTIPLE_ELEMENT = "AS-WEB-GLUE-00146";
@LogMessageInfo(
message = "Invalid send-error property value {0} for virtual server {1}: Missing path component",
level = "WARNING")
public static final String SEND_ERROR_MISSING_PATH = "AS-WEB-GLUE-00147";
@LogMessageInfo(
message = "Unable to add listener of type {0} to virtual server {1}",
level = "SEVERE",
cause = "The listener is not an instance of ContainerListener or LifecycleListener",
action = "Verify if the listener type is supported")
public static final String INVALID_LISTENER = "AS-WEB-GLUE-00148";
@LogMessageInfo(
message = " Unable to load extension class {0} from web module {1}",
level = "SEVERE",
cause = "An exception occurred loading extension class",
action = "Check the exception for the error")
public static final String UNABLE_TO_LOAD_EXTENSION = "AS-WEB-GLUE-00149";
@LogMessageInfo(
message = "Object of type classname {0} not an instance of Valve or GlassFishValve",
level = "WARNING")
public static final String NOT_A_VALVE = "AS-WEB-GLUE-00150";
@LogMessageInfo(
message = "Error adding HttpProbes. NetworkListener {0}'s HttpCodecFilter is {1}",
level = "SEVERE",
cause = "HttpCodecFilter is either NULL or empty",
action = "Verify the NetworkListener is valid")
public static final String CODE_FILTERS_NULL = "AS-WEB-GLUE-00151";
@LogMessageInfo(
message = "Error adding HttpProbes",
level = "SEVERE",
cause = "An exception occurred adding HttpProbes",
action = "Check the exception for the error")
public static final String ADD_HTTP_PROBES_ERROR = "AS-WEB-GLUE-00152";
@LogMessageInfo(
message = "Disabling Single Sign On (SSO) for virtual server {0} as configured",
level = "FINE")
public static final String DISABLE_SSO= "AS-WEB-GLUE-00153";
@LogMessageInfo(
message = "Enabling Single Sign On (SSO) for virtual server {0} as configured",
level = "FINE")
public static final String ENABLE_SSO = "AS-WEB-GLUE-00154";
@LogMessageInfo(
message = "SSO entry max idle time set to {0} for virtual server {1}",
level = "FINE")
public static final String SSO_MAX_INACTIVE_SET= "AS-WEB-GLUE-00155";
@LogMessageInfo(
message = "SSO expire thread interval set to {0} for virtual server {1}",
level = "FINE")
public static final String SSO_REAP_INTERVAL_SET = "AS-WEB-GLUE-00156";
@LogMessageInfo(
message = "Allowing access to {0} from {1}",
level = "FINE")
public static final String ALLOW_ACCESS = "AS-WEB-GLUE-00157";
@LogMessageInfo(
message = "Denying access to {0} from {1}",
level = "FINE")
public static final String DENY_ACCESS = "AS-WEB-GLUE-00158";
@LogMessageInfo(
message = "Virtual server {0} enabled context {1}",
level = "FINE")
public static final String VS_ENABLED_CONTEXT = "AS-WEB-GLUE-00159";
@LogMessageInfo(
message = "Unable to delete {0}",
level = "WARNING")
public static final String UNABLE_TO_DELETE = "AS-WEB-GLUE-00160";
@LogMessageInfo(
message = "Unable to reconfigure access log valve",
level = "SEVERE",
cause = "An exception occurred during access log valve reconfiguration",
action = "Check the exception for error")
public static final String UNABLE_RECONFIGURE_ACCESS_LOG = "AS-WEB-GLUE-00161";
@LogMessageInfo(
message = "Virtual server {0} added context {1}",
level = "FINE")
public static final String VS_ADDED_CONTEXT = "AS-WEB-GLUE-00162";
@LogMessageInfo(
message = "Application {0} is not found",
level = "SEVERE",
cause = "The deployed application is not found",
action = "Check if the application is valid")
public static final String APP_NOT_FOUND = "AS-WEB-GLUE-00163";
@LogMessageInfo(
message = "Cannot create context for undeployment",
level = "SEVERE",
cause = "An IOException occurred during undeployment",
action = "Check the exception for error")
public static final String REMOVE_CONTEXT_ERROR = "AS-WEB-GLUE-00164";
@LogMessageInfo(
message = "Successfully removed context {0}",
level = "FINE")
public static final String REMOVED_CONTEXT = "AS-WEB-GLUE-00165";
@LogMessageInfo(
message = "Modifying web.xml {0}",
level = "FINE")
public static final String MODIFYING_WEB_XML = "AS-WEB-GLUE-00166";
@LogMessageInfo(
message = "Error adding HttpProbes. NetworkListener {0}'s GrizzlyProxy is NULL",
level = "SEVERE",
cause = "GrizzlyProxy is NULL",
action = "Verify the NetworkListener is valid")
public static final String PROXY_NULL = "AS-WEB-GLUE-00167";
// ------------------------------------------------------------ Constructor
/**
* Default constructor that simply gets a handle to the web container
* subsystem's logger.
*/
public VirtualServer() {
origPipeline = pipeline;
vsPipeline = new VirtualServerPipeline(this);
accessLogValve = new PEAccessLogValve();
accessLogValve.setContainer(this);
}
// ----------------------------------------------------- Instance Variables
/*
* The custom pipeline of this VirtualServer, which implements the
* following virtual server features:
*
* - state (disabled/off)
* - redirects
*/
private VirtualServerPipeline vsPipeline;
/*
* The original (standard) pipeline of this VirtualServer.
*
* Only one (custom or original) pipeline may be active at any given time.
* Any updates (such as adding or removing valves) to the currently
* active pipeline are propagated to the other.
*/
private Pipeline origPipeline;
/**
* The id of this virtual server as specified in the configuration.
*/
private String _id = null;
/**
* The logger to use for logging this virtual server
*/
protected Logger _logger = DEFAULT_LOGGER;
/**
* The descriptive information about this implementation.
*/
private static final String _info =
"com.sun.enterprise.web.VirtualServer/1.0";
/**
* The config bean associated with this VirtualServer
*/
private com.sun.enterprise.config.serverbeans.VirtualServer vsBean;
/**
* The mime mapping associated with this VirtualServer
*/
private MimeMap mimeMap;
/*
* Indicates whether symbolic links from this virtual server's docroot
* are followed. This setting is inherited by all web modules deployed on
* this virtual server, unless overridden by a web modules allowLinking
* property in sun-web.xml.
*/
private boolean allowLinking = false;
private String[] cacheControls;
private ClassLoaderHierarchy clh;
private Domain domain;
private ServiceLocator services;
// Is this virtual server active?
private boolean isActive;
private String authRealmName;
/*
* The accesslog valve of this VirtualServer.
*
* This valve is activated, that is, added to this virtual server's
* pipeline, only when access logging has been enabled. When acess logging
* has been disabled, this valve is removed from this virtual server's
* pipeline.
*/
private PEAccessLogValve accessLogValve;
// The value of the ssoCookieSecure property
private String ssoCookieSecure = null;
private boolean ssoCookieHttpOnly = false;
private String defaultContextPath = null;
private ServerContext serverContext;
private Config serverConfig;
private GrizzlyService grizzlyService;
private WebContainer webContainer;
private boolean ssoFailoverEnabled = false;
private volatile FileLoggerHandler fileLoggerHandler = null;
private volatile FileLoggerHandlerFactory fileLoggerHandlerFactory = null;
private Deployment deployment = null;
private ArchiveFactory factory = null;
private ActionReport report = null;
private HttpProbeImpl httpProbe = null;
// ------------------------------------------------------------- Properties
/**
* Return the virtual server identifier.
*/
public String getID() {
return _id;
}
/**
* Set the virtual server identifier string.
*
* @param id New identifier for this virtual server
*/
public void setID(String id) {
_id = id;
}
/**
* Sets the state of this virtual server.
*
* @param isActive true if this virtual server is active, false otherwise
*/
public void setIsActive(boolean isActive) {
this.isActive = isActive;
if (isActive) {
vsPipeline.setIsDisabled(false);
vsPipeline.setIsOff(false);
if (pipeline == vsPipeline && !vsPipeline.hasRedirects()) {
// Restore original pipeline
setPipeline(origPipeline);
}
}
}
/**
* Gets the value of the allowLinking property of this virtual server.
*
* @return true if symbolic links from this virtual server's docroot (as
* well as symbolic links from archives of web modules deployed on this
* virtual server) are followed, false otherwise
*/
public boolean getAllowLinking() {
return allowLinking;
}
/**
* Sets the allowLinking property of this virtual server, which determines
* whether symblic links from this virtual server's docroot are followed.
*
* This property is inherited by all web modules deployed on this virtual
* server, unless overridden by the allowLinking property in a web module's
* sun-web.xml.
*
* @param allowLinking Value of allowLinking property
*/
public void setAllowLinking(boolean allowLinking) {
this.allowLinking = allowLinking;
}
/**
* Gets the config bean associated with this VirtualServer.
*/
public com.sun.enterprise.config.serverbeans.VirtualServer getBean(){
return vsBean;
}
/**
* Sets the config bean for this VirtualServer
*/
public void setBean(
com.sun.enterprise.config.serverbeans.VirtualServer vsBean){
this.vsBean = vsBean;
}
/**
* Gets the mime map associated with this VirtualServer.
*/
public MimeMap getMimeMap(){
return mimeMap;
}
/**
* Sets the mime map for this VirtualServer
*/
public void setMimeMap(MimeMap mimeMap){
this.mimeMap = mimeMap;
}
/**
* Gets the Cache-Control configuration of this VirtualServer.
*
* @return Cache-Control configuration of this VirtualServer, or null if
* no such configuration exists for this VirtualServer
*/
public String[] getCacheControls() {
return cacheControls;
}
/**
* Sets the Cache-Control configuration for this VirtualServer
*
* @param cacheControls Cache-Control configuration settings for this
* VirtualServer
*/
public void setCacheControls(String[] cacheControls) {
this.cacheControls = cacheControls;
}
public void setServices(ServiceLocator services) {
this.services = services;
}
public String getInfo() {
return _info;
}
public void setDefaultContextPath(String defaultContextPath) {
this.defaultContextPath = defaultContextPath;
}
public void setFileLoggerHandlerFactory(FileLoggerHandlerFactory factory) {
fileLoggerHandlerFactory = factory;
}
public void setClassLoaderHierarchy(ClassLoaderHierarchy clh) {
this.clh = clh;
}
public void setDomain(Domain domain) {
this.domain = domain;
}
@Override
public Container findChild(String contextRoot) {
if (defaultContextPath != null && "/".equals(contextRoot)) {
return super.findChild(defaultContextPath);
} else {
return super.findChild(contextRoot);
}
}
// --------------------------------------------------------- Public Methods
/**
* Configures the Secure attribute of the given SSO cookie.
*
* @param ssoCookie the SSO cookie to be configured
* @param hreq the HttpServletRequest that has initiated the SSO session
*/
@Override
public void configureSingleSignOnCookieSecure(Cookie ssoCookie,
HttpServletRequest hreq) {
super.configureSingleSignOnCookieSecure(ssoCookie, hreq);
if (ssoCookieSecure != null &&
!ssoCookieSecure.equals(SessionCookieConfig.DYNAMIC_SECURE)) {
ssoCookie.setSecure(Boolean.parseBoolean(ssoCookieSecure));
}
}
@Override
public void configureSingleSignOnCookieHttpOnly(Cookie ssoCookie) {
ssoCookie.setHttpOnly(ssoCookieHttpOnly);
}
// ------------------------------------------------------ Lifecycle Methods
/**
* Adds the given valve to the currently active pipeline, keeping the
* pipeline that is not currently active in sync.
*/
public synchronized void addValve(GlassFishValve valve) {
super.addValve(valve);
if (pipeline == vsPipeline) {
origPipeline.addValve(valve);
} else {
vsPipeline.addValve(valve);
}
}
/**
* Adds the given Tomcat-style valve to the currently active pipeline,
* keeping the pipeline that is not currently active in sync.
*/
public synchronized void addValve(Valve valve) {
super.addValve(valve);
if (pipeline == vsPipeline) {
origPipeline.addValve(valve);
} else {
vsPipeline.addValve(valve);
}
}
/**
* Removes the given valve from the currently active pipeline, keeping the
* valve that is not currently active in sync.
*/
public synchronized void removeValve(GlassFishValve valve) {
super.removeValve(valve);
if (pipeline == vsPipeline) {
origPipeline.removeValve(valve);
} else {
vsPipeline.removeValve(valve);
}
}
private ConfigBeansUtilities getConfigBeansUtilities() {
if (services == null) return null;
return services.getService(ConfigBeansUtilities.class);
}
// ------------------------------------------------------ Protected Methods
/**
* Gets the context root of the web module that the user/configuration
* has designated as the default-web-module for this virtual server.
*
* The default-web-module for a virtual server is specified via the
* 'default-web-module' attribute of the 'virtual-server' element in
* server.xml. This is an optional attribute and if the configuration
* does not specify another web module (standalone or part of a
* j2ee-application) that is configured at a context-root="", then
* a default web module will be created and loaded. The value for this
* attribute is either "${standalone-web-module-name}" or
* "${j2ee-app-name}:${web-module-uri}".
*
* @return null if the default-web-module has not been specified or
* if the web module specified either could not be found or
* is disabled or does not specify this virtual server (if
* it specifies a value for the virtual-servers attribute) or
* if there was an error loading its deployment descriptors.
*/
protected String getDefaultContextPath(Domain domain,
ApplicationRegistry appRegistry) {
String contextRoot = null;
String wmID = getDefaultWebModuleID();
if (wmID != null) {
// Check if the default-web-module is part of a
// j2ee-application
Applications appsBean = domain.getApplications();
WebModuleConfig wmInfo = findWebModuleInJ2eeApp(appsBean, wmID,
appRegistry);
if (wmInfo == null) {
ConfigBeansUtilities cbu = getConfigBeansUtilities();
if (cbu == null) {
contextRoot = null;
}
else {
contextRoot = cbu.getContextRoot(wmID);
}
} else {
contextRoot = wmInfo.getContextPath();
}
if (contextRoot == null) {
Object[] params = { wmID, getID() };
_logger.log(Level.SEVERE, VS_DEFAULT_WEB_MODULE_NOT_FOUND, params);
}
}
return contextRoot;
}
protected WebModuleConfig getDefaultWebModule(Domain domain,
WebArchivist webArchivist, ApplicationRegistry appRegistry) {
WebModuleConfig wmInfo = null;
String wmID = getDefaultWebModuleID();
if (wmID != null) {
// Check if the default-web-module is part of a
// j2ee-application
Applications appsBean = domain.getApplications();
wmInfo = findWebModuleInJ2eeApp(appsBean, wmID, appRegistry);
if (wmInfo == null) {
ConfigBeansUtilities cbu = getConfigBeansUtilities();
String contextRoot = null;
String location = null;
if (cbu != null) {
contextRoot = cbu.getContextRoot(wmID);
location = cbu.getLocation(wmID);
}
if (contextRoot!=null && location != null) {
File docroot = new File(location);
final WebBundleDescriptorImpl wbd = webArchivist.getDefaultWebXmlBundleDescriptor();
wmInfo = new WebModuleConfig();
wbd.setName(Constants.DEFAULT_WEB_MODULE_NAME);
wbd.setContextRoot(contextRoot);
wmInfo.setLocation(docroot);
wmInfo.setDescriptor(wbd);
wmInfo.setParentLoader(EmbeddedWebContainer.class.getClassLoader());
WebappClassLoader cloader = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public WebappClassLoader run() {
return new WebappClassLoader(EmbeddedWebContainer.class.getClassLoader(), wbd.getApplication());
}
});
wmInfo.setAppClassLoader(cloader);
}
}
if (wmInfo == null) {
_logger.log(Level.SEVERE, VS_DEFAULT_WEB_MODULE_NOT_FOUND, new Object[] {wmID, getID()});
}
}
return wmInfo;
}
/**
* If a default web module has not yet been configured and added to this
* virtual server's list of web modules then return the configuration
* information needed in order to create a default web module for this
* virtual server.
*
* This method should be invoked only after all the standalone modules
* and the modules within j2ee-application elements have been added to
* this virtual server's list of modules (only then will one know whether
* the user has already configured a default web module or not).
*/
public WebModuleConfig createSystemDefaultWebModuleIfNecessary(
WebArchivist webArchivist) {
WebModuleConfig wmInfo = null;
// Add a default context only if one hasn't already been loaded
// and then too only if docroot is not null
//
String docroot = getAppBase();
if (getDefaultWebModuleID() == null && findChild("") == null
&& docroot != null) {
final WebBundleDescriptorImpl wbd =
webArchivist.getDefaultWebXmlBundleDescriptor();
wmInfo = new WebModuleConfig();
wbd.setModuleID(Constants.DEFAULT_WEB_MODULE_NAME);
wbd.setContextRoot("");
wmInfo.setLocation(new File(docroot));
wmInfo.setDescriptor(wbd);
wmInfo.setParentLoader(
serverContext.getCommonClassLoader());
if ( wbd.getApplication() == null ) {
Application application = Application.createApplication();
application.setVirtual(true);
application.setName(Constants.DEFAULT_WEB_MODULE_NAME);
wbd.setApplication(application);
}
WebappClassLoader loader = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public WebappClassLoader run() {
return new WebappClassLoader(serverContext.getCommonClassLoader(), wbd.getApplication());
}
});
loader.start();
wmInfo.setAppClassLoader(loader);
}
return wmInfo;
}
/**
* Returns the id of the default web module for this virtual server
* as specified in the 'default-web-module' attribute of the
* 'virtual-server' element.
*/
protected String getDefaultWebModuleID() {
String wmID = vsBean.getDefaultWebModule();
if ("".equals(wmID)) {
wmID = null;
}
if (wmID != null && _logger.isLoggable(Level.FINE)) {
Object[] params = { wmID, _id };
_logger.log(Level.FINE, VS_DEFAULT_WEB_MODULE, params);
}
return wmID;
}
/**
* Finds and returns information about a web module embedded within a
* J2EE application, which is identified by a string of the form
* a:b
or a#b
, where a
is the name
* of the J2EE application and b
is the name of the embedded
* web module.
*
* @return null if id
does not identify a web module embedded
* within a J2EE application.
*/
protected WebModuleConfig findWebModuleInJ2eeApp(Applications appsBean,
String id, ApplicationRegistry appRegistry) {
WebModuleConfig wmInfo = null;
// Check for ':' separator
int separatorIndex = id.indexOf(Constants.NAME_SEPARATOR);
if (separatorIndex == -1) {
// Check for '#' separator
separatorIndex = id.indexOf('#');
}
if (separatorIndex != -1) {
String appID = id.substring(0, separatorIndex);
String moduleID = id.substring(separatorIndex + 1);
com.sun.enterprise.config.serverbeans.Application appBean =
appsBean.getModule(
com.sun.enterprise.config.serverbeans.Application.class, appID);
if ((appBean != null) && Boolean.valueOf(appBean.getEnabled())) {
String location = appBean.getLocation();
String moduleDir = DeploymentUtils.getRelativeEmbeddedModulePath(
location, moduleID);
ApplicationInfo appInfo = appRegistry.get(appID);
final Application app = appInfo != null? appInfo.getMetaData(Application.class) : null;
if (appInfo == null) {
// XXX ApplicaionInfo is NULL after restart
Object[] params = { id, getID() };
_logger.log(Level.SEVERE, VS_DEFAULT_WEB_MODULE_DISABLED,
params);
return wmInfo;
}
final WebBundleDescriptorImpl wbd = app.getModuleByTypeAndUri(WebBundleDescriptorImpl.class, moduleID);
String webUri = wbd.getModuleDescriptor().getArchiveUri();
String contextRoot = wbd.getModuleDescriptor().getContextRoot();
if (moduleID.equals(webUri)) {
StringBuilder dir = new StringBuilder(location);
dir.append(File.separator);
dir.append(moduleDir);
File docroot = new File(dir.toString());
wmInfo = new WebModuleConfig();
wbd.setName(moduleID);
wbd.setContextRoot(contextRoot);
wmInfo.setDescriptor(wbd);
wmInfo.setLocation(docroot);
wmInfo.setParentLoader(EmbeddedWebContainer.class.getClassLoader());
WebappClassLoader cloader = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public WebappClassLoader run() {
return new WebappClassLoader(EmbeddedWebContainer.class.getClassLoader(), app);
}
});
wmInfo.setAppClassLoader(cloader);
}
} else {
Object[] params = { id, getID() };
_logger.log(Level.SEVERE, VS_DEFAULT_WEB_MODULE_DISABLED,
params);
}
}
return wmInfo;
}
/**
* Virtual servers are maintained in the reference contained
* in Server element. First, we need to find the server
* and then get the virtual server from the correct reference
*
* @param appName Name of the app to get vs
*
* @return virtual servers as a string (separated by space or comma)
*
private String getVirtualServers(String appName) {
String ret = null;
Server server = Globals.getDefaultHabitat().forContract(Server.class).get();
for (ApplicationRef appRef : server.getApplicationRef()) {
if (appRef.getRef().equals(appName)) {
return appRef.getVirtualServers();
}
}
return ret;
} */
/**
* Delete all aliases.
*/
public void clearAliases(){
aliases = new String[0];
}
private void setIsDisabled(boolean isDisabled) {
vsPipeline.setIsDisabled(isDisabled);
vsPipeline.setIsOff(false);
if (isDisabled && pipeline != vsPipeline) {
// Enable custom pipeline
setPipeline(vsPipeline);
}
}
private void setIsOff(boolean isOff) {
vsPipeline.setIsOff(isOff);
vsPipeline.setIsDisabled(false);
if (isOff && pipeline != vsPipeline) {
// Enable custom pipeline
setPipeline(vsPipeline);
}
}
private void close(FileLoggerHandler handler) {
if (handler != null && !handler.isAssociated()) {
if (fileLoggerHandlerFactory != null) {
// should always be here
fileLoggerHandlerFactory.removeHandler(handler.getLogFile());
}
handler.flush();
handler.close();
}
}
private void setLogger(Logger newLogger, String logLevel) {
_logger = newLogger;
// wrap into a cataline logger
CatalinaLogger catalinaLogger = new CatalinaLogger(newLogger);
catalinaLogger.setLevel(logLevel);
setLogger(catalinaLogger);
}
/**
* @return The properties of this virtual server
*/
List getProperties() {
return vsBean.getProperty();
}
/**
* Configures this virtual server.
*/
public void configure(
String vsID,
com.sun.enterprise.config.serverbeans.VirtualServer vsBean,
String vsDocroot,
String vsLogFile,
MimeMap vsMimeMap,
String logServiceFile,
String logLevel) {
setDebug(debug);
setAppBase(vsDocroot);
setName(vsID);
setID(vsID);
setBean(vsBean);
setMimeMap(vsMimeMap);
String defaultContextXmlLocation = Constants.DEFAULT_CONTEXT_XML;
String defaultWebXmlLocation = Constants.DEFAULT_WEB_XML;
//Begin EE: 4920692 Make the default-web.xml be relocatable
Property prop = vsBean.getProperty("default-web-xml");
if (prop != null) {
defaultWebXmlLocation = prop.getValue();
}
//End EE: 4920692 Make the default-web.xml be relocatable
// allowLinking
boolean allowLinking = false;
prop = vsBean.getProperty("allowLinking");
if (prop != null) {
allowLinking = Boolean.parseBoolean(prop.getValue());
}
setAllowLinking(allowLinking);
prop = vsBean.getProperty("contextXmlDefault");
if (prop != null) {
defaultContextXmlLocation = prop.getValue();
}
setDefaultWebXmlLocation(defaultWebXmlLocation);
setDefaultContextXmlLocation(defaultContextXmlLocation);
// Set vs state
String state = vsBean.getState();
if (state == null) {
state = ON;
}
if (DISABLED.equalsIgnoreCase(state)) {
setIsActive(false);
} else {
setIsActive(Boolean.parseBoolean(state));
}
setLogFile(vsLogFile, logLevel, logServiceFile);
}
/**
* Configures the valve_ and listener_ properties of this VirtualServer.
*/
protected void configureCatalinaProperties(){
List props = vsBean.getProperty();
if (props == null) {
return;
}
for (Property prop : props) {
String propName = prop.getName();
String propValue = prop.getValue();
if (propName == null || propValue == null) {
_logger.log(Level.WARNING,
NULL_VIRTUAL_SERVER_PROPERTY,
getName());
}
if (propName != null) {
if (propName.startsWith("valve_")) {
addValve(propValue);
} else if (propName.startsWith("listener_")) {
addListener(propValue);
} else if (propName.equals("securePagesWithPragma")){
setSecurePagesWithPragma(Boolean.valueOf(propValue));
}
}
}
}
/*
* Configures this virtual server with the specified log file.
*
* @param logFile The value of the virtual server's log-file attribute in
* the domain.xml
*/
synchronized void setLogFile(String logFile, String logLevel, String logServiceFile) {
/** catalina file logger code
String logPrefix = logFile;
String logDir = null;
String logSuffix = null;
if (logPrefix == null || logPrefix.equals("")) {
return;
}
int index = logPrefix.lastIndexOf(File.separatorChar);
if (index != -1) {
logDir = logPrefix.substring(0, index);
logPrefix = logPrefix.substring(index+1);
}
index = logPrefix.indexOf('.');
if (index != -1) {
logSuffix = logPrefix.substring(index);
logPrefix = logPrefix.substring(0, index);
}
logPrefix += "_";
FileLogger contextLogger = new FileLogger();
if (logDir != null) {
contextLogger.setDirectory(logDir);
}
contextLogger.setPrefix(logPrefix);
if (logSuffix != null) {
contextLogger.setSuffix(logSuffix);
}
contextLogger.setTimestamp(true);
contextLogger.setLevel(logLevel);
*/
/*
* Configure separate logger for this virtual server only if
* 'log-file' attribute of this and 'file'
* attribute of are different (See 6189219).
*/
boolean noCustomLog = (logFile == null ||
(logServiceFile != null && new File(logFile).equals(
new File(logServiceFile))));
if ((fileLoggerHandler == null && noCustomLog) ||
(fileLoggerHandler != null && logFile != null &&
logFile.equals(fileLoggerHandler.getLogFile()))) {
return;
}
Logger newLogger = null;
FileLoggerHandler oldHandler = fileLoggerHandler;
//remove old handler
if (oldHandler != null) {
_logger.removeHandler(oldHandler);
}
if (noCustomLog) {
fileLoggerHandler = null;
newLogger = _logger;
} else {
// append the _logger name with "._vs."
String lname = _logger.getName() + "._vs." + getID();
newLogger = LogManager.getLogManager().getLogger(lname);
if (newLogger == null) {
newLogger = new Logger(lname, null) {
// set thread id, see LogDomains.getLogger method
@Override
public void log(LogRecord record) {
if (record.getResourceBundle() == null) {
ResourceBundle bundle = getResourceBundle();
if (bundle != null) {
record.setResourceBundle(bundle);
}
}
record.setThreadID((int)Thread.currentThread().getId());
super.log(record);
}
// use the same resource bundle as default vs logger
@Override
public ResourceBundle getResourceBundle() {
return rb;
}
@Override
public synchronized void addHandler(Handler handler) {
super.addHandler(handler);
if (handler instanceof FileLoggerHandler) {
((FileLoggerHandler)handler).associate();
}
}
@Override
public synchronized void removeHandler(Handler handler) {
if (!(handler instanceof FileLoggerHandler)) {
super.removeHandler(handler);
} else {
boolean hasHandler = false;
Handler[] hs = getHandlers();
if (hs != null) {
for (Handler h : hs) {
if (h == handler) {
hasHandler = true;
break;
}
}
}
if (hasHandler) {
super.removeHandler(handler);
((FileLoggerHandler)handler).disassociate();
}
}
}
};
synchronized(Logger.class) {
LogManager.getLogManager().addLogger(newLogger);
}
}
// remove old handlers if necessary
Handler[] handlers = newLogger.getHandlers();
if (handlers != null) {
for (Handler h : handlers) {
newLogger.removeHandler(h);
}
}
// add handlers from root that is not GFFileHandler
Logger rootLogger = Logger.global.getParent();
if (rootLogger != null) {
Handler[] rootHandlers = rootLogger.getHandlers();
if (rootHandlers != null) {
for (Handler h : rootHandlers) {
if (!(h instanceof GFFileHandler)) {
newLogger.addHandler(h);
}
}
}
}
// create and add new handler
fileLoggerHandler = fileLoggerHandlerFactory.getHandler(logServiceFile);
newLogger.addHandler(fileLoggerHandler);
newLogger.setUseParentHandlers(false);
}
setLogger(newLogger, logLevel);
close(oldHandler);
}
/**
* Adds each host name from the 'hosts' attribute as an alias
*/
void configureAliases() {
List hosts = StringUtils.parseStringList(vsBean.getHosts(), ",");
for (int i=0; i < hosts.size(); i++ ){
String alias = hosts.get(i).toString();
if ( !alias.equalsIgnoreCase("localhost") &&
!alias.equalsIgnoreCase("localhost.localdomain")){
addAlias(alias);
}
}
}
void configureAliases(String... hosts) {
for (String host : hosts) {
if ( !host.equalsIgnoreCase("localhost") &&
!host.equalsIgnoreCase("localhost.localdomain")){
addAlias(host);
}
}
}
/**
* Configures this virtual server with its authentication realm.
*
* Checks if this virtual server specifies any authRealm property, and
* if so, ensures that its value identifies a valid realm.
*
* @param securityService The security-service element from domain.xml
*/
void configureAuthRealm(SecurityService securityService) {
List properties = vsBean.getProperty();
if (properties != null && properties.size() > 0) {
for (Property p: properties) {
if (p != null && "authRealm".equals(p.getName())) {
authRealmName = p.getValue();
if (authRealmName != null) {
AuthRealm realm = null;
List rs = securityService.getAuthRealm();
if (rs != null && rs.size() > 0) {
for (AuthRealm r : rs) {
if (r != null &&
r.getName().equals(authRealmName)) {
realm = r;
break;
}
}
}
if (realm == null) {
_logger.log(Level.SEVERE, INVALID_AUTH_REALM,
new Object[] {getID(), authRealmName});
}
}
break;
}
}
}
}
/**
* Gets the value of the authRealm property of this virtual server.
*
* @return The value of the authRealm property of this virtual server,
* or null of this virtual server does not have any such property
*/
String getAuthRealmName() {
return authRealmName;
}
/**
* Adds the Valve
with the given class name to this
* VirtualServer.
*
* @param valveName The valve's fully qualified class nam
*/
protected void addValve(String valveName) {
Object valve = safeLoadInstance(valveName);
if (valve instanceof Valve) {
addValve((Valve) valve);
} else if (valve instanceof GlassFishValve) {
addValve((GlassFishValve) valve);
} else {
_logger.log(Level.WARNING, NOT_A_VALVE, valveName);
}
}
/**
* Adds the Catalina listener with the given class name to this
* VirtualServer.
*
* @param listenerName The fully qualified class name of the listener
*/
protected void addListener(String listenerName) {
Object listener = safeLoadInstance(listenerName);
if ( listener == null ) return;
if (listener instanceof ContainerListener) {
addContainerListener((ContainerListener)listener);
} else if (listener instanceof LifecycleListener){
addLifecycleListener((LifecycleListener)listener);
} else {
_logger.log(Level.SEVERE, INVALID_LISTENER,
new Object[] {listenerName, getID()});
}
}
@Override
protected Object loadInstance(String className) throws Exception {
// See IT 11674 for why CommonClassLoader must be used
Class clazz = serverContext.getCommonClassLoader().loadClass(className);
return clazz.newInstance();
}
private Object safeLoadInstance(String className){
try{
return loadInstance(className);
} catch (Throwable ex){
_logger.log(Level.SEVERE, UNABLE_TO_LOAD_EXTENSION, ex);
}
return null;
}
/**
* Configures this VirtualServer with its send-error properties.
*/
void configureErrorPage() {
ErrorPage errorPage = null;
List props = vsBean.getProperty();
if (props == null) {
return;
}
for (Property prop : props) {
String propName = prop.getName();
String propValue = prop.getValue();
if (propName == null || propValue == null) {
_logger.log(Level.WARNING,
NULL_VIRTUAL_SERVER_PROPERTY,
getID());
continue;
}
if (!propName.startsWith("send-error_")) {
continue;
}
/*
* Validate the prop value
*/
String path = null;
String reason = null;
String status = null;
String[] errorParams = propValue.split(" ");
for (int j=0; j props = vsBean.getProperty();
if (props == null) {
return;
}
for (Property prop : props) {
String propName = prop.getName();
String propValue = prop.getValue();
if (propName == null || propValue == null) {
_logger.log(Level.WARNING,
NULL_VIRTUAL_SERVER_PROPERTY,
getID());
continue;
}
if (!propName.startsWith("redirect_")) {
continue;
}
/*
* Validate the prop value
*/
String from = null;
String url = null;
String urlPrefix = null;
String escape = null;
String[] redirectParams = propValue.split(" ");
for (int j=0; j 0
&& urlPrefix != null && urlPrefix.length() > 0) {
_logger.log(Level.WARNING,
REDIRECT_BOTH_URL_AND_URL_PREFIX,
new Object[] { propValue, getID() });
}
boolean escapeURI = true;
if (escape != null) {
if ("yes".equalsIgnoreCase(escape)) {
escapeURI = true;
} else if ("no".equalsIgnoreCase(escape)) {
escapeURI = false;
} else {
_logger.log(Level.WARNING,
REDIRECT_INVALID_ESCAPE,
new Object[] { propValue, getID() });
}
}
vsPipeline.addRedirect(from, url, urlPrefix, escapeURI);
}
if (vsPipeline.hasRedirects()) {
if (pipeline != vsPipeline) {
// Enable custom pipeline
setPipeline(vsPipeline);
}
} else if (isActive && pipeline != origPipeline) {
setPipeline(origPipeline);
}
}
/**
* Configures the SSO valve of this VirtualServer.
*/
void configureSingleSignOn(boolean globalSSOEnabled,
WebContainerFeatureFactory webContainerFeatureFactory,
boolean ssoFailoverEnabled) {
if (!isSSOEnabled(globalSSOEnabled)) {
/*
* Disable SSO
*/
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, DISABLE_SSO, getID());
}
boolean hasExistingSSO = false;
// Remove existing SSO valve (if any)
GlassFishValve[] valves = getValves();
for (int i=0; valves!=null && i listenerList = StringUtils.parseStringList(
vsBean.getNetworkListeners(), ",");
String[] listeners = (listenerList != null) ?
listenerList.toArray(new String[listenerList.size()]) :
new String[0];
List networkListeners = new ArrayList();
for (String listener : listeners) {
for (NetworkListener networkListener :
serverConfig.getNetworkConfig().getNetworkListeners().getNetworkListener()) {
if (networkListener.getName().equals(listener)) {
networkListeners.add(networkListener);
}
}
}
for (final NetworkListener listener : networkListeners) {
try {
final GrizzlyProxy proxy = (GrizzlyProxy) grizzlyService.lookupNetworkProxy(listener);
if (proxy != null) {
GenericGrizzlyListener grizzlyListener = (GenericGrizzlyListener) proxy.getUnderlyingListener();
List codecFilters = grizzlyListener.getFilters(HttpCodecFilter.class);
if (codecFilters == null || codecFilters.isEmpty()) {
// if it's AJP listener - it's ok if we didn't find HttpCodecFilter
if (grizzlyListener.isAjpEnabled()) {
continue;
}
_logger.log(Level.SEVERE, CODE_FILTERS_NULL, new Object[] {listener.getName(), codecFilters});
} else {
for (HttpCodecFilter codecFilter : codecFilters) {
if (codecFilter.getMonitoringConfig().getProbes().length == 0) {
httpProbe = new HttpProbeImpl(listener, isAccessLoggingEnabled(globalAccessLoggingEnabled));
codecFilter.getMonitoringConfig().addProbes(httpProbe);
}
}
}
grizzlyListener.getTransport().getConnectionMonitoringConfig().addProbes(new ConnectionProbe.Adapter() {
RequestProbeProvider requestProbeProvider = webContainer.getRequestProbeProvider();
@Override
public void onReadEvent(Connection connection, Buffer data, int size) {
if (requestProbeProvider != null) {
requestProbeProvider.dataReceivedEvent(size);
}
}
@Override
public void onWriteEvent(Connection connection, Buffer data, long size) {
if (requestProbeProvider != null) {
requestProbeProvider.dataSentEvent(size);
}
}
});
} else {
// check the listener is enabled before spitting out the SEVERE log
if (Boolean.parseBoolean(listener.getEnabled())) {
_logger.log(Level.SEVERE, PROXY_NULL, new Object[] {listener.getName()});
}
}
} catch (Exception ex) {
_logger.log(Level.SEVERE, ADD_HTTP_PROBES_ERROR, ex);
}
}
}
/**
* Reconfigures the access log of this VirtualServer with its
* updated access log related properties.
*/
void reconfigureAccessLog(String globalAccessLogBufferSize,
String globalAccessLogWriteInterval,
ServiceLocator services,
Domain domain,
boolean globalAccessLoggingEnabled) {
try {
if (accessLogValve.isStarted()) {
accessLogValve.stop();
}
boolean start = accessLogValve.updateVirtualServerProperties(
vsBean.getId(), vsBean, domain, services,
globalAccessLogBufferSize, globalAccessLogWriteInterval);
if (start && isAccessLoggingEnabled(globalAccessLoggingEnabled)) {
enableAccessLogging();
} else {
disableAccessLogging();
}
} catch (LifecycleException le) {
_logger.log(Level.SEVERE, UNABLE_RECONFIGURE_ACCESS_LOG, le);
}
}
/**
* Reconfigures the access log of this VirtualServer with the
* updated attributes of the access-log element from domain.xml.
*/
void reconfigureAccessLog(
HttpService httpService,
WebContainerFeatureFactory webcontainerFeatureFactory) {
try {
boolean restart = false;
if (accessLogValve.isStarted()) {
accessLogValve.stop();
restart = true;
}
accessLogValve.updateAccessLogAttributes(
httpService,
webcontainerFeatureFactory);
if (restart) {
accessLogValve.start();
if (httpProbe != null)
httpProbe.enableAccessLogging();
}
} catch (LifecycleException le) {
_logger.log(Level.SEVERE, UNABLE_RECONFIGURE_ACCESS_LOG, le);
}
}
/**
* @return the accesslog valve of this virtual server
*/
PEAccessLogValve getAccessLogValve() {
return accessLogValve;
}
/**
* Enables access logging for this virtual server, by adding its
* accesslog valve to its pipeline, or starting its accesslog valve
* if it is already present in the pipeline.
*/
void enableAccessLogging() {
if (!isAccessLogValveActivated()) {
addValve((GlassFishValve) accessLogValve);
} else {
try {
if (accessLogValve.isStarted()) {
accessLogValve.stop();
}
accessLogValve.start();
if (httpProbe != null)
httpProbe.enableAccessLogging();
} catch (LifecycleException le) {
_logger.log(Level.SEVERE, UNABLE_RECONFIGURE_ACCESS_LOG, le);
}
}
}
/**
* Disables access logging for this virtual server, by removing its
* accesslog valve from its pipeline.
*/
void disableAccessLogging() {
removeValve(accessLogValve);
if (httpProbe != null)
httpProbe.disableAccessLogging();
}
/**
* @return true if the accesslog valve of this virtual server has been
* activated, that is, added to this virtual server's pipeline; false
* otherwise
*/
private boolean isAccessLogValveActivated() {
Pipeline p = getPipeline();
if (p != null) {
GlassFishValve[] valves = p.getValves();
if (valves != null) {
for (int i=0; i values = StringUtils.parseStringList(cacheControl, ",");
if (values != null && !values.isEmpty()) {
setCacheControls(values.toArray(new String[values.size()]));
}
}
}
/**
* Checks if SSO is enabled for this VirtualServer.
*
* @return The value of the sso-enabled property for this VirtualServer
*/
private boolean isSSOEnabled(boolean globalSSOEnabled) {
String ssoEnabled = "inherit";
if (vsBean != null) {
ssoEnabled = vsBean.getSsoEnabled();
}
return "inherit".equals(ssoEnabled) && globalSSOEnabled
|| ConfigBeansUtilities.toBoolean(ssoEnabled);
}
private void setSingleSignOnForChildren(SingleSignOn sso) {
for (Container container : findChildren()) {
if (container instanceof StandardContext) {
StandardContext context = (StandardContext)container;
for (GlassFishValve valve: context.getValves()) {
if (valve instanceof AuthenticatorBase) {
((AuthenticatorBase)valve).setSingleSignOn(sso);
break;
}
}
}
}
}
/**
* Determines whether access logging is enabled for this virtual server.
*
* @param globalAccessLoggingEnabled The value of the
* accessLoggingEnabled property of the http-service element
*
* @return true if access logging is enabled for this virtual server,
* false otherwise.
*/
boolean isAccessLoggingEnabled(boolean globalAccessLoggingEnabled) {
String enabled = vsBean.getAccessLoggingEnabled();
return "inherit".equals(enabled) && globalAccessLoggingEnabled ||
ConfigBeansUtilities.toBoolean(enabled);
}
@Override
public void setRealm(Realm realm) {
if ((realm != null) && !(realm instanceof RealmAdapter)) {
_logger.log(Level.SEVERE, IGNORE_INVALID_REALM,
new Object[] { realm.getClass().getName(),
RealmAdapter.class.getName()});
} else {
super.setRealm(realm);
}
}
/**
* Configures the security level of the SSO cookie for this virtual
* server, based on the value of its sso-cookie-secure attribute
*/
private void configureSingleSignOnCookieSecure() {
String cookieSecure = vsBean.getSsoCookieSecure();
if (!"true".equalsIgnoreCase(cookieSecure) &&
!"false".equalsIgnoreCase(cookieSecure) &&
!cookieSecure.equalsIgnoreCase(
SessionCookieConfig.DYNAMIC_SECURE)) {
_logger.log(Level.WARNING, INVALID_SSO_COOKIE_SECURE,
new Object[] {cookieSecure, getID()});
} else {
ssoCookieSecure = cookieSecure;
}
}
private void configureSingleSignOnCookieHttpOnly() {
ssoCookieHttpOnly = Boolean.parseBoolean(vsBean.getSsoCookieHttpOnly());
}
/**
* Configures the error report valve of this VirtualServer.
*
* The error report valve of a virtual server is specified through
* a property with name errorReportValve, whose value is the
* valve's fully qualified classname. A null or empty classname
* disables the error report valve and therefore the container's
* default error page mechanism for error responses.
*/
void configureErrorReportValve() {
Property prop = vsBean.getProperty(Constants.ERROR_REPORT_VALVE);
if (prop != null) {
setErrorReportValveClass(prop.getValue());
}
}
void setServerContext(ServerContext serverContext) {
this.serverContext = serverContext;
}
void setServerConfig(Config serverConfig) {
this.serverConfig = serverConfig;
}
void setGrizzlyService(GrizzlyService grizzlyService) {
this.grizzlyService = grizzlyService;
}
void setWebContainer(WebContainer webContainer) {
this.webContainer = webContainer;
}
// ----------------------------------------------------- embedded methods
private VirtualServerConfig config;
private List listeners = new ArrayList();
/**
* Sets the docroot of this VirtualServer.
*
* @param docRoot the docroot of this VirtualServer.
*/
public void setDocRoot(File docRoot) {
this.setAppBase(docRoot.getPath());
}
/**
* Gets the docroot of this VirtualServer.
*/
public File getDocRoot() {
return new File(getAppBase());
}
/**
* Sets the collection of WebListener instances from which
* this VirtualServer receives requests.
*
* @param webListeners the collection of WebListener instances from which
* this VirtualServer receives requests.
*/
public void setWebListeners(WebListener... webListeners) {
if (webListeners != null) {
listeners = Arrays.asList(webListeners);
}
}
/**
* Gets the collection of WebListener instances from which
* this VirtualServer receives requests.
*
* @return the collection of WebListener instances from which
* this VirtualServer receives requests.
*/
public Collection getWebListeners() {
return listeners;
}
/**
* Registers the given Context with this VirtualServer
* at the given context root.
*
* If this VirtualServer has already been started, the
* given context will be started as well.
*/
public void addContext(Context context, String contextRoot)
throws ConfigException, GlassFishException {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, VS_ADDED_CONTEXT);
}
if (!(context instanceof ContextFacade)) {
// embedded context should always be created via ContextFacade
return;
}
if (!contextRoot.startsWith("/")) {
contextRoot = "/"+contextRoot;
}
ExtendedDeploymentContext deploymentContext = null;
try {
if (factory==null)
factory = services.getService(ArchiveFactory.class);
ContextFacade facade = (ContextFacade) context;
File docRoot = facade.getDocRoot();
ClassLoader classLoader = facade.getClassLoader();
ReadableArchive archive = factory.openArchive(docRoot);
if (report==null)
report = new PlainTextActionReporter();
ServerEnvironment env = services.getService(ServerEnvironment.class);
DeployCommandParameters params = new DeployCommandParameters();
params.contextroot = contextRoot;
params.enabled = Boolean.FALSE;
params.origin = OpsParams.Origin.deploy;
params.virtualservers = getName();
params.target = "server";
ExtendedDeploymentContext initialContext =
new DeploymentContextImpl(report, archive, params, env);
if (deployment==null)
deployment = services.getService(Deployment.class);
ArchiveHandler archiveHandler = deployment.getArchiveHandler(archive);
if (archiveHandler==null) {
throw new RuntimeException("Cannot find archive handler for source archive");
}
params.name = archiveHandler.getDefaultApplicationName(archive, initialContext);
Applications apps = domain.getApplications();
ApplicationInfo appInfo = deployment.get(params.name);
ApplicationRef appRef = domain.getApplicationRefInServer(params.target, params.name);
if (appInfo!=null && appRef!=null) {
if (appRef.getVirtualServers().contains(getName())) {
throw new ConfigException(
"Context with name "+params.name+" is already registered on virtual server "+getName());
} else {
String virtualServers = appRef.getVirtualServers();
virtualServers = virtualServers + ","+getName();
params.virtualservers = virtualServers;
params.force = Boolean.TRUE;
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, "Virtual server "+getName()+" added to context "+params.name);
}
return;
}
}
deploymentContext = deployment.getBuilder(
_logger, params, report).source(archive).archiveHandler(
archiveHandler).build(initialContext);
Properties properties = new Properties();
deploymentContext.getAppProps().putAll(properties);
if (classLoader != null) {
ClassLoader parentCL = clh.createApplicationParentCL(classLoader, deploymentContext);
ClassLoader cl = archiveHandler.getClassLoader(parentCL, deploymentContext);
deploymentContext.setClassLoader(cl);
}
ApplicationConfigInfo savedAppConfig =
new ApplicationConfigInfo(apps.getModule(com.sun.enterprise.config.serverbeans.Application.class, params.name));
Properties appProps = deploymentContext.getAppProps();
String appLocation = DeploymentUtils.relativizeWithinDomainIfPossible(deploymentContext.getSource().getURI());
appProps.setProperty(ServerTags.LOCATION, appLocation);
appProps.setProperty(ServerTags.OBJECT_TYPE, "user");
appProps.setProperty(ServerTags.CONTEXT_ROOT, contextRoot);
savedAppConfig.store(appProps);
Transaction t = deployment.prepareAppConfigChanges(deploymentContext);
appInfo = deployment.deploy(deploymentContext);
if (appInfo!=null) {
facade.setAppName(appInfo.getName());
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, VS_ADDED_CONTEXT, new Object[]{getName(), appInfo.getName()});
}
deployment.registerAppInDomainXML(appInfo, deploymentContext, t);
} else {
if (report.getActionExitCode().equals(ActionReport.ExitCode.FAILURE)) {
throw new ConfigException(report.getMessage());
}
}
// Update web.xml with programmatically added servlets, filters, and listeners
File file = null;
boolean delete = true;
com.sun.enterprise.config.serverbeans.Application appBean = apps.getApplication(params.name);
if (appBean != null) {
file = new File(deploymentContext.getSource().getURI().getPath(), "/WEB-INF/web.xml");
if (file.exists()) {
delete = false;
}
updateWebXml(facade, file);
} else {
_logger.log(Level.SEVERE, APP_NOT_FOUND);
}
ReadableArchive source = appInfo.getSource();
UndeployCommandParameters undeployParams = new UndeployCommandParameters(params.name);
undeployParams.origin = UndeployCommandParameters.Origin.undeploy;
undeployParams.target = "server";
ExtendedDeploymentContext undeploymentContext =
deployment.getBuilder(_logger, undeployParams, report).source(source).build();
deployment.undeploy(params.name, undeploymentContext);
params.origin = DeployCommandParameters.Origin.load;
params.enabled = Boolean.TRUE;
archive = factory.openArchive(docRoot);
deploymentContext = deployment.getBuilder(_logger, params, report).source(archive).build();
if (classLoader != null) {
ClassLoader parentCL = clh.createApplicationParentCL(classLoader, deploymentContext);
archiveHandler = deployment.getArchiveHandler(archive);
ClassLoader cl = archiveHandler.getClassLoader(parentCL, deploymentContext);
deploymentContext.setClassLoader(cl);
}
deployment.deploy(deploymentContext);
// Enable the app using the modified web.xml
// We can't use Deployment.enable since it doesn't take DeploymentContext with custom class loader
deployment.updateAppEnabledAttributeInDomainXML(params.name, params.target, true);
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, VS_ENABLED_CONTEXT, new Object[]{getName(), params.name()});
}
if (delete) {
if (file != null) {
if (file.exists() && !file.delete()) {
String path = file.toString();
_logger.log(Level.WARNING, UNABLE_TO_DELETE, path);
}
}
}
if (contextRoot.equals("/")) {
contextRoot = "";
}
WebModule wm = (WebModule) findChild(contextRoot);
if (wm != null) {
facade.setUnwrappedContext(wm);
wm.setEmbedded(true);
if (config != null) {
wm.setDefaultWebXml(config.getDefaultWebXml());
}
} else {
throw new ConfigException("Deployed app not found "+contextRoot);
}
if (deploymentContext != null) {
deploymentContext.postDeployClean(true);
}
} catch (Exception ex) {
if (deployment!=null && deploymentContext!=null) {
deploymentContext.clean();
}
throw new GlassFishException(ex);
}
}
/**
* Stops the given context and removes it from this
* VirtualServer.
*/
public void removeContext(Context context) throws GlassFishException {
ActionReport report = services.getService(ActionReport.class, "plain");
Deployment deployment = services.getService(Deployment.class);
String name;
if (context instanceof ContextFacade) {
name = ((ContextFacade)context).getAppName();
} else {
name = context.getPath();
}
ApplicationInfo appInfo = deployment.get(name);
if (appInfo == null) {
report.setMessage("Cannot find deployed application of name " + name);
report.setActionExitCode(ActionReport.ExitCode.FAILURE);
throw new GlassFishException("Cannot find deployed application of name " + name);
}
ReadableArchive source = appInfo.getSource();
if (source == null) {
report.setMessage("Cannot get source archive for undeployment");
report.setActionExitCode(ActionReport.ExitCode.FAILURE);
throw new GlassFishException("Cannot get source archive for undeployment");
}
UndeployCommandParameters params = new UndeployCommandParameters(name);
params.origin = UndeployCommandParameters.Origin.undeploy;
params.target = "server";
ExtendedDeploymentContext deploymentContext = null;
try {
deploymentContext = deployment.getBuilder(_logger, params, report).source(source).build();
deployment.undeploy(name, deploymentContext);
deployment.unregisterAppFromDomainXML(name, "server");
} catch (IOException e) {
_logger.log(Level.SEVERE, REMOVE_CONTEXT_ERROR, e);
report.setActionExitCode(ActionReport.ExitCode.FAILURE);
throw new GlassFishException("Cannot create context for undeployment ", e);
} catch (TransactionFailure e) {
throw new GlassFishException(e);
} finally {
if (deploymentContext!=null) {
deploymentContext.clean();
}
}
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, REMOVED_CONTEXT, name);
}
}
/**
* Finds the Context registered at the given context root.
*/
public Context getContext(String contextRoot) {
if (!contextRoot.startsWith("/")) {
contextRoot = "/"+contextRoot;
}
return (Context)findChild(contextRoot);
}
/**
* Gets the collection of Context instances registered with
* this VirtualServer.
*/
public Collection getContexts() {
Collection ctxs = new ArrayList();
for (Container container : findChildren()) {
if (container instanceof Context) {
ctxs.add((Context)container);
}
}
return ctxs;
}
/**
* Reconfigures this VirtualServer with the given
* configuration.
*
* In order for the given configuration to take effect, this
* VirtualServer may be stopped and restarted.
*/
public void setConfig(VirtualServerConfig config)
throws ConfigException {
this.config = config;
configureSingleSignOn(config.isSsoEnabled(),
Globals.getDefaultHabitat().getService(
PEWebContainerFeatureFactoryImpl.class),
false);
if (config.isAccessLoggingEnabled()) {
enableAccessLogging();
} else {
disableAccessLogging();
}
setDefaultWebXmlLocation(config.getDefaultWebXml());
setDefaultContextXmlLocation(config.getContextXmlDefault());
setAllowLinking(config.isAllowLinking());
configureRemoteAddressFilterValve(config.getAllowRemoteAddress(), config.getDenyRemoteAddress());
configureRemoteHostFilterValve(config.getAllowRemoteHost(), config.getAllowRemoteHost());
configureAliases(config.getHostNames());
}
/**
* Gets the current configuration of this VirtualServer.
*/
public VirtualServerConfig getConfig() {
return config;
}
@Override
public synchronized void stop() throws LifecycleException {
if (fileLoggerHandler != null) {
_logger.removeHandler(fileLoggerHandler);
close(fileLoggerHandler);
fileLoggerHandler = null;
}
setLogger(_logger, "INFO");
super.stop();
}
public void updateWebXml(ContextFacade facade, File file) throws Exception {
Map servlets = facade.getAddedServlets();
Map mappings = facade.getServletMappings();
List listeners = facade.getListeners();
Map filters = facade.getAddedFilters();
Map servletNameFilterMappings = facade.getServletNameFilterMappings();
Map urlPatternFilterMappings = facade.getUrlPatternFilterMappings();
if (!filters.isEmpty() || !listeners.isEmpty() || !servlets.isEmpty()) {
if (_logger.isLoggable(Level.FINE)) {
_logger.log(Level.FINE, MODIFYING_WEB_XML, file.getAbsolutePath());
}
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = null;
Element webapp = null;
if ((file != null) && (file.exists())) {
doc = dBuilder.parse(file);
webapp = doc.getDocumentElement();
} else {
doc = dBuilder.newDocument();
webapp = doc.createElement("web-app");
webapp.setAttribute("xmln", "http://java.sun.com/xml/ns/j2ee");
webapp.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
webapp.setAttribute("xsi:schemaLocation",
"http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd");
webapp.setAttribute("version", "2.4");
doc.appendChild(webapp);
}
boolean entryFound = false;
// Update
for (Map.Entry entry : filters.entrySet()) {
NodeList filterList = doc.getElementsByTagName("filter-name");
for (int i=0; i initParams =
facade.getFilterRegistration(entry.getKey().toString()).getInitParameters();
if ((initParams != null) && (!initParams.isEmpty())) {
Element initParam = doc.createElement("init-param");
for (Map.Entry param : initParams.entrySet()) {
Element paramName = doc.createElement("param-name");
paramName.setTextContent(param.getKey().toString());
initParam.appendChild(paramName);
Element paramValue = doc.createElement("param-value");
paramValue.setTextContent(param.getValue().toString());
initParam.appendChild(paramValue);
}
filter.appendChild(initParam);
}
webapp.appendChild(filter);
}
}
// Update
for (Map.Entry mapping : servletNameFilterMappings.entrySet()) {
Element filterMapping = doc.createElement("filter-mapping");
Element filterName = doc.createElement("filter-name");
filterName.setTextContent(mapping.getKey().toString());
filterMapping.appendChild(filterName);
Element servletName = doc.createElement("servlet-name");
servletName.setTextContent(mapping.getValue().toString());
filterMapping.appendChild(servletName);
webapp.appendChild(filterMapping);
}
for (Map.Entry mapping : urlPatternFilterMappings.entrySet()) {
Element filterMapping = doc.createElement("filter-mapping");
Element filterName = doc.createElement("filter-name");
filterName.setTextContent(mapping.getKey().toString());
filterMapping.appendChild(filterName);
Element urlPattern = doc.createElement("url-pattern");
urlPattern.setTextContent(mapping.getValue().toString());
filterMapping.appendChild(urlPattern);
webapp.appendChild(filterMapping);
}
entryFound = false;
// Update
for (Map.Entry entry : servlets.entrySet()) {
NodeList servletList = doc.getElementsByTagName("servlet-name");
for (int i=0; i initParams =
facade.getServletRegistration(entry.getKey().toString()).getInitParameters();
if ((initParams != null) && (!initParams.isEmpty())) {
Element initParam = doc.createElement("init-param");
for (Map.Entry param : initParams.entrySet()) {
Element paramName = doc.createElement("param-name");
paramName.setTextContent(param.getKey().toString());
initParam.appendChild(paramName);
Element paramValue = doc.createElement("param-value");
paramValue.setTextContent(param.getValue().toString());
initParam.appendChild(paramValue);
}
servlet.appendChild(initParam);
}
webapp.appendChild(servlet);
}
}
entryFound = false;
// Update
for (Map.Entry mapping : mappings.entrySet()) {
NodeList servletList = doc.getElementsByTagName("servlet-name");
for (int i=0; i