Wednesday, March 21, 2007

JSP EL expressions are being ignored by tomcat

Keywords:
tomcat JSP JSTL EL

Problem:
Hopefully this is my last post about the possible problems with JSP/web-app specs and EL. In this case, there's a JSP using EL
Eg:

<%
String myUrl = (String)session.getAttribute("SESSION_KEY_MY_URL");
pageContext.setAttribute("myUrl", returnUrl);
%>
<form name="load" action="${myUrl}" method="GET">


It's coming out in HTML with the EL untouched (but the scriptlet is definitely being run).

<form name="load" action="${myUrl}" method="GET">


Why is the EL being ignored?

Solution:
As with the previous 2 posts on this issue, you have to fix the schema reference in the web.xml (there's too many differing copies of the web.xml(s) I'm dealing with here) and make sure the JSP has the right tablib uri reference - see this post.

For the first time I found this didn't immediately solve the problem! The HTML is coming out the same with EL unevaluated. The issue is that the JSP has been compiled to TOMCAT_HOME\work\Catalina\localhost\MyApp\org\apache\jsp\jsp\myfolder\MyJSP.java and tomcat sees no need to recompile even though I've updated the spec of the webapp.

The solution is to stop tomcat, remove the contents of TOMCAT_HOME\work and restart (OR update the timestamp on the JSP source file(s) to force recompilation). The JSP will be recompiled (to the right spec 2.0 now) and the EL will be evaluated as you expect.

Tuesday, March 20, 2007

How-to turn off tomcat session serialization

Keywords:
tomcat session serialization NotSerializableException "Cannot serialize session attribute" Manager

Problem:
On restarting tomcat there's a stacktrace (below) about an attribute in the session not being serializable. It doesn't seem to effect the application starting up and the application works fine, but these messages at startup are annoying.

2007-03-20 10:50:57,890 INFO [org.apache.catalina.session.ManagerBase@898] - 
java.io.NotSerializableException: com.example.package.MyBeanClassName
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1054)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:278)
        at java.util.ArrayList.writeObject(ArrayList.java:531)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


If you want to put (transient) non-serializable objects in the session, how do you stop tomcat from serializing them at shutdown/startup?

Solution:
This was hard to find, but you need to configure a Manager in the context of the application. This should be put in either:
  • the YourApp.war:/META-INF/context.xml

  • the TOMCAT_HOME/conf/Catalina/localhost/YourApp.xml file

  • OR the default context ...

<!-- Turn off session serialization -->
    <Manager className="org.apache.catalina.session.PersistentManager"
      debug="0" distributable="false" saveOnRestart="false">
        <Store className="org.apache.catalina.session.FileStore"/>
    </Manager>


The tomcat documentation for the Manager element will give a bit more information, but it doesn't show the className for the file-store Store element, which is crucial if you're using the PersistentManager class - even if you're configuring it to do nothing!

You'll know it's working when there are no longer any files called "SESSIONS.ser" in the TOMCAT_HOME/work/Catalina/localhost/YourApp folder.

Thursday, March 15, 2007

Can't get or find errorData attribute in JSP pageContext

Keywords:
error JSP pageContext errorData scriplet

Problem:
Writing a JSP that handles errors from JSP, servlets (and other!) need to access the ErrorData object in a scriptlet rather that the convenient JSP EL ${pageContext.errorData}.

Tried:
pageContext.getAttribute("errorData"); but this returns null. Maybe it's not in the page scope.
pageContext.findAttribute("errorData"); but still null.

Solution:
Thankfully there's the convenience method:
pageContext.getErrorData();

This works. It seems the JSP EL ${pageContext.errorData} is a way of referencing this accessor rather than an element in the pageContext "map".

Wednesday, March 14, 2007

Structured data to GWT component with JSON

Keywords:
GWT JSON stuctured initialisation data

Problem:
In a previous post I described using the internationalisation Dictionary class to pass in initialisation data. But what if the data is more complex than key-value pairs? You could define a dictionary value as being a delimited (e.g. space or comma separated) list of tokens but is there an easier way of getting in basic structured data without writing your own parser?

Solution:
JavaScript Object Notation (JSON) is a ".. text-based, human-readable format for representing objects and other data structures" (definition from wikipedia - the article includes a good introduction with examples). GWT supports reading and producing data in this format via the com.google.gwt.json.client package. For data interchange I think your still better off using a GWT remote service and sending your beans to it (let GWT handle the encoding/decoding) but for the host page giving data to the component JSON comes into its own.

Step 1


In the host page, define a dictionary as before but the value (or values) is/are now JSON strings rather than plain strings. In this example I'm creating an array of objects, each object having a property "id" and optionally a property "label" (it's got to be on one line as far as I can tell for the dictionary to allow it):
showHide: "[{\"id\": \"A\", \"label\": \"see A detail?\"}, {\"id\": \"B\", \"label\": \"include B detail?\"}, {\"id\": \"C\"}]"

Step 2


In the GWT component, use the dictionary to get at the JSON string. Then use the JSONParser to convert this to a JSON instance - in this example a JSONArray of JSONObjects. For a JSONObject you can get at each of its properties like you would a map via the get(String key) method.
public void onModuleLoad() {
    Dictionary properties = Dictionary.getDictionary("ModuleProperties");
  
    String showHideConfigString = properties.get("showHide");
    JSONArray showHideConfigs = (JSONArray)JSONParser.parse(showHideConfigString);
    
    List panels = new ArrayList();
    for (int i = 0; i < showHideConfigs.size(); i++) {
        JSONObject config = (JSONObject)showHideConfigs.get(i);
        
        JSONString idValue = (JSONString) config.get("id");
        String id = idValue.stringValue();
        
        JSONString labelValue = (JSONString) config.get("label");
        String label = (labelValue == null)? "include?" : labelValue.stringValue();
        
        // ... now we can do stuff with the data
        ShowHidePanel showHidePanel = new ShowHidePanel(label, id);
        RootPanel.get(id).add(showHidePanel);
        panels.add(showHidePanel);
    }
    
    // ... etc


Notes:
Someone asked me via comments how would you handle request parameters ... it's up to you to make something that can process the request parameters (CGI, java servlet, ASP?) and write a host page containing the data from the request params for the GWT component to then have access to them.

For many this will be obvious, but I felt bad for not including their comment ... but I don't want questions on the blog. Hope that helps.

If the data is more complex/rich than what JSON allows, there's XML.