Archive for November, 2007

Atom Conditional GET in Servlet

I’m using ROME to write an Atom/RSS newsreader client. ROME has this neat little interface called FeedFetcherCache that works with HttpURLFeedFetcher to support “conditional GETs”. This means the ROME client will first send an HTTP request with the “If-Modified-Since” header. If the server replies with HTTP 304 Not Modified, Rome knows not to bother fetching the entire feed. This can significantly reduce load on servers that generate dynamic feeds.

Atom

For this to work, your server-side code needs to properly handle this kind of request. If your feed is a static file delivered via Apache or comes from some blogging tool, it probably already works.

But in my case, I am generating an Atom feed dynamically using a servlet. My servlet ignored the If-Modified-Since header, so every request resulted in the whole feed being generated from the database.

How I Fixed It

First, I Googled and found this wonderful explanation of HTTP conditional GET by Charles Miller. The fix is very easy, requiring two changes to the servlet. First, I populate the Last-Modified header in my doGet(...) method.

Note that I also generate the entire feed in the doGet(...) method. ROME needs to download the feed the first time, then it caches this Last-Modified date in its FeedFetcherCache. Here is the important part of the code from my servlet:

protected void doGet(...) {
  Date feedModifiedDate = ...;
  servletResponse.setDateHeader("Last-Modified", feedModifiedDate.getTime());

  ... generate the feed
}

This handles the normal HTTP GET. But how does the servlet know how to process a request containing the If-Modified-Since header? It turns out this is built-in to the servlet API, you simply need to override the getLastModified(...) method in your servlet:

protected long getLastModified(HttpServletRequest req) {
  Date d = ...compute the modified date for the feed
  return (d == null) ? -1L : d.getTime();
}

And that’s it. Now my Atom newsreader client only downloads the entire feed when the date actually changes.

Not Just for Atom

Clever It’s Just a Bunch of Stuff That Happens readers will recognize this technique works for all kinds of servlets, not just Atom-producing servlets. Whenever you can determine a modification date, you should always strive to:

  • Set the Last-Modified HTTP header on the servlet response
  • ALSO override the getLastModified(...) method

These work together, along with intelligent HTTP clients, to reduce network traffic and server load.

Guice Questions (with Answers)

I mentioned that ClassBus uses Guice, and received some questions:

Speaking of Guice, don’t you have to reference Guice APIs to bootstrap the dependency injection? In general how should “third party” libraries handle Guice? As an app developer how should I handle libraries that use Guice? Do I care?

First, let me explain how ClassBus uses Guice. ClassBus is a tiny project with a handful of interfaces and classes. For example, BasicEventService depends on a DeliveryStrategy interface:

@Inject
public BasicEventService(DeliveryStrategy deliveryStrategy) {
  this.deliveryStrategy = deliveryStrategy;
}

See that “@Inject”? That’s Guice. The DeliveryStrategy interface declares a default implementation:

@ImplementedBy(EdtDeliveryStrategy.class)
public interface DeliveryStrategy {
 ...
}

That’s because I anticipate most people will use this framework in Swing GUIs and will want event dispatch thread delivery semantics.

I also use the @Singleton tag in one place:

@Singleton
public class BasicEventService implements EventService {
  ...
}

Again, that’s the most common (anticipated) usage pattern.

Ramifications

Using these Guice annotations means I need Guice in my classpath when I compile ClassBus.

Let me be perfectly clear about this: You do not need Guice to use ClassBus. Projects using ClassBus don’t need a Guice JAR file anywhere, either at build or run time.

Of course, if you wish to use dependency injection with Guice, you’ll then need to include Guice in your classpath.

Bootstrap Example

Two of the demonstration programs use Guice. It’s pretty basic stuff:

private static void swingSafeMain() {
  EventService es = Guice.createInjector().getInstance(EventService.class);
  new ProgressDemo(es).setVisible(true);
}
Why Not?

That’s it. One line of code to create the injector and get an implementation of the EventService interface. Since the EventService interface specifies an @ImplementedBy(BasicEventService.class) annotation, you get the default. And since BasicEventService specifies the @Singleton annotation, it is a singleton. And finally, since the BasicEventService constructor uses @Inject, you get the EdtDeliveryStrategy. All by magic.

Non Guice

If you don’t want to use Guice, you just need to either use some other DI framework, or manually construct the classes:

DeliveryStrategy deliveryStrategy = new EdtDeliveryStrategy();
EventService es = new BasicEventService(deliveryStrategy);

Third Party

And finally, this question:

In general how should “third party” libraries handle Guice?

I don’t see any downside to me including Guice annotations in ClassBus. You can ignore them if you don’t use Guice. If you use Guice in your application, then ClassBus will blend right in.

Static Imports Rock

I’m really loving Java 5 static imports. Let’s suppose we have an event service that lets you broadcast “events” (actually any type of object) to arbitrary numbers of subscribers:

public interface EventService {
  <T> void publish(String channel, T event);

