JSP Date Snippet

Being a traditionalist, I tend to forget some of the things you can do with tag libraries like JSTL above and beyond simple things like outputting information. A colleague asked me about putting the current year on a page and my first response was something like this:

<%@ page import="java.util.*"%>
<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jstl/fmt" prefix="fmt"%>
 
<%
	Date date = new java.util.Date();
	pageContext.setAttribute("date", date);
%>
<c:set var="date" value="${date}" />
<fmt:formatDate pattern="yyyy" value="${date}" />

It’s quite obvious looking at it that there’s a bit of redundancy in setting the date with a scriptlet and then making it available to JSTL to output with the Format tag library. That’s when I came across the solution to use the JSP useBean tag with JSTL resulting in the much simpler solution as follows:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
 
<jsp:useBean id="now" class="java.util.Date" />
<fmt:formatDate var="year" value="${now}" pattern="yyyy" />
 
<c:out value="${year}" />

I don’t believe it has any version dependencies (as I’ve encountered with some of the JSTL libraries that only work with the JSP 2.0 spec and the like) and certainly feels cleaner. Most importantly, it gets rid of the scriptlet and, in the JSP world, that’s a win.

Comments Off

Javascript Sorting

Not too long ago, I was asked, as a theoretical question, how I might take a string of random alphabetical characters and sort them in order using Javascript. Thus, given NFARAKDMSLSJDQKJKCXLK, find a simple way to turn it into AACDDFJJKKKKLLMNQRSSX. It’s a pretty basic question for anyone who uses Javascript and I immediately thought of splitting and joining the string as an array (a quick and easy way to tokenize the string). However, for some reason, I completely forgot about the Array.sort() function that’s pretty much a universal across languages.

Instead, the first thing that came to mind was the last time I had to sort a collection and started thinking of Java sorting. In the work I’ve done, such sorting usually requires the use of comparators because the default sort order is often not the one that’s desired. As a case in point, we have a set of JSP pages for rendering content including archive and list pages that display in posting date or sequence order derived from the content. For example, here’s some code to sort by a custom “sequence” attribute using the Vignette Content Management API (this particular snippet is the work of the inimitable Yong Chen):

Comparator aComparator = new Comparator(){
	public int compare(Object obj1, Object obj2) {
		int result=0;
		try {
			Integer s1 = (Integer) ((ContentInstance) obj1).getRelations(CT_RELATION_HEALTH_PLAN)[0].getAttribute("sequence").getValue();
			Integer s2 = (Integer) ((ContentInstance) obj2).getRelations(CT_RELATION_HEALTH_PLAN)[0].getAttribute("sequence").getValue();
			result=s1.compareTo(s2);
		} catch (com.vignette.as.client.exception.ApplicationException e) {
		}
		return result;
	}
};

For debugging, I might break it out a little differently to avoid the multiple casts in a single line. I think the Vignette API is fairly robust, but I would still split the ContentInstance cast apart from the Java native Integer cast in this case. But that might just be me.

In any event, while Javascript can also use comparators without much loss of speed, for a task like the one delineated initially, a simple sort will do the job and the whole can even be condensed to a single line function like this:

function order(unsortedString) {
	return unsortedString.split("").sort().join("");
}

Depending on the browser, the sort function will be some variation on a quick sort or a merge sort. It depends on whether the browser architects chose a stable algorithm or opted for some other version based on various considerations. Mozilla used to use a quicksort prior to Firefox 3.5, but they opted for a merge sort instead in more recent versions. In the course of reading about sort implementations, I came across notes on timsort, Python’s default sort implementation, that I found particularly intriguing.

As an aside the return value for a comparator that works in Firefox may fail with Webkit (Chrome and Safari) since you need to return -1 instead of zero (and a boolean false will also fail). You can read more about Webkit’s Array.sort() handling.

With Java, it looks like this:

String unsorted = "xzya";
char[] content = unsorted.toCharArray();
java.util.Arrays.sort(content);
String sorted = new String(content);

With Perl, you can do something like:

