2007-11-23

Newsmap

Newsmap is a really neat way to visualize news headlines available via the Google News RSS feeds.

AddThis Social Bookmark Button

2007-11-22

Configuring Mac OS X Terminal

I recently installed Leopard (Mac OSX 10.5) on a new mac. There are a few factory settings I usually change on a new installation, although by far fewer than I do typically with Windows. One of them is the default keyboard configuration for Ctrl+Left Arrow, Ctrl+Right Arrow, Page Up, Page Down, Home, and End in Terminal. The default settings drive me a bit potty since I'm used to using Linux and emacs every day at work.

Changing them is easy, fortunately. Just visit Keyboard under Settings in Terminal->Preferences, and modify the following keys, so that their action matches the value shown. You can edit the keystroke for an item by double clicking on it, selecting "send string to shell", and typing the indicated keys.

Key Action Keystrokes
control cursor left \033b ESC b
control cursor right \033f ESC f
end \005 CTRL+e
home \001 CTRL+a
page down \026 CTRL+v
page up \033v ESC v

AddThis Social Bookmark Button

2007-11-14

Detecting Concurrent Changes with the Decorator Pattern

Recently, our bug tracking system started receiving reports of a ConcurrentModificationException. The API in question was only ever supposed to be used on one thread, and yet a caller somewhere was making modifications on a background thread.

One thing that makes it tricky to diagnose this kind of problem is that a ConcurrentModificationException thrown during iteration only tells you that a concurrent modification was detected. But no information is present in the stack trace about where the rogue write actually happened. Wouldn't it be nice to have something like this?

java.util.ConcurrentModificationException
  at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
  ...
Caused by: java.lang.Throwable: List modified
  at ...
  at org.foo.SomeRogueCaller.writeOnTheWrongThread(SomeRogueCaller.java:30)

It's pretty easy to do this using the decorator pattern. The basic idea is to write a decorator for java.util.List that records a stack trace when modifications are made to the list, and sets the trace of the last modification as the cause of any ConcurrentModificationException thrown while iterating.

I used the Google Collections Library as part of my implementation, primarily because its ForwardingList, ForwardingListIterator and ForwardingIterator base classes make it really easy to decorate the respective collections classes.

So the basic idea is to write a decorator that can audit writes. I created a subclass of ForwardingList that stores a Throwable representing the last modification. The audit method will be used to record modifications, and the setLastModificationAsCause method is used to initialize the cause of a ConcurrentModificationException to the last modification (if any).

final class AuditedWriteList<E> extends ForwardingList<E> {
  private Throwable lastModification;

  protected AuditedWriteList(List<E> delegate) {
    super(delegate);
  }

  private void audit() {
    synchronized (this) {
      lastModification = new Throwable( "List modified" );
    }
  }

  private void setLastModificationAsCause( Throwable t ) {
    synchronized (this) {
      if ( lastModification != null ) t.initCause( lastModification );
    }
  }

  // ...
}

Now, we override all List methods that modify the list, and make them audit. For example, here's the implementation for add(E):

@Override
public boolean add( E object ) {
  audit();
  return super.add( object );
}

Finally, we implement the iterator() and listIterator() methods to return a decorator Iterator and ListIterator respectively that catches a ConcurrentModificationException and calls the setLastModificationAndCause method:


@Override
public Iterator<E> iterator() {
  return new AuditingIterator<E>( super.iterator() );
}

// Inner class
private final class AuditingIterator<T> extends ForwardingIterator<T> {
  protected AuditingIterator(Iterator<T> delegate) {
    super( delegate );
  }
  
  @Override
  public T next() {
    try {
      return super.next(); 
    } catch ( ConcurrentModificationException e ) {
      setLastModificationAsCause(e);
      throw e;
    }
  }
}

Now, if we do something like this:

List<String> list = newAuditedWriteList( Lists.newArrayList( "One", "Two", "Three" ) );
for ( Iterator<String> i = list.iterator(); i.hasNext(); ) {
  i.next();
  list.add( "Four" );
}

We get a helpful stack trace telling us exactly where the modification took place. The beauty of the decorator approach is that the only change we made to our client code was to wrap the creation of our list with the call to newAuditedWriteList. Since this diagnostic is likely to be slow when there are a lot of writes, it could be conditionally turned on in debug environments.

The full source code is available in the dubh-examples google code module.

AddThis Social Bookmark Button

2007-09-03

San Francisco Walk: Bay Bridge to Golden Gate

I've really started to enjoy walking since I moved to San Francisco. A fun, but somewhat exhausting, walk I've done before was from the Bay Bridge to the Golden Gate Bridge. On Saturday, I wandered along the Embarcadero just to get coffee at the Ferry Terminal, but since it was a nice day, just kind of kept on going. Five and a half hours later, I arrived back home with slightly sore feet...

Since I like to engage geek foo with such things, I plotted out the route of this walk (in blue; the red line is another long walk I took last year) on Google Maps:

All in all, it was a great walk. Had some really nice euphoric moments. My iPod was playing uplifting songs, the sun was setting over the Golden Gate Bridge, and it felt pretty good to be living here...

AddThis Social Bookmark Button

2007-08-25

Java Blooper #2 Solution: Must be a Better Way

