2

Obviously I want to write decoupled components. One part is a form engine. I don't want it to be dependent on the servlet API, but I have to inialize it per-request (or at least per-session).

In an application I would use something like

public static void setLocale(Locale l);

then my individual classes could get it with a static getter. This is not feasable in a servlet environment (servlets lack even a static getServletContext() method thru which static behaviour could be emulated).

I absolutely don't want to use factory (I will have 10+ classes all of which will use some configuration, Locale at least) or worse than that: construct each object with a parameter block (which contains Locale and other settings).

I would like to know what's the best practive in this situation. Can static behavior emulated in a usable way or does the servlet API has an answer to this problem?

If every other possibility fails I thought of using something like:

class MyParameters {
    private Map<Thread, MyParameters> threadParameters = new Map<Thread, MyParameters>();

    public static void setParameters(MyParameters parameters) {
        threadParameters.put(Thread.getCurrentThread(), parameters);
    }

    public static MyParameters getParameters() {
        return threadParameters.get(Thread.getCurrentThread());
    }    
}

... but this creates some security concerns (a servlet may fail to initialize it and use the values set up during a previous request served by the same thread). - Although using a different user's Locale is not as much of a threat.

vbence
  • 20,084
  • 9
  • 69
  • 118

2 Answers2

3

but I have to inialize it per-request (or at least per-session).

Use a Filter, HttpServlet or ServletRequestListener (or a HttpSessionListener).

but this creates some security concerns

Also, threads are pooled by the container. The very same thread can be reused more than once for different subsequent requests. When you put something in the thread and don't remove it by the end of the request, you would end up with threadunsafe code.

Your best bet is to create a ThreadLocal<T> class. Assuming that you want it to be request/response based, here's a kickoff example:

public final class Context {

    private static ThreadLocal<Context> instance = new ThreadLocal<Context>();

    private HttpServletRequest request;
    private HttpServletResponse response;

    private Context(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    public static Context getInstance() {
        return instance.get();
    }

    public static Context newInstance(HttpServletRequest request, HttpServletResponse response) {
        Context context = new Context(request, response);
        instance.set(context);
        return context;
    }

    public void release() {
        instance.remove();
    }

    // ...
}

Get and set it in a Filter.

Context context = null;
try {
    context = Context.newInstance(request, response);
    chain.doFilter(request, response);
} finally {
    if (context != null) context.release();
}

(note that it's very important to release the context in the finally block of the try block where you're acquiring it, otherwise it won't be released whenever the request-response processing throws an exception)

Finally you can get it everywhere in your code as follows:

Context context = Context.getInstance();
context.setLocale(locale); 
Locale foo = context.getLocale();
// ...

wherein you delegate the methods to the local request and/or response variables.

Note that similar construct already exist in some MVC frameworks, like JSF with its FacesContext. Instead of homegrowing one, you'd like to look if the grass isn't greener over there.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks! Of course my `MyParameters` example would work thru a single request, I did not assume that a thread will be constant thru a session. – vbence Apr 22 '11 at 13:41
  • What I wrote is: "I did not assume that a thread will be constant thru a session" – vbence Apr 22 '11 at 14:43
  • Just one more question: is this a generally used practice or is there a special design addressing this issue? – vbence Apr 22 '11 at 18:00
  • In MVC frameworks which use a threadlocal context, such as JSF, Spring MVC, Wicket, etc yes this is the general way it's been achieved. You have to be extremely careful with this, releasing the context should really happen in the `finally` as demonstrated in the code example, otherwise you end up with huge threadsafety issues. The only design pattern which applies here is the facade pattern. The `Context` in this example is basically a facade if you don't expose methods which returns the "raw" request/response. You should only supply methods which delegate to them. – BalusC Apr 22 '11 at 18:09
0

You could also consider using my approach which is discussed here: JSP/Servlet design question - Make request/response globally available via JNDI

In my approach the request and response objects are stored in JNI instead of ThreadLocal. Apart from that the setup and cleanup of them is done in a Filter like in the approach above...

Community
  • 1
  • 1
Takis Bouyouris
  • 121
  • 1
  • 7