Groovy: Quellprogramme direkt ausführen

Von kleineren Experimenten abgesehen wird man in der Praxis Groovy in der Regel nicht interaktiv mit groovysh und groovyConsole, sondern in der Form ausführbarer Dateien anwenden. Wie dies funktioniert, werden wir uns jetzt einmal ansehen.

Ein Beispielprogramm

Bearbeiten

Die verschiedenen Möglichkeiten, ein Groovy-Programm zu erstellen und in Gang zu setzen, demonstrieren wir am besten anhand eines einfachen Beispielprogramms. Wir wollen hier nicht noch einmal das alte „Hello World“ strapazieren, sondern eine kleines Hilfsprogramm schreiben, das auch wirklich einen gewissen Nutzen hat. Und bei der Gelegenheit erhalten Sie gleich einen ersten Eindruck davon, was Groovy-Programme mit Java-Programmen gemein haben und was sie unterscheidet.

Unsere kleine Utility dient dazu, alle vorhandenen System-Properties der Java-Laufzeitumgebung nach Namen sortiert auszugeben. Wenn dem Programm ein Argument mitgegeben worden ist, dann werden jedoch nur diejenigen System-Properties angezeigt, deren Name mit diesem Argument beginnen. In Java könnte das etwa so aussehen, wie hier dargestellt (wir verwenden dabei die Java-5-Syntax, aber keine Typparameter):

// Java
import java.util.*;
public class SystemProperties {

  public static void main (String[] args) {
    String prefix = args.length > 0 ? args[0] : "";
    ArrayList entries = new ArrayList();
    for (Map.Entry e : System.getProperties().entrySet()) {
      if (e.getKey().toString().startsWith(prefix)) {
        entries.add(e);
      }
    }
    Collections.sort(entries,new MeinComparator());
    for (Object e : entries) {
       System.out.println(e);
    }
  }
}

class MeinComparator implements Comparator {
  public int compare(Object o1, Object o2) {
     return ((Map.Entry)o1).getKey().toString()
         .compareTo(((Map.Entry)o2).getKey().toString());
  }
}

Wenn Sie ein wenig Java verstehen (und davon gehen wir in diesem Buch aus), wird Ihnen schnell klar sein, was das Programm macht: Es baut eine ArrayList aus den Namen den Map.Entry-Elementen auf, bei deren Schlüsselnamen der vorgegebene Präfix passt, sortiert die Liste mit Hilfe einer eigenen Comporator-Klasse und gibt sie schließlich der Reihe nach aus.

Sie kompilieren das Programm wie üblich:

> javac SystemProperties.java

Wenn sie es starten, erhalten Sie alle System-Properties, fein säuberlich sortiert ausgegeben. Um die Selektion nach Präfix zu testen, geben wir ein Argument ein, und definieren auch gleich eine passende zusätzliche System-Property namens user.laune in der Eingabezeile

> java -Duser.laune=neugierig SystemProperties user
user.country=DE
user.dir=C:\workspace\groovy\Kap-01\src
user.home=C:\Users\jst
user.language=de
user.laune=neugierig
user.name=jst
user.timezone=
user.variant=

Denselben Programmcode könnten Sie auch – mit demselben Ergebnis – als Groovy-Programm verwenden. Das ist nicht besonders eindrucksvoll, denn dazu brauchen Sie keine neue Programmiersprache, aber es funktioniert. Groovy gibt uns aber die Möglichkeit, das Programm von allerlei Ballast zu befreien, der eigentlich unnötig ist. Folgendes Beispiel zeigt eine Variante des SystemProperties, der einige der arbeitsparenden Möglichkeiten der Sprache Groovy nutzt.

prefix = args.length ? args[0] : ""
entries = []
for (e in System.properties) {
  if (e.key.startsWith(prefix)) {
  entries.add(e)
  }
}
entries.sort { e1,e2->e1.key.compareTo(e2.key) }
for (entry in entries) {
  println entry
}