print (join “”, sort split //,$_)

In bash, this will do the same job:

echo “teststring” | grep -o . | sort -n |tr -d ‘\n’; echo

All in all, not only did I refresh my memory about good ways to sort strings and arrays in Javascript, I also learned some new things about sort algorithms and implementations of those algorithms.

Comments Off

Creating an RSS Feed in JHTML

Because we use an older version of ATG Dynamo (6.2.0) at my place of employment, we’re sometimes constrained in what we can do and aren’t able to take advantage of features in newer versions of Dynamo. One of those features is the ability to generate an RSS feed from a content repository (which I believe is available now as part of the suite of personalization features ATG offers). If you have the ability to deploy droplet code, there’s certainly an RSSFeed module. But if all you need is a basic RSS feed for a particular collection, the following is what I came up with.

<?xml version="1.0" encoding="UTF-8" ?>
<importbean bean="/atg/targeting/TargetingForEach">
<importbean bean="/atg/dynamo/droplet/Switch">
 
<%-- import files --%> 
<%@ page import="java.util.*, java.text.*" %>
 
<%-- Generate the RSS XML --%>
 
<%-- Set the rss type --%>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
   <channel>
      <title>News</title>
      <link>http://www.foobar.com/</link>
      <description>News and information.</description>
   <textInput>
      <title>News</title>
         <link>http://www.foobar.com/</link>
         <description>News and information.</description>
   </textInput>
   <skipHours>
      <hour>0</hour>
   </skipHours>
      <language>en-us</language>
      <webMaster>webmaster@foobar.com</webMaster>
 
      <droplet bean="/atg/targeting/TargetingForEach">
         <param name="targeter" value="bean:/atg/registry/RepositoryTargeters/News/archiveNews">
         <param name="fireContentEvent" value="false">
         <param name="firecontentTypeEvent" value="false">
         <param name="sortProperties" value="-postingDate">
         <oparam name="output">
            <droplet bean="/atg/dynamo/droplet/Switch">
               <param name="value" value="param:element.linkURL">
               <oparam name="unset">
                  <item> 
                     <title><valueof param="element.title"/></title>
                     <description><valueof param="element.description"/></description>
                     <link>http://www.foobar.com/news/news.jhtml?reposid=<valueof param="element.repositoryId"/></link>
                     <pubDate><valueof param="element.postingDate" converter="Date" date="EEE, dd MMM yyyy HH:mm:ss Z"/></pubDate>
                  </item>
               </oparam>
               <oparam name="default">
                  <item> 
                     <title><valueof param="element.title"/></title>
                     <description><valueof param="element.description"/></description>
                     <link><valueof param="element.linkURL"/></link>
                     <pubDate><valueof param="element.postingDate" converter="Date" date="EEE, dd MMM yyyy HH:mm:ss Z"/></pubDate>
                  </item>
               </oparam>
            </droplet>
         </oparam>
         <oparam name="empty">
            <p>No archived news</p>
         </oparam>
      </droplet>
   </channel>
</rss>

A couple of the important things with an RSS feed is to have a properly formatted date and to properly include the various elements and the like. Some readers are more forgiving than others. The date version here is the RSS 2.0-compatible RFC822 and not the older ISO8601, though you can read all about the ins and outs of RSS dates. Many elements are optional but the output may display strangely depending on the reader and are included here primarily for consistent display with the built-in readers on IE and Firefox.

Comments Off

A Breadcrumb Story

Where I work, one of the site features is a breadcrumb trail on all pages allowing linking through the content hierarchy. All of the breadcrumbs in the breadcrumb trail was generated using a rather lengthy Javascript file. The main reason for the length was due how the folders were named and the number of exceptions or special cases. As a note, for this to work all directory names were CamelCase (lowerCamelCase, to be precise) except where they were legacy items or inconsistently named (increasing the number of special cases that needed handling).

But it worked better than much breadcrumb code I’ve seen, so all was well and good until two things happened. The first was that mysterious 404 errors began to crop up in our logs. I finally traced them back to bots crawling the site, coming across the pieces of the Javascript that constructed the links in the breadcrumbs and indexing them as valid (not processed) links. So our logs were littered with failures to find pages like about_gh/.*/badministrator/b.*)/i, or /health_plans/+howmany[i+2]+. The second thing that occurred was we began developing a new version of one of our sites and it didn’t make sense to use the existing Javascript since the majority of it’s special cases were for our main site. Further, we would just be perpetuating the log errors caused by misbehaving seach engine bots.

