Dem Greifen Leben einhauchen



Ähnliche Dokumente
Kommunikations-Management

In diesem Tutorial lernen Sie, wie Sie einen Termin erfassen und verschiedene Einstellungen zu einem Termin vornehmen können.

Diese Ansicht erhalten Sie nach der erfolgreichen Anmeldung bei Wordpress.

Adminer: Installationsanleitung

Eine Anwendung mit InstantRails 1.7

Mit der Maus im Menü links auf den Menüpunkt 'Seiten' gehen und auf 'Erstellen klicken.

Die Dateiablage Der Weg zur Dateiablage

Er musste so eingerichtet werden, dass das D-Laufwerk auf das E-Laufwerk gespiegelt

SICHERN DER FAVORITEN

Upgrade-Leitfaden. Apparo Fast Edit. Wechsel von Version 2 auf Version oder Wechsel von Version auf Version 3.0.

Kommunikations-Management

Durchführung der Datenübernahme nach Reisekosten 2011

GeoPilot (Android) die App

DOKUMENTATION VOGELZUCHT 2015 PLUS

ARCO Software - Anleitung zur Umstellung der MWSt

BSV Software Support Mobile Portal (SMP) Stand

Bedienungsanleitung für den SecureCourier

Die Beschreibung bezieht sich auf die Version Dreamweaver 4.0. In der Version MX ist die Sitedefinition leicht geändert worden.

Punkt 1 bis 11: -Anmeldung bei Schlecker und 1-8 -Herunterladen der Software

Urlaubsregel in David

iphone-kontakte zu Exchange übertragen

Stammzertifikat Importieren

Installationsanweisung Gruppenzertifikat

3 ORDNER UND DATEIEN. 3.1 Ordner

Lineargleichungssysteme: Additions-/ Subtraktionsverfahren

Bedienungsanleitung. Stand: Copyright 2011 by GEVITAS GmbH

Speichern. Speichern unter

! " # $ " % & Nicki Wruck worldwidewruck

LimeSurvey -Anbindung

Anton Ochsenkühn. amac BUCH VERLAG. Ecxel für Mac. amac-buch Verlag

Advoware mit VPN Zugriff lokaler Server / PC auf externe Datenbank

Inhalt. 1 Einleitung AUTOMATISCHE DATENSICHERUNG AUF EINEN CLOUDSPEICHER

Outlook 2000 Thema - Archivierung

Outlook. sysplus.ch outlook - mail-grundlagen Seite 1/8. Mail-Grundlagen. Posteingang

Wichtige Hinweise zu den neuen Orientierungshilfen der Architekten-/Objektplanerverträge

Fotogalerie mit PWGallery in Joomla (3.4.0) erstellen

Import, Export und Löschung von Zertifikaten mit dem Microsoft Internet Explorer

OUTLOOK-DATEN SICHERN

AutoCAD Dienstprogramm zur Lizenzübertragung

Ordner Berechtigung vergeben Zugriffsrechte unter Windows einrichten

Step by Step Webserver unter Windows Server von Christian Bartl

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Sichern der persönlichen Daten auf einem Windows Computer

HANDBUCH PHOENIX II - DOKUMENTENVERWALTUNG

Artikel Schnittstelle über CSV

32.4 Anpassen von Menüs und Symbolleisten 795i

Video-Tutorial: Einrichten einer Facebook Landing Page in der Facebook Chronik (Timeline)

Einrichtung des Cisco VPN Clients (IPSEC) in Windows7

TTS - TinyTimeSystem. Unterrichtsprojekt BIBI

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0)

Tipps und Tricks zu Netop Vision und Vision Pro

Wie halte ich Ordnung auf meiner Festplatte?

Installation/Einrichtung einer Datenbank für smalldms

Titel. SCSM ITIL - CMDB - neue CI Klasse erstellen und benutzen. Eine beispielhafte Installationsanleitung zur Verwendung im Testlab

Einkaufslisten verwalten. Tipps & Tricks

Kleines Handbuch zur Fotogalerie der Pixel AG

