I was wondering if there were a particular reason why
EmbeddedCatalinaServiceSX was written to support http and warp
connectors, but not Ajp13. I added an initAjpConnector method
which takes the default Embedded engine and then substitutes 'Ajp'
for 'Warp' for the connector-specific code, and this seems to work
(ie real .html files are displayed by Apache, fake ones are rejected
by Apache, real jsp files are displayed by Catalina, and fake ones
are rejected by Catalina). Was this support left out because
the tomcat folks call their ajp connector support beta and recommend
using warp? I'd use warp, but it doesn't seem to dig into war
files for web.xml, and jboss will only look in war files for web.xml
- I'd rather not have to support both. Also, Warp doesn't seem
to automatically deliver static content to Apache and dynamic content
to catalina, although that is a promised feature, and I can't direct
it to specifically serve all *.jsp files.
Should I be afraid of using Ajp?
Aaron
/* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.web.catalina;
import java.io.InputStream;
import java.io.IOException;
import java.io.File;
import java.io.PrintWriter;
import java.net.UnknownHostException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.net.InetAddress;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.Iterator;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.jboss.deployment.DeploymentException;
import org.jboss.security.SecurityDomain;
import org.jboss.web.AbstractWebContainer;
import org.jboss.web.AbstractWebContainer.WebDescriptorParser;
import org.jboss.web.WebApplication;
import org.jboss.web.catalina.security.JBossSecurityMgrRealm;
import org.jboss.web.catalina.security.SSLServerSocketFactory;
import org.apache.log4j.Category;
import org.apache.log4j.Priority;
import org.apache.catalina.Connector;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Deployer;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Logger;
import org.apache.catalina.Realm;
import org.apache.catalina.Valve;
import org.apache.catalina.authenticator.AuthenticatorBase;
import org.apache.catalina.connector.http.HttpConnector;
import org.apache.catalina.connector.warp.WarpConnector;
import org.apache.catalina.connector.warp.WarpHost;
import org.apache.catalina.connector.warp.WarpEngine;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.loader.WebappClassLoader;
import org.apache.catalina.startup.Embedded;
import org.apache.ajp.tomcat4.*;
import org.apache.ajp.*;
/** An implementation of the AbstractWebContainer for the Jakarta Tomcat
4.0 servlet container. This uses the Embedded as the integration class. It
does not parse the catalina server.xml.
@see org.jboss.web.AbstractWebContainer
@see org.apache.catalina.startup.Embedded
@author [EMAIL PROTECTED]
@version $Revision: 1.2 $
*/
public class EmbeddedCatalinaServiceSX extends AbstractWebContainer implements EmbeddedCatalinaServiceSXMBean
{
// Constants -----------------------------------------------------
public static final String NAME = "EmbeddedCatalinaSX";
/** The embedded instance used to configure catalina */
private Embedded catalina;
/** The catalina host container */
private Host catalinaHost;
/** The catalina debug level */
private int debugLevel;
/** The port the web server listens on */
private int port = 8080;
/** The interface to bind to. This is useful for multi-homed hosts
that want control over which interfaces accept connections. */
private InetAddress bindAddress;
/** The accept count for this Connector. */
private int acceptCount = 10;
/** The "enable DNS lookups" flag. */
private boolean enableLookups = false;
/** The minimum number of processors to start at initialization time. */
protected int minProcessors = 5;
/**The maximum number of processors allowed, or <0 for unlimited. */
private int maxProcessors = 20;
/** The JNDI name of the SecurityDomain implementation binding */
private String securityDomain;
/** The type of connector that Tomcat will run (HTTP or WARP or Ajp) */
private String connectorType = "http";
/** Any extended configuration information specified via a config
element in the mbean definition.
*/
private Element extendedConfig;
public EmbeddedCatalinaServiceSX()
{
}
public String getName()
{
return NAME;
}
public void setPort(int port)
{
this.port = port;
}
public int getPort()
{
return port;
}
public String getBindAddress()
{
String address = "0.0.0.0";
if( bindAddress != null )
address = bindAddress.getHostAddress();
return address;
}
public void setBindAddress(String host) throws UnknownHostException
{
if( host == null || host.length() == 0 )
bindAddress = null;
else
bindAddress = InetAddress.getByName(host);
}
public String getConnectorType()
{
return this.connectorType;
}
public void setConnectorType(String type)
{
type = type.toLowerCase();
if( type.equals("http") == false && type.equals("warp") == false && type.equals("ajp")==false )
{
String msg= "Invalid connector type: "+connectorType
+ " must be one of, http warp ajp";
throw new IllegalArgumentException(msg);
}
this.connectorType = type;
}
public int getMinProcessors()
{
return this.minProcessors;
}
public void setMinProcessors(int minProcessors)
{
this.minProcessors = minProcessors;
}
public int getMaxProcessors()
{
return this.maxProcessors;
}
public void setMaxProcessors(int maxProcessors)
{
this.maxProcessors = maxProcessors;
}
public int getAcceptCount()
{
return this.acceptCount;
}
public void setAcceptCount(int acceptCount)
{
this.acceptCount = acceptCount;
}
public boolean getEnableLookups()
{
return enableLookups;
}
public void setEnableLookups(boolean enableLookups)
{
this.enableLookups = enableLookups;
}
public String getSecurityDomain()
{
return this.securityDomain;
}
public void setSecurityDomain(String securityDomain)
{
this.securityDomain = securityDomain;
}
/** This method is invoked to import an arbitrary XML configuration tree.
Subclasses should override this method if they support such a configuration
capability. This implementation does nothing.
*/
public void setConfig(Element config)
{
this.extendedConfig = config;
}
public void startService() throws Exception
{
boolean debug = log.isDebugEnabled();
log.info("Starting " + NAME + "....");
// Start create the embeded catalina container but don't let it overwrite the thread class loader
URLClassLoader cl = (URLClassLoader) Thread.currentThread().getContextClassLoader();
URLClassLoader parent = cl;
while( parent != null )
{
log.trace(parent);
URL[] urls = parent.getURLs();
for(int u = 0; u < urls.length; u ++)
log.trace(" "+urls[u]);
parent = (URLClassLoader) parent.getParent();
}
// Determine the catalina debug level from the enabled priority
/** The catalina debug level */
private int debugLevel;
/** The port the web server listens on */
private int port = 8080;
/** The interface to bind to. This is useful for multi-homed hosts
that want control over which interfaces accept connections. */
private InetAddress bindAddress;
/** The accept count for this Connector. */
private int acceptCount = 10;
/** The "enable DNS lookups" flag. */
private boolean enableLookups = false;
/** The minimum number of processors to start at initialization time. */
protected int minProcessors = 5;
/**The maximum number of processors allowed, or <0 for unlimited. */
private int maxProcessors = 20;
/** The JNDI name of the SecurityDomain implementation binding */
private String securityDomain;
/** The type of connector that Tomcat will run (HTTP or WARP or Ajp) */
private String connectorType = "http";
/** Any extended configuration information specified via a config
element in the mbean definition.
*/
private Element extendedConfig;
public EmbeddedCatalinaServiceSX()
{
}
public String getName()
{
return NAME;
}
public void setPort(int port)
{
this.port = port;
}
public int getPort()
{
return port;
}
public String getBindAddress()
{
String address = "0.0.0.0";
if( bindAddress != null )
address = bindAddress.getHostAddress();
return address;
}
public void setBindAddress(String host) throws UnknownHostException
{
if( host == null || host.length() == 0 )
bindAddress = null;
else
bindAddress = InetAddress.getByName(host);
}
public String getConnectorType()
{
return this.connectorType;
}
public void setConnectorType(String type)
{
type = type.toLowerCase();
if( type.equals("http") == false && type.equals("warp") == false && type.equals("ajp")==false )
{
String msg= "Invalid connector type: "+connectorType
+ " must be one of, http warp ajp";
throw new IllegalArgumentException(msg);
}
this.connectorType = type;
}
public int getMinProcessors()
{
return this.minProcessors;
}
public void setMinProcessors(int minProcessors)
{
this.minProcessors = minProcessors;
}
public int getMaxProcessors()
{
return this.maxProcessors;
}
public void setMaxProcessors(int maxProcessors)
{
this.maxProcessors = maxProcessors;
}
public int getAcceptCount()
{
return this.acceptCount;
}
public void setAcceptCount(int acceptCount)
{
this.acceptCount = acceptCount;
}
public boolean getEnableLookups()
{
return enableLookups;
}
public void setEnableLookups(boolean enableLookups)
{
this.enableLookups = enableLookups;
}
public String getSecurityDomain()
{
return this.securityDomain;
}
public void setSecurityDomain(String securityDomain)
{
this.securityDomain = securityDomain;
}
/** This method is invoked to import an arbitrary XML configuration tree.
Subclasses should override this method if they support such a configuration
capability. This implementation does nothing.
*/
public void setConfig(Element config)
{
this.extendedConfig = config;
}
public void startService() throws Exception
{
boolean debug = log.isDebugEnabled();
log.info("Starting " + NAME + "....");
// Start create the embeded catalina container but don't let it overwrite the thread class loader
URLClassLoader cl = (URLClassLoader) Thread.currentThread().getContextClassLoader();
URLClassLoader parent = cl;
while( parent != null )
{
log.trace(parent);
URL[] urls = parent.getURLs();
for(int u = 0; u < urls.length; u ++)
log.trace(" "+urls[u]);
parent = (URLClassLoader) parent.getParent();
}
// Determine the catalina debug level from the enabled priority
debugLevel = 0;
if( log.isTraceEnabled() )
debugLevel = 2;
if (debug)
log.debug("Setting catalina debug level to: "+debugLevel);
try
{
// Set the catalina.home property from the Embedded class location
ProtectionDomain pd = Embedded.class.getProtectionDomain();
URL catalinaHome = pd.getCodeSource().getLocation();
String homePath = catalinaHome.getFile();
File homeDir = new File(homePath, "../../..");
homePath = homeDir.getCanonicalPath();
if (debug)
log.debug("Setting catalina.home to: " + homePath);
System.setProperty("catalina.home", homePath);
System.setProperty("catalina.base", homePath);
initCatalina(cl);
catalina.start();
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
log.info("OK");
}
public void stopService()
{
if( catalina != null )
{
try
{
catalina.stop();
}
catch(Exception e)
{
}
}
}
/** Perform the tomcat specific deployment steps.
*/
protected WebApplication performDeploy(String ctxPath, String warUrl,
WebDescriptorParser webAppParser) throws Exception
{
if( ctxPath.equals("/") )
{
log.info("Changing root context path from '/' to ''");
ctxPath = "";
}
log.info("deploy, ctxPath="+ctxPath+", warUrl="+warUrl);
ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();
URL url = new URL(warUrl);
WebApplication appInfo = createWebContext(ctxPath, url, webAppParser);
if (log.isDebugEnabled())
log.debug("Initialized: "+appInfo);
return appInfo;
}
/** Perform the tomcat specific deployment steps.
*/
public void performUndeploy(String warUrl) throws Exception
{
// find the javax.servlet.ServletContext in the repository
WebApplication appInfo = getDeployedApp(warUrl);
Context context = null;
if( appInfo != null )
context = (Context) appInfo.getAppData();
if(context == null)
throw new DeploymentException("URL " + warUrl + " is not deployed");
String ctxPath = context.getPath();
Deployer deployer = (Deployer) catalinaHost;
deployer.remove(ctxPath);
}
/** Create and configure a org.apache.catalina.startup.Embedded
instance. We do not use the server.xml file as we obtain all
of the required customization from our mbean properties.
*/
private void initCatalina(ClassLoader parent) throws Exception
{
Logger jbossLog = new Log4jLogger(this.log);
Realm jbossRealm = new JBossSecurityMgrRealm();
catalina = new Embedded(jbossLog, jbossRealm);
catalina.setDebug(debugLevel);
catalina.setUseNaming(false);
// Setup the primary engine and connector
if( connectorType.equals("http") )
initHttpConnector(parent, jbossLog, jbossRealm);
else if( connectorType.equals("warp") )
initWarpConnector(parent, jbossLog, jbossRealm);
else if( connectorType.equals("ajp") )
initAjpConnector(parent, jbossLog, jbossRealm);
else
throw new IllegalStateException("No valid connectorType");
// Apply any extended configuration
ConfigHandler handler = new ConfigHandler();
handler.applyHostConfig(extendedConfig, catalina, debugLevel > 0);
}
private void initHttpConnector(ClassLoader parent, Logger jbossLog, Realm jbossRealm)
throws IOException, NamingException
{
log.info("Building Http engine and connector");
String hostname = "localhost";
if( bindAddress != null )
hostname = bindAddress.getHostName();
// Create the engine
Engine engine = catalina.createEngine();
engine.setDefaultHost(hostname);
engine.setParentClassLoader(parent);
// Create a host for the root context
catalinaHost = catalina.createHost(hostname, "");
engine.addChild(catalinaHost);
if( log.isTraceEnabled() )
debugLevel = 2;
if (debug)
log.debug("Setting catalina debug level to: "+debugLevel);
try
{
// Set the catalina.home property from the Embedded class location
ProtectionDomain pd = Embedded.class.getProtectionDomain();
URL catalinaHome = pd.getCodeSource().getLocation();
String homePath = catalinaHome.getFile();
File homeDir = new File(homePath, "../../..");
homePath = homeDir.getCanonicalPath();
if (debug)
log.debug("Setting catalina.home to: " + homePath);
System.setProperty("catalina.home", homePath);
System.setProperty("catalina.base", homePath);
initCatalina(cl);
catalina.start();
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
log.info("OK");
}
public void stopService()
{
if( catalina != null )
{
try
{
catalina.stop();
}
catch(Exception e)
{
}
}
}
/** Perform the tomcat specific deployment steps.
*/
protected WebApplication performDeploy(String ctxPath, String warUrl,
WebDescriptorParser webAppParser) throws Exception
{
if( ctxPath.equals("/") )
{
log.info("Changing root context path from '/' to ''");
ctxPath = "";
}
log.info("deploy, ctxPath="+ctxPath+", warUrl="+warUrl);
ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();
URL url = new URL(warUrl);
WebApplication appInfo = createWebContext(ctxPath, url, webAppParser);
if (log.isDebugEnabled())
log.debug("Initialized: "+appInfo);
return appInfo;
}
/** Perform the tomcat specific deployment steps.
*/
public void performUndeploy(String warUrl) throws Exception
{
// find the javax.servlet.ServletContext in the repository
WebApplication appInfo = getDeployedApp(warUrl);
Context context = null;
if( appInfo != null )
context = (Context) appInfo.getAppData();
if(context == null)
throw new DeploymentException("URL " + warUrl + " is not deployed");
String ctxPath = context.getPath();
Deployer deployer = (Deployer) catalinaHost;
deployer.remove(ctxPath);
}
/** Create and configure a org.apache.catalina.startup.Embedded
instance. We do not use the server.xml file as we obtain all
of the required customization from our mbean properties.
*/
private void initCatalina(ClassLoader parent) throws Exception
{
Logger jbossLog = new Log4jLogger(this.log);
Realm jbossRealm = new JBossSecurityMgrRealm();
catalina = new Embedded(jbossLog, jbossRealm);
catalina.setDebug(debugLevel);
catalina.setUseNaming(false);
// Setup the primary engine and connector
if( connectorType.equals("http") )
initHttpConnector(parent, jbossLog, jbossRealm);
else if( connectorType.equals("warp") )
initWarpConnector(parent, jbossLog, jbossRealm);
else if( connectorType.equals("ajp") )
initAjpConnector(parent, jbossLog, jbossRealm);
else
throw new IllegalStateException("No valid connectorType");
// Apply any extended configuration
ConfigHandler handler = new ConfigHandler();
handler.applyHostConfig(extendedConfig, catalina, debugLevel > 0);
}
private void initHttpConnector(ClassLoader parent, Logger jbossLog, Realm jbossRealm)
throws IOException, NamingException
{
log.info("Building Http engine and connector");
String hostname = "localhost";
if( bindAddress != null )
hostname = bindAddress.getHostName();
// Create the engine
Engine engine = catalina.createEngine();
engine.setDefaultHost(hostname);
engine.setParentClassLoader(parent);
// Create a host for the root context
catalinaHost = catalina.createHost(hostname, "");
engine.addChild(catalinaHost);
// Install the engine
catalina.addEngine(engine);
// Create the warp connector and set its properties
HttpConnector connector = (HttpConnector) catalina.createConnector(bindAddress, port, false);
connector.setAcceptCount(acceptCount);
connector.setMinProcessors(minProcessors);
connector.setMaxProcessors(maxProcessors);
connector.setEnableLookups(enableLookups);
// Enable a secure connector if a security domain was specified
if( securityDomain != null )
{
connector.setScheme("https");
connector.setSecure(true);
InitialContext iniCtx = new InitialContext();
SecurityDomain domain = (SecurityDomain) iniCtx.lookup(securityDomain);
connector.setFactory(new SSLServerSocketFactory(domain));
}
catalina.addConnector(connector);
}
private void initWarpConnector(ClassLoader parent, Logger jbossLog, Realm jbossRealm)
{
log.info("Building Warp engine and connector");
String hostname = "localhost";
if( bindAddress != null )
hostname = bindAddress.getHostName();
// Create the engine
WarpEngine warpEngine = new WarpEngine();
warpEngine.setDebug(debugLevel);
warpEngine.setLogger(jbossLog);
warpEngine.setRealm(jbossRealm);
warpEngine.setDefaultHost(hostname);
warpEngine.setParentClassLoader(parent);
// Create a host for the root context
WarpHost warpHost = new WarpHost();
warpHost.setAppBase("");
warpHost.setName(hostname);
warpHost.setDebug(debugLevel);
warpEngine.addChild(warpHost);
// Install the engine
catalina.addEngine(warpEngine);
// Create the warp connector and set its properties
WarpConnector warpConnector = new WarpConnector();
warpConnector.setAcceptCount(acceptCount);
warpConnector.setEnableLookups(enableLookups);
warpConnector.setPort(port);
if (bindAddress != null)
warpConnector.setAddress(hostname);
catalina.addConnector(warpConnector);
catalinaHost = warpHost;
}
private void initAjpConnector(ClassLoader parent, Logger jbossLog, Realm jbossRealm)
throws IOException, NamingException
{
log.info("Building Ajp engine and connector");
String hostname = "localhost";
if( bindAddress != null )
hostname = bindAddress.getHostName();
// Create the engine
Engine engine = catalina.createEngine();
engine.setDefaultHost(hostname);
engine.setParentClassLoader(parent);
// Create a host for the root context
catalinaHost = catalina.createHost(hostname, "");
engine.addChild(catalinaHost);
// Install the engine
catalina.addEngine(engine);
// Create the ajp connector and set its properties
Ajp13Connector ajpconnector = new Ajp13Connector();
ajpconnector.setAcceptCount(acceptCount);
ajpconnector.setMinProcessors(minProcessors);
ajpconnector.setMaxProcessors(maxProcessors);
ajpconnector.setEnableLookups(enableLookups);
ajpconnector.setPort(port);
//catalina.addConnector(ajpconnector);
// Enable a secure connector if a security domain was specified
if( securityDomain != null )
{
ajpconnector.setScheme("https");
ajpconnector.setSecure(true);
InitialContext iniCtx = new InitialContext();
SecurityDomain domain = (SecurityDomain) iniCtx.lookup(securityDomain);
ajpconnector.setFactory(new SSLServerSocketFactory(domain));
}
catalina.addConnector(ajpconnector);
}
private WebApplication createWebContext(String ctxPath, URL warUrl,
final WebDescriptorParser webAppParser) throws IOException
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
final WebApplication appInfo = new WebApplication(warUrl.getPath(), warUrl, loader);
final StandardContext context = (StandardContext) catalina.createContext(ctxPath, warUrl.getFile());
context.setParentClassLoader(loader);
/* We need to establish the JNDI ENC prior to the start of the web container
so that init on
startup servlets are able to interact with their ENC. We
hook into the context lifecycle events to be notified of the start of the
context as this occurs before the servlets are started.
*/
context.addLifecycleListener(new LifecycleListener()
{
public void lifecycleEvent(LifecycleEvent event)
{
Object source = event.getSource();
if( source == context && event.getType().equals(Lifecycle.START_EVENT) )
{
if (log.isDebugEnabled())
log.debug("Context.lifecycleEvent, event="+event);
contextInit(context, appInfo, webAppParser);
}
}
}
);
// A debug level of 1 is rather verbose so only enable debugging if trace priority is active
if( debugLevel <= 1 )
context.setDebug(0);
catalinaHost.addChild(context);
return appInfo;
}
/** Build the web application ENC.
*/
private void contextInit(Context context, WebApplication appInfo, WebDescriptorParser webAppParser)
{
try
{
InputStream stream = null;
ServletContext servletCtx = context.getServletContext();
if (servletCtx == null)
return;
stream = servletCtx.getResourceAsStream("/WEB-INF/web.xml");
if( stream == null )
{
log.warn("No /WEB-INF/web.xml descriptor found");
return;
}
/* We need to go through the context valves and set the cache flag
on any AuthenticatorBase to false or else the JBossSecurityMgrRealm
is not asked to authenticate every request. This can result in
an authenticated user thread not receiving its authenticated
Subject and this results in an authorization failure.
*/
Valve[] valves = ((StandardContext)context).getValves();
for(int v = 0; v < valves.length; v ++)
{
Valve valve = valves[v];
if( valve instanceof AuthenticatorBase )
{
AuthenticatorBase auth = (AuthenticatorBase) valve;
auth.setCache(false);
}
}
// Apply any extended configuration to the context
// Get the web-app.xml and jboss-web.xml deployment descriptors
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
parser.setEntityResolver(new LocalResolver());
Document webDoc = parser.parse(stream);
Element web = webDoc.getDocumentElement();
Element jbossWeb = null;
stream = servletCtx.getResourceAsStream("/WEB-INF/jboss-web.xml");
if( stream != null )
{
Document jbossWebDoc = parser.parse(stream);
jbossWeb = jbossWebDoc.getDocumentElement();
}
// Setup the wep app JNDI java:comp/env namespace
ClassLoader scl = context.getLoader().getClassLoader();
webAppParser.parseWebAppDescriptors(scl, web, jbossWeb);
// Create a web application info object
appInfo.setWebApp(web);
appInfo.setJbossWeb(jbossWeb);
appInfo.setAppData(context);
}
catch(Exception e)
{
log.error("Failed to setup web application ENC", e);
}
}
/** An implementation of EntityResolver for the web.dtd and jboss-web.dtd
*/
private class LocalResolver implements EntityResolver
{
private HashMap dtds = new HashMap();
public LocalResolver()
{
dtds.put("-//JBoss//DTD Web Application 2.2//EN", "org/jboss/metadata/jboss-web.dtd");
dtds.put("-//JBoss//DTD Web Application 2.3//EN", "org/jboss/metadata/jboss-web.dtd");
dtds.put("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", "javax/servlet/resources/web-app_2_2.dtd");
hook into the context lifecycle events to be notified of the start of the
context as this occurs before the servlets are started.
*/
context.addLifecycleListener(new LifecycleListener()
{
public void lifecycleEvent(LifecycleEvent event)
{
Object source = event.getSource();
if( source == context && event.getType().equals(Lifecycle.START_EVENT) )
{
if (log.isDebugEnabled())
log.debug("Context.lifecycleEvent, event="+event);
contextInit(context, appInfo, webAppParser);
}
}
}
);
// A debug level of 1 is rather verbose so only enable debugging if trace priority is active
if( debugLevel <= 1 )
context.setDebug(0);
catalinaHost.addChild(context);
return appInfo;
}
/** Build the web application ENC.
*/
private void contextInit(Context context, WebApplication appInfo, WebDescriptorParser webAppParser)
{
try
{
InputStream stream = null;
ServletContext servletCtx = context.getServletContext();
if (servletCtx == null)
return;
stream = servletCtx.getResourceAsStream("/WEB-INF/web.xml");
if( stream == null )
{
log.warn("No /WEB-INF/web.xml descriptor found");
return;
}
/* We need to go through the context valves and set the cache flag
on any AuthenticatorBase to false or else the JBossSecurityMgrRealm
is not asked to authenticate every request. This can result in
an authenticated user thread not receiving its authenticated
Subject and this results in an authorization failure.
*/
Valve[] valves = ((StandardContext)context).getValves();
for(int v = 0; v < valves.length; v ++)
{
Valve valve = valves[v];
if( valve instanceof AuthenticatorBase )
{
AuthenticatorBase auth = (AuthenticatorBase) valve;
auth.setCache(false);
}
}
// Apply any extended configuration to the context
// Get the web-app.xml and jboss-web.xml deployment descriptors
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder parser = factory.newDocumentBuilder();
parser.setEntityResolver(new LocalResolver());
Document webDoc = parser.parse(stream);
Element web = webDoc.getDocumentElement();
Element jbossWeb = null;
stream = servletCtx.getResourceAsStream("/WEB-INF/jboss-web.xml");
if( stream != null )
{
Document jbossWebDoc = parser.parse(stream);
jbossWeb = jbossWebDoc.getDocumentElement();
}
// Setup the wep app JNDI java:comp/env namespace
ClassLoader scl = context.getLoader().getClassLoader();
webAppParser.parseWebAppDescriptors(scl, web, jbossWeb);
// Create a web application info object
appInfo.setWebApp(web);
appInfo.setJbossWeb(jbossWeb);
appInfo.setAppData(context);
}
catch(Exception e)
{
log.error("Failed to setup web application ENC", e);
}
}
/** An implementation of EntityResolver for the web.dtd and jboss-web.dtd
*/
private class LocalResolver implements EntityResolver
{
private HashMap dtds = new HashMap();
public LocalResolver()
{
dtds.put("-//JBoss//DTD Web Application 2.2//EN", "org/jboss/metadata/jboss-web.dtd");
dtds.put("-//JBoss//DTD Web Application 2.3//EN", "org/jboss/metadata/jboss-web.dtd");
dtds.put("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN", "javax/servlet/resources/web-app_2_2.dtd");
dtds.put("-//Sun Microsystems, Inc.//DTD Web Application
2.3//EN", "javax/servlet/resources/web-app_2_3.dtd");
}
public InputSource resolveEntity(String publicId, String systemId)
{
String dtd = (String) dtds.get(publicId);
InputSource is = null;
if (dtd != null)
{
try
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream dtdStream = loader.getResourceAsStream(dtd);
if( dtdStream == null )
log.warn("Failed to find local dtd: "+dtd);
else
is = new InputSource(dtdStream);
}
catch(Exception ignore)
{
// ignore
}
}
return is;
}
}
}
}
public InputSource resolveEntity(String publicId, String systemId)
{
String dtd = (String) dtds.get(publicId);
InputSource is = null;
if (dtd != null)
{
try
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream dtdStream = loader.getResourceAsStream(dtd);
if( dtdStream == null )
log.warn("Failed to find local dtd: "+dtd);
else
is = new InputSource(dtdStream);
}
catch(Exception ignore)
{
// ignore
}
}
return is;
}
}
}
--
Aaron Butler
Fairfield Language Technologies
http://www.RosettaStone.com
(800) 788-0822
(1) (540) 432-6166
Aaron Butler
Fairfield Language Technologies
http://www.RosettaStone.com
(800) 788-0822
(1) (540) 432-6166
