Tuesday, March 30, 2010

Jasig UK 2010 meeting 21 and 22 June

Jasig are a consortium of educational institutions and commercial affiliates sponsoring open source software projects for higher education. Jasig project of particular note include uPortal (a powerful framework for producing campus portals) and CAS (a secure enterprise authentication system and single sign-on service).

The Jasig UK 2010 meeting will be held at Bristol University from Monday 21 to Tuesday 22 June.  The meeting will start at 14.00 on the Monday and finish by 14.00 on the Tuesday. Details can be found at:

http://www.ja-sig.org/wiki/display/UK/2010+Meeting+Bristol

If anyone wants to attend please update the "Interested in Attending" and "Suggested Topics" wiki pages with your details and items you are interested in discussing at the meeting. There is no charge for attending the meeting.

Friday, March 19, 2010

LinkedHashMap enhanced

In my day to day Java programming it is rare for me to feel the need to re-engineer or significantly enhance something quite fundamental to the Java language. I am a pretty average programmer, I get the job done, I like to do things elegantly but I do not spend my spare time creating my own languages and compilers (that stuff looks harder than "rocket science"). Most of the time the standard Java Collections Framework with the ArrayList, HashSet, HashMap and LinkedHashMap is more than ample for my meagre needs. Sometimes I have looked elsewhere to solve a particular problem; I had previously encountered the ArrayListMultimap from the Google Collections Library. This deviates from the standard Map implementations in that it allows you to create a "Map" which may associate multiple values with a single key (well technically it does not implement the Map interface but never mind!).

Google Collections' ArrayListMultimap

The ArrayListMultimap is really useful and very powerful. Imagine for example you wanted tag cloud functionality for a blog. You can iterate through your pages, putting them in your "cloudmap" (new ArrayListMultimap<String,URL>) using the tag as the map key. You can very easily get back a list of URLs with that tag key.


List<URL> links = cloudmap.get("java");

You can also very easily produce the tag counts necessary for a tag cloud using something like.


int linkcount = cloudmap.get("java").size();

My contribution: LinkedHashMap augmented

I have been working on a timetable related application recently which provoked me to extend the behaviour of LinkedHashMap. My situation was that I needed to produce a Map where the entry order of the data was important (e.g. insertion-order). Java Collections' LinkedHashMap is designed specifically for those requirements. I had an additional requirement to be able to fetch a portion of my map whose keys range from fromKey to toKey. LinkedHashMap does not itself implement this. TreeMap is a collections class which does permit accessing ranges of data, however, TreeMap does not support insertion-order. Instead TreeMap supports data with a natural ordering (e.g. numbers in numeric order, dates in chronological order). In my map, although the keys and values were important data, the natural ordering does not provide anything useful.

So I set about extending LinkedHashMap and came up with a class which implements the following interface:


public interface ILinkedHashMapAugmented<K, V> extends Map<K, V> {

LinkedHashMapAugmented<K, V> subMap(K fromKey, K toKey);

LinkedHashMapAugmented<K, V> subMap(int fromIndex, int toIndex);

Map.Entry<K, V> getEntry(int idx);
K getKey(int idx);
V getValue(int idx);
}

You can access the implementation of this interface at this link here LinkedHashMapAugmented.java. I make no claims about this being the most efficient code ever, if I wanted that I would take a copy of open source of LinkedHashMap and rather than extend it I would completely re-engineer it. I wanted something simple and what I have produced is useful and just feels right to me. The LinkedHashMap also supports access-ordering, I have not considered how my enhancement impacts on this but it could be useful.

So for a simplified example of my new class, I can define a week schedule like this:


LinkedHashMapAugmented<String, String> schedule = new LinkedHashMapAugmented<String, String>();
schedule.put("SV14", "21-Sep-09");
schedule.put("0", "28-Sep-09");
schedule.put("1", "05-Oct-09");
schedule.put("2", "12-Oct-09");
schedule.put("3", "19-Oct-09");
schedule.put("CV1", "14-Dec-09");
schedule.put("11", "11-Jan-10");
schedule.put("12", "18-Jan-10");
schedule.put("13", "25-Jan-10");
schedule.put("EV1", "22-Mar-10");
schedule.put("21", "19-Apr-10");
schedule.put("22", "26-Apr-10");
schedule.put("23", "03-May-10");
schedule.put("SV1", "21-Jun-10");