So, for the new site, I rewrote the Javascript as a JHTML include. Since we’re using Dynamo and haven’t migrated any of our dynamic pages to be JSP pages (and encountered some problems with that due to the older version we’re running on), I learned some interesting things about using Java inline on a single page like this.

The first part of the page requires declaring any imports, like so:

<java type="import">
	java.util.regex.*;
</java>

The second part of the page is the main Java code that gets the URL and performs some operations on it:

<java>
	String originalURL = request.getRequestURL().toString();
 
	if (originalURL.indexOf("somejavaAppPathID") != -1) {
		if (originalURL.indexOf("javaApp") != -1) {
			breadcrumbPathString += divider + "<a href=\"/somespecialidentifierParent/index.jhtml\">JavaAppParent</a>" + divider + "<a href=\"/somejavaAppPathID/javaApp/JavaAppMethod?forwardUrl_success=/someAppResultLocation/javaApp/index.jhtml\">JavaApp</a>";
		}
	} else if (originalURL.indexOf("pageNameWithParam.jhtml") != -1) {
			//itemKey is the parameter that has the path to the content
			String paramKey = "paramname";
			breadcrumbPathString = makeTrail(request.getParameter( paramKey ), baseLoc, divider);
	} else {
		breadcrumbPathString = makeTrail(request.getRequestURI(), baseLoc, divider);
	}
 
	breadcrumbPathString = fixDirectories(breadcrumbPathString);
 
	out.print(breadcrumbPathString);
</java>

Originally, my thought was to use the Request Scheme like this:

String thisRequestScheme = request.getScheme();
if (thisRequestScheme.startsWith("https") == true) {
	baseLoc ="https://"+ request.getServerName() ;
} else{
	baseLoc ="http://"+ request.getServerName() ;
}
if (request.getServerPort() != 0) {
	baseLoc += ":"+request.getServerPort();
}

But since our server configuration includes F5 load balancers, that was incorrect and the request object contains different information than the URL we’re looking for. I’d prefer to use this implementation, but the previous one starting with request.getRequestURL() will work.

Lastly, I created some methods for handling special cases and doing some other work on the URLs:

<java type="class">
	public String makeTrail(String breadCrumb, String urlPath, String thisDivider) throws IOException {
		urlPath += "/";
		String outputString =  "<a href=\""+urlPath+"index.jhtml\">Home</a>";
		String linkName = "";
		String linkString = breadCrumb;
		breadCrumb = removeDirectories(breadCrumb);
		if (breadCrumb != null) {
			String[] breadCrumbArr = breadCrumb.split("/");
			String[] linkStringArr = linkString.split("/");
			if(breadCrumbArr.length!=0) {
				for(int i=1; i<linkStringArr.length-1; i++) {
					urlPath += linkStringArr[i]+"/";
					if (breadCrumbArr[i] != null && breadCrumbArr[i].length() > 0) {
						linkName = makeProper(breadCrumbArr[i]);
						outputString +=  thisDivider+"<a href=\""+urlPath+"index.jhtml\">"+linkName+"</a>" ;
					}
				}
			}
		}
		return outputString;
	}
 
	public String makeProper(String theString) throws IOException {
		StringReader in = new StringReader(theString);
		boolean precededBySpace = true;
		boolean precededByCap = true;
		StringBuffer properCase = new StringBuffer();
		while(true) {
			int i = in.read();
			if (i == -1)  break;
			char c = (char)i;
			if (Character.isSpaceChar(c)) {
				properCase.append(c);
				precededBySpace = true;
			} else if (Character.isUpperCase(c)) {
				if (precededByCap) {
					properCase.append(c);
				} else {
					properCase.append(' ');
					properCase.append(c);
				}
				precededByCap = true;
			} else if (c == '-'||c == '_') {
				properCase.append(' ');
				precededBySpace = true;
			} else {
				if (precededBySpace) {
					properCase.append(Character.toUpperCase(c));
				} else {
					properCase.append(Character.toLowerCase(c));
				}
				precededBySpace = false;
				precededByCap = false;
			}
		}
		return properCase.toString();
	}
 
	public String removeDirectories(String theString) {
		//completely remove these directories from the breadcrumbs
		theString = replaceWith(theString,"ignore/","/");
		theString = replaceWith(theString,"anotherDirectoryToSkip/","/");
		return theString;
	}
	public String fixDirectories(String theString) {
		//replace these nonsense names with real words
		//    theString.replaceWith("(?i)\\babout[ _]us\\b","About Us"); //A weird special case since the directory name is not CamelCase
		theString = replaceWith(theString,"(?i)\\bpeople\\splaces\\b","People &amp; Places");
		theString = replaceWith(theString,"(?i)\\babbr\\b","Full Unabbreviated Directory Name");
		return theString;
	}
 
	private static String replaceWith(String aPath, String aPattern, String aReplacement ){
		Pattern pattern = Pattern.compile(aPattern, Pattern.CASE_INSENSITIVE);
		Matcher matcher = pattern.matcher(aPath);
		return matcher.replaceAll(aReplacement);
	}
