Generating RSS in Java Web Frameworks 1
Sportsvite, a web start-up focused on 1) connecting recreational sports enthusiasts and 2) facilitating communication and scheduling of sports activities (e.g team and league games), is expanding the role of RSS across the site. The most recent addition is a feed of the Sportsvite classifieds section. For example, if I wanted a list of all of the soccer teams looking for more players in my area by zip code, the relevant url would be: http://www.sportsvite.com/xml/rss/listings?type=1&zip=20009&sportId=14
The task of generating and serving up RSS first involves initiating the appropriate query to the persistence layer from a given HTTP GET request. The query string parameters in the example above are defining the "type" of classified listing (teams looking for players), the zip code, and the associated sport identifier with the team. Sportsvite is built with the popular Java framework Struts and simply requires an Action class mapped to the endpoint url.
Hibernate is the object-relational mapping and persistence layer of choice, so the query for soccer teams looking for players in northwest Washington DC will return a set of POJOs derived from the data model for Sportsvite classifieds. For each object in the result set list, an instance of a class representing an individual RSS "item" is instantiated. This RSS object is then populated with "get" method calls on the object from the result set list. The RSS class is very basic and defined as:
public class RSS {
public RSS() {}
private String title;
private String link;
private String guid;
private String pubDate;
private String description;
// (getter and setter methods...)
As an example, populating the pubDate involves creating the RFC822 date format as per the RSS specification.
Using java.text.SimpleDateFormat, an RFC822 date string can be formatted with:
SimpleDateFormat RFC822DATEFORMAT = new SimpleDateFormat
("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z",Locale.US);
The RSS object would then be populated with:
Date createdOn = (Date)listing.getCreatedOn(); rssItem.setPubDate(RFC822DATEFORMAT.format(createdOn));...where 'listing' is the name of the result set object and 'rssItem' is the instance of the RSS class.
As RSS objects are created and populated, they are collected in a list. The next step is to convert this list to XML using the ever powerful Castor marshalling tool. Castorization will produce an XML representation of the list data structure containing the RSS objects, which will then be transformed to the actual RSS feed. Here is how Castor is called:
private Document marshallRSSXML(ArrayList RSSList) {
Document doc = buildDocument();
try {
Marshaller.marshal(RSSList, (Node)doc);
} catch (MarshalException e) {
e.printStackTrace();
} catch (ValidationException e) {
e.printStackTrace();
}
return doc;
}
The Document object is of type org.w3c.dom, and the 'buildDocument' method simply creates an empty Document (using javax.xml.parsers.DocumentBuilderFactory)
to accept the result of the 'marshal' call.
The last step involves passing this XML Document in memory to a separate servlet of the web application that functions as an XSLT serialization service. In this case, it is serialization in the sense of sending the output of the XSLT engine over HTTP to the web client. The XSLT servlet is very straightforward and the key lines of code are below:
DOMSource source = new DOMSource(doc);
transformer.transform( source,
new StreamResult(response.getOutputStream()));
The javax.xml.transform.dom.DOMSource instance is created using the generated Document object available in memory
(stored in the session by the forwarding Action class).
The javax.xml.transform.Transformer instance is grabbed from a pre-compiled cache of XSLT modules, and using the
'getOutputStream' method on the javax.servlet.http.HttpServletResponse of the main 'service' method of the
servlet class allows us to send the transformation output to the requesting web client.
The XSLT is not even worth including as it just matches on '/array-list' (the root of the Castor generated XML document), creates the top level RSS 'channel' elements from passed in parameters, and applies-templates on <RSS> elements to create <item> elements.