Sunday, November 21, 2010

Simple ESB with Camel and Groovy

I'm not sure if writing an ESB service can be considered fun - but when using Groovy and Camel together it comes pretty close. Camel provedes a nice Java based DSL which makes the routing very clean and easy to follow. When you mix in the power of Groovy you get a very elegant solution.

With Groovy you can say a closure implements an interface. This allows us to embed Groovy code inline as a Processor in a Camel route.

    from("jetty:http://localhost:8080/hello")
    .process({Exchange exchange ->
      exchange.out.setBody "Hello World"
    } as Processor)

We can go one step futher by taking advantage of Groovy's dynamic metaClass to create our own method which takes a closure directly. The following adds a new method 'x' to the RouteDefinition class.

RouteDefinition.metaClass.x = {Closure c -> ((RouteDefinition)delegate).process(c as Processor)}

Our route definition now becomes much more elegant

    from("jetty:http://localhost:8080/hello")
    .x {Exchange ex -> ex.out.setBody "Hello"}
    .x {Exchange ex -> ex.out.body = ex.in.body + " World"}

Add in some Grab annotations from Groovy's Grape extension to automatically download the Camel libraries and the whole thing becomes a single, small, self-contained script.

#!/usr/bin/env groovy

@Grab(group="org.apache.camel", module="camel-core", version="2.5.0")
@Grab(group="org.apache.camel", module="camel-jetty", version="2.5.0")
import org.apache.camel.CamelContext
import org.apache.camel.impl.DefaultCamelContext
import org.apache.camel.builder.RouteBuilder
import org.apache.camel.Processor
import org.apache.camel.Exchange
import org.apache.camel.model.RouteDefinition

RouteDefinition.metaClass.x = {Closure c -> ((RouteDefinition)delegate).process(c as Processor)}

CamelContext cxt = new DefaultCamelContext()

cxt.addRoutes(new RouteBuilder(){
  void configure(){
    from("jetty:http://localhost:8080/hello")
    .x {Exchange ex -> ex.out.setBody "Hello"}
    .x {Exchange ex -> ex.out.body = ex.in.body + " World"}
  }
})

cxt.start()

Sunday, November 14, 2010

Git version control with a ClearCase like workspace

I have been using the git version control system for a while now. It took a little time to get comfortable with the commands and to fully understand everything it was doing.

When I first read about the fast branch switching I was envisioning something along the lines of a ClearCase view. It has been a while since I used ClearCase - but from what I remember when you switch from one view to another, the virtual file system saved your whole workspace (including things not checked in yet) and then restored your whole workspace from the new view to the exact state it was in when you left. Git doesn't work exactly this way.

When you change to another branch in git it only switches files it is tracking. Any new files you are working on are not affected and therefore appear to magically come over to the new branch. Also, any files you have changed that are tracked will come over if your changes do not cause a merge conflict.

Git does have a stash command that allows you to save off your changes and then apply them again later - but in my opinion it is a little cumbersome. It does not save new files - only ones that are currently tracked, and to apply a specific stash you have to look at the stash list and then apply one as a numerical offset.

For me I would much rather git worked like a clearcase view so that I can save my workspace as-is and then later load it back up. Luckily git is quite powerful and allows you to create some very complex aliases to use right along side other git commands. I created the following two aliases which can be added to your .gitconfig file.
    save = "!git add -A && BR=$(git symbolic-ref HEAD) && echo saving workspace ${BR##*/} && SAVE=$(git stash create Workspace) && git config workspace.${BR##*/}.save $SAVE && git reset --hard HEAD"

    load = "!BR=$(git symbolic-ref HEAD) && echo loading workspace ${BR##*/} && SAVE=$(git config --get workspace.${BR##*/}.save) && git stash apply -q $SAVE && git reset HEAD && git config workspace.${BR##*/}.hist $SAVE && git config --unset workspace.${BR##*/}.save"
Typing git save will save off your workspace as a revision and use a git variable to associate it with the current branch name. You can then change to another branch and come back later. When you come back, typing git load will look for the saved workspace revision associated to the current branch and reapply those changes. This will save and load all files (tracked and untracked) except for the ones you have specifically told git to ignore.