Sorry for the delay in this week's blooper solution. On Monday we saw this code:

boolean hasThing( List things, Thing thing ) {
  for ( int i=0; i < things.size(); i++ ) {
    if ( thing.equals( things.get( i ) ) ) {
      return true;
    }
  }
  return false;
}

Can we simplify this? Sure. It pays to know the class libraries well, and the collections framework in Java in particular:

boolean hasThing( Collection things, Thing thing ) {
  return things.contains( thing );
}

As well as being more compact, this idiom is safer if the collection is a synchronized wrapper (as pointed out by reader alex in the comments). We were also able to specify the things parameter as a Collection rather than a List, following item 34 in EJ ("Refer to objects by their interfaces"), since we no longer need the ability to iterate items in the collection by index, which may well have been inefficient depending on whatever implementation of list was passed to us.

Blog readers jeff and Mike Kaufman also pointed out that this code doesn't check parameters for validity. Specifically, if this is a public method, it should check if the two parameters are null, or document the behavior when they are null in its javadoc.

Indeed, the whole method itself is very likely to be unnecessary in this particular example. But only because I super-simplified the original code, which of course contained some side effects. Joy :)

Back on Monday with another blooper...

AddThis Social Bookmark Button

2007-08-20

Java Blooper #2: Must be a Better Way...

It's Monday, which means it's time for another blooper... What's wrong with this code?

boolean hasThing( List things, Thing thing ) {
  for ( int i=0; i < things.size(); i++ ) {
    if ( thing.equals( things.get( i ) ) ) {
      return true;
    }
  }
  return false;
}
Update: Minor edit to add missing parenthesis from if statement that got "lost in translation" en-route to the blog :)

AddThis Social Bookmark Button

2007-08-17

Java Blooper #1 Solution: Ternary Insanity

class Thing {
  private boolean _visible;

  boolean isVisible() {
    return _visible ? true : false;
  }
}

This code is unnecessarily using the ternary conditional operator when it's not needed.

Occasionally developers get so captivated by the expressiveness of this operator that they find it tempting to use it when it's not really needed. In this particular example, it almost looks like the original writer forgot that the type of the _visible field was boolean anyway and could just be returned directly:

class Thing {
  private boolean _visible;

  boolean isVisible() {
    return _visible;
  }
}

AddThis Social Bookmark Button

2007-08-14

The Ups and Downs

Great news first thing this morning... I'm now a permanent resident of the United States! The whole process was a lot less painful than I'd expected. It was a terribly exciting start to the day.

In other news, I lost $1,000 in my portfolio today as the market continues to plummet. Ouch. My finger is twitching over the sell button ;)

AddThis Social Bookmark Button

2007-08-12

Java Blooper #1: Ternary Insanity

From time to time, we all write code that could be clearer. Sometimes in the rush of solving a problem, we don't pay attention to the micro details of the code flowing from our fingertips. Other times, we refactor some existing code, and don't necessarily take the opportunity to clean up as much as we could.

I find it useful sometimes when reading code to think about whether it could be rewritten in a more straightforward way, and if so whether any lessons can be learned about writing tight and expressive, and most importantly, readable code.

Over the next few weeks, I'm going to blog weekly examples of some Java code bloopers that I've seen. All the examples are real and have been observed "in the wild". However some have been simplified somewhat to make a point. I'll post each blooper on a Monday, and follow up with a rewritten version the following Friday.

Most of the examples are pretty simple, and easily cleaned up - feel free to post observations as comments to the entries, and don't be shy to smack me down on the solutions if there's a better way to express the same thing.

The first installment is called Ternary Insanity.

class Thing {
  private boolean _visible;

  boolean isVisible() {
    return _visible ? true : false;
  }
}

AddThis Social Bookmark Button

2007-07-25

More on email inbox bliss

So far my attempt to maintain an empty inbox is working out pretty well.

One of the most effective things that worked was to get rid of folders. Previously, I was a folder freak: my email was "organized" into a bewildering, ever changing, hierarchy of folders. Rather than making it easier to find stuff, it was actually much harder. Before I could find something quickly, I had to try to figure out which folder I had decided to put it into.

I draw a comparison between this and usage of, say, Google Search vs. a directory service like dmoz. Directory services categorize the web into a wonderful hierarchy. But in practice, it's almost always more effective to just search the conceptual single folder containing the whole web via google search.

I now have a small number of folders. Apart from the inbox, trash, and sent folder, the remaining folders can be categorized as:

  • A single @Respond folder. Messages that I need to respond to, but can't do so immediately because they require some investigation go here. I treat this like a todo list, and review it several times a day.
  • A single Archive folder. Anything that I don't need to keep track of actively, but might be interesting for future reference goes here. This is where the vast majority of email that I don't delete ends up.
  • Important short term projects for which it's convenient to collocate all the messages. I currently have a single folder that falls into this category, for tracking correspondence related to my green card application. Although I have several other important short term projects, none of them really need a separate folders.
  • High-volume, low value mailing lists auto filters. For instance, I have a folder called Bugs into which gets automatically filtered all notification emails from our bug database system. I rarely have to act immediately on such emails, but it's useful to review them once or twice a day. I usually mass delete the contents of these folders on a daily basis, since they're basically copies of information available elsewhere.

