Just Write a Program or a Real Parser, Damn It.

Paul Brown @ 2005-05-10T10:17:50Z

I have come to loathe .properties and .xml configuration files. (The use of them together is just inexcusable.) People tend to grab a properties or XML file when they need to parse something, and something is usually a configuration file of some stripe. This is convenient, as it happens that parsers for properties and XML files are readily available and built into Java, but both flunk on some aspects of usability:

  • A configuration should be verifiable outside of the runtime container. I am deeply frustrated by compiling an application, building artifacts, and deploying those artifacts only to find out that a property was misnamed, a configuration file was not in the correct location, or a combination or parameters is unsupported.
  • A configuration should be relatively easy to write. "Easy" in this context doesn't mean pretty colors and auto-completion, but it does mean that the configuration scheme should be human writable. (Human readable is a subordinate goal.) Overloading a markup language and thus forcing users to type everything twice doesn't count as "easy" and neither does overloading property naming for poor man's namespaces or hierarchy.

There are (at least) two viable alternatives:

  • Use programmatic configuration. Build a reasonable, well-documented configuration API into your application and have users write to it.
  • Invent a simple language and write a parser. It's not that difficult to pick up ANTLR or JavaCC and create a little language that meets your configuration requirements.

The use of a scripting language (like Beanshell or Groovy) can combine both approaches. (For example, Bob's approach for dynaop is a good example.)

(comment bubbles) 0 comments

4% Coverage

Paul Brown @ 2005-05-09T22:46:33Z

I've only been to two of fifty. (It would be three, but the Gambero Rosso that I've been to is in Vernazza, not San Vincenzo.)

(comment bubbles) 0 comments

Simple CVS Sandboxing with rsync

Paul Brown @ 2005-04-26T11:33:12Z

PXE is composed of 30-ish (I run out of fingers and toes somewhere around 20...) modules that are all part of a central build. I typically work on one module at a time, but sometimes I don't want to commit all of my changes at once. Nonetheless, policy dictates that the mainline builds at all times, so I should rebuild and test with each major block of changes that I commit.

So, I check out a clean tree somewhere, use rsync -C to copy over the modules I've changed, then build and run smoke tests. The -C flag ignores files that would normally be ignored by CVS, so it's equivalent to having made my changes to the clean build.

(comment bubbles) 0 comments

Public Should be on Purpose

Paul Brown @ 2005-04-26T11:19:08Z

Depending on how you look at things, integrated development environments (IDEs) are evil because they make it possible to write software without knowing what you're doing. With the IDE's help, it's very easy to auto-import and control-spacebar yourself into a pickle, all without reading documentation, looking at source code, or otherwise paying your dues for reusing code.

Changing your IDE to create classes that are either private or at least package-private by default (as opposed to public) is a good ten-second hit of preventative medicine for ensuring that visibility helps to enforce architectural constraints. In fact, package-private is what you get by default in Java unless you type public or private on purpose (i.e., for some reason), but most IDEs ship with configurations that make decisions for you.

(comment bubbles) 0 comments

The Long Tail of Integration and Room for Startups

Paul Brown @ 2005-04-16T16:03:13Z

An internetnews.com article on IBM's acquisition of Ascential had an interesting comment from Ron Schmelzer:

"[...] I think we're seeing just the beginning of consolidation in this space. I would expect to see more around process, management, security, event-driven capabilities, policy and performance. [This year] will be a big year for consolidation. The question remains: is there room for start ups?"

Consolidation in integration is making room for startup ventures, although not necessarily in integration as such. The bigger the animal, the bigger the meals and the bigger the, um..., poops; any or all of these may make a fertile habitat for some new creatures. Hopefully, this is the genesis of all kinds of interesting critters that couldn't have existed otherwise.

(comment bubbles) 0 comments

Fatherhood

Paul Brown @ 2005-04-06T19:53:00Z

As of today, I'm a dad.

(comment bubbles) 0 comments

StreamCorruptedException and Class Loading

Paul Brown @ 2005-03-28T19:01:00Z

Here's an otherwise innocuous utility method:

public static Object toObject(byte[] bytes) throws IOException,
    ClassNotFoundException
{
  ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
  ObjectInputStream ois = new ObjectInputStream(bis);
  return ois.readObject();
}

Why would something that works in a unit testing environment fail with a StreamCorruptedException in a more complex container? (HINT: Class loading is almost always the culprit...) As the javadoc for toObject() says, a StreamCorruptedException can result if the stream violates internal consistency checks, but what does this have to do with class loading?

Well... if you trace through the source, which is no mean feat, you'll see that ObjectInputStream uses the most recent non-null ClassLoader from the call stack, i.e., the ClassLoader that loaded the class with the utility method, when trying to locate classes by name. The StreamCorruptedException will show up if you use non-default serialization for a class and that class is not visible to the ClassLoader that loaded the class with the utility method!

Thus, if you must, a better form for the method would be:

public static Object toObject(byte[] bytes, ClassLoader cl)
    throws IOException, ClassNotFoundException
{
  ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
  ObjectInputStream ois = new ObjectInputStream(bis) {
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException,
      ClassNotFoundException
    {
      String name = desc.getName();
      Class c = cl.loadClass(name);
      return c;
    }
  };
  return ois.readObject();
}

This can have security implications (some folks don't want you to subclass on ObjectInputStream for obvious reasons), but it will work right under most circumstances, unlike the original. For what it's worth, it's probably better to not use a utility method and locate this operation with the caller and avoid the issue in the first place.

You just never know when Class.forName() is going to jump out and bite you...

(comment bubbles) 0 comments

All Posts contains 399 items in 57 pages of 7 items each:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57