Sunday, July 19, 2009

Q: What is the warranty of Open Source?

A: Here, you figure it out.


This posting is rated
PG
[Pretty Geeky]
Knowing about code is helpful,
but not required
.

After seven years of enterprise programming in .NET/C#, over the past year I've been relearning the hardcore aspects of enterprise level Java. Maven, Spring, Jetty, Jersey and Eclipse have become my new and free-for-download best friends.

It was hard breaking away from the Redmondians. But after the bait and switch tactic of ASP.NET MVC, I decided to take a rest from the lemming like culture of Visual Studio's "Productivity Out of the Box". I mean, couldn't those guys on Lake Washington figure out that ViewState was a bad idea from the get go?

Anyway, all aspirations come with a price and a story. This is mine:

A few weeks ago I got this bright idea to exercise my Java coding prowess by making a Java library that provides a randomization service against often used data, in this case the city, state, longitude, latitude information associated with a given United States Postal Service zip code.

It was a simple idea. The library publishes a method, getAddress(). Behind the call to getAddress() is code that gets a random Address object from a list of Address objects. The list of Address objects is composed of data that resides in an XML file that contains all the address information for zipcodes in the United States.

The XML file is embedded as a resource in the Java project to allow the library to be transportable. I got the zipcode XML file from the Internet. The effort seemed like a no brainer.

So I make the library code as a Maven project under Eclipse and write my unit tests every step of the way using TestNG. (I am obnoxiously loyal to Test Drive Development.)

I run the unit tests under Eclipse and also from the command line, just to be extra special sure. No problem. All works as planned. At the end of it all I have a nice JAR file which I can share with my coding brethren and qualified family members.

Then I get another bright idea, "Say, wouldn't it be great to expose my Random Address library as a REST service". After all, I am just as susceptible to coding trends as the next guy. So getting a handle on writing a Java based REST service using that new fangled OpenSource project, Jersey, seems a nice way to kill two birds with one stone.

(This is the part in story where the skies beginning to blacken. Evil things are about to happen.)

That night I go home from the day job and begin to read up on Jersey. It seems that all the code examples on the Internet are referencing beta versions of the Jersey artifact, which is weird because I know for a fact that there is a 1.0 version in play. All the coders at work doing REST under Jersey are using the 1.0. Anyway, I figure to myself, what the hell, just get the Jersey code examples to work and take care of upgrading to 1.0 later.

So I do. I use Jersey to get a simple REST site up and running under a Jetty web server.

Then I fiddle with the code to my Jersey REST site to make calls to the API in my Address Randomizer JAR/Library.

You know what? THE ADDRESSS RANDOMIZER LIBRARY DOES NOT WORK!

I figure, OK, I'll work around the Jersey enabled web code; after all maybe the beta version really is a dog. I write a unit test within the REST Web project that accesses the Address Randomizer directly, straight call to the JAR file.

THE UNIT TEST FAILS TOO!

I ask a colleague for guidance. He says to debug the unit test in the Web Project as a remote server. So, I fire up the Surefire debugger from the command line and bind in the unit test under Eclipse.

(Now for those of you common folks that are looking for breathing apparatus by which to survive this descent into the perilous depths of Java coding, please know this: if all this geekiness is causing you to lose interest, take heart! Read on knowing that in 5 years all of this technology will be replaced with a whole new set of gizmos that will be just as hard to learn and equally exasperating to use.)

Back to the coding.

So I look at the code under the remote debugger. It turns out that the XML file is not loading under the REST Web Project. I don't know why. All I know is that there is a null value where the file based InputStream transformed by getResourceAsStream() is supposed to be.

The wheels begin to spin and the self-doubt sets in. What am I doing wrong? What don't I understand? Am I loading the resource properly? Is there something about the Jetty web server that I do not understand? Is the Jersey beta code that wacky? Is there something more about the XML file format that I need to learn?

I go to lunch with a coding friend. We talk about the problem. He says that I might want to check the XML to make sure that the prolog is correct. And, he goes on to say, that it's a real craps shoot coding to XML in Java because all the XML parsers seem to work differently.

So, I fiddle with the encoding. Still, the XML file won't load.

I do some new coding in the original Address Randomizer library using the Xerces parser directly. I get a new error: Content is not allowed in prolog. I track down the error message on the Internet.

At one point I am taken to a Java bug report, UTF-8 encoding does not recognize initial BOM.

I think, can it be this deep that I have to start looking at bytes in the XML file? But, I figure, what the hell? At this point I'll do anything. I am that frazzled.

So I download the workaround code. The code is literally doing byte inspection, not my favorite topic in the world of computer programming. Turns out that the code had portions commented out. Can I trust this code? I go through it line by line trying to follow the logic. It seems that some of the comments were left in by error. I start uncommenting code. Then recommenting code.

Three hours later I am still at a standstill. I go to sleep quivering in my bed completely obsessed about the error of my ways. I just can't get it. The code is working running the unit tests under Eclipse. But, when I try to use the code in the REST Web Project, running against Maven from the command line, it fails.

It's a new day. It's the weekend. I can hit the code really hard.

So I start fresh, getting ready to completely rewrite the whole Random Address library. Then I notice something.

I try to follow good coding practice. Thus, I put the name of the XML file in the resource as a constant value like so:

/** The Constant ZIPCODES_FILESPEC. */
private static final String ZIPCODES_FILESPEC = "zipCodes.xml";

Just for giggles, I look at the name of the resource file in the file system.

The name of the XML, zipcodes.xml.

Again, the name of the XML file in the file system is, zipcodes.xml. The value assigned to the constant in my code is, zipCodes.xml. One little 'c'!

So I go back and change the constant value to:

private static final String ZIPCODES_FILESPEC = "zipcodes.xml";

The code works everywhere!

So what do we have? I spent at least three evenings trying to find the bug and fix it. I took the time of at least two of my friends trying to leverage their expertise to solve my problem. All for what?

Here's for what: Learning that the libraries under Eclipse will load a resource file, case insensitive against a filename:


/**
* This is a helper method that fetches an Xml file that is embedded as a
* resources as an InputStream and converts that input stream into a string
* that represents an in memory representation of that Xml file
*
* @param resourceFilename
* the name of the xml file. You do NOT need to prepend a '/'
* symbol to the file name. This method make the prepend for you.
* @return the xml file as a string
*
@throws IOException Signals that an I/O exception has occurred.
*/
String getXmlFileString(String resourceFilename) throws IOException {
InputStream is = this.getClass().getResourceAsStream(
String.format("/%s", resourceFilename));
return convertStreamToString(is);
}



While the libraries in my Web Project will not!

Had Eclipse failed from the get go, I might have noticed that one little 'c' a whole lot earlier and avoided many a night of fitful sleep.

I love to code, always have, and always will. Coding is an enormously demanding, yet intensely satisfying creative experience that's hard to describe to anybody but another programmer. Still, when I signed up to work with code as a way of life, I don't remember reading the paragraph that said to be suspicious of all that you see and never to expect anything to really work, particularly if you follow the Way of the OpenSource.

It's like this: most painter's don't have to know about the in's and out's of each type of paint in order to make a portrait. Paint making is mostly a third party affair. An artist gets some paint and executes the intention.

I really wish that the same could be said of OpenSource programming. I do. I really, really do.


Muse Alert!

I need to thank my wife for her patience on this one. I spent the whole weekend getting the code to run and then writing up on it.

She didn't give me any trouble at all; no "You are spending too much time in your geekiness."

Most guys would have been sleeping on the couch for lesser offenses.