As a result of this, I now have roughly 5 folders (not including inbox, trash and sent). This works well for me. It speeds up the rate at which I can process incoming email, since there are fewer choices about which action to take for each incoming message.

Merlin Mann's 43 Folders site talks about this a lot. His recent tech talk on Inbox Zero summarizes a lot of the useful content related to email management posted on the site.

AddThis Social Bookmark Button

2007-07-20

Google Code Project Hosting Gets Upgrades

The folks over at Google Code have been doing some sterling work in the last few weeks fixing various issues with its project hosting support. Here are some of my favorite fixes:

Issue 250: Issue summaries are unnecessary abbreviated. In the issue list, the summaries would be truncated arbitrarily. This was pesky on a large display, since there was plenty of space to see the whole summary.

Issue 138: projectname.googlecode.com should redirect to project page. So now you can go to jd-ant.googlecode.com as well as code.google.com/p/jd-ant.

Issue 306: IssueTracker: Provide a means of displaying more than 25 issues at a time. Now you see 100 issues at a time, which makes for less paging about in large issue lists.

Glad to see these improvements. Google's project hosting is straightforward, fast, and very useful.

AddThis Social Bookmark Button

2007-07-06

Asserting Control over the INBOX

Sometimes I'm a bit disorganized. Last week, after purging my INBOX of some 15,000 messages (discovering quite a few that I had read but not replied to in the process), I decided that it's finally time to assert control over my INBOX.

It's not the first time I've tried this. The lofty goal of maintaining an empty INBOX is very appealing in theory, but it's easy to get lazy. Before you know it, you end up with thousands of disorganized messages again.

The first step in this was turning down my "autocheck" frequency. I think a big part of the reason that I'm a bit disorganized is that email messages arrive in a constant stream throughout my day, and so I'm always processing them while doing other tasks.

My approach now is to set aside 5-10 minute periods every hour or so specifically for triaging email. Any email I can respond to, or action, within that period, I do so immediately. Anything else, I add to my TODO list on the excellent Remember the Milk service, and then archive the message to a folder.

The second part of this is making it easy (and I mean really easy) to archive messages. For any message I read in my INBOX, I must do one of the following immediately:

  • Delete it if it's spam, or automated email that I don't care about
  • Reply to it if it can be actioned within the 5-10 minute email period, then archive it to a folder or delete it.
  • Add a TODO item, then archive it to a folder.

I've pared down my list of folders to a minimum (3 main folders, with some extras for server side filtered automated email) so that it's easier to figure out the destination for any given message. Thunderbird makes it really easy to search for messages within a folder, so I realized that having a gazillion hierarchical folders was actually making it harder to find old messages.

To make it really easy to quickly move messages into a folder, I'm using the excellent keyconfig extension for Thunderbird to map a single keystroke to moving messages to a folder. For example, I can now hit Ctrl+J on a message to immediately move it to my "JDeveloper" folder. I can't overstate how useful this is. It's probably the single most effective thing I've done to make it easier to control my INBOX.

AddThis Social Bookmark Button

2007-06-10

Scary Statues

It may have something to do with that odd tradition they have in the USA of completely shutting down all decent television programs for a block of about four months in the summer and the result that my DVR is being seriously under-used at the moment, but I'm really getting into the latest series of the new Doctor Who.

I've been an unabashed fan boy of Doctor Who since I was small enough to effectively hide behind our rather brown, early-eighties sofa in Edinburgh watching Tom Baker, Peter Davison, Colin Baker and Sylvester McCoy do their turns as the Gallifreyan time lord. I'm pretty sure it was the seed of my life long addiction to science fiction books and so-called telefantasy TV shows.

When the series came back a few years ago, I was desperately excited. That excitement carried me through most of the first two series. Even though to be frank, some of the storylines and episodes were pretty poor, with the odd gem here and there (Dalek, Father's Day, The Empty Child, The Parting of the Ways, New Earth, School Reunion, The Girl in the Fireplace, and Love & Monsters).

I don't know what changed in the third series. Certainly, the Doctor has a new companion in the form of Martha Jones (played with wonderful enthusiasm by Freema Agyeman). But the episodes in series three seem to be consistently better than the previous two series. The episodes have that creeping, mysterious fun and fear in exactly the combination that was common in the golden days of the old Doctor Who.

Take this week's Blink for instance. Statues. Terrifying, monstrous, looming, weeping angel statues that "kill" people by sending them back in time.

In common with one of my other favorite episodes with the new Doctor, Love & Monsters, this episode doesn't actually feature the Doctor and his companion much at all (they're stuck in 1969, having been transported there by the statues while the TARDIS remains in the present day). Thanks in great part to the fine acting of guest actress Carey Mulligan as Sally Sparrow, the episode remains riveting (not to mention sofa-hidingly scary. I actually yelled out in fear at one point, which isn't something I'm taken to do on a regular basis).

And last week we had seriously spooky scarecrows... This new series just keeps getting better :)

AddThis Social Bookmark Button

2007-06-04

Test From Adobe Contribute

