Tuesday, February 24, 2009

Baseball is Here

'Clack, clack, clack' go the metal spikes against the floor.  The doors open and the afternoon sun floods into the dark locker room.  Cold, late-winter air hits you in the face, but it smells good, like the thaw that signals the arrival of Spring.  Most pair up to toss the ball, picking up after months like no time has passed, while the first-timers nervously look for someone to join them.  'Snap!'  The sweet, crisp sound of balls arriving at their destination.  

Ahh, baseball is here.  

Thursday, February 19, 2009

Reading Feeds using the ROME API

A recent task had me doing something pretty simple - reading some RSS feeds for display on pages inside our application.  I know that it's easy enough to just write some custom code that parses an RSS feed - after all it's just XML, right?  I didn't want to do that, so I did some digging, and found two real options - ROME, and Commons FeedParser.

It quickly became obvious that ROME was the correct choice, and that's when the fun started. ROME is a Sun project that seemed to provide the most flexibility as far as reading different syndication formats, and clarity of API docs.  Using this tutorial from the site, getting the feed and parsing it was really really easy.  Just pass a feed url to the feed reader, and get some content items back.  

Loop through them and display the correct content.  


URL feedUrl = new URL( feed );

SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build( new XmlReader( feedUrl ) ;

List feedEntries = feed.getEntries();

There are some subtleties, however, that seemed to merit a post, as I didn't really find any clear explanations for these things in one place.

Issue 1:  Content Encoding

We are parsing a feed from a wordpress blog, and it seems that some posters always post content that has the weird characters that signify a content encoding issue.  The weird diamonds with question marks in them (or just empty boxes in Opera) that are inserted where there is a sort of 'half-space' on the actual blog.  I determined that the blog was using UTF-8 (this seems to be the default encoding for a WordPress instance.  After much searching, I came across this post, which seemed to contain about a million suggestions for how to handle the error.  What worked for some didn't seem to work for others, and certainly didn't work for me! I tried to read the url as a stream, and to no avail.  

Instead, I settled on setting the character encoding type on the HttpServletResponse object, which seems to take care of things.  Seems a little weird to me, but that's okay as long as it works and I don't have to write custom parsers.  After updating things, here's how my code looked:


URL feedUrl = new URL( feed );
String respEncoding = "";
if ( encoding == null )
{
encoding = "UTF-8";
respEncoding = "UTF8";
}
else
{
respEncoding = encoding.replaceAll( "-", "" );
}

XmlReader.setDefaultEncoding( "UTF-8" );

SyndFeedInput input = new SyndFeedInput();
SyndFeed feed = input.build( new XmlReader( feedUrl.openStream(), true ) ) ;

List feedEntries = feed.getEntries();

response.setCharacterEncoding( respEncoding );

Issue 2: Where's My Content?

The first blog I tested was easy to parse, once I got that list of feeds.  I just needed to to display the description field on the SyndFeedEntry object, and it gave me a nicely formatted (accounting for html inside the post) abridged posting.  Then I tried to display a blog that was hosted by the blogger platform (the very blog you are reading now).  Would you believe that the description property was unset.  No content. Now I am left having to get the raw content  straight out of the raw content feed.  I didn't really want an if-else for this in the display, and the way the SyndEntry was made, it wasn't really super simple to subclass it, so I went ahead and created my own class that took that SyndEntryImpl object and decorated with a few simple convenience methods:



/**
* Helper method to return the contents whether they come from the description field (ie wordpress is kind and does this) or raw content
* @return
*/
public String getAbridgedContents() {
//first try the description
if ( myEntry.getDescription() != null && myEntry.getDescription().getValue() != null )
{
return myEntry.getDescription().getValue();
}

//if that's not working, use the raw contents
StringBuilder sb = new StringBuilder();
SyndContent sc = null;

for ( int i = 0; i < myEntry.getContents().size(); i++ )
{
sc = (SyndContent) myEntry.getContents().get( i );
sb.append( sc.getValue() );
}

String ret = sb.substring( 0, 255 ) + " [...]";

return ret;
}

public String getDateString()
{
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d" );

return dateFormat.format( myEntry.getPublishedDate() );
}

public String getCatName()
{
if ( myEntry.getCategories() != null && myEntry.getCategories().size() > 0 )
{
SyndCategory sc = (SyndCategory) myEntry.getCategories().get( 0 );

return sc.getName();
}
else
{
return null;
}
}

public String getCatUri()
{
if ( myEntry.getCategories() != null && myEntry.getCategories().size() > 0 )
{
SyndCategory sc = (SyndCategory) myEntry.getCategories().get( 0 );

return sc.getTaxonomyUri();
}
else
{
return null;
}
}



Hopefully this will help people get their feedreader working quickly.

Thursday, February 12, 2009

Dear Winter

Winter,

I would like to invite you to go the hell away.  Pitchers and Catchers reported today.  We don't have any more use for you.  You can take your subzero wind chills and lack of snow and get the hell on.  Can't wait til opening day.  Spring - come on down!

Kirk

Developers and Writers

When I worked at Blackboard, one of the things that people frequently groused about (myself included) was the requirement that we write a certain amount of posts on the internal blog (we used Confluence by Atlassian, which had some blog/journaling-type functionality.  It was hard enough finishing the never-ending assignments that often ran concurrently in groups of five or six, so how could we possibly jump out of the IDE once or twice a day and write something about all this work?  Isn't that just a waste of time?!!?  

Looking back, the answer is unequivocally "No".  

Anyone, including the lowliest junior foot soldier developer, should be able to elucidate their work in plain language, so that someone who is not technical can read and understand it.  This is an important skill that has to be constantly developed.  It's another thing that must be treated as part of a complete developer arsenal, just like learning programming languages, libraries, important protocols, database servers, and operating systems.   Next time you are asked to draft a design document or blog about what you are working on, don't look at it as a black hole of timewaste.  Look at it as a way to get better at your job.  Any dummy can code - it's the people that can explain what and why they are doing it and make sense that are actually valuable.

Often writing something down and then reading it can help you realize that what you have done is a monstrocity, or unnecessary, or doesn't actually fulfill the requirement.  Even more often, if you don't see something after reading your own work, someone else who reads it might have a 'light bulb moment' themselves. Either way, you have a) learned something new, b) made your product better, c) gotten some valuable writing practice.  

