Nov 132009
 

One of the most useful things you can do for any project is provide command line friendly tools for administration, diagnostics and maintenance. As nice as browser based administration tools are, not everyone has access to production machines behind firewalls and the sort with a browser, most administration is done via ssh. Giving operations tools that they can interconnect with normal Unix development tools makes their life and your life a whole lot better. They can build the tools they need with the foundation tools you provide.

In the past I have written most of my command line programs in Python. It is batteries included, standard on any Unix or Linux distribution worth using, and it just works. I have recently been introduced to Groovy and have been using it to produce some very sophisticated tools in a very short period of time.

But one of the downsides is that it inherits all the deployment difficulties of Java as well as all the benefits like the extensive standard library and third party code available. Even as easy as it is to add Groovy to the Extensions directory of your JDK installation, it doesn’t help your end users who might not know how to do such a thing. Everyone loves a standalone executable. Having to add a bunch of .jar files to your CLASSPATH environment variable isn’t any better or portable. Wrapper shell scripts aren’t a perfect solution either, bash is pretty ubiquitous, but not everyone uses bash, and what about Windows?

The best solution is to bundle your application with all its dependencies in a single .jar file. For most things this is a great way to distribute command line tools to hosting operations personnel and other end users that might not be Java experts. But this isn’t the easiest thing to accomplish with the basic jar tool that sun provides. Here I present a simple Ant based solution that can be modified and used to bundle any code base up into a standalone executable .jar file that can be executed on any platform that support Java, without any of the dependencies needing to be installed before hand.

Here is a basic build-jar target.

<target name="build-jar" depends="compile">
    <jar destfile="${dist.dir}/app.jar" compress="true">
        <manifest>
            <attribute name="Main-Class" value="main"/>
        </manifest>
        <fileset dir="${build.dir}/classes" includes="**/*.class"/>
        <zipgroupfileset dir="${lib.dir}">
            <includesfile name="dependencies.list"/>
        </zipgroupfileset>
    </jar>
</target>

What this will do is it wil include all the contents of the .jar files listed in dependencies.list file that is in your ${lib.dir} in with your .class files from your ${build.dir}/classes directory and set the default executable class to main. The dependencies.list is just a plain text file with the name of each .jar file to include on each on a separate line. Here is an example.

JSAP-2.1.jar
xstream-1.3.1.jar
groovy-all-1.6.5.jar
mysql-connector-java-5.1.7.jar
ojdbc-10.2.0.4.0.jar
Nov 122009
 

This adds a .truncate() to the String objects in Groovy. It lets you tell what the max length of a String should be and then truncates it to that length – 2 with an ellipsis on the end to let you know that the contents were truncated. You could easily modify this to just truncate the string and not suffix it with the ellipsis.

// this adds a "truncate(#)" method to String
String.metaClass.truncate = { len ->
    if (delegate == null) {return }
    if (delegate.length() > len) {return delegate[0..(len - 2)] + “\u2026″}
    return delegate
}
Oct 122009
 

Groovy has some wrappers around the apache.commons.cli via their CLIBuilder class. This is a pretty old and crusty library that has some significant limitations. I prefer to use the Java Simple Argument Parser (JSAP) library. Especially since they have added the ability to declare argument definitions in a declarative XML file. This reduces the code footprint in your Groovy or Java program significantly. Normally I am adverse to XML configuration programming but in this case the syntax is very succinct and an appropriate use.

Here is a partial example of argument declarations for an example program that scans for open ports on a server.

<jsap>
  <parameters>
    <switch>
      <id>help</id>
      <shortFlag>h</shortFlag>
      <longFlag>help</longFlag>
      <help>Display this help</help>
   </switch>
   <flaggedOption>
     <id>host</id>
     <stringParser>
       <classname>StringStringParser</classname>
     </stringParser>
     <required>true</required>
     <shortFlag>h</shortFlag>
     <longFlag>host</longFlag>
     <help>Server to use to scan for open ports</help>
   </flaggedOption>
   <unflaggedOption>
      <id>ports</id>
      <stringParser>
        <classname>IntegerStringParser</classname>
      </stringParser>
      <greedy>true</greedy>
      <list>true</list>
      <listSeparator>,</listSeparator>
      <help>List of ports to scan on the server</help>
    </unflaggedOption>
  </parameters>
</jsap>

Then you can use the following boilerplate code to initialize the parser and use it. Assuming the code is saved in file named “main.groovy” and the configuration file is named “main.jsap” and both are built into a .jar file called main.jar

JSAP jsap = new JSAP(main.getResource("main.jsap"));
JSAPResult config = jsap.parse(args)

if (config.getBoolean("help") || !config.success())
{
    println "Usage: java -jar main.jar " + jsap.usage
    println ""
    println jsap.help
    if (!config.success())
    {
        for (e in config.getErrorMessageIterator())
        {
            println e
        }
    }
    System.exit(0)
}

That is basically all the code you need to easily and powerfully parse command line arguments in Groovy.