More Efficient Request Mapping with the Ad-Hoc Mechanism in GlassFish
By jluehe on May 12, 2006
More Efficient Request Mapping with the Ad-Hoc Mechanism in GlassFishEver wondered how a request for an EJB webservice endpoint is routed to its target EJB endpoint in GlassFish?
Join me for a look behind the covers ...
Let's start by taking a look at how requests for servlet webservice endpoints are routed to their target in GlassFish. As you may already have figured out, requests for JAXWS endpoints are mapped to the com.sun.enterprise.webservice.JAXWSServlet, and requests for JAXRPC endpoints are mapped to the com.sun.enterprise.webservice.JAXRPCServlet. These two servlets are responsible for forwarding the mapped requests to their intended targets.
For this approach to work, the
web.xml deployment descriptor of a WAR file containing servlet endpoints is augmented with servlet mappings of each endpoint address to the
com.sun.enterprise.webservice.JAXRPCServlet, respectively, depending on the endpoint type. The generated mappings can be seen by deploying a WAR file containing servlet endpoints and checking the contents of the
web.xml in install-dir/domains/domain1/generated/xml/j2ee-modules/<module-name>/WEB-INF/web.xml.
For EJB webservice endpoints, no such transformation of the
web.xml needs to take place! Instead, the web container's ad-hoc mechanism is used to map and route requests for EJB webservice endpoints to their intended targets. What is this ad-hoc mechanism, and how does it work?
The web container's ad-hoc mechanism allows any interested GlassFish component to have a URI, or an entire URI subtree, serviced by an ad-hoc servlet that is registered programmatically via the ad-hoc registration API, instead of declaratively in the
web.xml. The ad-hoc mechanism is
convenient when it is impossible to declare all of a web application's servlet mappings at the time the web application is assembled or deployed, because the exact form of these mappings may not be known in advance.
A URI that is mapped to an ad-hoc servlet is referred to as an ad-hoc path. Likewise, a URI subtree mapped to an ad-hoc servlet is referred to as an ad-hoc subtree.
com.sun.enterprise.web.WebContainer provides the following ad-hoc registration API for turning a URI into an ad-hoc path, by mapping it to an ad-hoc servlet:
public void registerAdHocPath(String path, String ctxtRoot, String appName, AdHocServletInfo servletInfo)
and this API for turning a URI and an entire subtree beneath it into an ad-hoc path and subtree:
public void registerAdHocPathAndSubtree(String path, String subtree, String ctxtRoot, String appName, AdHocServletInfo servletInfo)
The corresponding unregistration APIs are defined as follows:
public void unregisterAdHocPath(String path, String ctxtRoot) public void unregisterAdHocPathAndSubtree(String path, String subtree, String ctxtRoot)
The com.sun.enterprise.web.AdHocServletInfo parameter contains information about the ad-hoc servlet that is to receive any requests on its associated ad-hoc path or subtree. More specifically, it contains the fully-qualified servlet class name, the servlet name, and the servlet's init parameters.
ctxtRoot parameter specifies the context root component of the ad-hoc path being registered. When an ad-hoc path is registered, the web container will first check if a web context at the given context root already exists. If so, it will add the ad-hoc servlet built and initialized from the
com.sun.enterprise.web.AdHocServletInfo parameter to it. Otherwise, the web container creates a new web context, registers it at the specified context root, and adds the ad-hoc servlet as its child.
A web context all of whose children are ad-hoc servlets is referred to as an ad-hoc context. If an ad-hoc context has been created and registered, and a user webapp is deployed to the same context root later on, the ad-hoc context will be unregistered in order to make room for the user web context, and all of the children of the ad-hoc context will be transferred over to the user web context. When the user webapp is unregistered, and some of its ad-hoc servlets are still active, the ad-hoc context is restored, and the ad-hoc servlets transferred back to it.
Currently, an ad-hoc path takes precedence over any user-defined servlet mappings declared in a user webapp. Based on feedback from the GlassFish community, we may want to consider aborting deployment of a user webapp if its intended context root has already been occupied by an ad-hoc context, and reject the registration of an ad-hoc path if its context root conflicts with that of an already deployed user webapp.
The web container's ad-hoc mechanism provides its own request processing pipeline, which means that even if an ad-hoc servlet has been added to a user context, any request mapped to the ad-hoc servlet will not be processed by the user context's regular request processing pipeline. This means that an ad-hoc servlet will never inherit any of the security settings of the user context it may have been added to.
In the case of EJB webservice endpoints, we've implemented an com.sun.enterprise.web.EjbWebServiceRegistryListener for EJB webservice registration and unregistration events emitted by the webservice engine. Upon receiving an EJB webservice registration event, this listener parses the endpoint's address into its context root and endpoint path components, which are then registered as an ad-hoc path, along with information describing the ad-hoc servlet that is to receive the requests. In this case, the ad-hoc servlet is an instance of com.sun.enterprise.webservice.EjbWebServiceServlet, which dispatches an incoming request to the target EJB webservice endpoint.
The big advantage of the ad-hoc mechanism is that it enables the web container to determine, by examining the request URL, which requests are targeted for EJB webservice endpoints, and which ones aren't. In previous implementations, the web container had to delegate this decision to the EJB webservice registry, making any and all HTTP requests suffer from the extra lookup. The extra lookup used to be necessary because EJB webservice endpoints are declared in EJB-specific deployment descriptors and are not reflected in the deployment descriptors of regular web applications. With the ad-hoc mechanism, the extra lookup is no longer needed.
In addition to supporting EJB webservice endpoints, the web container's ad-hoc mechanism is currently also being leveraged by the Java Web Start support for app clients in GlassFish. See Tim Quinn's blog for details.