Sunday, September 7, 2008

John McCain, Rogue Cop

Everybody loves the maverick cop who plays by his own rules - Dirty Harry, Axel Foley, Mel Gibson, so of course everyone loves The Maverick John McCain.  But don't you think there's a reason they never get to be Chief of Police????

Tuesday, July 15, 2008

Holy Bastard Offspring of John Lennon and Bryan Ferry!

Brian Eno singing "Tomorrow Never Knows": 801 Live.

As an added bonus, though I haven't yet heard it: June 1, 1974

Monday, July 14, 2008

What's up Eclipse?

How come a long-running build won't automatically cancel when I hit save? Why does it block the entire app instead?

Saturday, July 12, 2008

Wednesday, July 9, 2008

Don't Use java.io.File!

One of my biggest gripes with Sun's Java libraries is their I/O implementation, particularly the class java.io.File. Even worse is its ubiquity in the method signatures of third-party libraries. Why? I'll explain.

Consider an interface that gives you the method public void upload(java.io.File file), which is supposed to upload a file to a server. Now suppose you want, instead, to upload some data you created programmatically, or that exists at a remote URL. Oh no! Now you have to download that data to a file on your local file system, and upload THAT file. Ouch!

Believe it or not, people charge actual money for systems with APIs that work this way.

This illustrates the real weakness behind using java.io.File in a public API - File is a concrete class that is directly tied to the native file system. You can't mock it for unit testing, you can't substitute a URL. You're stuck.

What to use instead? Well, URLs/URIs are an obvious choice, and work well. I would recommend actually using java.net.URL instead of String in method signatures, so that the signature explicity indicates what kind of data it wants. This also means your code won't have to handle or throw MalformedURLException. Finally, always handling URLs as java.net.URL prevents chains of casting back and forth between String and URL, which often happens when using 2 or more APIs together that aren't consistent in their use of URLs vs. Strings.

When you're working with internal APIs and you need an actual file object, I'd recommend using Apache commons-vfs instead of java.io. As the web site says, "Commons VFS provides a single API for accessing various different file systems. It presents a uniform view of the files from various different sources, such as the files on local disk, on an HTTP server, or inside a Zip archive." For unit testing, the RAM disk implementation is very useful, allowing you to mock output files when necessary.

Wednesday, July 2, 2008

Easy Layouts in SWT?

I'm trying out a layout engine for Swing and SWT called MiGLayout. Their claim for it is "MiG Layout makes complex layouts easy and normal layouts one-liners." We'll see. So far it seems pretty good. Here's a snippet of (SWT) code I've written:

Label label = new Label(panel, SWT.NONE);
label.setText("Test Name:");
label.setLayoutData(new CC().growX(0));
final Text text = new Text(panel, SWT.BORDER);
text.setLayoutData(new CC().spanX(2).growX());
Button button = new Button(panel, SWT.PUSH);
button.setText("Load");
Button runButton = new Button(panel, SWT.PUSH);
runButton.setText("Run");
runButton.setLayoutData(new CC().wrap());
browser = new Browser(panel, SWT.MOZILLA | SWT.BORDER);
browser.setLayoutData(new CC().spanX().growX().growY());


This gives you something that looks like this:

And the label, textbox, and buttons on the top row grow/shrink as they should. Nice. Definitely worth exploring further.

Friday, May 16, 2008

Making java.exe Use a JDK on Windows

So let's say you're running an application, such as Sonar, that invokes java.exe directly and doesn't allow you to configure your java path (as far as I can tell, anyway). Now let's say you want to run in -server mode. You try it, but what pops up?
Error: no `server' JVM at `C:\Program Files\Java\jre1.6.0_06_\bin\server\jvm.dll'.
Oops. That's because you're running in a JRE, which doesn't include a server JVM. So you think, "Ok, well, I'll just fix my PATH variable to point at my JDK." Maybe you even try setting JAVA_HOME. But none of it works. Why not?

It doesn't work because Java is launched differently these days. If you look in \WINDOWS\System32, you'll notice that java.exe and javaw.exe are in there. When you launch java.exe, the copy that gets run is the one in System32.

If you look at the Properties of the java.exe file in System32, you'll notice it's tagged with the version of the JRE it came from. When you launch it, then, it looks in the registry for a compatible JRE, and gets resources from that JRE. The relevant registry key is HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment.

You'll notice if you fire up regedit and look at the above key that this key defines the value "JavaHome". Ah, wow, so now Java actually records different JAVA_HOME values for each version of the JRE. Now look at the value of JavaHome. You'll notice it points to your stand-alone JRE, not the JDK's JRE. So the solution is just to change the value to point at <JDK home>/jre.

Simple, eh? Now why isn't this documented anywhere?