10

I have a ServletContextListener which performs some database management functions when my Java EE application starts. This runs in my application before JPA and other pieces of the application are started/loaded. If the database maintenance fails I am logging the errors. If the database maintenance fails the application will not function properly and I would like to halt the application.

How can I gracefully and correctly stop the application from ServletContextListener.contextInitialized?

Solution given by Viven below is close but not quite. When I throw a RuntimeException Glassfish is left in an inconsistent state where its admin console is not accessible but some process is still running and keeping port 3700 (IIOP?) open which then prevents a restart.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Freiheit
  • 8,408
  • 6
  • 59
  • 101

2 Answers2

5

If your ServletContextListener throws an exception, the webapp won't load correctly and the application server may block all subsequent request (and respond with a 500 error).

It isn't exactly preventing the application to start, nor stopping the application, but it prevents any further usage of the app and could be useful in your case.

After proper verification in the spec, this behaviour isn't mandatory in the specification. The server may (not must) return 500 errors. This solution has to be used carefully, therefore.

See this Answer for a quote from the Servlet spec.

Community
  • 1
  • 1
Vivien Barousse
  • 20,555
  • 2
  • 63
  • 64
  • 2
    "If your ServletContextListener throws an exception, the webapp won't load correctly" - how do you know this? The spec defines no such thing. It's just as likely that any given app server will simply report the exception and continue regardless. `ServletContextListener` is not designed to influence the lifecycle of the application. – skaffman Jul 11 '11 at 22:20
  • 2
    It is described, paragraph 11.6: "Listeners exceptions". - "The container may respond to all subsequent requests to the Web application with an HTTP status code 500 to indicate an application error." – Vivien Barousse Jul 11 '11 at 22:22
  • 1
    Ah, fair enough. You may want to qualify your original answer with a URL and quote from that reference. The language is too woolly, though, I wouldn't want to rely on "the container may respond". – skaffman Jul 11 '11 at 22:25
  • 1
    Just realised it actually says "may", not "must". Not as accurate as I first thought... – Vivien Barousse Jul 11 '11 at 22:27
  • Throwing a `Runtime Exception` works however in Glassfish v2.? it seems to leave a Java process running that keeps port 3700 open. Is this specific to Glassfish or generic to J2EE? – Freiheit Jul 12 '11 at 16:02
  • Not exactly graceful but the dirty way is System.exit though calling it from a servlet may not be a fantastic idea. – Keibosh Jul 12 '11 at 16:52
  • `System.exit(1)` exhibits similar behaviour as `RuntimeException` at least in Glassfish 2.x – Freiheit Jul 12 '11 at 17:11
  • 5
    Throwing a `RuntimeException` doesn't stop the app server. It **may** prevent the app from beeing started and **may** respond to all subsequent requests to the app with a 500 (Server error) response code. Using `System.exit` is a very bad idea. It forces a server shutdown, even if other (perfectly working) applications are deployed on the same server. I used to deal with an app doing that (Alfresco), and believe me, it's more than annoying! – Vivien Barousse Jul 13 '11 at 08:21
  • Upvote for the info, but unfortunately throwing an exception didn't stop the server startup for me. – Kevin Workman Jan 27 '18 at 02:42
5

In your listener, catch any exceptions and use servlet context attributes to store flags or other useful information about the error. You should probably also log something to indicate that the app is non-functional.

At this point, your options may be dictated by the architecture of your app. If all requests are handled by a single controller/dispatcher servlet, it might make sense to have its init method check the context attributes and throw an UnavailableException. Just be aware that the exception only applies to the specific servlet throwing it. This makes the approach less manageable if your app contains many servlets or allows direct access to other resources.

Another option would be to create a filter that intercepts every request, checks the context attributes and then throws an exception. Other variations are certainly possible.

kschneid
  • 5,626
  • 23
  • 31
  • In my listener I set a context attribute then react to that in a filter. The filter throws a ServletException (HTTP 500) which stops the UI, but doesn't stop my webservices. Is there someplace I can implement a filter (or similar) to check for this context attribute? – Freiheit Jul 15 '11 at 20:38
  • Not sure what you mean by stopping your webservices. If the filter is configured to intercept every request, then every request should result in an exception. Can you provide some more details on the webservices part of your app? – kschneid Jul 18 '11 at 17:43
  • My webservices all utilize EnterpriseBeans while the UI utilizes Servlets/ActionBeans. So for the UI I have a Filter which can check for this application state. For the EnterpriseBeans I have to implement something like an Iterceptor to check for the application state and respond appropriately. – Freiheit Jul 18 '11 at 17:45