RSS Untangled: Exposing a Java API from ColdFusion
Note: This article uses the RSS Untangled (RSSU) Java library and ColdFusion component interface. The RSSU library is part of DevNet Resource Kit (DRK) Volume 4.
Get
DevNet Resource Kit (DRK) Volume 4
It seems like there are Java APIs for everything these days. From XML parsers to code for games for my cell phone, the Java community has done a terrific job of providing a tool for almost every task. Best of all for a ColdFusion developer, ColdFusion MX makes it easy for you to tap into these Java APIs through CFScript or by creating CFX tags.
One technique that is particularly interesting is using ColdFusion components (CFCs) to "wrap up" or organize Java code. "Wrapping up" Java code inside of CFCs means taking the functionality provided by the Java code and exposing it using a CFC. When you code in this way you appear to be using a CFC, however you are really dealing with the underlying Java code. CFCs are objects, and because of this, they let you mirror the Java object world in a seamless way. This gives you the best of both worlds: the completeness of the Java API and the convenience of ColdFusion.
An example of wrapping up a Java API using a CFC is the RSS Untangled (RSSU) Java library and ColdFusion component interface—now available on DRK 4. RSS is a standard for syndicating information on the Internet. Like many Internet standards, RSS is simply an XML specification. However, unlike most standards that exist, different versions of the RSS specification are not consistent. This can make dealing with RSS a hassle.
I built RSSU to meet this challenge. RSSU takes an arbitrary RSS feed and converts it to a set of generic Java objects, regardless of the RSS version. It can also generate RSS documents by converting Java objects to a specific version of the RSS specification. You no longer need to be concerned with the specifics of an RSS feed. Instead, you can focus on the important part: the data it contains.
For a full description of RSSU and a definition of terms, see the article accompanying the package on DRK Volume 4.
Download the sample code (TXT)
Recipe for Wrapping Up Your Java Code in a CFC
Below are some general steps for wrapping up a Java API in a CFC using RSSU:
- Identify the Java objects you want to expose.
Before you can decide what your CFC will look like, you must get an idea of what parts of the Java API you’d like to expose. Review the different objects in the Java API and decide which ones are most critical to the task. For example, in the RSSU Java library, there are three parsers to parse the different versions of RSSU. They include an RssStyleParser to parse RSS-style feeds, an RdfStyleParser to parse RDF-style feeds and an AutoParser to parse an unknown feed. However, I am only exposing the AutoParser that knows how to parse any kind of feed, keeping the other parser objects hidden. I did this to keep the API as simple as possible. - Create corresponding CFCs for the Java objects.
In general, it's best to create a CFC for each Java object. In the case of RSSU, I have a variety of Parser and Generator objects that correspond well to a Parser and a Generator CFC, Generator.cfc, and Parser.cfc - Create methods on your CFCs that call the underlying Java code.
This, again, is an opportunity to hide the complexity or annoyances of the Java API behind a ColdFusion method of your choice. Create Parser.parseFile, Parser.parseUrl, Generator.generateToFile, and Generator.generateToString. - Use and enjoy!
ColdFusion takes care of the rest, automatically linking the ColdFusion and Java worlds. The code in the 'Putting It All Together' section below shows how this works. Here's an example of the code:parser = createObject("component", "com.macromedia.rssu.Parser"); parser.parseUrl("http://www.macromedia.com/go/ccantrell_rss")
A Complication
Following the above recipe, creating Parser.cfc was a breeze. The parse methods return a Java Channel object and the ColdFusion code seamlessly uses them. (In other words, you don't need know many details about the objects that have been returned to you.)
However, in the process of creating Generator.cfc, I stumbled upon a complication. The methods on this component expected to have a Java Channel object handed to them. When I first saw this, I thought I would have to create the Channel object by hand. This would have been unfortunate, because having to create a bunch of Java objects manually takes away from the elegance and simplicity of the ColdFusion interface.
I first attempted to solve this problem by making methods on the Generator interface take in simple strings or structures. This had the advantage of relieving you of having to know the details of the Java objects involved. Unfortunately, sending in strings and structures made for an overly clunky solution.
In my second attempt—the one that I settled on—I took a lesson from the object-oriented programming (OOP) community. The OOP community tends to group standard solutions to problems into categories, thus creating a set of patterns. The pattern that I borrowed is known as the Factory pattern. In the Factory pattern, you create an object that encapsulates and conceals the details of how other objects are constructed. This results in the creation of a CFC whose only job is to create Java objects that I wanted to hide from the ColdFusion developer. While this took a little more effort to build, it simplifies the job immensely for the ColdFusion developer.
Here are two code samples that contrast two approaches to this problem. The first code sample doesn't use the RssTypeFactory CFC included in the RSSU package. Notice how you are expected to know quite a few details about how to construct and use the object:
image = createObject("java", "com.macromedia.rssu.Image");
image.setTitle("my title");
image.setUrl("http://www.url.com/image1.gif");
image.setDescription("my description");
channel.setImage(image);
In the second code example, I take advantage of the typeFactory. I
created this earlier in the code by using code such as: typeFactory
= createObject("java", "com.macromedia.rssu.RssTypeFactory").
Notice how much more compact this code is:
channel.setImage(typeFactory.createImage("http://www.url.com/image1.gif", "my title", "my description"));
Putting It All Together
The two code snippets demonstrate how you can efficiently wrap up a Java API in a ColdFusion component. They also provide a good example of how to use the RSSU component, assuming that you have installed RSSU as described in the article accompanying the DRK 4 distribution.
The first example parses a feed and extracts some information about it.
1 <cfset parser =
createObject("component","com.macromedia.rssu.Parser")/>
2 <cfset u = “http://www.macromedia.com/go/ccantrell_rss"/>
3 <cfset channel = parser.parseUrl(u)/>
4
5 <cfoutput>
6 Title: #channel.getTitle()#<br>
7 Link: #channel.getTitle()#<br>
8 Number of items: #channel.getItems().size()#<br>
9 First Item's title:
#channel.getItems().get(0).getTitle()#<br>
10 </cfoutput>
The second example generates an RSS feed.
1 <cfset typeFactory = createObject("component",
2 "com.macromedia.rssu.RssTypeFactory")/>
3 <cfset generator = createObject("component",
4 "com.macromedia.rssu.Generator")/>
5 <cfscript>
6 channel = typeFactory.createChannel("RSS feed: " & title, "", feedUrl);
7 channel.setLanguage("us-en");
8 channel.setCopyright("Copyright (C) You 2003");
9 channel.setCreator("You");
10 channel.setPubDate(now());
11 channel.setCategory(typeFactory.createCategory("My Category"));
12 item = typeFactory.createItem();
13 item.setTitle("First Item");
14 item.setLink(firstItemUrl);
15 item.setGuid(typeFactory.createGuid("first-item-id"));
16 </cfscript>
17
18 <cfoutput>
19 <pre>#xmlFormat(generator.generateToString(channel, "rss"))#</pre>
20 </cfoutput>
The Benefits of Wrapping Up Java in ColdFusion
Using existing Java APIs as part of your ColdFusion development gives you access to a vast amount of functionality; you don't need to rewrite code to recreate it.
As the above example demonstrates, wrapping up your Java code in CFCs has many benefits. The interface is easy to write because of the object-oriented nature of both the Java and CFCs. The interface is easy to use because you can put a simple ColdFusion API on what may be a complex Java API. Thus, you inherit the benefits of Java while adding the power and convenience of ColdFusion.
About the author
Ben Simon is Director of Systems Engineering at Amazing Media, Inc. He has vast experience programming in Java, Perl, Scheme, awk, and even a little ColdFusion. When he's not programming, Ben peruses comp.lang.functional or Linux Journal.
Submit feedback on our tutorials, articles, and sample applications.