I do a lot of model-driven software engineering and code generation. But you might not know that, because I've never written about it at all in my blog. In the next couple of posts, I'll go about changing that.
First, a bit about the application that I'm going to build. I have long believed in having wrapper classes for resources and properties. Visual Studio and .NET now do a lot of this for you automatically. In Java, we're still pretty much on our own. What I would like to do is automatically generate a Java class which exposes a strongly-typed getter for each property in a .properties file.
To accomplish this, I'm going to use one of my favorite model-driven development tools, openArchitectureWare (oAW). oAW is comprised of a pretty extensive toolchain for model transformation, validation, and code generation, and of course, it's open-source. As you will see, it integrates well with the Eclipse Modeling Framework (EMF). If you would like to follow along, install the openArchitecture Eclipse plugin. While you're at it, check out the oAW documentation, particularly the oAW-EMF tutorial (but note that we're going to take a simpler approach that what is described there).
In Eclipse, I start by creating a new "openArchitectureWare Project", which is available courtesy of the oAW plugin. I took the option to "Create a sample", because it creates a number of EMF and oAW files that I need. The sample project looks like this:
Right now, it's possible to right-click the "generator.oaw" file and select "Run As...oAW Workflow" and see some sample Java code get generated into the src-gen folder from Model.xmi.
Rather than stop right now and discuss what each of these files does, I'll proceed through the development of my application and hopefully you'll pick things up intuitively. For starters, I'm not going to use extensions, so I can go ahead and delete Extensions.ext and GeneratorExtensions.ext. This will break the generator.oaw build for now, but I'll put it back together as I proceed.
One of the most important files, and the focus of this post (finally!) is the .ecore file, which I will rename to "Properties.ecore". This is where the metamodel is defined. In this example, I want to create models for properties, so my metamodel needs to describe what a "property" is. In the Java .properties file sense, it is basically a "name", a "type", and a "value". Additionally, I want to bundle individual properties into "property sets" which are stored in .properties files. The property sets themselves need a "name" and, optionally, a Java package to live in. Finally, for illustrative purposes, I'll support loading them either as Java classloader resources or resource bundles.
When I double-click to edit the .ecore file, it opens in the "Sample Ecore Model Editor" by default. This editor is nothing to write home about, and in fact I suspect they call it "Sample" because the idea behind EMF is that tool builders will write (and sell you) their own higher-end Ecore editors, probably in the form of Rational-Rose-like graphical modeling environments. No matter -- this editor will work fine for my purposes here. The upside of the simple Ecore editor is that it is quite intuitive to use -- just right-click nodes to add children (classes, enums, attributes, references to other classes, etc.), and use the Properties view to configure them. My metamodel ends up looking like this:
The only trick I want to point out here is how to configure the "Properties" EReference on the PropertySet EClass. First, I want to have multiple Property instances in a PropertySet, which I achieve by setting the "Upper Bound" on Properties to be "-1". Second, a PropertySet logically "contains" its Properties, so I set the "Containment" property to "true". (If you don't do this last step, you will experience perhaps-confusing difficulties when you actually go to create a Property while modeling in the Eclipse EMF model editor.)
Now I need to use Eclipse to create a sample model based on this metamodel to use for testing while I develop code generation templates. I'll demonstrate that in my next post.
Saturday, February 28, 2009
Saturday, February 14, 2009
In the learn-something-new-every-day department, in a code review this week for one of the developers on my team, I noticed that he was calling Integer.getInteger(). I had never seen this before. Turns out that this method and its overloads get system properties as Integers, handling the numeric conversion for you and returning null if it fails. There is also a Long.getLong() that does the same thing for (you guessed it) Longs. So all of those times I called System.getProperty() followed by Integer.parseInt() with a catch of NumberFormatException, I was doing WAY too much work. Good to know.