javaservletsjakarta-eepage-lifecyclejava-ee-8

How to hook BeginRequest and EndRequest in JavaEE?


Short Version

In JavaEE, i want to know when:

and be able to inspect the request and response objects.

Long Version

In the ASP.net world, if you want to know when a request starts and ends, you write an IHttpModule:

public class ExampleModuleForThisQuestion : IHttpModule
{
}

And then register your "module" in the web xml configuration file:

web.config:

    <system.webServer>
        <modules>
            <add name="DoesntMatter" type="ExampleModuleForThisQuestion "/>
        </modules>
    </system.webServer> 

Inside your module you can register callback handlers for:

The web-server infrastructure then calls you Init method. That is your opportunity to register that you want to receive notifications when a request starts, and when a request ends:

public class ExampleModuleForThisQuestion : IHttpModule
{
   public void Init(HttpApplication application)
   {
      application.BeginRequest += new EventHandler(beginRequest); //register the "BeginRequet" event
      application.EndRequest += new EventHandler(endRequest); //register the "EndRequest" event
   }
}

And now we have our callbacks when a request starts:

private void beginRequest(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;

   //Record the time the request started
   application.Context.Items["RequestStartTime"] = DateTime.Now;

   //We can even access the Request and Response objects
   application.ContenxtLog(application.Context.Request.Headers["User-Agent"]);
}

and we have our callback when a request ends:

private void endRequest(object sender, EventArgs e)
{
   HttpApplication application = (HttpApplication)sender;

   //We can even access the Request and Response objects

   //Get the response status code (e.g. 418 I'm a teapot)
   int statusCode = application.Context.Response.StatusCode;

   //Get the request method (e.g. GET, POST, BREW)
   String method = application.context.Request.RequestType;

   //Get the path from the request (e.g. /ViewCustomer)
   String path = application.context.Request.AppRelativeCurrentExecutionFilePath'
   
   //Get when the request started - that we recorded during "Begin Request"
   DateTime requestStartTime = (DateTime)application.Context.Items["RequestStartTime"];

   //And we can modify the response
   if ((DateTime.Now - requestStartTime).TotalSeconds = 17)
       application.Context.Response.StatusCode = 451;
}

Now how to do it in JavaEE?

The question is: what is the moral equivalent of IHttpModule in the Java web-server world?

Some people say that it is an ServletRequestListener:

Interface for receiving notification events about requests coming into and going out of scope of a web application.

A ServletRequest is defined as coming into scope of a web application when it is about to enter the first servlet or filter of the web application, and as going out of scope as it exits the last servlet or the first filter in the chain.

Others insist that you want a "filter" and a "filter chain".

Some say that a "filter" gives you everything that ServletRequestListener does, but that a filter can also be configured to run for only certain URL.

This random page on docs.oracle.com says nothing about "filters", and instead i need a ServletContextListener, because that's the only way to receive a notification for each request. But then they have a table that seems to contradict that, and that i want a ServletRequestEvent:

Object Event Listener Interface and Event Class
Web context Initialization and destruction javax.servlet.ServletContextListener and ServletContextEvent
Web context Attribute added, removed, or replaced javax.servlet.ServletContextAttributeListener and ServletContextAttributeEvent
Session Creation, invalidation, activation, passivation, and timeout javax.servlet.http.HttpSessionListener, javax.servlet.http.HttpSessionActivationListener, and HttpSessionEvent
Session Attribute added, removed, or replaced javax.servlet.http.HttpSessionAttributeListener and HttpSessionBindingEvent
Request A servlet request has started being processed by web components javax.servlet.ServletRequestListener and ServletRequestEvent
Request Attribute added, removed, or replaced javax.servlet.ServletRequestAttributeListener and ServletRequestAttributeEvent

I don't know what any of these things are. I just want to be notified during a web-request:

Writing Java code blind

I can try to transcribe the ASP.net code into Java-esque code on the fly, and hopefully someone can just fix it.

First we'll create a class that implements...ServletRequestListener?:

public class ExampleListenerForThisQuestion 
      implements javax.servlet.ServletRequestListener {

}

And then we register our "module" in our web xml configuration file:

web.xml

<listener>
    <listener-class>ExampleListenerForThisQuestion</listener-class>
</listener>

Now we will implement the requestInitialized method to create our event listeners:

public class ExampleListenerForThisQuestion 
      implements javax.servlet.ServletRequestListener {

   public void requestInitialized(ServletRequestEvent sre) {
      //...now i'm stuck 
   }
}

That didn't get very var.

The closest question on stackoverflow to what i want is:

Event like .net's "Application_Start" and "Begin_Request" for java/tomcat/JSP?

The only problem is that the accepted answer doesn't answer how to do it. That makes sense: the question wasn't asking how to do it. The question was only asking if Java has an equivalent. Apparently it does - but we won't tell you how.

Research Effort

I know that trying to figure out how to do it in JavaEE will take me at least 4 days. I'm hoping to cut that down to 6 or 7 hours by asking Stackoverflow.

This question took me an hour-and-a-half to write up. I wrote the ASP.net code, from memory, in 25 seconds. It took me longer to ask the question about how to do it in Java than it would have just taken me to do it in ASP.net - which shows just how crushed and defeated i am right now.

Edit: I happen to be using Java 8. I assume that corresponds to JavaEE 8.


Solution

  • The answer is: it is not possible.