views:

108

answers:

2

I've encountered a problem with JSP pages server-side caching.

Suppose I have an internal error page which is a custom JSP that will display a unique ID each time it's visited/requested. This unique ID is also logged in the server log for debugging. However, I noticed that if I implement the error ID using:

<%!private String <b>abc</b> = UUID.randomUUID().toString();%>

After a few requests...the variable abc seems to be cached on the server side and the same value keep poping up.

Oddly enough, on the same page, I also display the time in which the error is encountered with

XXXError encountered on <%=Calendar.getInstance().getTime().toString()%>

which never gets cached and always display the current time.

So I did a little experiment, instead of displaying time using the above, I used

<%!private String etime = Calendar.getInstance().getTime().toString();%>

and print onscreen that string, and SNAP, it's getting cached after a few calls.

So my question is, how do I stop the server from caching these variables?

A: 

After looking at the generated .java codes. Turned out the

<%!private String abc = UUID.randomUUID().toString();%>

part is declared as a member variable, hence only called on session initialization. So it never really gets called again after the initialization of the session.

I decided to go for a work around fix by putting the call inside a function and call that function instead, seems to be working fine. Please feel free to answer with a better approach.

John
+1  A: 

Roughly translated, this is been declared as instance variable of the servlet class which the JSP page at end get compiled to. E.g.

public class pagename_jsp_servlet extends HttpServlet {
    private String abc = UUID.randomUUID().toString();

    protected void service(HttpServletRequest ...

As JSPs usually get compiled only once during startup (or after change, if hotdeploy at server is enabled), the very same servlet instance will be shared among all requests! You don't want to do that.

After all, you should not be using scriptlets in JSP pages. Java code belongs in a real Java class. In this particular case you could use an EL function, or a bean class, or a servlet class.

The EL function would finally look like this:

<c:set var="uuid" value="${uuid:random()}" />
<p>UUID: ${uuid}</p>

A bean class would look like this:

public class UUIDBean {
    public String getRandom() {
        return UUID.randomUUID().toString();
    }
}

which can be used as:

<jsp:useBean id="uuid" class="com.example.UUIDBean" />
<p>First UUID: ${uuid.random}</p>
<p>Next UUID: ${uuid.random}</p>

A servlet class should be mapped on an url-pattern covering the JSP page (or vice versa) and should have the doGet() method implemented to preprocess requests before displaying data in a JSP page:

UUID uuid = UUID.randomUUID().toString();
request.setAttribute("uuid", uuid);
request.getRequestDispatcher("page.jsp").forward(request, response);

the forwarded JSP page can look like this:

<p>UUID from servlet: ${uuid}</p>

Further, the <%=Calendar.getInstance().getTime().toString()%> is better to be replaced as follows:

<jsp:useBean id="now" class="java.util.Date" />
<p>The date is now: ${now}
<p>The date in yyyy-MM-dd format: <fmt:formatDate value="${now}" pattern="yyyy-MM-dd" />

It keeps the code much cleaner and better maintainable.

BalusC