Thursday, May 22, 2008

Units DSL in Groovy

A while back I saw Guillaume Laforge's article about building a Groovy DSL for unit manipulations. I recently needed to implement something similar in a project, so I decided to take Guillaume's code and update it a bit. I wanted a nice way to package it up so I could quickly enable unit manipulation support on a particular class. I also added a pair of methods to make things more flexible. Here's my UnitDSL.groovy:

package org.psicat.model

import org.jscience.physics.amount.*
import javax.measure.unit.*

/**
* A helper class for setting up the Units DSL
*/
class UnitDSL {
private static boolean isEnabled = false;
private UnitDSL() { /* singleton */ }

/**
* Initialize the Units DSL.
*/
static enable() {
// only initialize once
if (isEnabled) return

// mark ourselves as initialized
isEnabled = true

// enable inheritance on EMC
ExpandoMetaClass.enableGlobally()

// transform number properties into an mount of a given unit represented by the property
Number.metaClass.getProperty = { String symbol -> Amount.valueOf(delegate, Unit.valueOf(symbol)) }

// define opeartor overloading, as JScience doesn\'t use the same operation names as Groovy
Amount.metaClass.static.valueOf = { Number number, String unit -> Amount.valueOf(number, Unit.valueOf(unit)) }
Amount.metaClass.multiply = { Number factor -> delegate.times(factor) }
Number.metaClass.multiply = { Amount amount -> amount.times(delegate) }
Number.metaClass.div = { Amount amount -> amount.inverse().times(delegate) }
Amount.metaClass.div = { Number factor -> delegate.divide(factor) }
Amount.metaClass.div = { Amount factor -> delegate.divide(factor) }
Amount.metaClass.power = { Number factor -> delegate.pow(factor) }
Amount.metaClass.negative = { -> delegate.opposite() }

// for unit conversions
Amount.metaClass.to = { Amount amount -> delegate.to(amount.unit) }
Amount.metaClass.to = { String unit -> delegate.to(Unit.valueOf(unit)) }
}

/**
* Add Units support to the specified class.
*/
static addUnitSupport(clazz) {
clazz.metaClass.setProperty = { String name, value ->
def metaProperty = clazz.metaClass.getMetaProperty(name)
if (metaProperty) {
if (metaProperty.type == Amount.class && value instanceof String) {
metaProperty.setProperty(delegate, Amount.valueOf(value))
} else {
metaProperty.setProperty(delegate, value)
}
}
}
}

/**
* Remove Units support from the specified class.
*/
static removeUnitSupport(clazz) {
GroovySystem.metaClassRegistry.removeMetaClass(clazz)
}
}


To enable the DSL, you have to call UnitDSL.enable(). This adds a few methods to the metaclasses on Number and Amount. The majority of the code in enable() is a straight cut and paste job from Guillaume's article.

I did add two methods. The first:

Amount.metaClass.static.valueOf = { Number number, String unit -> Amount.valueOf(number, Unit.valueOf(unit)) }


allows you to create an Amount using a Number and a String, e.g. Amount.valueOf(1.5, "cm").

The other new method:

Amount.metaClass.to = { String unit -> delegate.to(Unit.valueOf(unit)) }

allows conversions with the unit specified as a String, e.g. 1.5.m.to("cm")

The final enhancement I added was to create a addUnitSupport(clazz) method. This method overrides the setProperty() method of the passed class to support setting Amount properties as strings. All assignments in the following scenario are valid:

class Foo {
Amount bar
}

// test
UnitDSL.enable()
UnitDSL.addUnitSupport(Foo)

def foo = new Foo()
foo.bar = Amount.valueOf(3, SI.METER)
foo.bar = Amount.valueOf(3, "m")
foo.bar = Amount.valueOf("3m")
foo.bar = 3.m
foo.bar = "3m"


To use this code, you'll have to grab the latest JScience release.

Wednesday, May 21, 2008

Visualizer, Part 3: Poor Man's PDE Build

This is the third in my series (Part 1, Part 2) of posts about Visualizer. In this post I'll be talking about how to create a simplified PDE build.

As I mentioned in the previous post, Visualizer is built on OSGi. My preferred development environment for doing any Java development, but especially OSGi development, is Eclipse because of its wonderful JDT and PDE tooling. The PDE team has created an awesome environment for developing and managing OSGi bundles. However, one of the requirements that I had for Visualizer was that anyone could download the source code and build it, regardless of their IDE or environment preferences. PDE includes the ability to perform a headless build, but I didn't really want to expect the user to download Eclipse or to include a stripped down version of Eclipse in the Visualizer distribution just so the user could build it from the commandline. So I set out to create a "Poor Man's PDE Build" using just Ant.

