Encode URI

To encode an URI you can simply use Java’s URLEncoder’s encode method which has been available since JDK 1.4.

String encodedUri;
  try {
    encodedUri = URLEncoder.encode(uri, "UTF-8");
  }
  catch (UnsupportedEncodingException exc) {
    // this should never happen
    logger.warn("UTF-8 is not a supported encoding?  Not encoding for now...", exc);
    encodedUri = uri;
  }

Unobtrusive JavaScript

Unobtrusive JavaScript’s goal is to move all the functionality (the Controller) out of the HTML (the Model) and the CSS (the View).  This is also called full MVC separation.

This is how typically JavaScript and HTML mix.  For example in submitting a form using a text link.

<a href="javascript:submit(document.testForm)">Submit</a>

Or for jumping to different parts of a page using a dropdown.

 <input type="image" src="/img/buttons/update.gif"
   onClick="window.location.hash=
document.jumpTo.names.options[document.jumpTo.names.selectedIndex].value">

Using the unobtrusive JavaScript technique one can separate the JavaScript from the HTML.

<div id="foo">Submit</div>

<script type="text/javascript">
 Event.observe($('foo'), 'click', function(event) {
   $(Event.element(event)).form.submit();
   return false;
 });
</script>

We use the Protoculous JavaScript file which combines the Prototype framework and Scriptaculous libraries to do unobtrusive JavaScript.

mod_rewrite to bypass security

Many Apache webserver installations use uriworkermap to configure requests are forwarded to Tomcat/JBoss and which are not.   This provides a certain level of security.  For example:

## APACHE RESOURCES (static files):
!/*.gif=myapp
!/*.html=myapp

## DISALLOW  (security-related filter):
!/*.jsp=myapp
!/*.xml=myapp

## TOMCAT RESOURCES:
/*.do=myapp

However if you dynamically generate your sitemap.xml or any other XML files using a servlet then this security will be a problem since the XML request will not make it to Tomcat/JBoss.  This is when mod_rewrite comes to the rescue.

You can set up mod_rewrite to rewrite the sitemap.xml request to be a sitemap.do request.

RewriteRule ^/sitemap\.xml$ /sitemap.do [PT,L]

Then you can set up Struts to forward this request to sitemap.xml.

<action path="/sitemap" forward="/sitemap.xml"/>

Dynamically generate sitemap.xml

sitemap.xml is a top level document on your website “for webmasters to inform search engines about pages on their sites that are available for crawling.”  Google not surprisingly has its own documentation on how to improve your site’s visibility using sitemap.xml.

Typically sitemap.xml is a static file that is hand generated.  But on large sites it makes more sense to generate this dynamically.  One way to do this is to generate it on demand using a servlet.  Here is my simple solution.  I did not include the implementation for outputPages() since that will be specific to each application server’s DB hierarchy or web server’s file structure.

public class SiteMap extends HttpServlet {

  protected static final String MIME_TYPE_XML = "application/xml";

  // XML tags
  protected static final String SITE_MAP_XML_INFO = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
  protected static final String SITE_MAP_BEGIN =
      "<urlset\n\txmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9\n\t\thttp://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\">";
  protected static final String SITE_MAP_END = "</urlset>";

  protected static final String LOC_BEGIN = " <loc>";
  protected static final String LOC_END = "</loc>";
  protected static final String PRIORITY_BEGIN = " <priority>";
  protected static final String PRIORITY_END = "</priority>";
  protected static final String URL_BEGIN = "<url>";
  protected static final String URL_END = "</url>";

  @Override
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {

    // set content type to be XML
    response.setContentType(MIME_TYPE_XML);

    // get writer
    PrintWriter out = response.getWriter();

    // output header
    out.println(SITE_MAP_XML_INFO);
    out.println(SITE_MAP_BEGIN);

    // output pages
    outputPages(request, out);

    // output end
    out.println(SITE_MAP_END);
    out.close();
  }

  protected void outputPage(String uri, String priority, PrintWriter out, String urlStart) {
    out.println(URL_BEGIN);
    out.println(LOC_BEGIN + urlStart + uri + LOC_END);
    out.println(PRIORITY_BEGIN + priority + PRIORITY_END);
    out.println(URL_END);
  }
}

Then you configure web.xml to use the SiteMap servlet.

<servlet>
    <servlet-name>sitemap</servlet-name>
    <servlet-class>com.upromise.olm.app.servlet.SiteMap</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>sitemap</servlet-name>
    <url-pattern>/sitemap.xml</url-pattern>
</servlet-mapping>

Undefined

Nouveau Variation on Flickr

(Photo: Nouveau Variation by Syntopia)

I find the undefined keyword and identity operators (=== and !==) in JavaScript pretty useful.  For example if I am parsing a JSON input and I am not sure if something is there or not I test it like this.

if (root.Foo === undefined)

If I want to test if something is defined I do it like this.

if (root.Bar !== undefined)

saladwithsteve explains it well in his JavaScript undefined vs. null post.

Update 12-14-2009: Unfortunately the above method did not work for testing a variable directly.  I ended up following the advice of this post, Javascript IsDefined Function.  To test if a variable is defined I now do this.

if (typeof(foo) != "undefined")

Sleep

I always forget how to sleep or wait in Java though it’s quite easy, just use the static method Thread.sleep.

For example:

    // sleep the filter's wait interval
    try {
      Thread.sleep(filter.getWaitInterval() * 1000);
    }
    catch (InterruptedException exc) {
      logger.error("unexpected interrupt", exc);
    }

Sun has a tutorial calling Pausing Execution with Sleep.

DynamicBeanMap

Previously I posted about using the atg.beans.DynamicBeanMap class to wrap a RepositoryItem so that it is accessible via JSTL.  However it turns out this is not a great solution.

If we want to access a simple property in a RepositoryItem wrapped in a DynamicBeanMap it is relatively straightforward.  For example,

${user.name}

However if we want to access a RepositoryItem property like this,

${user.address}

then we end up getting a StackOverflowError as the DynamicBeanMap spins going back forth between the user RepositoryItem and the address RepositoryItem.

Interestingly enough accessing a simple property from the RepositoryItem property works fine.

${user.address.city}

One solution is to set the recursive argument to false when creating the DynamicBeanMap.

DynamicBeanMap itemBean = new DynamicBeanMap(pValue, false);

When you do this the following will work correctly.

${user.address}

However this no longer works.

${user.address.city}

We ended up abandoning the DynamicBeanMap and creating a library of strongly typed repository item wrapper proxy objects.

ATG Support helped me tremendously to figure out what was going on. They suggested an alternative which we never tried because of the large impact it would have on our JSP.

What I determined in looking at this further is that the DynamicBeanMap class is not really documented for customer use, but there is a DSP/DSPEL tag called “tomap” that uses this class that we do document. See the appendix in our 2006.3 Page Developer’s guide.

So, this tag would avoid this problem since it does have an undocumented “recursive” attribute that defaults to “false”, but I think it might be preferable to set it to “true” and use another undocumented option. After using the “tomap” tag with recursive=true, you can then use a _realObject property to unwrap your “final” object being accessed.

So if your tag is:

<dspel:getvalueof var="address" param="user.address" />

You can change it to use:

<dspel:getvalueof var="address" param="user.address._realObject" />

Or if you were doing:

<dspel:valueof param="user" />

you could use:

<dspel:valueof param="user._realObject" />

Basically you just unwrap whatever end/final object you’re trying to get to with _realObject.  Since we can’t see exactly what code called hashCode that caused the StackOverflowError, I can’t be certain this will avoid the StackOverflowError, but I suspect it will.

This solution will have the benefit of having minimal impact on your ability to access properties with JSTL.

I’ve entered a PR #155848 about some of these properties not being documented.

Also PR #81771 was submitted requesting the ability to recursively access repository items in JSTL.

Removing a Cookie

To remove a cookie the Java API suggests getting the cookie, setting its maxAge to 0, and then adding that cookie to the response.  Digging around deeper I realized you also need to set the domain and the path to match the cookie’s domain and path.  Here is an example of how to do this.

    Cookie [] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
      if (cookie.getName().equals(COOKIE_WE_WANT)) {
        cookie.setMaxAge(0);
        cookie.setDomain(".betweengo.com");
        cookie.setPath("/");
        response.addCookie(cookie);
        break;
      }
    }

Note that if the domain was not set when the cookie was created then you should not set it when you try to remove it. Similarly with the path property. For example if the domain was not set at creation then the code would look like this:

    Cookie [] cookies = request.getCookies();
    for (Cookie cookie : cookies) {
      if (cookie.getName().equals(COOKIE_WE_WANT)) {
        cookie.setMaxAge(0);
        cookie.setPath("/");
        response.addCookie(cookie);
        break;
      }
    }

Also you should ensure that you add the cookie to the response before the response has already been committed.  Previously the above code was in a tag but that was too late to modify the response.  I moved this code to a filter and then it worked fine.

Finally you can do this in JavaScript. Doing it in JavaScript has the downside that it is done after the page is loaded. But it’s definitely helpful for testing. Here’s an example of deleting the cookie named “foo”.

document.cookie = 'foo=;expires='+new Date(0).toUTCString()+';';

In the above example I did not set the path or the domain. One will need to do that if the path and/or domain were set in the cookie at creation.

Unexplainable JSP Compilation Problem

I was getting a JSP compilation problem that I could not solve.

org.apache.jasper.JasperException: Unable to compile class for JSP
        at org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:510)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:375)
        at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
        at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)

org.apache.jasper.JasperException: Unable to compile class for JSP
        at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:572)
        at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:303)

java.lang.NumberFormatException: For input string: "${status.index}"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
        at java.lang.Integer.parseInt(Integer.java:447)
        at java.lang.Integer.valueOf(Integer.java:553)
        at org.apache.jasper.compiler.JspUtil.coerceToInt(JspUtil.java:752)
        at org.apache.jasper.compiler.Generator$GenerateVisitor.convertString(Generator.java:2949)

The major problem was this was happening on the server but not locally.  The compilation problem was occurring for this line.

<uportal:module definition="${module}" moduleIndex="${status.index}"/>

The moduleIndex value is “${status.index}”. Locally when the JSP compiler encounters this it knows to call my setter for moduleIndex that takes a String parameter. But on the server the JSP compiler seemed to insist on using the setter for moduleIndex that takes an integer parameter, hence the compilation problem.

I finally posted on the Sun Forums and with the help of evnafets I came up with two solutions.

  1. The correct solution is to upgrade my application to use JSTL 1.1.  Then the JSTL expressions such as “${status.index}” will be evaluated by the container.  Then I don’t have to have a setter that takes a String parameter, the JSTL expression, and evaluate it myself.  I can just use a setter that takes an integer parameter.
  2. The quick, hack solution which is to get rid of the setter that takes an integer parameter.  Wherever the application passes in an integer parameter, I change it to pass in a String representation of that integer.

Upgrading to JSTL 1.1

Based on this excellent post I came up with the following instructions for upgrading from JSTL 1.1.

  1. Update URI in JSP pages to use JSTL 1.1.
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  2. Install in WEB-INF/lib the two JSTL 1.1 jars, standard.jar and jstl.jar.  You can get these from The Jakarta Site – Standard 1.1 Taglib Downloads.
  3. Update the start of web.xml to look like this.
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
        version="2.4">