tools

Scripting magic with Groovy, Grape and Jetty

Posted in groovy, java, tools on December 31st, 2009 by Joerg – 1 Comment

Groovy 1.7 has just been release and it’s time to play again. One of the new features, Grape inspired me to the try the following. I created a script that acts as a simple webserver using embedded jetty without the need to install anything else than Groovy 1.7 on your computer. Just save the script as simpleWebServer, make it executable and start it like

./simpleWebServer -d someDirWithHTMLFiles -p 9000

Surf to http://localhost:9000 and you will see.

Here is the full script. I will explain the details further down.

#!/usr/bin/env groovy

@Grab('org.mortbay.jetty:jetty:6.1.22')
import org.mortbay.jetty.*;
import org.mortbay.jetty.handler.*

def cli = new CliBuilder (usage:'simpleHtmlServer -p PORT -d DIRECTORY')
cli.with {
 h longOpt:'help', 'Usage information'
 p longOpt:'port',argName:'port', args:1, type:Number.class,'Default is 8080'
 d longOpt:'dir', argName:'directory', args:1, 'Default is .'
}

def opts = cli.parse(args)
if(!opts) return
if(opts.help) {
  cli.usage()
  return
}

def server = new Server(opts.port.toInteger()?:8080)
def resourceHandler = new ResourceHandler(welcomeFiles:["index.html"],
                                         resourceBase:opts.dir?:".")
server.handler = new HandlerList(handlers:[resourceHandler, new DefaultHandler()])

server.start()
server.join()

Here are the magic details about the script:

1. The Shebang

The first important thing about this script is the shebang.

#!/usr/bin/env groovy

If you are using a real operating system (sorry Windows users), this will let you start the script like a normal executable. I usually skip the .groovy appendix on script files, so it really feels like you are using a normal command line utility.

2. Grape

The next line uses the new feature of Groovy 1.7, called Grape. This is a dependency System that allows to load any dependency, that is available in the maven-repositories to be used inside a script.

@Grab('org.mortbay.jetty:jetty:6.1.22')

The syntax is pretty easy. It uses the maven notation: groupId:artifactId:version. There is an alternative version that uses separate attributes for each but I prefer the shortcut.
This line will lookup the dependency in the maven repository, download it and store it in ~/.groovy/grape. So the first start of the script might take a moment. The second time will be faster.
Grape allows to use the full java ecosystem in a simple groovy script without any additional install. Groovy 1.7 is enough. I think this makes scripting in groovy incredible powerful.

3. The CliBuilder
The script should really feel like a command line utility. Therefore it needs to deal with parameters. This is where the CliBuilder comes in.

def cli = new CliBuilder (usage:'simpleHtmlServer -p PORT -d DIRECTORY')
cli.with {
 h longOpt:'help', 'Usage information'
 p longOpt:'port',argName:'port', args:1, type:Number.class,'Default is 8080'
 d longOpt:'dir', argName:'directory', args:1, 'Default is .'
}

def opts = cli.parse(args)
if(!opts) return
if(opts.help) {
  cli.usage()
  return
}

Groovy includes Apache commons CLI. But where the Java version is already helpful in parsing parameters, the Groovy version gets really simple. The example above creates one CliBuilder, that provides a “DSL” for defining the parameters. Further down they are three parameters defined. This is all thats needed.
After the args are parsed we can just simply use them using Groovy properties syntax like opts.parameterName. Even a pretty usage statement can be printed, when –help is called.

4. Dynamic constructors
I used one of the embedded Jetty examples (FileServer.java) as the foundation of my script. The configuration of the handlers looked something like that in Java:

ResourceHandler resource_handler=new ResourceHandler();
resource_handler.setWelcomeFiles(new String[]{"index.html"});
resource_handler.setResourceBase(args.length==2?args[1]:".");

HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[]{resource_handler,new DefaultHandler()});

Thats pretty long. Now the Groovy version looks like that:

def resourceHandler = new ResourceHandler(welcomeFiles:["index.html"],
                                          resourceBase:opts.dir?:".")
server.handler = new HandlerList(handlers:[resourceHandler, new DefaultHandler()])

It uses dynamic constructors. Groovy allows to call a virtual constructor with a map of arguments, where the elements are actually bean properties. This allows a much more concise construction of an object, even if the original creator wasn’t so kind to provide a convenience constructor.

5. The Elvis Operator

You probably wondered what the following statement did in the last example:

opts.dir?:"."

Well, that was Elvis. In Java there is the ternary operator, which goes like this:

(condition)?(result if true):(result if false)

