1

Here are the requirements for the problem:

  • java web application running in Tomcat 7
  • The initialization code needs to talk to an external database
  • The external database might not be available during start-up of the application
  • The application start-up can not fail otherwise tomcat will mark the application as not running and will not send the application any requests. Instead the application should start-up accept requests and if it finds that the app specific initialization is not complete it should try to complete it during the request processing.

I am trying to use the servlet filter below to solve the problem. and I have following questions.

  • Is this Servlet filter thread safe, will it execute the initialization code only once?
  • Is there a way to solve this problem without using a servlet filter?
  • Is there a better way to solve this problem?
 package com.exmaple;
    @WebFilter("/*")

 public class InitFilter implements Filter 
 {
    private volatile boolean initialized = false;

    public void destroy() {
        System.out.println("InitFilter.destroy()");
    }

        // is this method thread safe and will only execute the init code once
        // and will cause all requests to wait until initialization code is executed
        // thread code
        public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            System.out.println("InitFilter.doFilter()");

            if (initialized == false) {
                synchronized (this) {
                    // do expensive initialization work here
                    initialized = true;
                }
            }
            chain.doFilter(request, response);
        }

        public void init(FilterConfig fConfig) throws ServletException {
            System.out.println("InitFilter.init()");
        }
      }
Stephen P
  • 14,422
  • 2
  • 43
  • 67
ams
  • 60,316
  • 68
  • 200
  • 288
  • You can use an `Executors.newSingleThreadPool()` executing a `FutureTask`; then you'll access your `Foo` using this `Future`'s `.get()` – fge Mar 21 '14 at 19:45
  • 1
    The pattern test-synchronize-set is inherently unsafe because thread-A can test `initialized==false` then be suspended prior to `synchronized(this)` - thread-B then tests initialized, does the synchronization, then starts the init; thread-B is then suspended on I/O and thread-A tries `synchronized(this)` and is blocked because B still has the sync. When thread-B finishes and unlocks thread-A will continue and run the initialization again. – Stephen P Mar 21 '14 at 20:03
  • at the best least initialized = true; should be first line of code. Better to see singleton pattern and use that, even though its not the best - for academic reasons, in real life apps i have seen this kind of initialization work very well. we connect to do db by pre touching a servlet and have a singleton load resources but the check is more like http://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java and http://stackoverflow.com/questions/427902/what-is-the-best-approach-for-using-an-enum-as-a-singleton-in-java – tgkprog Mar 23 '14 at 08:38

2 Answers2

1

I would approach it as a ServletContextListener and run the initialization in the contextInitialized method, as a separate thread, maybe using a FutureTask as @fge suggests, or a newSingleThreadExecutor rather than a pool.

Maybe something along the lines of...

public void contextInitialized(ServletContextEvent sce)
{
    Executors.newSingleThreadExecutor().execute(new Runnable() {

        @Override
        public void run()
        {
            // Long running initialization code, or a call to it.
        }

    });

}

This avoids problems with synchronization and only runs the initialization once. (Once per Context)

In any case, doing this or a Filter, the rest of your program has to deal with initialization being incomplete.

Stephen P
  • 14,422
  • 2
  • 43
  • 67
  • So this way the app starts up successfully but how to fail requests that depend on the initialized being complete until the init is complete. – ams Mar 21 '14 at 21:13
  • @ams - to fail requests you could use a Filter, but all it would have to check would be something like an `initiazationComplete` flag; no sync needed or lock contention. You could use an `AtomicBoolean` for the flag, and have the init code set it to true when it's done. – Stephen P Mar 21 '14 at 22:50
0

I recommend you to put your long-running initialization in a thread, like:

public void init() throws ServletException {
    //Configure logging, app, pool ...
    MyAppStarter.getInstance().start();
}
Danilo Muñoz
  • 623
  • 1
  • 7
  • 17