Just a little test entry. I just took the plunge and upgraded my Macromedia Studio 8 to Adobe Creative Suite 3, so I'm testing out Adobe Contribute (which was completely dysfunctional in its previous incarnation with blogger).

Seems pretty nice so far. Rather scarily, I'm sort of editing this blog entry in-place (or at least, that's the intent of the UI illusion it creates). Quite nifty.

Notice that there's no spell checking though, which is definitely a step down from regular blog posting via an HTML form with Firefox. Boo.

AddThis Social Bookmark Button

2007-05-25

Messing about with blogger

Was messing about with the blogger template a little. The banner at the top now shows my wee multi display setup in the office based on this original image:

I think it's a bit over-cropped... will probably tweak it some more when I'm bored :)

AddThis Social Bookmark Button

2007-05-18

Google Reader tracks funky hours...

Ah... the trends feature in Google Reader continues to remind me that I really must try harder to live in the times of day that most people regard as "normal":

AddThis Social Bookmark Button

2007-05-15

Never underestimate the power of pictures

Suppose I whimsically decided to call my next little project something like "itikka". If you're the curious sort, you might wonder where that name comes from, and punch it into google to see what gives. Go on... give it a try... I'll wait until you come back...

With a bit of diligence (mainly clicking a few of those result links), you might have figured it out. OK.. try it again, but this time use Google Image Search. Instantly, you see: lots of pictures of insects (bugs). My next project might be a bug database or a bug finding tool, or something of that ilk. It may or may not be translated into Finish though ;)

Pictures are powerful.

P.s. I claim dibs on using this name for an application that involves bugs in any way. Even one that has some...

AddThis Social Bookmark Button

2007-05-10

It's only polite to turn up for your BOF...

Just taking 5 minutes from wandering around at the JavaOne conference. Pulled myself out of the (very cool) battle bot arena in the afterdark party to go see Fabiano Cruz and Marcelo Mayworm talk about creating an OSGi based framework for Swing applications (BOF-3487). I was particularly interested in this BOF, because we've been thinking about OSGi in my group at work, and we're developing a very large and modular Swing application.

Unfortunately, the speakers didn't turn up. Barring major catastrophe, that's just terribly rude. Speakers get a full free pass for the conference, and the least they can do in return is actually show up for their own sessions. Tsk ;) Needless to say, that was the only session evaluation I've filled out so far that's had many marks to the right of the center divide...

More blogging on the conference to come... (I know... I've been remiss in blogging while here. I always forget how hectic things are. But I've got a bunch of stuff "buffered up"). Planning to grab a bite to eat and then go see my good friends (and collegues) Alex Ruiz and Yvonne Price talk about their cool testing framework, FEST at BOF-3478.

Update: Turns out this was an administrative error at JavaOne. The session had been canceled by the speakers, but the conference organizers forgot to remove it from the schedule. Ah well... all is forgiven ;)

AddThis Social Bookmark Button

2007-05-09

How pants relate to nine year old code

Rediscovered a heap of Java code I wrote 9 years ago the other day. Good grief - the passage of time is really apparent when you go surfing through code you haven't seen for such a long time...

One of the little things I found distracting while surfing through the code was due to a language other than Java... I see that back then, I was still spelling in British English - dialogue instead of dialog, initialise instead of initialize. For example: AgentConfigDialogue.java .

British English spellings for many words look strangely wrong to me now when I see them. I got into the habit of spelling things the American way years before I came to live here, mainly because the coding I do at work requires me to use American English.

I suppose my roots are still there, since I do still seem to trip up people in the USA with occasional random Britishness (like saying I'll meet someone at "half two"). And I never probably will get comfortable with the "restroom" or the "washroom". Or with "pants" for that matter :)

This is a "pre-recorded" blog entry. More JavaOne stuff soon...

AddThis Social Bookmark Button

2007-05-07

Why Subversion is better than CVS for Java developers

Over on the JDeveloper forum, John Stegeman responds to a question about whether CVS or Subversion is better for Java development:

... "Subversion," especially if you are using ADF business components. My reason for saying this is that we initially tried CVS [in an environment where] the network was not the most reliable. We had some problems where the network would drop in the middle of the commit (not a JDev/CVS problem), and half of the changes would be committed to the repository, and half of them were not. In the case of the Business Components, having the XML files and Java source files out of synch was a major major problem. This particular problem is one that Subversion solves; with Subversion, either the whole commit happens or none of it happens, just like a good database.

He makes a very good point. Atomic commits are one serious advantage Subversion has over CVS. In Java applications, where you tend to have a lot of files (as opposed to C where a lot of logic is concentrated into a smaller number of source files), it's vitally important that all of your changes are submitted along with each other.

Another big advantage of Subversion compared to CVS is directory versioning. In Subversion, directories have versions, just like files. The history of a directory is tracked over time. In the Java world, we like to move stuff around a lot (let's refer to it as "refactoring", although that word has additional implications). It's nice to use a version control system that does a good job of handling complex move operations over time without resetting element history.

AddThis Social Bookmark Button

2007-05-06

JavaOne 2007: This year's Bag-o-Stuff

Went down to Moscone today to register for the conference. Blimey, it's hot! Anyway, here are the contents of this year's backpack:

You can already start playing "spot the Java geek" on the streets of San Francisco :)

I like the fold-out conference schedule. Not sure if they had that last year and I just missed it, but it sure will come in handy. I've not been able to figure out what the mysterious white rubbery "holdzalot" thing from SAP is for... Apparently, you should move it frequently when it's on natural wood surfaces. I'll remember to do that. If I ever figure out what it is.

More (unexciting) photos in my JavaOne 2007 Album...

AddThis Social Bookmark Button

2007-05-05

San Francisco Prepares for JavaOne 2007

For the first time ever, I'm planning to make like a tourist and actually use my camera this year at JavaOne... Was wandering around town today in search of a decent coffee and I happened to pass by the Moscone center, so I took a few of pictures of the JavaOne signage at the Moscone Center. Quiet before the storm... :)

My JavaOne 2007 Album on Picasa has more. You can even subscribe to the RSS feed...

AddThis Social Bookmark Button

2007-05-03

Sessions for JavaOne

The last few months at work have been packed. We've been working to get a preview release of the next version of JDeveloper out to customers in time for JavaOne. Since we're planning to cut the final build within the next few days, some of the pressure will be off next week, and I can hopefully enjoy a few interesting technical sessions and BOFs at the conference.

I was fortunate enough to have the opportunity to speak at the conference for three years in a row, but it's a bit of a relief not to be speaking at JavaOne this year. Speaking at the conference is great fun, and I hope to do it again in the future. But this year, it will be nice just to be an attendee for a change and not be stressing out about speaking the whole time...

Here's the list I've signed up for so far - certainly won't make all of them, but I'll do my very best ;)

