Mais conteúdo relacionado
Semelhante a Von Java Zu Groovy (17)
Von Java Zu Groovy
- 1. W-JAX Workshop
Von Java zu Groovy
Dierk König Johannes Link Tammo Freese
dierk.koenig@canoo.com business@johanneslink.net business@tammofreese.de
- 2. Herzlich Willkommen!
Dierk König
• Canoo Engineering AG, Basel (CH)
• Rich Internet Applications
Produkte, Projekte, Beratung, Schulung
www.canoo.com
• Trainer, Berater, Softwareentwickler
• Groovy- und Grails-Committer
• Autor: Groovy in Action
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 3. Herzlich Willkommen!
Johannes Link
• Unabhängiger Softwarecoach
• johanneslink.net
• Autor: Softwaretests mit Java
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 4. Herzlich Willkommen!
Tammo Freese
• Freiberuflicher Diplom-Informatiker
• Extreme Programmer (Ruby/Java/...)
• http://tammofreese.de
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 5. Agenda
• Groovy Übersicht
• Präsentation, Demo, Übung
• Integration Java/Groovy
• Präsentation, Demo, Übung
• Meta-Programmierung in Groovy
• Präsentation, Übung
• Einfacher Testen
• Präsentation, Übung
• Einsatz von Groovy
• Präsentation, Diskussion
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 6. Groovy in der Sprachlandschaft
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 7. Dynamik ist mehr als Scripting
• Meta-Objekt-Protokoll • Auf original JDK Klassen
Eigenschaften und Fähigkeiten arbeiten, aber trotzdem mehr
zur Laufzeit dynamisch Funktionalität haben (GDK)
hinzufügen oder ändern • Nie mehr
„incomplete library smell“
• Methodenaufrufe abgreifen • Nicht nur Abhängigkeiten
• Tracing und Debugging werden injizierbar, sondern
• Mocks und Stubs auch Verhalten
• Beliebige Methoden und und zwar „non-intrusive“!
Eigenschaften bereitstellen • Patterns nur einmal schreiben
• Ähnlich „AOP“ oder „Mixin“ • Vermeidet Code-Duplikation
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 8. Groovy Bonbons
• Volle Objektorientierung • Closures
keine primitiven Datentypen • GPath
• Operatoren auf Objekten effiziente Objektnavigation
selbst implementierbar • GroovyBeans
• Multimethoden Properties und Events
Dispatch am dynamischen Typ Deklaration und Zugriff
• Klassifikatoren (grep, switch)
• Literale Deklaration von Listen • Der ganze Rest
(Arrays), Maps, Ranges und Templates, Builder, Swing, Ant,
Regular Expressions Markup, XML, HTML, Parser,
• Mächtige Operatoren [] SQL, XML-RPC, Windows
• Interpolierte Strings (GString) Scripting, GORM, Grails, Unit
Tests, Mocks,...
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 9. Groovy Vorspeise
System.out.println(quot;Hello World!quot;); • optional ; ()
println 'Hello, World!' GDK method
def vorname = 'Stefan' • Typ optional
println quot;$vorname, ich hol' den Wagen.quot; • GString
String lang = quot;quot;quot;Du, ${vorname}, der
Wagen steht eine Zeile weiter.quot;quot;quot; • java.lang.String
assert 0.5 == 1/2 • BigDecimal.equals
def printSize(obj) { • optionales
print obj?.size() duck typing
} • safe dereferencing
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 10. Regular Expressions
if (quot;Hello World!quot; =~ /Hello/) • Find operator
if (quot;Hello World!quot; ==~ /Hellob.*/) • Match operator
~/Hellob.*/ • Pattern operator
quot;Hello World!quot;.replaceAll(/w+/){ match ->
• Replace mit
match.size()
berechneten
} Werten
-> 5 5!
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 11. Listen, Maps, Ranges
def leer = [] def leer = [:]
def voll = [1, 2, 'W-JAX'] def voll = [a: 1, b: 2]
assert voll + voll == voll * 2 assert voll['a'] == 1
assert voll.a == 1
assert voll[0] == 1
assert voll[0..1] == [1, 2] voll.a = 2
assert voll == [a: 2, b: 2]
voll[0..1] = [0, 1, 2, 3]
assert voll == def inclusive = 'a'..'z'
[0, 1, 2, 3, 'W-JAX'] inclusive.each {…}
def exclusive = 0..<10
for (i in exclusive) {…}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 12. Closures
3.times { println 'Hi' } def houston(Closure machwas) {
(10..1).each { countdown ->
[0, 1, 2].each { number -> machwas(countdown)
println number }
} }
[0, 1, 2].each { println it }
houston { println it }
def printit = { println it }
[0, 1, 2].each printit
new File('/data.txt').eachLine {
println it
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 13. GroovyBeans und GPath
class Dir { assert root.dirs.name ==
String name ['a','b']
List dirs
} assert root.dirs.name*.size() ==
[1, 1]
def root =
new Dir (name: '/', dirs: [ Dir.methods.name.
new Dir (name: 'a'), grep(~/(g|s)et.*/)
new Dir (name: 'b') -> [getName, setName, getDirs,
]) setDirs, …]
assert root.dirs[0].name == 'a'
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 14. Kontrollstrukturen
if (1) switch (10) {
if (object) case 0 : println 'ist 0'; break
if (list) case 0..9 :…
case [8,9,11] :…
for (item in iterable) { } case Float :…
case {it%3 == 0}: …
[a:1, b:2].each { key, value -> case ~/../ :…
println quot;$key : $valuequot; default :
} }
throw, catch, finally implementiere isCase()
while, eachWithIndex, eachLine
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 15. Ausgewählte Methoden
col.sort() obj.find { }
col.sort { a, b -> a <=> b } obj.findAll { }
col.sort { a -> a.foo() } obj.grep (case)
obj.findIndexOf { }
+, -, *, <<, ==, [], []=
remove(pos), remove(item), obj.collect { }
removeAll(col), unique(), obj.each { }
size(), pop(), flatten(), reverse() obj.eachWithIndex { item, i -> }
intersect(col), disjoint(col),
max(), min(), sum(), obj.every { }
count(item), join(trenner), obj.any { }
inject(start) { temp, item -> }
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 16. Toolbox
• Original Java support für
Profiling, Debugging,
Code Coverage, etc.
• IDE Integrations
• Eclipse: eigene Arbeitsgruppe
• IntelliJ IDEA: JetBrains
• NetBeans: Sun Microsystems
• Editoren
Emacs, Vim, UltraEdit, Textmate, ...
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 17. Demo I
• Arbeiten mit der groovyConsole
• Erstelle Klasse Person mit Property name
• Erstelle Liste von Person Objekten
• Schreibe die Liste aller Namen, durch Komma getrennt
• Suche nach Personen mit 'a' im Namen
• Variationen
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 18. Demo II
• Erweitere Person um 'tags'
• Schreibe alle tags
• Entferne Doppler
• Sortiere nach Taglänge
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 19. Übung I
• Sortiere die Liste von Personen nach der Anzahl ihrer
tags
• Geeks: Säuberungsaktion
• Lösche alle Personen ohne Groovy tag
• Ultra-Geeks: Tag quot;Cloudquot;
• Sortiere die Liste eindeutiger tags nach ihrer
Häufigkeit absteigend
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 21. Groovy Objekte sind Java Objekte
• Egal ob Scripts oder Klassen,
immer werden Objekte vom Typ
java.lang.Class erzeugt
• Verzahnung
Compilezeit / Laufzeit
• JVM Sicherheitsmodell
• JVM Klassen sind geschlossen
Groovy Klassen scheinen offen
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 22. Direktmodus contra Precompiled
• Kompilation
• groovyc -> *.class files
• Cross-compiler behebt Henne-Ei Problem
IDEs mit cross-compilation
javac auch bald soweit?
• Gemeinsame Interfaces sind trotzdem nützlich
• Direktmodus fühlt sich an wie 'interpretiert',
ist es aber nicht!
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 23. Dynamische Evaluation zur Laufzeit
• Eval.x (users,
quot;x.grep{ it.salary > 100000 }.address.townquot;);
// me, x(), xy(), xyz()
• GroovyShell, parse, binding, evaluate (String|File|Url)
• GroovyScriptEngine
für viele Sourcen und Pfadunterstützung
• GroovyClassLoader (transparente Quellen, Security!)
• Bean Scripting Framework und JSR-223 (Java 6)
• Groovy Spring Beans
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 25. Methodenaufrufe in Java und Groovy
In Java: In Groovy:
• Zur Übersetzungszeit wird • Zur Ausführungszeit wird
festgelegt, welche Methode dynamisch ermittelt,
auf welcher wie auf einen Methodenaufruf
Vererbungshierarchie reagiert wird
aufgerufen wird • Zur Ausführungszeit wird
dynamisch ermittelt,
wie auf einen Property-Zugriff
reagiert wird
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 26. Dynamischer Aufruf
class X { def x = new X()
def a = 1 def method, property
def b = 2
method = 'foo'
def foo () {
assert 1 == x.quot;$methodquot;()
1
}
method = 'bar'
def bar () { assert 2 == x.quot;$methodquot;()
2
} property = 'a'
} assert 1 == x.quot;$propertyquot;
property = 'b'
assert 2 == x.quot;$propertyquot;
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 27. Multimethoden
class MultiMethods { def mm = new MultiMethods()
def foo(String s) { 'string' }
def foo(Object o) { 'object' }def arg = 'a string'
def foo(Integer i) { 'integer' }
assert 'string' == mm.foo(arg)
}
arg = 42
assert 'integer' == mm.foo(arg)
class Complex {
def real, im arg = []
boolean equals(Complex other) assert 'object' == mm.foo(arg)
{
this.real == other.real && assert new Complex(real:1.0, im:2.0)
this.im == other.im .equals(new Complex(real:1.0, im:2.0))
} assert !new Complex(real:1.0,im:2.0)
}
.equals(new Object())
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 28. Kategorien
class FooCategory { • Kategorie: Klasse mit
static def foo(List self, arg) { statischen Methoden
self + [arg]
}
• Erstes Argument ist
static def foo(String self, arg) {
Empfänger der
self + arg Methode
} • Weitere Argumente
} sind Parameter der
Methode
use(FooCategory) {
assert [123].foo(456) == [123, 456]
• Verwendung der
assert '123'.foo('456') == '123456'
Kategorie mittels
}
use(...) { ... }
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 29. invokeMethod()
class PrintMethodInvocations { • Fängt Aufrufe nicht
def invokeMethod(String name, args) { vorhandener Methoden
println quot;Invoked $name with $argsquot;
• Erstes Argument ist
args.size()
Name der Methode
}
}
• Zweites Argument sind
Parameter der Methode
x = new PrintMethodInvocations()
• Implementiert die Klasse
assert 2 == x.foo(1,2) das Marker Interface
assert 3 == x.bar('just', 'a', 'test') GroovyInterceptable,
werden alle
Methodenaufrufe
gefangen!
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 30. methodMissing()
class PrintMissingMethods { • Seit Groovy 1.1
def methodMissing(String name, args) {
println quot;missing $name with $argsquot;
args.size()
• Wie invokeMethod()
}
} • Unterschied: Wird immer
nur für fehlende
x = new PrintMissingMethods() Methoden aufgerufen
assert 2 == x.foo(1,2)
• Empfehlung: Bei 1.1
assert 3 == x.bar('just', 'a', 'test')
methodMissing()
verwenden, falls möglich
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 31. Methoden zur Laufzeit hinzufügen (1)
String.metaClass.upperCaseCount = { -> • Seit Groovy 1.1
(delegate =~ /[A-Z]/).size()
}
• Sogenannte
assert 1 == quot;Onequot;.upperCaseCount() ExpandoMetaClass
assert 2 == quot;TWoquot;.upperCaseCount()
assert 3 == quot;ThReEquot;.upperCaseCount()
• Methode definieren:
Property der Metaklasse
Integer.metaClass.'static'.
auf eine Closure setzen,
theAnswerToEverything = { -> 42 }
fertig!
assert 42 == Integer.theAnswerToEverything()
• Auch Klassenmethoden
können definiert werden
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 32. Methoden zur Laufzeit hinzufügen (2)
ExpandoMetaClass.enableGlobally() • Defaultmäßig funktionieren
ExpandoMetaClasses nicht
Map.metaClass.toArray = { -> bei Vererbung
delegate.collect {
key, value -> [key, value]
}
• Kann aber eingeschaltet
} werden
assert [['a', 1], ['b', 2]] == • Dann können sogar auf
[a:1, b:2].toArray() Interfaces Methoden für
alle implementierenden
Klassen definiert werden
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 33. Wie passt das alles zusammen? (1)
• Groovy-Methodenaufruf: object.aMethod(arguments)
bedeutet (vereinfacht)
• Für Java-Objekte:
MetaClassRegistry.getMetaClass(object.getClass()).
invokeMethod(object, quot;aMethodquot;, arguments);
• Für Groovy-Objekte:
object.getMetaClass().
invokeMethod(object, quot;aMethodquot;, arguments);
• Für Groovy-Objekte, die GroovyInterceptable implementieren:
object.invokeMethod(quot;aMethod“);
• Der Methodenaufruf wird also meist
an eine Metaklasse delegiert
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 34. Wie passt das alles zusammen? (2)
• Die Metaklasse
• versucht, eine passende Methode in den Kategorien zu finden
• versucht, eine passende Methode bei sich zu finden
• ruft methodMissing() auf, falls keine Methode gefunden wurde
• Methoden der Metaklasse (Auswahl)
• invokeMethod(object, name, params);
• invokeConstructor(params);
• getProperty(object, name);
• setProperty(object, name, value);
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 37. Warum einfacher?
• assert ist eingebaut - und immer eingeschaltet
• Einfacher: Literale Testdaten, Selektionen, Duplikationen vermeiden
• class MyTest
extends GroovyTestCase
extends junit.framework.TestCase
assertArrayEquals(..)
assertLength(..)
assertContains(..)
assertScript(String script)
shouldFail(exceptionType, closure)
• Es ist möglich - und manchmal auch sinnvoll - Unit Tests
für Java Code in Groovy zu schreiben
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 38. Isolierte Unit Tests im Objektgeflecht
Ein »Unit Test« soll eine Klasse, ein Objekt oder eine Gruppe von Klassen und
Objekten in Isolation testen
• Problem: Programmeinheiten arbeiten nicht isoliert.
• Aufbau der Testumgebung ist oft aufwändig
• Testen von Ausnahmesituationen
• langsame Tests bei Überschreiten der Systemgrenzen
• Lösung: Für die Dauer der Tests ersetzen wir Abhängigkeiten zu
mitwirkenden Units durch die Einführung einfacher »Attrappen«
• Tests laufen schnell
• Auftretende Fehler sind leicht zu lokalisieren
• Geringer Aufwand für Aufbau der Testumgebung
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 39. Attrappen im Test
TestCase ClassUnderTest
<<interface>>
Collaborator
<<replacement>> RealCollaborator
Collaborator
Attrappe
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 40. Wie testet man euroAmount() ?
public class EuroCalculator {
private RateProvider provider;
public void setProvider(RateProvider provider) {
this.provider = provider;
}
public double euroAmount(double amount, String curr) {
return amount * provider.getRate(curr, quot;EURquot;);
}
}
public interface RateProvider {
double getRate(String fromCurr, String toCurr);
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 41. Attrappe / Dummy mit Java
public class EuroCalculatorTest extends TestCase {
public void testEuroAmount() {
RateProvider provider = new DummyRateProvider();
EuroConverter calculator = new EuroCalculator();
calculator.setProvider(provider);
assertEquals(7.5,
converter.euroAmount(5.0, quot;CHFquot;), 0.001);
}
}
public class DummyRateProvider implements RateProvider {
public double getRate(String from, String to) {
return 1.5;
}
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 42. Einfaches Dummy-Objekt mit Groovy
class EuroCalculatorTest extends GroovyTestCase {
def calculator = new EuroCalculator()
void testEuroAmount() {
calculator.provider = { from, to -> 1.5d } as RateProvider
assert 7.5 == calculator.euroAmount(5.0, quot;CHFquot;)
}
}
Wichtig: Anzahl der Closure-Parameter muss stimmen!
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 43. Crash Test Dummies
class EuroCalculatorTest...
void testEuroAmountWithUnknownCurrency() {
def dummy = {from, to ->
throw new IllegalArgumentException() } as RateProvider
calculator.provider = dummy
assert 0 == calculator.euroAmount(5.0, quot;XYZquot;)
}
void testProviderNotAvailable() {
def dummy = {from, to ->
throw new ProviderNotAvailableException() } as RateProvider
calculator.provider = dummy
shouldFail(EuroCalculatorException) {
calculator.euroAmount(5.0, ”CHFquot;)
}
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 44. Komplexere Attrappen (1)
interface RateProvider {
double getRate(String from, String to)
String providerName()
}
void testGetRateParametersAndProviderName() {
def mock = [
providerName: {quot;open ratexquot;},
getRate: {from, to ->
assert from == quot;CHFquot;
assert to == quot;EURquot;
2.0d }
] as RateProvider
assert quot;open ratexquot; == mock.providerName()
assert 2.0d == mock.getRate(quot;CHFquot;, quot;EURquot;)
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 45. Komplexere Attrappen (2)
interface RateProvider {
double getRate(String from, String to)
}
class ProviderMock implements RateProvider {
def returns, expects
double getRate(String from, String to) {
assert expects.from == from
assert expects.to == to
return returns.rate
}
}
void testStaticMock() {
def mock = new ProviderMock(
returns: [rate: 2.0d],
expects: [from: quot;CHFquot;, to: quot;EURquot;]
)
assert 2.0 == mock.getRate(quot;CHFquot;, quot;EURquot;)
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 46. Übung 4: Tests, Tests, Tests
Übung 4a
Schreiben Sie einen Test, der überprüft, dass auch der quot;umgekehrtequot; (to-
>from) Wechselkurs vom RateProvider ausreicht, falls der quot;richtigequot;
(from->to) nicht vorhanden ist. Decken Sie mit dem Test den Fehler in
der Implementierung auf und korrigieren Sie ihn!
Übung 4b
Schreiben Sie einen oder mehrere Tests, die überprüfen, dass bereits
ermittelte Wechselkurse gecacht werden. Implementieren Sie
anschließend diese Funktionalität im EuroCalculator!
Übung 4c
Schreiben Sie einen oder mehrere Tests, die überprüfen, dass gecachte
Wechselkurse nach einer Stunde neu vom RateProvider geholt
werden. Implementieren Sie anschließend diese Funktionalität im
EuroCalculator!
Anmerkung: Die Zeit ist im EuroCalculator über die timer-Property
verfügbar
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 48. 7 Patterns zum Einsatz von Scripting
• Alleskleber
• Weiches Herz
• Endoskopische Operation
• Kluge Anpassung
• Grenzenlose Offenheit
• Heinzelmännchen
• Prototyp
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 49. #1 Alleskleber
• Applikationen aus bestehenden Komponenten
zusammenbauen
• Java ist gut geeignet für stabile Infrastruktur: Middleware,
Frameworks, Widget Sets, Services
• Scripting ist gut geeignet flexible (agile) Applikationslayer:
View und Controller
• Grails, GSP, JBoss Seam, WebWork, Struts 2 Actions,...
• Beispiel: Zusammenzug von XML Parser, Java
Networking und Swing Widget Bibliothek, um einen
Standard-RSS Feed darzustellen
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 50. Alleskleber Beispiel: RSS Reader
def base = 'http://news.bbc.co.uk/rss/newsonline_uk_edition/'
def url = base +'front_page/rss091.xml'
def items = new XmlParser().parse(url).channel[0].item
def swing = new groovy.swing.SwingBuilder()
def frame = swing.frame(title: 'Top 10 BBC News') {
scrollPane {
table() {
tableModel(list: items[0..9]) {
closureColumn(header: 'title',
read: { item -> item.title.text() } )
closureColumn(header: 'text',
read: { item -> item.description.text() } )
} } } }
frame.pack(); frame.show()
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 51. #2 Weiches Herz
• Fachliche Modelle auslagern
• Vorgegebenes Applikationsgerüst in Java
• Fachlichen Erkenntnisfortschritt ermöglichen:
Entitäten, Beziehungen und Verhalten durch Scripting
flexibel halten
• Anwender: Rule Engines (JBoss Rules,
groovyrules.dev.java.net, JSR-94), Grails,
Versicherungswesen: Mutual of Omaha
• Beispiel: Berechnungsregeln für Boni
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 52. Weiches Herz Beispiel: Bonusberechnung
umsatz = mitarbeiter.umsatz
switch(umsatz / 1000) {
case 0..100 : return umsatz * 0.04
case 100..200 : return umsatz * 0.05
case {it > 200} : bonusClub.add(mitarbeiter)
return umsatz * 0.06
}
Binding binding = new Binding();
binding.setVariable(quot;mitarbeiterquot;, mitarbeiter);
binding.setVariable(quot;bonusClubquot;, bonusClub);
GroovyShell shell = new GroovyShell(binding);
File script = new File(filename);
float bonus = (float) shell.evaluate(script);
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 53. #3 Endoskopische Operation
• Minimal-invasive Eingriffe quot;in vivoquot;
• Viele Notwendigkeiten für Anpassungen
ad-hoc Anfragen sind nicht vorhersehbar
• Schlüsselloch für die Live Ausführung von Scripts
• Unglaublich wertvoll für
Produkt-Support, Fehleranalyse, Hot-Fixes, Notfälle
• Anwender: Oracle JMX Beans, XWiki, SnipSnap, Ant,
Canoo WebTest, Grails Console, ULC Admin Console
• Beispiel: ein Live-Groovy Servlet
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 54. Endoskopische Operation: im Servlet
Probleme mit der Datenbank Verbindung?
def ds = Config.dataSource
ds.connection = new DebugConnection(ds.connection)
Gefährliche Benutzer rauswerfen
users = servletContext.getAttribute('users')
bad = users.findAll { user -> user.cart.items.any { it.price < 0 } }
servletContext.setAttribute('users', users - bad)
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 55. #4 Kluge Anpassung
• Konfigurationen mit Ausführungs-Logik,
aka Smart Configuration
• Ersatz für XML-Konfigurationen
• Mit Referenzen, Schleifen, Bedingungen, Vererbung,
Ausführungslogik, Umgebungsermittlung, ...
• Typischer Anwendungsfall für domänen-spezifische
Sprachen (DSLs), Groovy Builder, Grails plugins,
Benutzer-Macros, Function Plotter
• Beispiel: Navis SPARCS N4
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 56. Smart Config Beispiel: Container Routing
def ensureEvent = { change ->
if (! event.getMostRecentEvent(change) {
event.postNewEvent(change)
}
}
switch (event.REROUTE_CTR) {
case 'OutboundCarrierId' :
ensureEvent('CHANGE_VSL')
break
case 'POD' :
if (! event.CHANGE_VSL) ensureEvent('CHANGE_POD')
break
}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 57. #5 Grenzenlose Offenheit
• Jede Zeile Code wird änderbar
• Manchmal sind die vorgesehenen Variationspunkte nicht
ausreichend
• Einfache Änderungen ohne langwierigen Setup für
Kompilation und Deployment
• Perl, PHP, Python, etc. machen es vor
• Beispiel: groovyblogs.org
(Grails Applikation)
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 58. #6 Heinzelmännchen
• Repetitive Aufgaben automatisieren
• Automatisierter Build, kontinuierliche Integration,
Deployment, Installationen, Server-Überwachung,
Reports, Statistiken, Erzeugen von Dokumentation,
funktionale Tests, HTML Scraping, Web Fernbedienung,
XML-RPC, WebServices
• Anwendungen mit Ant, Maven, AntBuilder, Gant, Canoo
WebTest, Grails scaffolding, ...
• Beispiele: dynamisch Mails per Ant verschicken,
Skripte mit Ant verbinden
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 59. Heinzelmännchen Beispiel: Mail schicken
def users = [ [name:'Dierk', email:'dierk.koenig@canoo.com'],
[name:'Other', email:'other@no.such.server'] ]
def ant = new AntBuilder()
for (user in users) {
ant.mail(mailhost: 'my.email.server', subject: 'build ist fertig') {
from(address: 'my@email.com')
to (address: user.email)
message( quot;quot;quot;
Hallo ${user.name},
Der Build ist mal wieder fertig:
${new Date().toGMTString()} quot;quot;quot; )
} }
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 60. Heinzelmännchen II: Musisches Ant
<groovy>
import org.apache.tools.ant.*
import org.jfugue.*
project.addBuildListener(new PlayListener())
class PlayListener implements BuildListener {
def play = { new Player().play(new Pattern(it)) }
void buildStarted(event) { }
void buildFinished(event) { }
void messageLogged(event) { }
void targetStarted(event) { play(quot;D Equot;) }
void targetFinished(event) { play(quot;C5majquot;) }
void taskStarted(event) { }
void taskFinished(event) { }
}
</groovy>
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 61. #7 Prototyp
• Machbarkeitsstudien auf der Zielplattform
• quot;Spikesquot; für technologische oder algorithmische Ideen mit besserer
Ausdrucksmächtigkeit, schnellerem Feedback und besseren
Analysemöglichkeiten
• Wahlmöglichkeit für spätere (Teil-)Portierung nach Java
• Anwendungen: Benutzerfeedback über Domänenmodell mit
funktionalem Grails Prototyp abfragen, Java Bildbearbeitungs-
Algorithmen
• Beispiel: Primzahlzerlegung
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 62. Prototyp Beispiel: Primzahlzerlegung
boolean isPrime(x) { return ! (2..<x).any { y -> x % y == 0 } }
int primeBelow(x) { (x..1).find { isPrime(it) } }
List primeFactors(x) {
if (isPrime(x)) return [x]
int p = primeBelow(x)
while (p > 1) {
if (x % p == 0) return [p, *primeFactors(x.intdiv(p))]
p = primeBelow(p-1)
}
}
for (n in 100..110) { println quot;$n : quot;+primeFactors(n)}
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 63. Primzahlzerlegung: Modulo ops zählen
class ModCountCategory {
static int count = 0
static int mod(Integer self, Integer argument) {
count++
return self - argument * self.intdiv(argument)
} }
use (ModCountCategory) {
for (n in 1000..1010) {
ModCountCategory.count = 0
factors = primeFactors(n)
println quot;$n : $factorsquot;.padRight(30) + quot;(in quot; +
quot;${ModCountCategory.count}quot;.padLeft(5) + quot; steps)quot;
assert n == factors.inject(1){result, item -> result *= item }
} }
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 64. Pattern Zusammenfassung
• Alleskleber
• Weiches Herz
• Endoskopische Operation
• Kluge Anpassung
• Grenzenlose Offenheit
• Heinzelmännchen
• Prototyp
Keep groovin' !
© 2007 by Dierk König, Tammo Freese & Johannes Link
- 65. Weitere Informationen
• groovy.codehaus.org
• grails.org
• Groovy in Action
groovy.canoo.com/gina
Manning, 2007, Vorwort von James Gosling
König mit Glover, Laforge, King, Skeet
• + Groovy Recipes
© 2007 by Dierk König, Tammo Freese & Johannes Link