  ...other methods
}

The channel is any string, allowing you to filter which subscribers receive the event. You can also filter based on the type of event.

Subscribers merely have to implement this interface:

public interface EventSubscriber<T>{
  void onEvent(T event);
}

How might we add subscribers to the event service?

How Not To Do It

When I started this framework, I envisioned several ways to filter on channel name:

  • Exact name match
  • Match on any channel
  • Regular expression match

And a few ways for receivers to filter events based on their type:

  • Exact type match
  • Subtype match

Just with these small lists, you have six possible combinations. Adding six separate methods to the EventService is a poor solution:

public interface EventService {
  <T> void publish(String channel, T event);

  <T> void subscribeByExactNameAndExactClass(String channel,
        Class<T> eventType, EventSubscriber<T> subscriber);

  ...5 other methods for other combinations
}

Not only do you end up with M * N methods, this approach does not offer any extensibility. What if someone wants to filter events based on some other type of pattern matching algorithm?

A Better Solution

Let’s start by stealing (part of) an interface from Guice:

public interface Matcher<T> {
  boolean matches(T object);
}

Now we can use matchers to subscribe:

<T> EventSubscriber<T> subscribe(Matcher<String> channelMatcher,
           Matcher<Object> eventMatcher,
           EventSubscriber<T> subscriber);

We can now provide many different Matcher implementations, and customers can even write their own Matchers. Instead of six methods, we have one, and it offers far more flexibility.

Static Imports Rock

Using the EventService is now pretty cumbersome, but we can simplify the code using a MatcherMaker class along with static imports. I really like that class name, by the way.

Here is one such method:

public static Matcher<String> anyChannel() {
  ...
}

And here is how event subscription code looks:

eventService.subscribe(anyChannel(), exactType(BaseEvent.class), subscriber);

In that example, the anyChannel() and exactType(...) methods are both static methods on the MatcherMaker class.

Other combinations are possible:

eventService.subscribe(exactChannel("A"),
        exactType(Integer.class), anIntSubscriber);
eventService.subscribe(nullChannel(),
        exactType(ProgressEvent.class), aProgressListener);

So you see, the static imports really clean up the code and make it more readable. (I think so, at least)

Get It

All of this is from my new ClassBus project — I hope to release the version 0.2 ZIP distribution in a few days, along with a more formal announcement. For now, it’s all available in Subversion.

CNN, Check Snopes First

A coworker took this picture of our TV at work, showing CNN in all of its glory:

CNN Snopes

Here is what Snopes has to say about that:

The U.S. Postal Service will not accept mail addressed to “Any Soldier,” “Any Wounded Soldier,” or the like because if it did, it could be providing a conduit for those who might do harm to armed services members. Such offerings are either returned to sender (if a return address has been provided or if one is found within the package) or donated to charities (if no address for the sender is found). Similarly, military hospitals will not accept letters, cards, or packages addressed in such manner for the same reason. Such beneficences, no matter how kindly meant, are not permitted to reach the soldiers they were intended for.

Good job, CNN!

In all fairness, I don’t have any context for this photo. Perhaps CNN was doing a story illustrating how easily fake news and urban legends circulate through Email? After talking to the person who took the picture, I have confirmed this was part of a Veterans Day story and they promoted the address as legitimate. Boo, CNN.

Gravatars Now Active

All comments on this blog now use gravatars - globally recognized avatars. I think this is a really cool concept, although scanning through historical comments shows hardly anybody with a picture (yet).

Since I modified the comment layout, repeat visitors may have to hold Shift-Reload to force your browser to get the latest CSS and background image.

Now I’m looking for a few brave souls to get their free Gravatar accounts, leave some comments, and check it out!

Do you use Gravatar on your blog?

Bug Tracking: How Do You Do It?

This quote from OpenJDK Infrastructure Roadmap resonates with me:

…they had considered something like that but that the blocker was the lack of a mechanism to have a fix target multiple releases.

Suppose you have trunk, 1.9, 1.10, and 1.11 branches. Customers use the software at all of those release levels (except for the trunk, of course), and critical bug fixes are often ported to numerous different branches. Most defect tracking tools do not support this, or do so poorly.

Speaking in general terms, a “classic” bug tracking tool has a core record with a name like “Issue” “Change Request” or “Defect”. Whatever you call it, the concept is generally the same. The Issue probably has attributes such as status (new|in progress|fixed|verified fixed), priority, responsibility, synopsis, and several other attributes.

The workflow might go like this:

  1. Someone reports a bug.
  2. You create an Issue, setting the Reported Against attribute to 1.10, since that is the version the customer uses.
  3. A programmer fixes the problem, marking the Issue “fixed”.
  4. The Issue goes to QA for testing, etc…

I already have questions about this workflow:

  • In which branch did the programmer commit the fix? 1.11? trunk?
  • Once the Issue is marked “fixed” (assuming in trunk), how do we backport to other branches?