Die Logik des Programms ist unverändert geblieben, wir haben aber allen Ballast entfernt, der in Java notwendig ist, damit Sie das Programm überhaupt kompilieren können, den Groovy aber nicht unbedingt benötigt, weil auch so zu erkennen ist, was das Programm tun soll. Dazu gehören manche Import-Anweisungen, die Klassendefinition mit der main()-Methode, die Deklaration der Variablen, Semikolons zur Begrenzung der Anweisungen an Zeilenenden, Klammern um einfache Methodenparameter (wie bei println() in der vorletzten Zeile.

Außerdem haben wir einige der Möglichkeiten von Groovy angewendet, mit weniger Code mehr auszudrücken, zum Beispiel beim Instantiieren einer ArrayList mit zwei eckigen Klammern (entries = []). Schließlich haben wir ein neues Konzept angewendet, das es in Java überhaupt nicht gibt: die Closure. Wir benutzen sie zum Sortieren der Liste entries anstelle der Klasse MeinComparator.

Vermutlich werden Ihnen jetzt nicht alle Details dieses Programms ganz klar sein – nach der Lektüre der beiden folgenden Kapitel werden Sie da klarer sehen – aber Sie können Sie sicher erkennen, wie der Code des Java-Programms zusammengeschrumpft ist. Dabei waren wir noch zurückhaltend bei der Komprimierung, damit Sie noch die Verwandtschaft mit Java deutlich erkennen können. Wenn man alle Möglichkeiten nutzt, ist es nämlich durchaus möglich, in Groovy das ganze Programm in eine einzige Anweisung zu schreiben, wie folgendes Beispiel zeigt.

System.properties.entrySet()
  .findAll { it.key.startsWith(args.length?args[0]:"") }
  .sort { x,y -> x.key<=>y.key }
  .each { println it }

Wir speichern das Programm unter dem Namen SystemPropertiesAnzeiger.groovy ab. Welche der drei Versionen wir nehmen, ist dabei völlig egal, denn sie werden alle drei von Groovy verstanden und tun genau dasselbe.

Tipp: Sie brauchen nicht unbedingt die Datei-Endung .groovy zu benutzen. Stattdessen können Sie auch eine der Endungen .gvy, .gy und .gsh verwenden oder die Endung ganz weglassen. Es hat sich aber mehr oder weniger eingebürgert, die Endung .groovy zu verwenden oder – nur in Unix-artigen Betriebssystemen – ganz auf die Endung zu verzichten, wenn das Programm ählich wie ein Shell-Skript direkt aufgerufen werden soll.

Ein Groovy-Programm direkt ausführen

Bearbeiten

Gehen Sie mit der Konsole in das Verzeichnis, in dem sich Ihr neues Skript SystemProperties.groovy befindet, und geben Sie die folgende Anweisung ein:

> groovy SystemProperties.groovy

Nun sollten alle in Java gesetzten System-Properties ordentlich sortiert erscheinen. Experimentieren Sie etwas herum, indem Sie beim Aufruf verschiedene Parameter mitgeben, um zu sehen, dass auch die richtigen Properties herausgefiltert werden. Sie können übrigens auch die Endung .groovy beim Aufruf weglassen; wenn Ihre Programmdatei eine der Endungen .groovy, .gvy oder .gy hat, wird sie auch dann noch gefunden.

Natürlich stehen Ihnen die betriebssystemspezifischen Möglichkeiten zur Verfügung, mit deren Hilfe Sie den Skript-Aufruf vereinfachen können. Unter Unix-ähnlichen Betriebssystemen etwa können Sie folgende Zeile an den Anfang Ihres Skripts einfügen:

#!/usr/bin/env groovy

Sorgen Sie noch dafür, dass das Skript ausführbar ist, dann brauchen Sie nur noch den Namen des Skripts einzugeben, damit es startet:

> chmod +x SystemProperties.groovy
> ./SystemProperties.groovy

Wenn Sie noch die Dateiendung entfernen und das Skript in ihr bin-Verzeichnis – oder ein anderes Verzeichnis im Unix-Pfad – legen, können Sie es einfach mit SystemProperties aufrufen wie jeden anderen Unix-Befehl.

Unter Windows könnte es sinnvoll sein, die Dateiendung .groovy mit dem Befehl groovy zu verknüpfen, damit Sie Groovy-Skripte per Mausklick aus dem Explorer starten können. Leider kann man aber unter Windows keine Verknüpfung mit einer Batchdatei wie dem Groovy-Startskript groovy.bat herstellen.

Im obigen Beispiel wäre das Ergebnis zwar nicht besonders beeindruckend, denn es würde nur kurz ein Fenster mit dem Ausgegebenen System-Properties erscheinen und sofort wieder verschwinden. Aber Sie können ja mit Groovy beispielsweise auch Programme mit grafischer Oberfläche erstellen, bei denen ein solcher Start durchaus angemessen ist.

Tipp: Eine Lösung für das Problem der Verknüpfung zwischen Dateiendung und Programm stellt der Groovy Native Launcher dar, für verschiedene Betriebssysteme, darunter auch Windows, verfügbar ist und der von den Groovy-Seiten heruntergeladen kann. Sie können das Programm einfach in das bin-Verzeichnis unter dem Groovy-Wurzelverzeichnis ablegen und anstelle des Skripts verwenden. Weitere Informationen unter http://docs.codehaus.org/display/GROOVY/Native+Launcher.

Für den Skriptaufruf gibt es noch eine Reihe von Optionen, die Sie sich mit groovy -h auflisten lassen können. In Befehlszeilenwerkzeuge sind sie noch einmal einzeln erläutert.