Tuesday

TS-1742 - Cool Things You Can Do with the Groovy Dynamic Language
TS-3942 - JSR 269: The Swing Application Framework
TS-2294 - Closures for the Java Programming Language
TS-2800 - OpenJDK Project Report
BOF-2400 - Modularity in the Next-Generation Java Platform, Standard Edition (Java SE): JSR 227 and JSR 294
BOF-3349 - Advanced Swing Drag-and-Drop

Wednesday

TS-9555 - Quick and Easy Profiling with Integrated Tools
TS-2689 - Effective Java Reloaded: This Time It's for Real
TS-6475 - Fast, Beautiful, Easy: Pick Three -- Building Web User Interfaces in the Java Programming Language with Google Web Toolkit
TS-3548 - Extreme GUI Makeover 2007
TS-2388 - Effective Concurrency for the Java Platform
BOF-9587 - Pimp My Java Application: Applying Static Analysis Tools to Boost Java Code Quality
BOF-3603 - Build Real-World Applications by Usnig Swing and JIDE

Thursday

TS-2401 - Java Language Modularity with Superpackages
TS-1419 - Best OSGi Practices
TS-3316 - Why Spaghetti Is Not Tasty: Architecting Full-Scale Swing Apps
TS-2318 - JSR 277: Java Module System
TS-6889 - Java Technology-Powered Microsoft Ajax
BOF-3487 - @Plugin World: Creating Your Own Lightweight OSGi-Based Framework for Building and Managing Pluggable Swing Applicatinos
BOF-3478 - Easy Test-Driven GUI Development

Friday

TS-3414 - Bringing Life to Swing Desktop Applications
TS-3631 - Writing Testable Desktop UIs
TS-3165 - Filthy-Rich Clients: Talk Dirty to Me
TS-3833 - Debugging and Optimizing Swing Applications

AddThis Social Bookmark Button

2007-05-02

Google Code Prettify

Up till now, I've been using Java2HTML to generate syntax highlighted Java code snippets for my blog. It's useful, but a little cumbersome to have to use a separate application and trim the HTML it generates for each snippet. The HTML it generates is also unavoidably gnarly, which makes tweaking the code after it has been published tedious.

google-code-prettify solves this problem in a neat way - syntax highlighting is performed on the code using JavaScript in the browser. It seems to work pretty well:

/**
 * Hi!
 */
final class HelloWorld {
  // The usual boring example
  public static void main( String[] args ) {
    System.out.println( "Hello Prettified World!" );
  }
}

AddThis Social Bookmark Button

2007-04-30

Continuous notification for continuous integration

Someone on my team implemented a very useful little gadget that helps everyone keep an eye on our continuous integration build:

Very useful - though I wish our team wouldn't cause the balloon to appear quite so often... <cough>.

Pretty impressively, it was implemented using Java 1.6 - I knew that support had been added in 1.6 for tray icons, but this is the first time I've actually seen an application put it to use in a way that I find personally helpful :)

AddThis Social Bookmark Button

2007-04-22

Tesco - They're Coming...

Heh... Tesco. They're nothing if not tenacious.

Many moons ago, while still at secondary school, I worked as a checkout operator (beep... beep... beep...) for a Scottish grocery chain called William Lows. Tesco bought Lows in 1994 for the princely sum of 257 million pounds. Since I worked in the "flagship" Edinburgh store, the transformation from one retailer to another was tremendously visible. From then until I hopped over the pond exactly ten years later, Tesco was a permanent (if somewhat mundane) fixture of my life.

The "Tesco Value" store brand (with its trademark white & blue striped labels) will always remind me of my student days in St. Andrews. One student I knew had literally plastered an entire wall of his room with Tesco Value Baked Bean labels. Very artistic, to be sure, but it scares me to think about the sheer amount of methane production that resulted from such conspicuous bean consumption...