Actually building the plugins with Ant is relatively simple. This short Ant file will build the plugin:

<?xml version="1.0" encoding="UTF-8"?>
<project default="build-plugin">
<property name="src.dir" value="src"/>
<property name="classes.dir" value="bin"/>
<property file="META-INF/MANIFEST.MF"/>
<property file="build.properties"/>

<path id="classpath">
<fileset dir="${dist.dir}">
<include name="*.jar"/>
</fileset>
<fileset file="${osgi.framework}"/>
<pathelement path="${java.class.path}"/>
</path>

<target name="init">
<mkdir dir="${classes.dir}"/>
</target>

<target name="compile" depends="init">
<echo message="Compiling the ${Bundle-SymbolicName} plugin"/>
<javac srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath" debug="true"/>
</target>

<target name="copy-resources">
<echo message="Copying resources"/>
<copy todir="${classes.dir}">
<fileset dir="." includes="${bin.includes}"/>
</copy>
</target>

<target name="build-plugin" depends="compile, copy-resources">
<jar jarfile="${dist.dir}/${Bundle-SymbolicName}_${Bundle-Version}.jar" basedir="${classes.dir}" manifest="META-INF/MANIFEST.MF"/>
</target>

<target name="clean">
<delete includeemptydirs="true">
<fileset dir="${classes.dir}" includes="**/*"/>
</delete>
</target>
</project>


As you can see here, there really isn't much to the actual build. The best part is we can use the META-INF/MANIFEST.MF and build.properties created when we're working in PDE to control the build.

For a single bundle with no dependencies, this effectively duplicates the PDE build process. The difficulties comes in when you start having dependencies. If you use the headless PDE build, it will sort out all the dependencies for you and build your bundles in the proper order.

Implementing proper dependency resolution seemed awfully complicated, especially since PDE build already implements it. Fortunately, Visualizer doesn't require complicated dependency resolution because I've structured the bundles in a logical order. There are three levels of bundles: "core" which implement the main functionality, "ui" which implement the user interface to the core bundles, and "application" bundles that build on both the core and ui bundles.

Armed with this knowledge, we can structure a three stage build process where we first build all of the core bundles then all of the ui bundles and then all of the application bundles. To accomplish this, we have a master build.xml that calls out to the template build-plugin.xml file listed above using a subant task.


<target name="build-framework" depends="init">
<!-- build org.andrill.visualizer, org.andrill.visualizer.services* -->
<subant target="build-plugin" genericantfile="build-plugin.xml" failonerror="false">
<property name="dist.dir" value="../${build.dir}"/>
<property name="osgi.framework" value="../framework.jar"/>
<dirset dir=".">
<include name="org.andrill.visualizer"/>
<include name="org.andrill.visualizer.services*"/>
</dirset>
</subant>
</target>


Here you can see we build first the org.andrill.visualizer bundle and then all of the org.andrill.visualizer.services bundles. As we build each bundle, we copy the bundled JAR file to our dist.dir. Each time a bundle is built, it creates its classpath from all of the JARs in dist.dar. So even though there are dependencies among bundles, we are progressively fulfilling those dependencies by collecting the built bundles in dist.dir.

Once all of the "core" bundles are built, we can kick off the build of the ui bundles:


<target name="build-ui" depends="build-framework">
<!-- build org.andrill.visualizer.ui* -->
<subant target="build-plugin" genericantfile="build-plugin.xml" failonerror="false">
<property name="dist.dir" value="../${build.dir}"/>
<property name="osgi.framework" value="../framework.jar"/>
<dirset dir=".">
<include name="org.andrill.visualizer.ui*"/>
</dirset>
</subant>
</target>


Finally we can build all of the "application" bundles by excluding everything we've already built:

<target name="build-apps" depends="build-framework, build-ui">
<subant target="build-plugin" genericantfile="build-plugin.xml" failonerror="false">
<property name="dist.dir" value="../${build.dir}"/>
<property name="osgi.framework" value="../framework.jar"/>
<dirset dir=".">
<include name="*.*"/>
<exclude name="org.andrill.visualizer"/>
<exclude name="org.andrill.visualizer.services*"/>
<exclude name="org.andrill.visualizer.ui*"/>
<exclude name="${build.dir}"/>
<exclude name="${dist.dir}"/>
</dirset>
</subant>
</target>


You can check out the full build file at: build.xml and build-plugin.xml.

It's not nearly as neat as just kicking off a PDE build and letting it do all of the hard work of figuring out the dependencies for you. However, I'm rather fond of my approach because it keeps me honest. If I create a new bundle and it starts breaking the build, then I know I need to go back and make sure I've thought through the dependencies and am not trying to mix "core" code with "ui" code and such. And there's no need to bundle Eclipse with the source to build the thing.