</java>

In reviewing this code, one thing I was unsure about was whether using

String originalURL = request.getRequestURL().toString();

was the correct way to go or if I should have used

String path = request.getPathTranslated();
path = replaceBacklash(path);

I realized that, for the way the site functions, we may pass an item parameter and we want to properly build the path to that item, not the page rendering the item. Using getRequestURL handles both situations.

Comments Off

JHTML Parameter Munging with Java

On our site, we have a search engine that does a file system crawl and returns a list of items, generating the URL to that item as it goes. We recently started using Teamsite forms for editors to create content and save it as XML. That XML is then rendered using a custom JHTML page that applies the appropriate XSL sheet and does some other work, but there’s no way to inform the search engine when that’s the case (at least not without splitting search into multiple repositories and doing a bunch of other work with the repositories).

One possible solution that I came up with, before abandoning it as a maintenance headache, is to detect the content type by its extension and then insert the necessary render page into the URL.

So we take the orginal JHTML values with the item parameter

<param name="searchItemURL" value="param:element.URLString">

that comes from the search results bean as it iterates through each item and generates the list of results within

<oparam name="output">

The results used to generate the href for the item result is this (note the backticks for the href):

<a href="`request.getParameter("searchItemURL")`"> <valueof param="element.title"></valueof></a>

And replace that with this snippet of Java code:

<java>
	String searchItemURL = request.getParameter( "element.URLString" );
	if(searchItemURL.endsWith(".xml")) {
		String[] linkStringArr = searchItemURL.split("/open");
		if(linkStringArr.length!=0) {
			searchItemURL = linkStringArr[0]+"/open/render.jhtml?item=/open"+linkStringArr[1];
		}
	}
	if(searchItemURL != null) {
		out.print("<a href=\""+searchItemURL+"\">"+request.getParameter( "element.title" )+"</a>");
	}
</java>

Comments Off

Spring Binding with Lists and A Form Gotcha

Suppose we have an application that uses two kinds of beans: a Subscriber bean and a Dependent bean. We have a form that is used to edit the Subscriber and each Subscriber may have zero or more Dependents who are also editable. All the fields for Subscriber have been bound with Spring <form:form> tags. However, the dependents are a list of beans. What we want is dynamic binding with a List of objects. Fortunately, iterating through the objects is made easier with the use of JSTL. The only tricky part is making sure the right form elements are bound to the right dependents.

In order to accomplish that, the code looks something like this:

<form:form commandName = "myCommandObject" method = "post" cssClass = "aForm" id = "aSearchForm">
    <h1>The subscriber</h1>
    <p>
        <form:input path = "subscriberObject.firstName" size = "15"/>
    </p>
    <p>
        <form:input path = "subscriberObject.lastName" size = "20"/>
    </p>
    <p>
        <form:radiobutton path = "subscriberObject.gender" value = "F"/>
        Female
        <form:radiobutton path = "subscriberObject.gender" value = "M"/>
        Male
    </p>
    <p>
        <label>
            <form:checkbox path = "subscriberObject.currentSubscriber" value = "Y"/>
            Current subscriber
        </label>
    </p>
    <c:choose>
        <c:when test = "${empty myCommandObject.subscriberObject.dependentObjects}">
            <p>No dependents listed</p>
        </c:when>
        <c:otherwise>
            <c:forEach items = "${myCommandObject.subscriberObject.dependentObjects}" var = "dependent" varStatus = "dependentRow">
                <form:input path = "subscriberObject.dependentObject[${dependentRow.index}].firstName" size = "15"/>
                <form:input path = "subscriberObject.dependentObject[${dependentRow.index}].lastName" size = "20"/>
                <p>
                    <form:radiobutton path = "subscriberObject.dependentObject[${dependentRow.index}].gender" value = "F"/>
                    Female
                    <form:radiobutton path = "subscriberObject.dependentObject[${dependentRow.index}].gender" value = "M"/>
                    Male
                </p>
                <p>
                    <label>
                        <form:checkbox path = "subscriberObject.dependentObject[${dependentRow.index}].currentSubscriber" value = "Y"/>
                        Current subscriber
                    </label>
                </p>
            </c:forEach>
        </c:otherwise>
    </c:choose>
    <input class = "buttonStyle" value = "submit" type = "submit"/>