Jumping forward, it only seems like yesterday I was popping into the Tesco Camberley store on my way home from work every couple of days to stock up on beer, bread, fruit and awesome prepared meals, the like of which I feared I'd never see again.

The Camberley store was enormous. You could buy all manner of random stuff there, including consumer electronics, stationery, clothing, plants, and, food. Extreme amounts of wonderfully varied food. Not long before I left the UK, they were installing self-service checkouts and modernizing to the chip-and-pin debit / credit card system. The bigger Tesco stores, in general, are well lit, technologically whizzy (there are LCD screens in most of the aisles, wasted on advertising), and carefully laid out to make you buy lots of stuff you don't actually need.

Anyway, every time I go to the (somewhat drab and depressing) Safeway store in San Francisco, I miss Tesco a little bit. So it was pretty cool to hear that Tesco are coming to the USA, the news of which provoked a flurry of excitement over on the BritishExpats.com USA forum when it was announced a year ago.

It looks like they're ramping up on the plans too, with the news that they plan to build a supply center with the worlds biggest solar roof in Riverside CA. It looks like even Warren Buffet thinks they're going to be successful.

One observation about supermarkets Stateside. It seems like the market is far less competitive compared to the UK. In the last ten years or so, the UK had enormous ongoing price wars between the major supermarket chains (Tesco, Asda [owned by Walmart], Sainsburys, and Morrisons [who took over the remaining Safeway stores in the UK]). It will be interesting to see if Tesco can succeed in the USA where others (notably Sainsburys) have failed, and maybe in the process spice things up a little bit.

AddThis Social Bookmark Button

2007-04-21

Preferential treatment? - netbeans

Well well... Bug 6182905 was open for 2.5 years, but now it's a NetBeans P1 issue (ala bug 6511815), and whoa... it suddenly got fixed. All Java applications are created equal, just some moreso than others.

Personally, I'm just glad it got fixed at all... This one often crops up as one of our "random but frequent exceptions from Java core libraries".

[This post is somewhat tongue in cheek in case you're wondering... Though I'm just a wee bit grumpy about the fact that apparently there's "almost no chance" bug 6510914 will ever get fixed... roll on open source java ;) ]

AddThis Social Bookmark Button

2007-03-05

Beware the hashcode!

(With thanks to my colleague Armand "jojo" Dijamco)

What does this code print?

Map map = new HashMap();
    
Collection things = new HashSet();
things.addmap );
System.out.printlnthings.containsmap ) );
    
map.put"foo""bar" );
System.out.printlnthings.containsmap ) );

Be wary of storing mutable objects in a HashSet, or using them as keys in a HashMap. An implementation side effect of using a collection that relies on hash codes is that making changes to the object in a way that alters its hash code will cause it to no longer be considered the same object. There's no way (short of removing and re-adding the item from the collection) to inform a collection that a mutable object needs to be re-hashed.

Item 13 in Josh Bloch's Effective Java tells us to "Favor Immutability". He also tells us in item 8 to "Always override hashCode when you override equals". A corollary is that you should not use mutable objects as keys in HashMaps or values in HashSets. If such objects correctly implement hashCode, they're not reliable in hashcode-based collections.

AddThis Social Bookmark Button

2007-03-03

Unit testing Swing components - impossible?

Testing Swing components seems to fill many developers with fear. "How can I unit test this thing?" they often ask, "it's full of icky event handling code and troublesome painting...".

Frameworks such as Abbot are often the solution developers find for this problem. Essentially, many developers abandon the idea of writing regular unit tests for Swing components, and resort to "click simulators" which are frequently functional tests rather than unit tests.

There is a lot you can do just to test regular Swing components using bog-standard JUnit (or Test-NG) tests. Consider the following fairly basic Swing component.

package org.dubh.blog;

import java.awt.Graphics;

import java.awt.event.MouseAdapter;

import java.awt.event.MouseEvent;

import java.util.List;

import java.util.concurrent.CopyOnWriteArrayList;

import javax.swing.JComponent;

/**
 * A user interface widget.
 */
public final class Widget extends JComponent {
  
  private List<WidgetListener> _listeners = 
    new CopyOnWriteArrayList<WidgetListener>();
  private String _label = "";
  