Monday, May 12, 2008

Open Participation in SimpleIssue

When I started writing the simple issue tracker it was with the goal of learning more about Grails and coming away with a generally useful project. I decided to blog it because I was hoping my insights might be useful to the community. The response has been awesome, with lots of encouragement and lots of great ideas.

It strikes me that I can probably learn more from the community than just working away on my own. So if you want to fix something I screwed up or you have ideas for new features or you just want to experiment, drop me a line and I'll add you to the SimpleIssue project out at Google Code. Mike Hugo has already pointed out my embarrassing lack of tests and has offered to lend a hand. This is great news for me because testing has never been my strong suit. It will give me an opportunity to study how it's done.

SimpleIssue is a nights and weekends project for me, so I don't expect any particular level of participation. If you've got ideas and want to contribute, then all the better for us.

Sunday, May 11, 2008

Writing a Simple Issue Tracker in Grails, Part 2

This is the long overdue follow up to my Writing a Simple Issue Tracker in Grails post. In this post I'll be detailing how to add security with the JSecurity plugin.

So let's dive right in and work on securing our application. I opted to use the JSecurity plugin for no other reason than I've used the Acegi plugin in the past and wanted to see how JSecurity compares. You could use the Acegi plugin with a similar process and results.

Following the JSecurity Quick Start guide, we'll begin by installing the plugin and running the quick start script:

grails install-plugin jsecurity
grails quick-start


The quick start script created a few domain classes as well as a controller for logging in and out. Now we need to setup an Administrator user and role to test things with. We'll just cut and paste the Administrator role setup right from the Quick Start guide into our Bootstrap.groovy file:

import org.jsecurity.crypto.hash.Sha1Hash

class BootStrap {

def init = {servletContext ->
// Administrator user and role.
def adminRole = new JsecRole(name: "Administrator").save()
def adminUser = new JsecUser(username: "admin", passwordHash: new Sha1Hash("admin").toHex()).save()
new JsecUserRoleRel(user: adminUser, role: adminRole).save()
}

def destroy = {
}
}


With the administrator user in place, we can start securing our controllers. JSecurity makes this drop dead simple by letting you specify rules in the conf/SecurityFilters.groovy file.

Before we dive in and start writing our rules, let's think about what we want users to be able to do. I'm going to keep things simple and have two classes of users: anonymous and administrators. However, you could easily create a third class of users, authenticated, that would have more permissions than the anonymous users but less than the administrators.

Administrators should be able to create, edit, and delete Projects, Components, and Issues. Additionally, Administrators should be able to access the admin controller.

Depending on how private you want your issue tracker, anonymous users might be able to list and show the Projects, Components, and Issues or they might not. They may also create new issues or they may not. To handle this, I'm going to create two new configuration parameters that control how secure the application is by adding the following lines to Config.groovy:

issue.secure.create = true
issue.secure.view = false


These configuration options will let us configure whether anonymous users can create issues (issue.secure.create = true) and whether anonymous users can view issues (issue.secure.view = false). In the above example, creating a new issue is secured (requires the user be logged in) but viewing is not.

Now that we have an idea of our security rules, let's codify them in the conf/SecurityFilters.groovy file:

import org.codehaus.groovy.grails.commons.ApplicationHolder

