This chapter describes the steps for integrating a third party web container into the JBoss application server framework. A web container is a J2EE server component that enables access to servlets and JSP pages. The most widely used servlet container is Tomcat, and this is the default web container used by JBoss.
Integrating a servlet container into JBoss consists of mapping web-app.xml JNDI information into the JBoss JNDI namespace using an optional jboss-web.xml descriptor as well as delegating authentication and authorization to the JBoss security layer. The org.jboss.web.AbstractWebContainer class exists to simplify these tasks. The focus of the first part of this chapter is how to integrate a Web container using the AbstractWebContainer class. The chapter concludes with a discussion on configuration topics like the use of secure socket layer (SSL) encryption with the JBoss/Tomcat bundle, as well as how to configure Apache with the JBoss/Tomcat bundle.
The org.jboss.web.AbstractWebContainer class is an implementation of a template pattern for web container integration into JBoss. Web container providers wishing to integrate their container into a JBoss server should create a subclass of AbstractWebContainer and provide the web container specific setup and WAR deployment steps. The AbstractWebContainer provides support for parsing the standard J2EE web.xml web application deployment descriptor JNDI and security elements as well as support for parsing the JBoss specific jboss-web.xml descriptor. Parsing of these deployment descriptors is performed to generate an integrated JNDI environment and security context. We have already seen the most of the elements of the jboss-web.xml descriptor in other chapters. Figure 9.1, “The complete jboss-web.xml descriptor DTD” provides an overview of the jboss-web.xml descriptor DTD for reference. The complete DTD with comments can be found in the JBOSS_DIST/docs/dtd.
The two elements that have not been discussed are the context-root and virtual-host. The context-root element allows one to specify the prefix under which web application is located. This is only applicable to stand-alone web application deployment as a WAR file. Web applications included as part of an EAR must set the root using the context-root element of the EAR application.xml descriptor. The sample jboss-web.xml descriptor shown in Example 9.1, “A sample jboss-web.xml descriptor for mapping a war to the root context” illustrates mapping a war to the root context.
Example 9.1. A sample jboss-web.xml descriptor for mapping a war to the root context
<jboss-web> <!-- An empty context root map the war to the root context, e.g., http://localhost:8080/ --> <context-root /> </jboss-web>
The virtual-host element specifies the DNS name of the virtual host to which the web application should be deployed. The details of setting up virtual hosts for servlet contexts depends on the particular servlet container. We will look at examples of using the virtual-host element when we look at the Tomcat servlet containers later in this chapter.
The AbstractWebContainer is an abstract class that implements the org.jboss.web.AbstractWebContainerMBean interface used by the JBoss J2EE deployer to delegate the task of installing war files needing to be deployed. We'll look at some of the key methods of the AbstractWebContainer below.
public boolean accepts(DeploymentInfo sdi) { String warFile = sdi.url.getFile(); return warFile.endsWith("war") || warFile.endsWith("war/"); }
The accepts method is implemented by JBoss deployers to indicate which type of deployments they accepts. The AbstractWebContainer handles the deployments of WARs as JARs or unpacked directories.
public synchronized void start(DeploymentInfo di) throws DeploymentException { Thread thread = Thread.currentThread(); ClassLoader appClassLoader = thread.getContextClassLoader(); try { // Create a classloader for the war to ensure a unique ENC URL[] empty = {}; URLClassLoader warLoader = URLClassLoader.newInstance(empty, di.ucl); thread.setContextClassLoader(warLoader); WebDescriptorParser webAppParser = new DescriptorParser(di); String webContext = di.webContext; if (webContext != null) { if (webContext.length() > 0 && webContext.charAt(0) != '/') { webContext = "/" + webContext; } } // Get the war URL URL warURL = di.localUrl != null ? di.localUrl : di.url; if (log.isDebugEnabled()) { log.debug("webContext: " + webContext); log.debug("warURL: " + warURL); log.debug("webAppParser: " + webAppParser); } // Parse the web.xml and jboss-web.xml descriptors WebMetaData metaData = (WebMetaData) di.metaData; parseMetaData(webContext, warURL, di.shortName, metaData); WebApplication warInfo = new WebApplication(metaData); warInfo.setDeploymentInfo(di); performDeploy(warInfo, warURL.toString(), webAppParser); deploymentMap.put(warURL.toString(), warInfo); // Generate an event for the startup super.start(di); } catch(DeploymentException e) { throw e; } catch(Exception e) { throw new DeploymentException("Error during deploy", e); } finally { thread.setContextClassLoader(appClassLoader); } }
This section corresponds to the start method. This method is a template pattern method implementation. The argument to the deploy method is the WAR deployment info object. This contains the URL to the WAR, the UnifiedClassLoader for the WAR, the parent archive such as an EAR, and the J2EE application.xml context-root if the WAR is part of an EAR.
The first step of the start method is to save the current thread context class loader and then create another URLClassCloader (warLoader) using the WAR UnifiedClassLoader as its parent. This warLoader is used to ensure a unique JNDI ENC (enterprise naming context) for the WAR will be created. Chapter 3, Naming on JBoss mentioned that the java:comp context's uniqueness was determined by the class loader that created the java:comp context. The warLoader ClassLoader is set as the current thread context class loader before the performDeploy call is made. Next, the web.xml and jboss-web.xml descriptors are parsed by calling parseMetaData. Next, the web container-specific subclass is asked to perform the actual deployment of the WAR through the performDeploy call. The WebApplication object for this deployment is stored in the deployed application map using the warUrl as the key. The final step is to restore the thread context class loader to the one that existed at the start of the method.
protected abstract void performDeploy(WebApplication webApp, String warUrl, WebDescriptorParser webAppParser) throws Exception;
This is the signature for the abstract performDeploy method. This method is called by the start method and must be overridden by subclasses to perform the web container specific deployment steps. A WebApplication is provided as an argument, and this contains the metadata from the web.xml descriptor, and the jboss-web.xml descriptor. The metadata contains the context-root value for the web module from the J2EE application.xml descriptor, or if this is a stand-alone deployment, the jboss-web.xml descriptor. The metadata also contains any jboss-web.xml descriptor virtual-host value. On return from performDeploy, the WebApplication must be populated with the class loader of the servlet context for the deployment. The warUrl argument is the string for the URL of the Web application WAR to deploy. The webAppParser argument is a callback handle the subclass must use to invoke the parseWebAppDescriptors method to set up the Web application JNDI environment. This callback provides a hook for the subclass to establish the web application JNDI environment before any servlets are created that are to be loaded on startup of the WAR. A subclass' performDeploy method implementation needs to be arranged so that it can call the parseWebAppDescriptors before starting any servlets that need to access JNDI for JBoss resources like EJBs, resource factories, and so on. One important setup detail that needs to be handled by a subclass implementation is to use the current thread context class loader as the parent class loader for any Web container-specific class loader created. Failure to do this results in problems for web applications that attempt to access EJBs or JBoss resources through the JNDI ENC.
public synchronized void stop(DeploymentInfo di) throws DeploymentException { URL warURL = di.localUrl != null ? di.localUrl : di.url; String warUrl = warURL.toString(); try { performUndeploy(warUrl); // Remove the web application ENC... deploymentMap.remove(warUrl); // Generate an event for the stop super.stop(di); } catch(DeploymentException e) { throw e; } catch(Exception e) { throw new DeploymentException("Error during deploy", e); } }
This is the stop method. It calls the subclass performUndeploy method to perform the container-specific undeployment steps. After undeploying the application, the warUrl is unregistered from the deployment map. The warUrl argument is the string URL of the WAR as originally passed to the performDeploy method.
protected abstract void performUndeploy(String warUrl) throws Exception;
This is the signature of the abstract performUndeploy method, which is called from the stop method. A call to performUndeploy asks the subclass to perform the Web container-specific undeployment steps.
public void setConfig(Element config) { }
The setConfig method is a stub method that subclasses can override if they want to support an arbitrary extended configuration beyond that which is possible through MBean attributes. The config argument is the parent DOM element for an arbitrary hierarchy given by the child element of the Config attribute in the mbean element specification of the jboss-service.xml descriptor of the web container service. You'll see an example use of this method and config value when you look at the MBean that supports embedding Tomcat into JBoss.
protected void parseWebAppDescriptors(DeploymentInfo di, ClassLoader loader, WebMetaData metaData) throws Exception { log.debug("AbstractWebContainer.parseWebAppDescriptors, Begin"); InitialContext iniCtx = new InitialContext(); Context envCtx = null; Thread currentThread = Thread.currentThread(); ClassLoader currentLoader = currentThread.getContextClassLoader(); try { // Create a java:comp/env environment unique for the web application log.debug("Creating ENC using ClassLoader: "+loader); ClassLoader parent = loader.getParent(); while (parent != null ) { log.debug(".."+parent); parent = parent.getParent(); } currentThread.setContextClassLoader(loader); metaData.setENCLoader(loader); envCtx = (Context) iniCtx.lookup("java:comp"); // Add a link to the global transaction manager envCtx.bind("UserTransaction", new LinkRef("UserTransaction")); log.debug("Linked java:comp/UserTransaction to JNDI name: UserTransaction"); envCtx = envCtx.createSubcontext("env"); } finally { currentThread.setContextClassLoader(currentLoader); } Iterator envEntries = metaData.getEnvironmentEntries(); log.debug("addEnvEntries"); addEnvEntries(envEntries, envCtx); Iterator resourceEnvRefs = metaData.getResourceEnvReferences(); log.debug("linkResourceEnvRefs"); linkResourceEnvRefs(resourceEnvRefs, envCtx); Iterator resourceRefs = metaData.getResourceReferences(); log.debug("linkResourceRefs"); linkResourceRefs(resourceRefs, envCtx); Iterator ejbRefs = metaData.getEjbReferences(); log.debug("linkEjbRefs"); linkEjbRefs(ejbRefs, envCtx, di); Iterator ejbLocalRefs = metaData.getEjbLocalReferences(); log.debug("linkEjbLocalRefs"); linkEjbLocalRefs(ejbLocalRefs, envCtx, di); String securityDomain = metaData.getSecurityDomain(); log.debug("linkSecurityDomain"); linkSecurityDomain(securityDomain, envCtx); log.debug("AbstractWebContainer.parseWebAppDescriptors, End"); }
The parseWebAppDescriptors method is invoked from within the subclass performDeploy method when it invokes the webAppParser.parseWebAppDescriptors callback to setup the web application ENC (java:comp/env) env-entry, resource-env-ref, resource-ref, local-ejb-ref and ejb-ref values declared in the web.xml descriptor. The creation of the env-entry values does not require a jboss-web.xml descriptor. The creation of the resource-env-ref, resource-ref, and ejb-ref elements does require a jboss-web.xml descriptor for the JNDI name of the deployed resources/EJBs. Because the ENC context is private to the web application, the web application class loader is used to identify the ENC. The loader argument is the class loader for the web application, and may not be null. The metaData argument is the WebMetaData argument passed to the subclass performDeploy method. The implementation of the parseWebAppDescriptors uses the metadata information from the WAR deployment descriptors and then creates the JNDI ENC bindings.
protected void addEnvEntries(Iterator envEntries, Context envCtx) throws ClassNotFoundException, NamingException { }
The addEnvEntries method creates the java:comp/env web application env-entry bindings that were specified in the web.xml descriptor.
protected void linkResourceEnvRefs(Iterator resourceEnvRefs, Context envCtx) throws NamingException { }
The linkResourceEnvRefs method maps the java:comp/env/xxx web application JNDI ENC resource-env-ref web.xml descriptor elements onto the deployed JNDI names using the mappings specified in the jboss-web.xml descriptor.
protected void linkResourceRefs(Iterator resourceRefs, Context envCtx) throws NamingException { }
The linkResourceRefs method maps the java:comp/env/xxx web application JNDI ENC resource-ref web.xml descriptor elements onto the deployed JNDI names using the mappings specified in the jboss-web.xml descriptor.
protected void linkEjbRefs(Iterator ejbRefs, Context envCtx, DeploymentInfo di) throws NamingException { }
The linkEjbRefs method maps the java:comp/env/ejb web application JNDI ENC ejb-ref web.xml descriptor elements onto the deployed JNDI names using the mappings specified in the jboss-web.xml descriptor.
protected void linkEjbLocalRefs(Iterator ejbRefs, Context envCtx, DeploymentInfo di) throws NamingException { }
The linkEjbLocalRefs method maps the java:comp/env/ejb Web application JNDI ENC ejb-local-ref web.xml descriptor elements onto the deployed JNDI names using the ejb-link mappings specified in the web.xml descriptor.
protected void linkSecurityDomain(String securityDomain, Context envCtx) throws NamingException { }
The linkSecurityDomain method creates a java:comp/env/security context that contains a securityMgr binding pointing to the AuthenticationManager implementation and a realmMapping binding pointing to the RealmMapping implementation that is associated with the security domain for the web application. Also creates is a subject binding that provides dynamic access to the authenticated Subject associated with the request thread. If the jboss-web.xml descriptor contained a security-domain element, the bindings are javax.naming.LinkRefs to the JNDI name specified by the security-domain element, or subcontexts of this name. If there was no security-domain element, the bindings are to org.jboss.security.plugins.NullSecurityManager instance that simply allows all authentication and authorization checks.
public String[] getCompileClasspath(ClassLoader loader) { }
The getCompileClasspath method is a utility method available for web containers to generate a classpath that walks up the class loader chain starting at the given loader and queries each class loader for the URLs it serves to build a complete classpath of URL strings. This is needed by some JSP compiler implementations (Jasper for one) that expect to be given a complete classpath for compilation.
To integrate a web container into JBoss you need to create a subclass of AbstractWebContainer and implement the required performDeploy(WebApplication, String, WebDescriptorParser) and performUndeploy(String) methods as described in the preceding section. The following additional integration points should be considered as well.
Although this issue was noted in the performDeploy method description, we'll repeat it here since it is such a critical detail. During the setup of a WAR container, the current thread context class loader must be used as the parent class loader for any web container specific class loader that is created. Failure to do this will result in problems for web applications that attempt to access EJBs or JBoss resources through the JNDI ENC.
JBoss uses the Apache log4j logging API as its internal logging API. For a web container to integrate well with JBoss it needs to provide a mapping between the web container logging abstraction to the log4j API. As a subclass of AbstractWebContainer, your integration class has access to the log4j interface via the super.log instance variable or equivalently, the superclass getLog() method. This is an instance of the org.jboss.logging.Logger class that wraps the log4j category. The name of the log4j category is the name of the container subclass.
Ideally both web application and EJB authentication and authorization are handled by the same security manager. To enable this for your web container you must hook into the JBoss security layer. This typically requires a request interceptor that maps from the web container security callouts to the JBoss security API. Integration with the JBossSX security framework is based on the establishment of a java:comp/env/security context as described in the linkSecurityDomain method comments in the previous section. The security context provides access to the JBossSX security manager interface implementations associated with the web application for use by subclass request interceptors. An outline of the steps for authenticating a user using the security context is presented in Example 9.2, “A pseudo-code description of authenticating a user via the JBossSX API and the java:comp/env/security JNDI context.” in quasi pseudo-code. Example 9.3, “A pseudo-code description of authorization a user via the JBossSX API and the java:comp/env/security JNDI context.” provides the equivalent process for the authorization of a user.
Example 9.2. A pseudo-code description of authenticating a user via the JBossSX API and the java:comp/env/security JNDI context.
// Get the username and password from the request context... HttpServletRequest request = ...; String username = getUsername(request); String password = getPassword(request); // Get the JBoss security manager from the ENC context InitialContext iniCtx = new InitialContext(); AuthenticationManager securityMgr = (AuthenticationManager) iniCtx.lookup("java:comp/env/security/securityMgr"); SimplePrincipal principal = new SimplePrincipal(username); if (securityMgr.isValid(principal, password)) { // Indicate the user is allowed access to the web content... // Propagate the user info to JBoss for any calls into made by the servlet SecurityAssociation.setPrincipal(principal); SecurityAssociation.setCredential(password.toCharArray()); } else { // Deny access... }
Example 9.3. A pseudo-code description of authorization a user via the JBossSX API and the java:comp/env/security JNDI context.
// Get the username & required roles from the request context... HttpServletRequest request = ...; String username = getUsername(request); String[] roles = getContentRoles(request); // Get the JBoss security manager from the ENC context InitialContext iniCtx = new InitialContext(); RealmMapping securityMgr = (RealmMapping) iniCtx.lookup("java:comp/env/security/realmMapping"); SimplePrincipal principal = new SimplePrincipal(username); Set requiredRoles = new HashSet(java.util.Arrays.asList(roles)); if (securityMgr.doesUserHaveRole(principal, requiredRoles)) { // Indicate user has the required roles for the web content... } else { // Deny access... }
In this section we'll discuss configuration issues specific to the JBoss/Tomcat 5 integration bundle. Tomcat 5 is the latest release of the Apache Java servlet container. It supports the Servlet 2.4 and JSP 2.0 specifications. The JBoss/Tomcat integration layer is controlled by the JBoss MBean service configuration. The MBean used to embed the Tomcat-4.1.x series of web containers is org.jboss.web.tomcat.tc5.Tomcat5, and it is a subclass of the AbstractWebContainer class. Its configurable attributes include:
While the jboss-service.xml file controls the JBoss/Tomcat integration, Tomcat has its own configuration file which guides its operation. This is the server.xml descriptor that you will find in the deploy/jbossweb-tomcat50.sar directory.
We'll now look at some of the configuration options available in the server.xml file. The top level element is is the the Server element is the root element, which should contain a Service element representing the the entire web subsystem. The only supported attribute is:
A Connector element configures a transport mechanism that allows clients to send requests and receive responses from the Service it is associated with. Connectors forward requests to the engine and return the results to the requesting client. Connectors support these attributes:
Additional attribute descriptions may be found in the Tomcat website document: http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/http11.html
Each Service must have a single Engine configuration. An engine handles the requests submitted to a service via the configured connectors. The child elements supported by the embedded service include Host, Logger, DefaultContext, Valve and Listener. The supported attributes include:
Additional information on the Engine element may be found in the Tomcat website document http://jakarta.apache.org/tomcat/tomcat-5.1-doc/config/engine.html.
A Host element represents a virtual host configuration. It is a container for web applications with a specified DNS hostname. The child elements supported by the embedded service include Alias, Logger, DefaultContext, Valve and Listener. The supported attributes include:
The Alias element is an optional child element of the Host element. Each Alias content specifies an alternate DNS name for the enclosing Host.
Additional information on the Host element may be found in the Tomcat website document http://jakarta.apache.org/tomcat/tomcat-4.1-doc/config/host.html.
The DefaultContext element is a configuration template for web application contexts. It may be defined at the Engine or Host level. The child elements supported by the embedded service include WrapperLifecycle, InstanceListener, WrapperListener, and Manager. The supported attributes include:
The Logger element specifies a logging configuration the Tomcat instance. The supported attributes include:
A Valve element configures a hook into the request processing pipeline for the web container. Valves must implement the org.apache.catalina.Valve interface. There is only one required configuration attribute:
The most commonly used valve is the AccessLogValve, which keeps a standard HTTP access log of incoming requests. The className for the access log value is org.jboss.web.catalina.valves.AccessLogValue. The addition Valve attributes supported by it include:
Additional information on the Valve element and the available valve implementations may be found in the Tomcat website document http://jakarta.apache.org/tomcat/tomcat-5.0-doc/config/valve.html.
There are a few ways one can configure HTTP over SSL for the embedded Tomcat servlet container.The main difference is whether or not you use the JBoss specific connector socket factory that allows one to obtain the JSSE server certificate information from a JBossSX SecurityDomain. This requires establishing a SecurityDomain using the org.jboss.security.plugins.JaasSecurityDomain MBean. These two steps are similar to the procedure we used in Chapter 8, Security on JBoss to enable RMI with SSL encryption. A server.xml configuration file that illustrates the setup of only an SSL connector via this approach is given in Example 9.4, “The JaasSecurityDoman and EmbeddedCatalinaSX MBean configurations for setting up Tomcat 5 to use SSL as its primary connector protocol.”. This configuration includes the same JaasSecurityDomain setup as Chapter 8, Security on JBoss, but since the descriptor is not being deployed as part of a SAR that includes the chap8.keystore, you need to copy the chap8.keystore to the server/default/conf directory.
Example 9.4. The JaasSecurityDoman and EmbeddedCatalinaSX MBean configurations for setting up Tomcat 5 to use SSL as its primary connector protocol.
<Server> <Service name="jboss.web" className="org.jboss.web.tomcat.tc5.StandardService"> <Connector port="8080" address="${jboss.bind.address}" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true"/> <Connector port="443" address="${jboss.bind.address}" maxThreads="100" minSpareThreads="5" maxSpareThreads="15" scheme="https" secure="true" clientAuth="false" keystoreFile="${jboss.server.home.dir}/conf/chap8.keystore" keystorePass="rmi+ssl" sslProtocol="TLS"/> <Engine name="jboss.web" defaultHost="localhost"> <Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm" certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping"/> <Logger className="org.jboss.web.tomcat.Log4jLogger" verbosityLevel="WARNING" category="org.jboss.web.localhost.Engine"/> <Host name="localhost" autoDeploy="false" deployOnStartup="false" deployXML="false"> <DefaultContext cookies="true" crossContext="true" override="true"/> </Host> </Engine> </Service> </Server>
A quick test of this config can be made by accessing the JMX console web application using this URL https://localhost/jmx-console/index.jsp.
Note: if your running on a *nix system (Linux, Solaris, OS X) that only allows root to open ports below 1024 you will need to change the port number above to something like 8443.
Factory configuration attributes:
Note that if you try to test this configuration using the self-signed certificate from the Chapter 8, Security on JBoss chap8.keystore and attempt to access content over an HTTPS connection, your browser should display a warning dialog indicating that it does not trust the certificate authority that signed the certificate of the server you are connecting to. For example, when the first configuration example was tested, IE 5.5 showed the initial security alert dialog listed in Figure 9.3, “The Internet Explorer 5.5 security alert dialog.”. Figure 9.4, “The Internet Explorer 5.5 SSL certificate details dialog.” shows the server certificate details. This warning is imporant as anyone can generate a self-signed certificate with any information they want. Your only way to verify that the system on the other side really represents the party it claim to is by verifying that it is signed by a trusted 3rd party.
Virtual hosts allow you to group web applications according to the various DNS names by which the machine running JBoss is known. As an example, consider the server.xml configuration file given in Example 9.5, “An example virtual host configuration.”. This configuration defines a default host named vhost1.mydot.com and a second host named vhost2.mydot.com, which also has the alias www.mydot.com associated with it.
Example 9.5. An example virtual host configuration.
<Server> <Service name="jboss.web" className="org.jboss.web.tomcat.tc5.StandardService"> <!-- A HTTP/1.1 Connector on port 8080 --> <Connector port="8080" address="${jboss.bind.address}" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true"/> <Engine name="jboss.web" defaultHost="vhost1"> <Realm className="org.jboss.web.tomcat.security.JBossSecurityMgrRealm" certificatePrincipal="org.jboss.security.auth.certs.SubjectDNMapping" /> <Logger className="org.jboss.web.tomcat.Log4jLogger" verbosityLevel="WARNING" category="org.jboss.web.localhost.Engine"/> <Host name="vhost1" autoDeploy="false" deployOnStartup="false" deployXML="false"> <Alias>vhost1.mydot.com</Alias> <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="vhost1" suffix=".log" pattern="common" directory="${jboss.server.home.dir}/log"/> <DefaultContext cookies="true" crossContext="true" override="true"/> </Host> <Host name="vhost2" autoDeploy="false" deployOnStartup="false" deployXML="false"> <Alias>vhost2.mydot.com</Alias> <Alias>www.mydot.com</Alias> <Valve className="org.apache.catalina.valves.AccessLogValve" prefix="vhost2" suffix=".log" pattern="common" directory="${jboss.server.home.dir}/log"/> <DefaultContext cookies="true" crossContext="true" override="true"/> </Host> </Engine> </Service> </Server>
When a WAR file is deployed, it will be by default associated with the virtual host whose name matches the defaultHost attribute of the containing Engine. To deploy a WAR to a specific virtual host you need to specify an appropriate virtual-host definition in your e jboss-web.xml descriptor. The following jboss-web.xml descriptor demonstrates how to deploy a WAR to the virtual host www.mydot.com. Note that we can use either the virtual host name in the config file and the actual host name.
<jboss-web> <context-root>/</context-root> <virtual-host>www.mydot.com</virtual-host> </jboss-web>
JBoss provides a default application that serves content for the root application context. This default context is the ROOT.war application in the jbossweb-tomcat50.sar directory. You can serve static files not associated with any other application by adding that content to the ROOT.war directory. For example, if you want to have a shared image directory you could create an image subdirectory inside of ROOT.war and place the images there. You could then access an image named myimage.jpg at http://localhost:8080/images/myimage.jpg.
In some architectures, it is useful to put an Apache web server in front of the JBoss server. External web clients talk to an Apache instance, which in turn speaks to the Tomcat instance on behalf of the clients. Apache needs to be configured to use the mod_jk module which speaks the AJP protocol to an AJP connector running in Tomcat. The provided server.xml file comes with this AJP connector enabled.
<Connector port="8009" address="${jboss.bind.address}" enableLookups="false" redirectPort="8443" debug="0" protocol="AJP/1.3" />
You'll need to consult the Apache and mod_jk documentation for complete installation instructions. Assuming you have a properly configured Apache instance, the following configuration fragment shows an example of how to connect with a WAR deployed with a context root of /jbosstest.
... LoadModule jk_module libexec/mod_jk.so AddModule mod_jk.c <IfModule mod_jk.c> JkWorkersFile /tmp/workers.properties JkLogFile /tmp/mod_jk.log JkLogLevel debug JkMount /jbosstest/* ajp13 </IfModule>
The workers.properties file contains the details of how to contact the JBoss instance.
JBoss supports clustering in the embedded Tomcat service. The steps to setup clustering of Tomcat embedded containers is:
<?xml version="1.0"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd "> <web-app> <distributable/> <!-- ... --> </web-app>
If you have deployed and accessed your application, go back to the jboss.cache:service=TomcatClusteringCache MBean and invoke the printDetails operation. You should see output resembling the following.
/JSESSION /n6HywRwITbY-xvzaZ0LS5Q** n6HywRwITbY-xvzaZ0LS5Q**: org.jboss.invocation.MarshalledValue@9c1dddab /R1T4Dapn7c8T-+Ynd9v9MA** R1T4Dapn7c8T-+Ynd9v9MA**: org.jboss.invocation.MarshalledValue@8c0f60b6
This output shows two separate web sessions that are being shared via JBossCache. If you don't see any output, either the application was not correctly marked as distributable or you haven't accessed the a part of application that places values in the HTTP session.