In Grovvy there is something called the Groovy truth, which says if a statement is null, then it is false, else it is true. This makes the Elvis operator possible. Elvis says, if the statement is true (as in Groovy truth) then use the value of the statement, else use the value after the colon. This is a very concise way for realizing default values, which is often needed in scripts

With all the scripting features that were added in earlier versions and with Grape in 1.7 I think Groovy is finally a great alternative to usual scripting languages. When you are experienced in Java it’s probably much simpler to write a script in Groovy than in Perl, Ruby or even Bash. For me this is definitely true.

Well done, Groovy team!

IntelliJ IDEAs new directory-based project format

Posted in java, software development, tools on October 17th, 2009 by Joerg – 2 Comments

I am currently playing with the EAP-Version (Early Access Program) of my favorite IDE IntelliJ IDEA. Since the new version is not that far away it is time to learn the new features and I discovered one that surprised me. A small but pretty nice change.

(Update: Thanks to Strug I have realized that this feature is already present in Idea 8, you can use the action “Open in New (Directory based) format” to convert your project. Fortunately they renamed it to “Save as Directory-Based Format …” in Maia. )

IDEA has a new format to store the project files. It is called directory-based. Instead of using the three famous files .ipr .iml and .iws IDEA will now store all information into a directory, which is simply called .idea. It is located in the root folder of the project. This seems to be somewhat similar to eclipse’s .project folder. In a small example project I created the content of the new directory looks like this:

-rw-r--r--  1 joerg  joerg    163 17 Okt 09:53 ant.xml
-rw-r--r--  1 joerg  joerg   2107 17 Okt 09:53 compiler.xml
drwxr-xr-x  3 joerg  joerg    102 17 Okt 09:53 copyright
drwxr-xr-x  3 joerg  joerg    102 17 Okt 09:53 dictionaries
-rw-r--r--  1 joerg  joerg    277 17 Okt 09:53 encodings.xml
-rw-r--r--  1 joerg  joerg    170 17 Okt 09:53 fileColors.xml
-rw-r--r--  1 joerg  joerg   1595 17 Okt 09:53 misc.xml
-rw-r--r--  1 joerg  joerg    258 17 Okt 09:53 modules.xml
-rw-r--r--  1 joerg  joerg    207 17 Okt 09:53 templateLanguages.xml
-rw-r--r--  1 joerg  joerg    169 17 Okt 09:53 vcs.xml
-rw-r--r--  1 joerg  joerg  38245 17 Okt 10:21 workspace.xml

The files included in this directory depend on the settings you change in the IDE. So, if you would for instance set the SQL dialect for your project there will be another file called sqldialects.xml containing all settings about this.

There is one special file in there, which is workspace.xml. This file contains individual settings for the workspace, which are definitely not intended to be shared via version control. This is equivalent to the .iws file of the old format. IDEA will put this file automatically on the ignore list of your version control.

I see some advantages of the new format.

  • First of all it is easier to find specific settings. The filenames are meaningful and the files are small.
  • The new structure allows a very detailed control of which settings you want to share with your colleagues. If you don’t want to share e.g. your file coloring (another new feature of Maia) just put the file on the ignore list.
  • Directories of the projects saved in the new format will be recognized as projects in the open-project dialog. In the past this was one annoying additional click as you had to choose the .ipr file before.

The new directory based format is a small change but a very good one. It is often a sum of little detail-improvements that save a lot of trouble in daily work. So I am looking forward to the other details to be discovered.

By the way JetBrains released an open source version of IDEA two days ago. So if you want to try this just go to www.jetbrains.org and download the Community Edition.

XMind on Mac with Java 6

Posted in apple, java, tools on February 27th, 2009 by Joerg – Be the first to comment

The Problem

XMind is a very nice mind mapping software. It is platform independent and it’s free. I started using it at work on a Windows PC. When I installed it on my Mac I had a bad surprise. When starting it, it stopped immediately with a message that the JVM terminated.

xminderror

Xmind is based on Eclipse RCP. Eclipse itself is using the Carbon framework on the Mac for it’s GUI. But Carbon is not supported on 64 Bit. But Java 1.6 on the Mac does only work on 64 Bit. So it will of course not work.

The Solution

You don’t need to uninstall Java 6 in order to run XMind. It turned out the solution was much simpler. You have to tell the XMind app what JVM to use. To do this use your favorite text editor and open the following file (I recommend VI :) ):

/Applications/XMind.app/Contents/Info.plist

Look for the following text and uncomment the -vm option:

<!-- to use a specific Java version (instead of the platform's default) uncomment
         the following options:-->
<string>-vm</string>
<string>/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Commands/java</string>

Make sure it points to the right JVM. I had to change it to 1.5.0 as it did only point to Current, which was 1.6.

Save, start XMind again and have fun creating Your mindmaps.