If a customer on release 1.9 calls up and reports the same problem, can you easily do a query and say “Yep, looks like that is fixed in version 1.12″ ?

Do you create new Issues for each and every branch you apply the fix to? That seems wasteful. But the original Issue is already marked Fixed.

One Idea

Perhaps the original Issue report shouldn’t have a Status at all? Maybe, instead, each Issue has a list of one or more “Work Request” records? Each Work Request belongs to a particular software release level, and each Work Request has its own status.

One issue might have three Work Requests: trunk, 1.10, and 1.11. You can then do a query to determine the issue is Fixed in trunk and 1.11, but not yet backported to 1.10.

How Do You Do It?

I’m very interested in learning how other companies handle this. Do any defect tracking tools support status tracking for multiple software branches, or do people just make copies of defect reports for each and every branch?

Android Shuns Java

Final results expected Nov 12, but early exit polling indicates the following:

Android Shuns Java

HOWTO: Publish Javadoc on Google Code

This entry shows how to publish Javadoc to your Google Code project site. The general idea is to add the Javadoc to Subversion, ensure the files have the correct svn:mime-type, and provide a link to the Google Code Subversion repository browser.

Step 1: Configure Subversion

When I first published Javadoc for my ClassBus project, I noticed the pages rendered OK in Internet Explorer but appeared as plain text in Firefox. This is a red flag that the MIME type is text/plain instead of text/html. To solve this problem, you must ensure that every .html file has svn:mime-type=text/html, and every .css file has svn:mime-type=text/css.

The svn:mime-type is a Subversion property. You can follow that link to learn all about Subversion properties. If you use TortoiseSVN on Windows, you can see these properties by right-clicking a file, selecting Properties, the Subversion tab, and then clicking the Properties… button:

Subversion Properties

Setting these properties one at a time is a pain, plus you will eventually forget to do it. Instead, configure automatic property setting. You can either edit files as explained in the Subversion manual, or with TortoiseSVN you can use the TortoiseSVN->Settings->General page, click the “Edit” button, and make sure the file contains something like this:

enable-auto-props = yes
[auto-props]
*.txt = svn:mime-type=text/plain
*.html = svn:mime-type=text/html
*.css = svn:mime-type=text/css
*.png = svn:mime-type=image/png
*.jpg = svn:mime-type=image/jpeg

Now, all newly added files with these extensions will have the correct mime types.

Step 2: Add Javadoc to Subversion

Google code projects have a Subversion repository with a trunk directory. I simply created a new directory under trunk called (cleverly) “javadoc”, and put the Javadoc there. Commit using normal Subversion commands.

Step 3: Find the Javadoc

From your Google Code project home page, click the Source tab. This contains a link to browse your Subversion repository. Just browse through the trunk/javadoc directories, and click your index.html file. Now you know the URL you’ll need to link to. For my project, the URL is:

http://classbus.googlecode.com/svn/trunk/javadoc/index.html

If you see plain text instead of HTML, you probably screwed up the svn:mime-type. Go back and fix that.

Step 4: Make the Link

Back on your Google Code project page, click the Administer tab. On the Project Summary editing page, scroll way down to the Links section. Add a link name “Javadoc”, and paste the URL from the previous step into the URL field.

Hit Save Changes, then go back to your project home page. You should see the link to your Javadoc on the right side of the page:

Javadoc Link

I hope someone finds this useful. Figuring out the MIME type was…fun. :-)

Comic: Android SDK Reactions

The Android SDK is coming on November 12. Woohoo!

Android SDK Coming November 12

See also: Schmidt

A Syntax Trick I Was Not Aware Of

Suppose you have an incredibly powerful Gadget class:

// Example 1
public class Gadget {
  public void doSomething(List<String> things) {
    for (String thing : things) {
      System.out.println(thing);
    }
  }
}

Now, somewhere else, you decide to use Gadget as follows:

// Example 2
Gadget g = new Gadget();
g.doSomething(Arrays.asList("Red", "Green", "Blue"));

Cool, no problem. You can also do this:

// Example 3
List<String> stringList = Collections.emptyList();
g.doSomething(stringList);

It’s all good. But wait…that last snippet can be inlined, right? Sorry, but this will not compile:

// Example 4
// won't compile
g.doSomething(Collections.emptyList());

I think that after compiling the Gadget class, we lose some type information about List<String> things due to erasure. (although whenever I blog about generics or erasure, someone corrects my misguided theory in the comments…)

Fortunately, this syntax makes it work:

// Example 5
g.doSomething(Collections.<String>emptyList());

I think I encountered code like that a long time ago and then forgot about. Last week I wasn’t able to get something very similar to work, so I split my code into two separate lines as shown in Example 3. That worked, but I was not happy about it.

Then earlier this week I was helping a coworker, and I noticed he used the syntax shown in Example 5. I think my reaction was something like:

WTF is that?

Which led me to research the syntax in the JLS, which led me to the JLS documentation bug mentioned in my previous post.

Now I find myself wondering what other syntax I do not yet fully grasp?