  public Widget() {
    // Just for demonstration purposes.
    addMouseListenernew MouseAdapter() {
      public void mouseClickedMouseEvent e ) {
        if e.getButton() != MouseEvent.BUTTON1 return;
        fireWidgetClicked();
      }
    });
  }
  
  /**
   * Adds a listener. 
   
   @param wl listener to add. Must not be null.
   * @category Event handling
   */
  public void addWidgetListenerWidgetListener wl ) {
    if wl == null throw new NullPointerException"wl is null" );
    
    _listeners.addwl );
  }
  
  /**
   * Removes a listener.
   
   @param wl listener to remove.
   * @category Event handling
   */
  public void removeWidgetListenerWidgetListener wl ) {
    _listeners.removewl );
  }
  
  /**
   * Notifies listeners that the widget was clicked.
   
   * @category Event handling
   */
  protected void fireWidgetClicked() {
    if _listeners.isEmpty() ) return;
    
    WidgetEvent event = new WidgetEventthis );
    for WidgetListener l : _listeners ) {
      l.widgetClickedevent );
    }
  }
  
  /**
   * Sets the label of the widget.
   
   @param label a widget label. Null is allowed, will be 
   *    converted to the empty string.
   */
  public void setLabelString label ) {
    if label == null label = "";
    if label.equals_label ) ) return;
    
    String oldLabel = _label;
    _label = label;
    repaint();
    firePropertyChange"label", oldLabel, label );
  }
  
  /**
   * Returns the label of the widget. 
   
   @return the label of the widget. Never returns null.
   */
  public String getLabel() {
    return _label;
  }
  
  @Override
  public void paintComponent(Graphics g) {
    g.drawString_label, 0, getHeight() );
  }
}

We can start off with the really simple stuff. Let's at least test that we can make new instances of Widget.

  public void testConstructor() {
    new Widget();
  }

Seems pretty dumb? Well... that constructor contains code, so maybe it could throw an exception. It'd be good to catch this when running our tests rather than when the code is out running in production. If you can do nothing else, at least constructing a class in a test is better than no test at all. But wait! There's a lot more we can do here. What about testing the pretty boring setLabel() / getLabel() set?

  public void testGetAndSetLabel() {
    Widget widget = new Widget();
    // Test the initial state.
    assertEquals"", widget.getLabel() );
    // Test setting and getting.
    widget.setLabel"Hello!" );
    assertEquals"Hello!", widget.getLabel() );
    // Test edge case ( null label )
    widget.setLabelnull );
    assertEquals"", widget.getLabel() );
  }

OK.. this is a bit more meaty. We're testing some real assertions here. Now for the "hard" stuff. How can we test events? Well... Ignore the fact that these are events for now, and just look at the code for what it is. The management of listeners and the sending of events doesn't actually require AWT in most Swing components. Even if it did, we're not testing AWT here, we're testing Widget.

Let's use a common technique for testing listeners - introduce an inner class that provides a stub listener which simply tracks the events it receives:

  private class WidgetListenerStub implements WidgetListener {
    List<WidgetEvent> receivedEvents = new ArrayList<WidgetEvent>();

    public void widgetClicked(WidgetEvent e) {
      receivedEvents.add);
    }
  }

Now testing that we can add and remove widget listeners and receive events is easy:

  public void testWidgetListeners() {
    Widget widget = new Widget();
    
    // Test firing when there are no listeners.
    widget.fireWidgetClicked();
    
    WidgetListenerStub l = new WidgetListenerStub();
    widget.addWidgetListener);
    
    widget.fireWidgetClicked();
    assertEquals1, l.receivedEvents.size() );
    assertSamewidget, l.receivedEvents.get).getSource() );
    
    widget.removeWidgetListener);
    widget.fireWidgetClicked();
    assertEquals1, l.receivedEvents.size() );
  }

OK... what hasn't been tested yet? Well, we probably want to test multiple listeners and property change event notifications. Those are a pretty easy extrapolation from the example above.

One thing we haven't tested yet is that actually clicking in the widget with the mouse causes WidgetEvents to be fired. To do this, we don't have to actually test that a low level operating system mouse click event will cause our event to be fired. In other words, again, we're not testing AWT. We trust that Sun did a good job testing AWT already. No Robots required. Let's focus on events just at the level of our component, using a bit of reflection magic:

  public void testMouseClickTriggersEvent() throws Exception {
    Widget widget = new Widget();
    WidgetListenerStub stub = new WidgetListenerStub();
    widget.addWidgetListenerstub );
    
    // Simulate a mouse click using reflection.
    MouseEvent event = new MouseEventwidget, MouseEvent.MOUSE_CLICKED, 0
      MouseEvent.BUTTON1_MASK, 10101false );
    Method process = Component.class.getDeclaredMethod
      "processEvent", AWTEvent.class );
    process.setAccessibletrue );
    process.invokewidget, event );
    
    assertEquals1, stub.receivedEvents.size() );
    
  }