class SecurityFilters {
def filters = {

// secure the project controller
projectCreationAndEditing(controller: "project", action: "(create|edit|save|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure the component controller
componentCreationAndEditing(controller: "component", action: "(create|edit|save|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure issue editing
issueEditing(controller: "issue", action: "(edit|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure admin controller
admin(controller: "admin", action: "*") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure creating issues if Config#issue.secure.create = true
if (ApplicationHolder.application.config?.issue?.secure?.create) {
issueCreation(controller: "issue", action: "(create|save)") {
before = {
accessControl {
role("Administrator")
}
}
}
}

// secure viewing issues if Config#issue.secure.view = true
if (ApplicationHolder.application.config?.issue?.secure?.view) {
issueBrowsing(controller: "issue", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}

componentBrowsing(controller: "component", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}

projectBrowsing(controller: "project", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}
}
}
}


So with that we should have a secured grails app. Obviously there are plenty of things we can improve. First off, there is no user management code. We'll probably want to generate a controller to allow new users to register as well as to allow Administrators to add new users. The views could be cleaned up quite a bit and we could add a custom logo. Finally there are numerous other options that folks have suggested, including saved searches, internationalization, etc.

I've gone ahead and created a new Google Code project with the code from this article. If you're interested in hacking on this code, let me know. In the next installment, which I promise won't take a month, I'll be adding search/filtering support via the Searchable plugin and creating an API so I can create new issues from external applications.

Cheers,
Josh

Tuesday, May 06, 2008

Visualizer, Part 2: OSGi & Native Libraries

This is the second in my series (Part 1) of posts about Visualizer. In this post I'll be talking about packaging an OSGi bundle that includes native libraries.

Visualizer uses the OpenGL bindings provided by JOGL project to display images and data. JOGL provides a series of platform-specific downloads that include a standard JAR file of Java classes and a set of native libraries for variety of platforms. This complicates the deployment of Visualizer because we need to install the appropriate version of JOGL for the user's platform. One option is to mimic JOGL and provide platform-specific builds of Visualizer that includes the appropriate version of JOGL. This isn't ideal because it adds extra steps to the build process and can introduce confusion for users trying to figure out which version of Visualizer they should download.

Fortunately, there's another option: OSGi. In a nutshell, OSGi is a component framework specification that allows you to assemble and manage applications as a collection of components (bundles). I'm not really doing OSGi justice so if you don't know what it is, you owe it to yourself to check it out. And odds are you've probably already used something built on OSGi because it seems to be everywhere these days.

Anyhow, OSGi elegantly solves our Visualizer deployment problem by allowing us to provide a single download. We simply combine the Java classes and all of the platform-specific native libraries provided into a single bundle and OSGi will detect and extract the appropriate set of native libraries based on the user's platform.

The first step was to download all of the JOGL packages for the platforms you want to support. I have users on Linux (32 & 64 bit), Mac OS X, and Windows (32 & 64 bit), so I downloaded all of these. From these downloads, I kept one copy of the JOGL JAR files and collected all of the native libraries.

The next step was to use Eclipse's excellent PDE tooling to create a new "Plugin Project from existing JAR files". I called it 'jogl' and pointed it at the JOGL JAR files. It sucked in all of the class files and spat out an OSGi bundle. If there were no native libraries, we'd be done.

Since we have native libraries, I copied them into the jogl bundle directory using a straightforward directory structure:


The 'native' directory structure is not required; you can use whatever makes sense to you. As you can see from the screenshot, I've got a set of libraries for 5 platform/processor combinations.

The final step is to make the OSGi framework aware of the libraries so it can extract the appropriate libraries when it starts up. This requires using the Bundle-NativeCode header in your bundle manifest:

Bundle-NativeCode: native/macosx/libgluegen-rt.jnilib;
native/macosx/libjogl_cg.jnilib;
native/macosx/libjogl_awt.jnilib;
native/macosx/libjogl.jnilib;
osname=mac os x;
processor=x86;
processor=ppc,
native/linux/x86/libgluegen-rt.so;
native/linux/x86/libjogl_cg.so;
native/linux/x86/libjogl_awt.so;
native/linux/x86/libjogl.so;
osname=linux;
processor=x86,
native/linux/x86-64/libgluegen-rt.so;
native/linux/x86-64/libjogl_cg.so;
native/linux/x86-64/libjogl_awt.so;
native/linux/x86-64/libjogl.so;
osname=linux;
processor=x86-64,
native/windows/x86/gluegen-rt.dll;
native/windows/x86/jogl_cg.dll;
native/windows/x86/jogl_awt.dll;
native/windows/x86/jogl.dll;
osname=win32;
processor=x86,
native/windows/x86-64/gluegen-rt.dll;
native/windows/x86-64/jogl_cg.dll;
native/windows/x86-64/jogl_awt.dll;
native/windows/x86-64/jogl.dll;
osname=win32;
processor=x86-64


One quick note: watch the whitespace when editing the bundle manifest. The OSGi specification is explicit about where whitespace is allowed and where it is required.

With this final piece we can JAR up our class files, native libraries, and bundle manifest and we should be able to use it in any OSGi implementation. When the OSGi implementation loads our bundle, it will extract the appropriate set of native libraries based on the user's osname and processor properties and make sure those libraries are available on the classpath.

I've tested this JOGL bundle on the Equinox implementation of OSGi across Mac, Windows, and Linux and it works great. If anyone is interested, I can make the pre-built bundle of JOGL available for download.

Busy Last Couple of Weeks

In the last 2.5 weeks, I was in the Bahamas for my wedding, Tallahassee for work, and in Iowa for a friend's wedding. I've spent a total of maybe 36 hours at home during that time. And to top it all off, my laptop went kaput while I was in the Bahamas and I'm waiting for a replacement. The blogging should pick back up now that I'm home for a bit.