</form:form>

Now for the gotcha. It turns out that the gender value for dependents may come back as either “F” or “Female” and “M” or “Male”. As near as I can tell, Spring MVC determines whether the radio button is selected based on whether the bound value matches the radio button value. In the form above, if subscriberObject.dependentObject[${dependentRow.index}].gender is set to “Female”, neither radio button will be selected.

The following (old-school) binding is therefore necessary:

<spring:bind path="eligibilityCommand.subscriberObject.dependentObject[ ${dependentRow.index} ].gender">
    <input type="radio" name="<c:out value="${status.expression}"/>" value="F"<c:if test="${status.value=='F'||status.value=='Female'}"> checked="checked"</c:if> /> Female
    <input type="radio" name="<c:out value="${status.expression}"/>" value="M"<c:if test="${status.value=='M'||status.value=='Male'}"> checked="checked"</c:if> /> Male
</spring:bind>

The subscriber object in the form only contains a List of dependents since the form is not dynamic (the user cannot add or remove dependents on the fly). If that were the case, it would have to use LazyList. Matt Fleming has this post and this one about dynamic list binding.

Comments Off

Downloads and Response Headers

One of the developers ran into a problem with a servlet he was working on recently. In his app, he was displaying a link that would cause the app to deliver a text file that the user would be prompted to save.

All was well and good with Firefox with the following code:

private final static String MIME_TYPE = "text/plain";
ByteArrayOutputStream myDataOutputStream = (ByteArrayOutputStream)writeResultsToStream(myData);
response.setContentType(MIME_TYPE);
String filename = "downloadfile.txt";
response.addHeader("Content-disposition","attachment; filename=" + filename);
response.setContentLength(myDataOutputStream.size());
response.getOutputStream().write(myDataOutputStream.toByteArray());
response.getOutputStream().flush();

Because the data may contain confidential information, options like saving it out as a flat file were precluded. All well and good except that our in-house users who would be accessing the servlet primarily use Internet Explorer 6.

One of the other developers suggested the following change that fixed the issue when the servlet was running on Tomcat (which we use for our desktop development):
response.addHeader("Content-disposition","attachment; filename=" + filename); to
response.addHeader("Content-disposition","attachment;filename=" + filename);

Unfortunately, the problem reoccurred when the application was deployed on our Dev server running ATG Dynamo.

We determined that part of the problem also lay in some of the headers likely being passed from ATG, where this note was helpful:
“The MIME types “text/plain” and “application/octet-stream” are termed ambiguous because they generally do not provide clear indications of which application or CLSID should be associated as the content handler.”
http://msdn.microsoft.com/en-us/library/ms775147.aspx
Which I read to mean that it attempts to derive the file name from the URL, even though we’ve passed a name in the header.
Also, ‘The main problem is that Internet Explorer strictly interprets a combination of SSL (https) and “cache-control: no-cache” as “do not save encrypted pages to disk.”’
http://www.alagad.com/go/blog-entry/error-internet-explorer-cannot-download-filename-from-webserver

My suggestion (per my research) was to make the following additional changes to the header:

response.addHeader("Pragma", "public");
response.addHeader("Cache-Control", "max-age=0");

I haven’t dug into the respective application server headers and settings, but I’m definitely hoping to get the chance to compare the server configurations and the headers the browser receives.

Comments Off