We're sending a mouse event directly to our widget component, and verifying that it causes the Widget to fire a WidgetEvent as expected. The really cool thing about this is that this does not require the component to be visible on screen, and it doesn't require native AWT event handling. Indeed, this test works perfectly fine even in headless mode (when the system property java.awt.headless=true, or you're running on a system with no graphics display).

One last thing we haven't tested: paintComponent(). This is arguably the toughest thing of all to test. Like the constructor example, it's at least a good idea to call this method in a test and make sure no exceptions occur. We can go a little bit further and actually test that paintComponent really painted something. More on that in my older blog entry, Unit Tesing: Coverage in Those Hard to Reach Places.

While frameworks like Abbot have their place, it's a lot easier to test Swing components with regular JUnit or Test-NG tests than you might think.

AddThis Social Bookmark Button

2007-03-02

What's up with the 2.0?

Well... If I was being more accurate, this would really be 4.0.

In the beginning, there was Brian Duff's Weblog over on Radio Userland (good grief, that wasn't even Web 1.0. You had to install a thick client application just to post. Yowzers), then I set up Orablogs, and moved over to there. Until fairly recently, I blogged (or rather, mostly didn't out of laziness) at blogs.oracle.com.

So why move now?

Well. I got a wee bit frustrated with the blog management software I was using - it had a troublesome tendency to mangle Java code in particular, which is something of a pain when you're trying to write a Java coding related blog. So far, I'm pretty happy with blogger.com's interface.

Another reason for the move is that I want to blog about more random stuff outside the world of Oracle. For instance, if I decide to play with Eclipse or JBoss (perish the thought), blogs.oracle.com doesn't really feel like the appropriate place. Even though my blog there tries not to be, like most corporate blogging sites, blogs.oracle.com suffers from the perception that the bloggers thereon are corporate marketing drones. OK, it's not just a perception - it might just about be true in some cases... .

A third reason is that I've owned this domain name (dubh.org) since about the time I finished university, and never did anything useful with it. Now, thanks to Rob, I'm totally in love with Google Apps and am using it to host all manner of fun stuff at the dubh.org domain. By the way, feel free to drop me an email at brian@dubh.org to say hi.... good grief... it's liberating being able to post mailto: links again safe in the knowledge that gmail's spam filters will deal with most of the crud ;).

Having a blog on my own domain also means that should I (perish the thought) ever move on to new pastures, I don't have to say adios to all of my blog content...

AddThis Social Bookmark Button

2007-03-01

Check parameters for validity... good advice!

I recently ran into a weird NullPointerException in part of our code:

Exception in thread "main" java.lang.NullPointerException
 at org.dubh.blog.Graph$Vertex.access$000(Graph.java:17)
 at org.dubh.blog.Graph.getVerticesConnectedTo(Graph.java:14)
 at org.dubh.blog.Graph.main(Graph.java:26)

Hmm... access$000? That's odd. The code looked something like this:

01 package org.dubh.blog;
02 
03 import java.util.ArrayList;
04 import java.util.HashMap;
05 import java.util.List;
06 
07 final class Graph
08 {
09   private HashMap _vertices = new HashMap();
10 
11   public List getVerticesConnectedToObject vertexKey )
12   {
13     Vertex vertex = (Vertex_vertices.getvertexKey );
14     return vertex.fromEdges;
15   }
16 
17   private final class Vertex
18   {
19     private final List fromEdges = new ArrayList();
20   }
21   
22   public static void mainString[] args )
23   {
24     Graph graph = new Graph();
25     graph.getVerticesConnectedTogetSomeVertex() );
26   }
27 }

Can you tell quickly from looking at these two pieces of information what the problem is?

It turns out that getSomeVertex() was returning null, and this was being passed in as the value of vertexKey. Unlike its older cousin, Hashtable, which would throw a NullPointerException if you tried to get null, HashMap.get( null ) returns null, so the vertex variable in getVerticesConnectedTo() was also null.

OK... so why did the NullPointerException happen on line 17 (which is the inner class declaration), instead of line 14, which is where we're actually dereferencing the null variable? Well, it's because the Java compiler creates a super-secret static method for accessing the fields of inner classes. With the geeky power of javap, you can see it being called in the bytecode:

public java.util.List getVerticesConnectedTo(java.lang.Object);
  Code:
   0:   aload_0
   1:   getfield        #4; //Field _vertices:Ljava/util/HashMap;
   4:   aload_1
   5:   invokevirtual   #5; //Method java/util/HashMap.get:(Ljava/lang/Object;)L
java/lang/Object;
   8:   checkcast       #6; //class org/dubh/blog/Graph$Vertex
   11:  astore_2
   12:  aload_2
   13:  invokestatic    #7; //Method org/dubh/blog/Graph$Vertex.access$000:(Lorg
/dubh/blog/Graph$Vertex;)Ljava/util/List;
   16:  areturn

If the generated method were written in Java it would look something like this:

private final class Vertex
{
  private final List fromEdges = new ArrayList();

  private static List access$000Vertex instance )
  {
    return instance.fromEdges;
  }
}

Now the reason for the NPE happening before vertex is dereferenced on line 14 is pretty obvious.

Two lessons from this:

1) Follow Josh Bloch's Advice in Effective Java - "Item 23: Check parameters for validity"

A simple null check in the getVerticesConnectedTo method would have produced a much more readable exception:

public List getVerticesConnectedToObject vertex )
{
  if vertex == null throw new NullPointerException"vertex is null" );
  ...
}

Yields:

Exception in thread "main" java.lang.NullPointerException: vertex is null
 at org.dubh.blog.Graph.getVerticesConnectedTo(Graph.java:13)
 at org.dubh.blog.Graph.main(Graph.java:27)

2) It's almost always better to access fields using method calls. Even in private inner classes.

It would have been better if the Vertex inner class above had provided an accessor method for the fromEdges field. If it had, the exception would have been clearer. A few people worry about the performance of method calls vs. field access. Remember that performance solutions aren't solutions until you can prove as much using a profiler, and that the point is somewhat moot in the above case, since there's effectively a static method call rather than a getfield in the generated bytecode anyway, canceling out the programmer's misguided attempt to save cycles and / or typing. Cough... the programmer in this case, of course, being me :)

AddThis Social Bookmark Button