If I want to get a Map containing data between the weeks labelled 21 to 23 I need only call:


schedule.subMap("21","23");

As insertion-order is significant I have also implemented the ability to retrieve the Nth position of Map.Entry, key or value.

I think I have produced a simple but useful enhancement to the LinkedHashMap. I could have implemented this functionality by using some combination of existing Collections classes and arrays but this single data structure approach feels better to me. I suppose I could complete the loop by implementing a similarly enhanced version of ArrayListMultimap but I currently do not have the need!

Tuesday, March 09, 2010

AJAX decoration: using jQuery Metadata for portlet AJAX

I recently examined a JSR 168 portlet which tackled the thorny area of AJAX in a Portlet ( incidentally the portlet I was looking at is the Jasig Calendar Portlet ). The technique used makes all AJAX requests into POSTs which are then passed via the portal and a redirect to a servlet to acquire the desired response. I am not new to JSR 168 portlets and have personally produced several portlets over the past few years. I have also solved the AJAX in a Portlet problem but in a completely different way. The solution I developed I am calling AJAX decoration and relies on the jQuery Metadata plugin. I think both techniques have their merits and possibly could be applicable to different scenarios. I will attempt to illustrate my solution with a simple example app (note this example is not an actual portlet and will work in your servlet container of choice).

The structure of each of my "portlet" JSPs in my example is something like this:

header.jsp


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src=""jquery-1.3.2.min.js"><!--" --></script>
<script type="text/javascript" src=""jquery.metadata.js"><!--" --></script>
</head>
<body>
<div id="content-area">

footer.jsp


</div>
<script type="text/javascript">
var pageContext = "${pageContext.request.contextPath}";
var targetArea = "div#content-area";
</script>
<script type="text/javascript" src=""ajaxDecorated.js"><!--" --></script>
</body>
</html>

somepage.jsp


<%@ include file="header.jsp" %>
<h1>Some Page</h1>

<!-- Content goes here -->

<%@ include file="footer.jsp" %>

Notice that we will be using a consistent target area for our AJAX loaded content; in this case a div with the ID of "content-area". The jQuery Metadata plugin makes it possible to read data stored within CSS classes, doing this is a relatively clean way of storing data within our page. In this approach the content links are decorated with data and in turn this data is used to assign appropriate AJAX behaviour.

For a typical link using a GET we could use:


<a href=""page1.jsp"" class="ajaxRenderURL {link: '/page1.jsp'}">page 1</a>

For form submission we could use:


<form action="page2.jsp" class="ajaxActionURL {link: '/page2.jsp'}">
<input type="submit" />
</form>

The magic happens in the "ajaxDecorated.js" file. When the page initially loads initPage() is invoked which attaches AJAX loading behaviour to links and forms.


$(document).ready(function() {
initPage();
});

function setupLinks(){
var data = $(this).metadata();
var loadlink;
var tsSeparator = "&";
if(data.link.indexOf("?") == -1){
tsSeparator = "?"
}
if(!data.link.match("^" + pageContext)){
loadlink = pageContext + data.link + tsSeparator + new Date().getTime() + " " + targetArea;
} else {
loadlink = data.link + tsSeparator + new Date().getTime() + " " + targetArea;
}
$(targetArea).load(loadlink, null,
function () {
initPage();
});
return false;
}

function setupForms(){
var data = $(this).metadata();
var formdata = $(this).serializeArray();
var loadlink;
if(!data.link.match("^" + pageContext)){
loadlink = pageContext + data.link + " " + targetArea;
} else {
loadlink = data.link + " " + targetArea;
}
$(targetArea).load(loadlink, formdata,
function(){
initPage();
});
return false;
}

function initPage(){
$(targetArea).find('a.ajaxRenderURL').click(setupLinks);
$(targetArea).find('form.ajaxActionURL').submit(setupForms);
}

This technique adds AJAX to a web page in an unobtrusive way. In this simple example the URLs loaded by AJAX and those that would be loaded without are the same (page1.jsp, index.jsp etc). However, in an environment where the AJAX URLs and web page URLs are likely to be different or even change dynamically (such as in a portal) then this technique is equally applicable.