If none of the above has inspired you, how about the fact that you get to do something other than completely nerding out for a little while?  Isn't that reason enough?

Go write, developers!  Life isn't all bits and bytes.

Wednesday, February 11, 2009

Fun and Games with Struts

I had a requirement for a project at work to insert some preprocessing into our Struts actions that will check to see if something fancy has to happen to decorate the page differently based on a branded association. I thought to myself, "hmm, that will be easy".  I was mostly right.  I have been working mostly with Struts 2 lately, which provides us with a handy dandy prepare() method to override, that is always called before the execute() method in a Struts 2 class that extends ActionSupport.  This is simple:

public class AwesomeActionSupport implements Preparable
{
private Integer integerToSet;
private Boolean someBool;

public void prepare() throws Exception
{
if( someBool )
{
integerToSet = new Integer( 1 );
}
else
{
integerToSet = 1;
}
}

public String execute()
{
System.out.println( integerToSet );

return SUCCESS;
}

//GETTERS/SETTERS FOR PRIVATE VARS ABOVE

}

As you can see it's quite simple when using Struts 2.  Sadly, most of the functionality in our application is still running Struts 1 for now.  This makes something easy much less simple.  There isn't really a built-in mechanism to make a pre-execution call.  Here's what I came up with:

public abstract class AwesomeAction extends Action
{
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception
{
//do prep work
request.setAttribute( "whatever the action needs", theValue );
return perform( mapping, form, request, response );
}

/**
* A stub for performing the execute method, to be implemented by each
* individual struts action, after the execute pre-processing is performed
*
* @param mapping
* @param form
* @param request
* @param response
* @return
* @throws Exception
*/
public abstract ActionForward perform( ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
So now when you write your actual action class, instead of extending the Action class, you extend this action class that does the preprocessing, then delegates the real work to the perform method that you have to define.  Seems to work great, with the only caveat being you can't use a Dispatch action with multiple methods.  If you really want to do that, then upgrade your action/application to Struts 2!

Tuesday, February 10, 2009

RUBA!

Just got back from a week in Aruba. Man, what an awesome place. The weather is virtually always perfect, the people are extremely friendly, and the food is delicious. Jena and I were lucky enough to tag along with her parents, her sister and bro-law, their son William (who calls Aruba 'Ruba', hence the title of the post), and her aunt. We had a great time. I spent most of it doing a combination of

1) sitting around doing nothing next to a pool
2) chasing our crazy nephew around the pool
3) floating in circles in the pool
4) drinking a tasty frozen drink in or near the pool
5) reading books next to a pool

I also played the Wii for the first time. Holy crap is that thing awesome. I hate video game systems like XBox and PS - I think that they are the scourge of an entire generation - but the Wii, just for its bare simplicity, amazing gameplay, and interactive nature has really nailed it. Amazing. I am not very good at the Wii games, but it's a good way to knock out 15 minutes. I think even Jena has agreed that we will get one sometime.

We got to play with our awesome nephew William, and even got to babysit one night. Note to babysitters everywhere, kids sleep much better when they are splashing about in pools for 8 hours before you get them. The diaper changing wasn't the best part of the night, but it was really something to read to him and put him down. He is a real joy to be around, and so smart. Last time we saw him, around Thanksgiving, he was babbling in near English, and now he is talking and repeating everything and learning how to say everything. Just amazing what a sponge he is!


As you can see, we had a really crappy view from our balcony =)

We had a couple of pretty ridiculous meals. One at El Gaucho, an Argentine steakhouse where they try to kill you by serving you insane quantities of meat. We were able to share three entrees to feed four people to the point of absurdity. It was delicious. Friday the whole gang went to Madam Jinette's where everything is awesome. I had a plate-sized serving of Wiener Schnitzel. So very good.

I also read some books. I finished off the book on hyperpartisan politics that I started shortly before my trip (more on that in a future post), read a silly Vince Flynn novel, and finally read Jurassic Park (book way better than movie). I am back on The Stuff of Thought, about humans interaction with language. So fascinating, though a bit heavy. I am also still reading the WW2 book about the Allied campaign in Italy. This has been a delight to read, and were it a bit slimmer, I would have brought it to Aruba, but sized as it is, it's a nightstand-only affair.