Ein häufiges Anwendungsfeld für Script-Sprachen ist die Analyse von Text, und weil Groovy unter anderem auch als Script-Sprache einsetzbar ist, kann man erwarten, dass sich Groovy bei dieser Art von Anwendung als nützliche Erweiterung von Java beweist.
Stellen wir uns vor, wir wollten eine Fremdsprache erlernen und die wichtigsten Vokabeln auswendig lernen. Am wichtigsten sind sicher die Worte, die in einem Text am häufigsten vorkommen. Diese wollen wir mithilfe eines kleinen Groovy-Scripts ermitteln.
Der Einfachheit halber sei unser Text wie in Listing 1 in einem String gespeichert. Wer meint, das sei unrealistisch und man sollte solche Information lieber aus einem File lesen, kann die erste Zeile durch def text = new File('data.txt').text ersetzen. So einfach ist das in Groovy.
def text ="""It takes two to program, two to program,till you really get the feeling for your test case,two to program, two to program,through the bands of code."""def words = text.split(/\W/).grep(~/\w+/)def frequencies = [:]words.each { word ->frequencies[word] = frequencies.get(word,0) + 1}def wordList = frequencies.keySet().toList()wordList.sort { frequencies[it] }def statistic = "\n"wordList[-1..-4].each { word ->statistic += word.padLeft(8) + ': 'statistic += frequencies[word] + "\n"}assert statistic =="""program: 4two: 4to: 4the: 2"""
assert statistic =="""program: 4two: 4to: 4the: 2"""
In typischer XP-Manier gehen wir rückwärts vor und überlegen uns, wie wir solch einen String erzeugen könnten. Angenommen, wir hätten eine nach Häufigkeit sortierte Wortliste und die Häufigkeit jedes Worts in einer Map gespeichert, dann könnten wir die letzen vier Worte in der Liste so in die Statistik einfließen lassen.
def statistic = "\n"wordList[-1..-4].each { word ->statistic += word.padLeft(8) + ': 'statistic += frequencies[word] + "\n"}
Die initiale Wortliste zu erzeugen ist ein Einzeiler. Wir spalten den Text an allen Nicht-Wort-Tokens (\W), und aus der resultierenden Liste behalten wir nur die Einträge, die ausschließlich aus Wort-Tokens bestehen und länger als ein Token sind (\w+). Die Map der Häufigkeiten ist initial leer und wird gefüllt, indem über alle Worte in der Liste iteriert und der jeweilige Wert in der Map inkrementiert wird. Bei der Ermittlung des Werts sorgt die get(word,0)-Methode dafür, dass unbekannte Worte die Häufigkeit 0 haben. Zu guter Letzt sortieren wir die Worte nach der ermittelten Häufigkeit.
def words = text.split(/\W/).grep(~/\w+/)def frequencies = [:]words.each { word ->frequencies[word] = frequencies.get(word,0) + 1}def wordList = frequencies.keySet().toList()wordList.sort { frequencies[it] }
Eine vergleichbare Implementierung in reinem Java ist massiv aufwendiger. Groovy unterstützt uns hier durch die leichte Verwendbarkeit von regulären Ausdrücken (split, grep), den leichtgewichtigen Umgang mit den Datentypen String, List, und Map sowie den zusätzlichen Methoden (get, sort) aus dem GDK. Groovy ist aber beileibe nicht auf textlastige Applikationen beschränkt. Man kann auch sehr leicht clientseitige GUIs bauen und mit Fern-Datenbeständen verbinden.
Rich Client für flickr
Als Nächstes bauen wir einen Bildbetrachter für die heute interessantesten Bilder bei flickr [1]. flickr hat seine eigene Meinung davon, welche Bilder interessant sind, und wir werden uns dieser Meinung anschließen. Wer sich bei flickr registriert, kann mithilfe seines persönlichen Schlüssels die URLs der interessantesten Bilder mittels eines REST-Services ermitteln. Diese wollen wir mithilfe eines minimalen Swing User Interface anzeigen, und zwar so, dass nach einem Klick auf das Bild das nächste Bild angezeigt wird. Abbildung 1 gibt einen Eindruck, wie dieses Interface aussehen kann. Sie werden natürlich andere Bilder sehen, denn diese ändern sich jeden Tag.import groovy.swing.SwingBuilderimport javax.swing.*key = 'KEY HIER EINTRAGEN'counter = 1def updateButton(button) {counter++def apiUrl = "http://www.flickr.com/services/rest/?" +"method=flickr.interestingness.getList&per_page=1&" +"page=$counter&api_key=$key"def rsp = new XmlParser().parse(apiUrl)def photo = rsp.photos.photo[0]def imageUrl = "http://static.flickr.com/" +"${photo.'@server'}/${photo.'@id'}_${photo.'@secret'}_m.jpg"button.icon = new ImageIcon(imageUrl.toURL())button.text = photo.'@title'return button}def frame = new SwingBuilder().frame(title: 'Groovy Flickr Viewer',defaultCloseOperation: WindowConstants.EXIT_ON_CLOSE) {updateButton( button (horizontalTextPosition: SwingConstants.CENTER,verticalTextPosition: SwingConstants.BOTTOM,actionPerformed: { event -> updateButton(event.source) }))}frame.pack()frame.visible = true
new SwingBuilder().frame {button()}
Die Methode updateButton setzt das Icon des Buttons auf das aktuelle flickr-Bild und den Button-Text auf den Text des Bildes. Das ist bei der initialen Darstellung des GUI zu tun und anschließend bei jedem Klick auf den Button. Damit ist das User Interface fertig.
Die Beschaffung der Bild-Informationen über den REST-Service ist denkbar einfach. Wir arbeiten mit jeweils nur einem Bild pro Seite, und damit wird die Seitennummer zur Bildnummer. Beides lässt sich in dem URL als Parameter angeben. Groovys XML Parser übernimmt den Verbindungsaufbau, das Empfangen des Ergebnisses und natürlich das Zerlegen in Objekte. Mithilfe eines GPath-Ausdrucks lokalisieren wir das erste (und einzige) <photo/>-Element. Von diesem benötigen wir die Attribute server, id, secret und title, um den effektiven Bild-URL zu ermitteln und den Button entsprechend zu befüllen.
Damit ist unsere zweite kleine Applikation fertig. Sie kombiniert verschiedene Aspekte der Groovy-Sprache und Laufzeitumgebung zu einer idiomatischen Lösung: das Builder Pattern, GStrings, um die URLs zu bauen, Groovy Beans inklusive Event Handling, XML plus Remoting und GPath sowie die Verwendung bestehender Java-Funktionalität (ImageIcon), und das Ganze als ausführbares Script, das keiner vorherigen Kompilation bedarf.
Groovy SOAP
REST-Services sind schön und gut und gerade in der dynamischen Welt der Script-Sprachen oftmals eine angemessene Lösung. Im Bereich der kommerziellen Softwareentwicklung sind typorientierte Protokolle allerdings stärker verbreitet, mit SOAP als dem bekanntesten Vertreter.Groovy ist für die Arbeit mit SOAP-Services bestens geeignet, sowohl auf der Client- wie auch auf der Serverseite, und erleichtert nicht nur das Testen und Prototyping von Applikationen, sondern ist auch reif für den produktiven Einsatz. Schon mit den üblichen "Bordmitteln" von Groovy kann man gut mit Web Services arbeiten [4], noch eleganter wird das Ganze jedoch mit dem Einsatz des GSOAP-Moduls, das man auf der Groovy-Website findet [3].
Mithilfe dieses Moduls kann man von Groovy aus sehr einfach einen Web Service aufrufen. Das momentane Wetter in Hamburg kann man z.B. so anfragen:
import groovy.net.soap.SoapClientdef url = 'http://www.webservicex.net/WeatherForecast.asmx?WSDL'def proxy = new SoapClient(url)def result = proxy.GetWeatherByPlaceName('Hamburg')println result.latitudeprintln result.details.weatherData[0].weatherImage
double add(double op1, double op2) {return (op1 + op2)}double square(double op1) {return (op1 * op1)}
import groovy.net.soap.SoapServerdef server = new SoapServer("localhost", 6990)server.setNode("MathService")System.out.println("start Math Server")server.start()
... und so geht's weiter
Groovy ermöglicht an vielen Stellen einen einfachen und direkten Zugang zu bestehenden Java-Funktionalitäten. Dies gilt vor allem auch für Javas reichhaltige Unterstützung für Webapplikationen, das Spring Framework und OR Mapping z.B. mit Hibernate.Wir haben hier drei Anwendungsbeispiele von Groovy gesehen, aber natürlich gibt es eine unerschöpfliche Menge weiterer Anwendungen. Groovy ist an keine Anwendungsdomäne gebunden und eignet sich für alle Arten dynamischer Programmierung. Viel Spaß beim Einsatz von Groovy und dem Erforschen neuer und spannender Einsatzgebiete!
Dierk König et al.: Groovy in Action, Manning, 2006