Datensicherung. Beschreibung der Datensicherung

Wordpress: Blogbeiträge richtig löschen, archivieren und weiterleiten

MailUtilities: Remote Deployment - Einführung

Newsletter. 1 Erzbistum Köln Newsletter

Virtueller Seminarordner Anleitung für die Dozentinnen und Dozenten

Updatehinweise für die Version forma 5.5.5

Import des persönlichen Zertifikats in Outlook Express

CodeSaver. Vorwort. Seite 1 von 6

Wie richten Sie Ihr Web Paket bei Netpage24 ein

Arbeiten mit dem Outlook Add-In

Diese Anleitung enthält Anweisungen, die nur durch erfahrene Anwender durchgeführt werden sollten!

INSTALLATION VON INSTANTRAILS 1.7

Upgrade-Leitfaden. Apparo Fast Edit 1 / 7

ACDSee Pro 2. ACDSee Pro 2 Tutorials: Übertragung von Fotos (+ Datenbank) auf einen anderen Computer. Über Metadaten und die Datenbank

Anleitung zur Webservice Entwicklung unter Eclipse

Ihre Interessentendatensätze bei inobroker. 1. Interessentendatensätze

Menü Macro. WinIBW2-Macros unter Windows7? Macros aufnehmen

Installationsanleitung für CashPro im Mehrbenutzerzugriff/Netzwerkbetrieb

Erstellung von Reports mit Anwender-Dokumentation und System-Dokumentation in der ArtemiS SUITE (ab Version 5.0)

Installationsanleitung CLX.PayMaker Home

Schrittweise Anleitung zur Erstellung einer Angebotseite 1. In Ihrem Dashboard klicken Sie auf Neu anlegen, um eine neue Seite zu erstellen.

Installation von NetBeans inkl. Glassfish Anwendungs-Server

Seite 1 von 14. Cookie-Einstellungen verschiedener Browser

Im Folgenden wird Ihnen an einem Beispiel erklärt, wie Sie Excel-Anlagen und Excel-Vorlagen erstellen können.

Live Update (Auto Update)

5.2 Neue Projekte erstellen

SEMINAR Modifikation für die Nutzung des Community Builders

:: Anleitung Hosting Server 1cloud.ch ::

Die Erstellung eigener Strukturprofile

Hex Datei mit Atmel Studio 6 erstellen

SMS4OL Administrationshandbuch

Erste Einstellungen im Alumni System

CALCOO Lite. Inhalt. 1. Projekt anlegen / öffnen. 2. Projekt von CALCOO App importieren

Der neue persönliche Bereich/die CommSy-Leiste

News & RSS. Einleitung: Nachrichten er-(veröffentlichen) und bereitstellen Nachrichten erstellen und bereitstellen

Neue Schriftarten installieren

Microblogging im TCC mit dem TCC Twitter

DELFI. Benutzeranleitung Dateiversand für unsere Kunden. Grontmij GmbH. Postfach Bremen. Friedrich-Mißler-Straße Bremen

Anleitung Lernobjekt-Depot (LOD)

Individuelle Formulare

4D Server v12 64-bit Version BETA VERSION

Task: Nmap Skripte ausführen

Firefox: Die Lesezeichen im Griff

Schulungsunterlagen zur Version 3.3

Transkript:

Griffon Das Tutorial Griffon im praktischen Einsatz Dem Greifen Leben einhauchen Quellcode auf CD! Nach der Einführung in die Konzepte von Griffon werden wir in diesem Teil Quellcode sehen und mit der Entwicklung beginnen. Dabei bekommen Sie Tipps für die Arbeit mit Griffon [1] sowie Lösungen zu bekannten Problemen. von Alexander Klein Bevor wir loslegen, soll zur Erinnerung die Problemstellung unseres Projekts Babylonier wiederholt werden. I18n-Unterstützung Zur Entwicklungsunterstützung von internationalisierten Anwendungen wird folgender Prozess umgesetzt: Während der Entwicklung werden.properties-dateien mit Key-Value-Paaren für Instanzen von java.util. ResourceBundle verwendet. Die Entwickler pflegen ausschließlich die.properties- Datei ohne Locale-Informationen, die im Weiteren als Default-Sprache bezeichnet wird. Eine Sprache wird als Basissprache für die Übersetzungen definiert und über einen redaktionellen Prozess aus der Default-Sprache erstellt und gepflegt. Die Basissprache wird an das Übersetzungsbüro übergeben und die übersetzten Texte werden parallel zu den Dateien der Default-Sprache und der Basissprache im Anwendungsquellcode abgelegt. Es muss überwacht werden, ob alle Texte in alle Sprachen übersetzt wurden, ob sich ein Text in der Default- Sprache geändert hat und neu übersetzt werden muss, oder gar ein Key aus der Anwendung gelöscht wurde. Für diesen Prozess muss unser Tool folgendes erfüllen: Quellpfad rekursiv nach den Dateien der Default- Sprachen von ResourceBundles durchsuchen und alle Key-Value-Paare mitsamt ihrem Ursprung in einer Datenbank ablegen. Dazu den Key-Status speichern: Key angelegt, verändert oder gelöscht Erfassen bzw. Ändern der Texte der Basissprache für die eingelesenen Keys Exportieren der Texte einer Sprache für das Übersetzungsbüro Importieren der übersetzten Texte für die jeweilige Sprache Erzeugen der sprachspezifischen ResourceBundle- Dateien an der richtigen Stelle im Quellpfad Das Layout Babylonier soll eine ordentliche Anwendung werden, deshalb betten wir es in ein gängiges Layout (Abb. 1, links: eine Menüzeile und Statusleiste, ein Navigationsbereich links und eine Fläche für die einzelnen Funktionen. Wenn externe Bibliotheken wie zum beispiel MiGLayout [2] als LayoutManager verwendet werden sollen, gibt es in Griffon drei Möglichkeiten, diese einzubinden: Man legt die.jar-datei in den /lib-ordner im Projektverzeichnis, dieses wird automatisch in den Classpath aufgenommen. Wenn die Bibliothek in einem Maven Repository zur Verfügung steht, kann sie als Abhängigkeit in griffon-app/config/buildconfig. unter griffon.project.dependency.resolution.dependencies eingetragen werden. Für einige Bibliotheken existieren Plug-ins [3]. Sie liefern nicht nur die.jar-datei mit, sondern bieten oft zusätzliche Funktionen. Mit griffon list-plugins kann man sehen, welche Plug-ins installierbar und welche installiert sind. Auf der Griffon- Webseite gibt es eine aufbereitete Liste mit weitergehenden Informationen. Plug-ins Für MiGLayout existiert ein Plug-in, das einen Builder- Knoten liefert und das wir mit dem Kommando griffon www.jaxenter.de javamagazin 9 2011 79

Das Tutorial Griffon install-plugin miglayout installieren. Weil das Menü und die Navigation mit Icons ausgestattet werden, installieren wir mit griffon install-plugin crystalicons Everaldos Listing 1: griffon-app/model/babylonianmodel. import.beans.bindable class BabylonianModel { @Bindable String currentelement = ' ' @Bindable String status Listing 2: griffon-app/views/babylonianview. build(babylonianactions application(title: 'Babylonian', name: 'MainFrame', // for shutdownhook size: [1000, 750], //pack: true //location: [50,50], locationbyplatform: true, iconimage: imageicon('/griffon-icon-48x48.png'.image, iconimages: [imageicon('/griffon-icon-48x48.png'.image, imageicon('/griffon-icon-32x32.png'.image, imageicon('/griffon-icon-16x16.png'.image] { menubar(build(babylonianmenu miglayout(layoutconstraints: 'fill' buttongroup(id: 'group' panel(id: 'navigation', constraints: 'dock west, width 150' { miglayout(layoutconstraints: 'wrap 1, fill', columnconstraints: 'fill', rowconstraints: 'fill' togglebutton(id: 'overviewbutton', action: overviewaction, buttongroup: group togglebutton(id: 'scanbutton', action: scanaction, buttongroup: group togglebutton(id: 'editbutton', action: editaction, buttongroup: group togglebutton(id: 'generatebutton', action: generateaction, buttongroup: group togglebutton(id: 'exportbutton', action: exportaction, buttongroup: group togglebutton(id: 'importbutton', action: importaction, buttongroup: group togglebutton(id: 'configbutton', action: configaction, buttongroup: group panel(id: 'content', constraints: 'dock center' { cardlayout( widget(app.views.overview.mainpanel, constraints: 'overview' widget(app.views.scan.mainpanel, constraints: 'scan' widget(app.views.edit.mainpanel, constraints: 'edit' widget(app.views.export.mainpanel, constraints: 'export' widget(app.views.import.mainpanel, constraints: 'import' widget(app.views.generate.mainpanel, constraints: 'generate' widget(app.views.config.mainpanel, constraints: 'config' controller.navigate('overview' panel(build(babylonianstatusbar, constraints: 'dock south' Crystal Icons Set [4]. Plug-ins können nicht nur Bibliotheken und Ressourcen liefern. Sie können Griffon sowohl zur Entwicklungszeit als auch zur Laufzeit erweitern: Skripte können zur Entwicklungszeit genutzt werden und erleichtern die Entwicklung (z. B. griffon crystalicon-selector öffnet ein Vorschaufenster zur Icon- Auswahl Builder und Builder-Knoten erweitern die Möglichkeiten, Views zu erstellen Plug-ins können neue Artefakte liefern (z. B. nutzt das Spock-Plug-in ein Artefakt für Test-Specs Sie können zusätzliche Funktionen wie einen Ladebildschirm oder neue Komponenten bieten Der Rahmen Nachdem wir im letzten Artikel die ModelViewCon troller-gruppe (im Weiteren MVCGroup genannt schon verwendet haben, ersetzen wir sie durch den Code in Listing 1 bis 3. BabylonianModel enthält nur zwei Eigenschaften vom Typ String, um eine Statusmeldung und die aktuelle Position in der Navigation anzuzeigen. Um die BabylonianView überschaubar zu halten, teilen wir die Oberfläche in mehrere Dateien auf und lösen die Erstellung der Actions (BabylonianActions, Listing 4, des Menüs (BabylonianMenu, Listing 5 und der Statuszeile (BabylonianStatusBar, Listing 6 heraus. Listing 3: griffon-app/controllers/ BabylonianController. import java.awt.event.windowevent import griffon.transform.threading class BabylonianController { // these will be injected by Griffon def model def view private def oldmvc // Navigation actions @Threading(Threading.Policy.SKIP def navigate = { mvcname -> model.currentelement = view."${mvcnamebutton".text view.group.setselected(view."${mvcnamebutton".model, true view.content.layout.show(view.content, mvcname app.event('navigation', [mvcname, oldmvc] oldmvc = mvcname // Menu actions def exit = { evt = null -> def wnd = app.windowmanager.findwindow('mainframe' wnd.processwindowevent(new WindowEvent(wnd, WindowEvent. WINDOW_CLOSING def about = { evt = null -> 80 javamagazin 9 2011 www.jaxenter.de

Griffon Das Tutorial Um auf die Actions im Menü und in der Navigation verweisen zu können, müssen sie zuerst erstellt werden. Das geschieht mit build(babylonianactions, wobei dieselbe Builder-Instanz wie bei BabylonianView für die Erstellung verwendet wird. Somit sind alle nicht lokalen Variablen und Komponenten mit id-attribut im gesamten Kontext des Builders verfügbar. BabylonianActions ist eine Sammlung von Actions, wie sie bei SwingBuilder [5] beschrieben ist. Die Attribute smallicon und swinglargeiconkey definieren die Icons in der Menüzeile und in den Navigationsbuttons. Das Crystal-Icon-Plug-in bietet uns mit dem Knoten crystalicon eine bequeme Möglichkeit, ein Icon aus der Bibliothek zu verwenden. Die Actions für Exit und About führen die gleichnamigen Closures in BabylonianControl ler aus. Alle anderen rufen die Methode navigate mit dem Namen der anzuzeigenden MVCGroup auf. Gehen wir zurück zu BabylonianView. Weil wir später das Applikationsfenster aus dem Code referenzieren müssen, bekommt der application-knoten den Namen MainFrame, dessen Größe wir auf 1000 x 750 definieren. Mit menubar(build(babylonianmenu binden wir die JMenuBar-Instanz, die das Script mit unserer Abb. 1: Layout für unseren Rahmen: Schema und Ergebnis Menüdefinition zurückliefert, an unser Fenster. Wenn ein SwingBuilder-Knoten eine Instanz als Parameter übergeben bekommt, wird keine neue erzeugt, sondern die übergebene Instanz an dieser Stelle verwendet. Die Menüleiste in BabylonianMenu besteht aus zwei Menüs: File und Help. Help hat ein JMenuItem, About, und wird mit glue( rechtsbündig ausgerichtet. Im File- Menü spiegeln wir die Einträge der Navigation und fügen den Punkt Exit hinzu (außer Mac-OS-X-System. Hier ist zu sehen, dass ein View-Skript ein normaler, ausführbarer Code ist und somit dynamisch generiert werden kann. Indem wir die Actions referenzieren, wer- Listing 4: griffon-app/views/babylonianactions. actions { action(id: 'overviewaction', name: 'Overview', shortdescription: 'Overview', mnemonic: 'O', accelerator: shortcut('o', smallicon: crystalicon(icon: 'agt_web', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'agt_web', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('overview' action(id: 'scanaction', name: 'Scan', shortdescription: 'Scan for unlocalized properties', mnemonic: 'S', accelerator: shortcut('s', smallicon: crystalicon(icon: 'filefind', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'filefind', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('scan' action(id: 'editaction', name: 'Edit', shortdescription: 'Edit translations', mnemonic: 'E', accelerator: shortcut('e', smallicon: crystalicon(icon: 'edit', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'edit', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('edit' action(id: 'generateaction', name: 'Generate', shortdescription: 'Generate localized properties', mnemonic: 'G', accelerator: shortcut('g', smallicon: crystalicon(icon: 'gear', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'gear', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('generate' action(id: 'exportaction', name: 'Export', shortdescription: 'Export keys for translation', mnemonic: 'x', accelerator: shortcut('ctrl E', smallicon: crystalicon(icon: 'download', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'download', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('export' action(id: 'importaction', name: 'Import', mnemonic: 'I', accelerator: shortcut('ctrl I', shortdescription: 'Import translated keys', smallicon: crystalicon(icon: 'folder_sent_mail', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'folder_sent_mail', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('import' action(id: 'configaction', name: 'Configure', shortdescription: 'Configure', mnemonic: 'C', accelerator: shortcut('ctrl f', smallicon: crystalicon(icon: 'configure', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'configure', size: 32, category: 'actions', closure: { evt = null -> controller.navigate('config' action(id: 'exitaction', name: 'Exit', shortdescription: 'Exit this application', mnemonic: 'x', accelerator: shortcut('ctrl X', smallicon: crystalicon(icon: 'exit', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'exit', size: 32, category: 'actions', closure: controller.exit action(id: 'aboutaction', name: 'About', shortdescription: 'Informations about this application', mnemonic: 'A', accelerator: shortcut('a', smallicon: crystalicon(icon: 'documentinfo', size: 16, category: 'actions', swinglargeiconkey: crystalicon(icon: 'documentinfo', size: 32, category: 'actions', closure: controller.about www.jaxenter.de javamagazin 9 2011 81

Das Tutorial Griffon Listing 5: griffon-app/views/babylonianmenu. import static griffon.util.griffonapplicationutils.isismacosx menubar { menu(text: 'File', mnemonic: 'F' { menuitem(overviewaction menuitem(scanaction menuitem(editaction menuitem(exportaction menuitem(importaction menuitem(generateaction menuitem(configaction if (!ismacosx { separator( menuitem(exitaction glue( menu(text: 'Help', mnemonic: 'H' { menuitem(aboutaction Listing 6: griffon-app/views/babylonianstatusbar. panel(id: 'statuspanel' { miglayout(layoutconstraints: 'fill', columnconstraints: '5[150][fill, right]' label(id: 'status', text: bind { model.status, horizontalalignment: SwingConstants.LEADING label(id: 'currentelement', text: bind { model.currentelement, horizontalalignment: SwingConstants.TRAILING Listing 7: griffon-app/views/overviewview. und alle anderen neuen Views scrollpane(id: 'mainpanel' { panel( { den die Informationen wie Text und Icon automatisch übernommen. Zurück in BabylonianView sehen wir ein JPanel mit unserer Navigation: eine ButtonGroup mit JToggleButtons für jeden Eintrag. Auch hier werden alle anzuzeigenden Informationen aus den Actions übernommen. Für den Hauptbereich verwenden wir ebenfalls ein JPanel, das CardLayout als LayoutManager bekommt. Das entspricht einer JTabbedPanel ohne Reiter, denn diese Funktion soll unsere Navigation bzw. das Menü übernehmen. Als Inhalt der einzelnen, reiterlosen Seiten fügen wir eine Komponente mit dem Namen mainpanel aus der entsprechenden View der MVCGroup hinzu. Leider ist es uns nicht unbedingt bekannt, welchen Typ mainpanel hat. Deshalb verwenden wir den Knoten widget, der zwar keine neue Instanz erzeugen, dafür aber alle Objekte vom Typ java.awt.component aufnehmen kann. Zudem existiert noch der Knoten container, der im Gegensatz zu widget andere verschachtelte Knoten aufnehmen kann. Der Inhalt Da wir noch gar keine MVCGroups für die einzelnen Funktionen haben, müssen wir die MVCGroups overview, scan, edit, generate, import, export und config mit griffon create-mvc overview etc. anlegen. Alle View- Skripte dieser MVCGroups sollen erst einmal wie Listing 7 aussehen und sind leere JScrollPanes. Zur Laufzeit müssen die MVCGroups instantiiert werden. Das kann man dynamisch mit dem Befehl buildmvcgroup(string groupname tun. Weil wir aber die MVCGroups beim Start instantiieren müssen, können wir das auch Griffon selbst erledigen lassen. In griffon-app/conf/application. gibt es unter application den Eintrag startgroups. Hier tragen wir MVCGroups ein, die beim Start instantiiert werden sollen. In unserem Fall also Folgendes: startupgroups = ['overview', 'scan', 'edit', 'generate', 'import', 'export', 'config', 'babylonian'] Bevor nun die Statusleiste aus Listing 6 eingebettet wird, müssen wir sicherstellen, dass beim Start die MVC- Group overview angezeigt wird. Dazu führen wir die navigate-methode programmatisch aus. Die Logik In BabylonianController steht unsere Logik, die über die Navigation und das Menü aufgerufen wird. Die Closure exit simuliert ein reguläres Schließen über den Schliessen-Button des Fensters, wobei wir über den WindowManager an das Fenster mit dem vorher vergebenen Namen MainFrame gelangen. Der Menüpunkt Help About soll hier nicht ausprogrammiert werden, deshalb schreiben wir nur eine leere Closure about. Alle anderen Aktionen rufen navigate auf. Wie im letzten Artikel schon erwähnt, werden alle Controller-Methoden standardmäßig außerhalb des Event Dispatch Threads aufgerufen. Dazu wird ein eigener Thread gestartet. Der Aufruf von navigate sollte das aber nicht tun, um Threads und Ressourcen zu sparen. Deshalb wird das Thread- Handling für diese Methode mit der Annotation @Threading(Threading.Policy.SKIP ausgeschaltet. 82 javamagazin 9 2011 www.jaxenter.de

Griffon Das Tutorial In navigate setzen wir zuerst den Buttontext des aktuell ausgewählten Menüpunkts in die Eigenschaft currentelement in unserem Modell, die an die Statusleiste gebunden ist. Dann wechseln wir die Selektion in der ButtonGroup und füllen den Inhaltsbereich mit der View des ausgewählten Menüpunkts. Zuletzt feuern wir ein Event Navigation, damit unsere Anwendung auf diese Selektion reagieren kann. Das Eventsystem Griffons Eventsystem ist zweigeteilt in Build-Events und Application-Events. Build- Events ermöglichen es, auf den Build-Prozess zu reagieren oder ihn gar zu beeinflussen. Jedes Griffon-Skript im Ordner scripts kann mit event("<eventname>", [<Parameter>] Nachrichten versenden. Im speziellen Griffon-Skript scripts/_ Events. können Listener registriert werden, indem man eine Closure mit dem Namen event<eventname> erstellt. Genauere Informationen sind im Griffon Guide, Kapitel 4 zu finden [6]. Application-Events sind Laufzeitevents. An einen zentralen Bus werden Events gesendet bzw. Listener registriert. An diesen Bus gelangen wir über die GriffonApplication, auf die wir von überall mittels der automatischen Variable app Zugriff haben: Mit app.event, app.eventasync und app.eventoutside, entsprechend der Logik des ThreadHandling aus dem vorigen Artikel, können Events versandt werden. Über app.addapplicationeventlistener werden Listener registriert. (Senior Consultant Java Technologies (m/w DSLs? J2SE & JEE? GUIs & RCP? Design & Architektur? Web, Mobile, Desktop? Um es dem Entwickler einfacher zu machen, sind automatisch alle Closures eines Controllers mit der folgenden Form als Listener registriert: on<eventname> = { args ->. So können z. B. in den Controllern der Inhaltsseiten Daten aktualisiert werden, sobald die View angezeigt wird: def onnavigation = { newmvc, oldmvc -> if(newmvc == 'overview' loaddata( Die Datei griffon-app/conf/events. fungiert als Platz für globale Event Handler, die schon vor dem Erstellen von MVCGroups funktionsbereit sind. Um eine Sicherheitsabfrage vor dem Schließen der Applikation zu implementieren, nutzen wir einen solchen globalen Event Handler und erstellen die Events. wie in Listing 8. Der Event Handler onbootstrapend wird aufgerufen, nachdem alle Plug-ins initialisiert wurden und bevor die erste MVCGroup erstellt wird. Zu diesem Zeitpunkt registrieren wir einen ShutdownHandler, der unsere Sicherheitsabfrage zeigt und ggf. das Beenden unterbricht. Im Griffon Guide, Kapitel 5 stehen nähere Details zu Application-Events und den Lifecycle-Events, die von Griffon gefeuert werden. Interessiert? Wir suchen Verstärkung für unser Java-Team! Listing 8: griffon-app/conf/events. import javax.swing.joptionpane onbootstrapend = { app -> app.addshutdownhandler([ canshutdown: { a -> return JOptionPane.showConfirmDialog( app.windowmanager.windows.find{it.focused, "Do you really want to exit?", "Exit", JOptionPane.YES_NO_OPTION == JOptionPane.YES_OPTION, onshutdown: { a -> ] as griffon.core.shutdownhandler Wir suchen Verstärkung für unser Java-Team! Weitere Informationen unter www.beone-group.com /stellenprofile Kontakt: evelyn.immegart@beone-group.com Tel. +49 711 656 93 100 Bewerbungsunterlagen bitte elektronisch an: recruitment@beone-group.com www.jaxenter.de javamagazin 9 2011 83

Das Tutorial Griffon Dienste Oft möchte man Funktionen zentralisieren, um sie wiederverwenden zu können. Das unterstützt Griffon mit dem Service-Konzept. Um den Zugriff auf unsere Datenbank zu zentralisieren, erstellen wir mittels griffon create-service database die Datei griffon-app/services/ babylonian/databaseservice. Ein Service ist eine reguläre Klasse, in der wir unsere Datenbankzugriffslogik implementieren können. Diese wird als Singleton behandelt, es wird von Griffon also nur eine Instanz automatisch instantiiert. Für Service-Klassen werden wie bei Controllern alle EventHandler Closures automatisch registriert. Um diese in einem Controller zu verwenden, müssen wir im Controller eine Variable mit dem Namen <ServiceName>Service erstellen. In unserem Fall also def databaseservice. Beim Erstellen des Controllers wird die Service-Instanz automatisch injiziert. Wenn von einem Service auf andere Services zugegriffen werden soll, benötigen wir Hilfe durch ein Inversionof-Control-Framework wie Spring, Guice oder Weld. Für diese drei Frameworks gibt es bereits Plug-ins, die wir z. B. mit griffon install-plugin spring installieren können. Nun sind auch Abhängigkeiten unter Services möglich. Der Quellcode und weitere Informationen Bis hierhin haben wir fast alle wichtigen Bereiche von Griffon behandelt. Der gesamte Quellcode des Babyloniers liegt bei und es sollte nun möglich sein, ihn zu verstehen. Er enthält Beispiele für Datenbankzugriffe, Tabellen, CRUD (Create/Read/Update/Delete usw. Der Quellcode verwendet weitere Plug-ins, die im Internet dokumentiert sind [3]. Als weitere Quellen für Griffon empfehle ich die Blogs von Andres Almiray [7], Nick Zhu [8] und mrhaki [9]. Zudem sind die Screencasts auf GriffonCast [10] sehenswert. Griffon beinhaltet Beispielanwendungen zur Veranschaulichung, dient aber auch als Hilfsmittel. Man findet sie unter $GRIFFON_HOME/samples auch unser Babylonier wird sich in Zukunft dort einreihen. Sehr zu empfehlen ist SwingPad (Abb. 3, eine der mitgelieferten Griffon-Beispielanwendungen, die das Erstellen von SwingBuilder-Code erheblich erleichtern. Während man auf der linken Seite Code schreibt, entsteht rechts daneben das Ergebnis. Zudem bringt Swing- Pad eine Menge an Beispielcode und Snippets mit. Fazit Griffon ist zwar zu großen Teilen in Groovy geschrieben und Groovy bietet als Sprache viele Vorteile, jedoch stellt die Verwendung von Groovy keinen Zwang dar. Es ist auch möglich, alle Artefakte in Java oder mittels Plug-ins auch in anderen Sprachen wie Clojure oder Scala zu schreiben. Griffon kann nicht zaubern, aber die Desktopentwicklung wird erheblich erleichtert. Die Kombination aus Convention over Configuration mit einer Vielzahl an Plug-ins liefert einen gut gefüllten Werkzeugkasten, ohne ein Korsett anzulegen. Abb. 2: Unsere fertige Applikation Overview Alexander Klein ist Senior Consultant bei der BeOne Stuttgart GmbH und seit 15 Jahren im Java-Umfeld als Entwickler, Architekt, Coach und Trainer hauptsächlich im Rich-Application-Umfeld tätig. Er ist bekennender Groovy-Jünger und Commiter bei Griffon. Links & Literatur Abb. 3: SwingPad: ein hilfreiches Tool in und für Griffon [1] Griffon-Webseite: http://griffon.codehaus.org [2] MiGLayout: http://www.miglayout.com [3] Griffon-Plug-ins: http://griffon.codehaus.org/plugins [4] Crystal Icons Set: http://everaldo.com/crystal [5] SwingBuilder: http://.codehaus.org/swing+builder [6] Griffon Guide: http://dist.codehaus.org/griffon/guide/index.html [7] Blog von Andres Almiray: http://www.jroller.com/aalmiray [8] Blog von Nick Zhu: http://nzhu.blogspot.com [9] Blog von mkhaki: http://mrhaki.blogspot.com [10] GriffonCast: http://griffoncast.com 84 javamagazin 9 2011 www.jaxenter.de