Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Mehr Dynamik Mit Groovy

4,977 views

Published on

Problems with Java and how dynamic scripting languages (especially Groovy) tackle some of them. A short introduction to some aspects of Groovy is included.

Published in: Technology
  • Be the first to comment

Mehr Dynamik Mit Groovy

  1. 1. Groovy Mehr Dynamik bei der Java- Entwicklung
  2. 2. Wer ich bin...
  3. 3. Wer ich bin... Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach Testgetrieben http://johanneslink.net
  4. 4. Java-Frust
  5. 5. Java-Frust public class Person... public String getName() { return name; }
  6. 6. Java-Frust public class Person... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  7. 7. Java-Frust public class Person... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  8. 8. Java-Frust public class Person implements Namable... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument implements Namable... public String getName() { return name; }
  9. 9. Java-Frust public class Person implements Namable... public String getName() { return name; } public class MyHelper... public static List<Person> Namable> List<T> sortByName(Set<T> namables) { public static <T extends sortByName(Set<Person> people) { List<Person> sortedResult = ArrayList<T>(namables); List<T> sortedResult = new new ArrayList<Person>(people); Comparator<Person> nameComparator = Comparator<T>() { Comparator<T> nameComparator = new new Comparator<Person>() { public int compare(Person T o2) { public int compare(T o1, o1, Person o2) { return o1.getName().compareTo(o2.getName()); return o1.getName().compareTo(o2.getName()); } } }; }; Collections.sort(sortedResult, nameComparator); Collections.sort(sortedResult, nameComparator); return sortedResult; return sortedResult; } } public class FinancialInstrument implements Namable... public String getName() { return name; }
  10. 10. Java-Frust public class Person... public String getName() { return name; } public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  11. 11. Java-Frust public class Person... public String getName() { return name; } public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { Collection sortByName return o1.getName().compareTo(o2.getName()); self sort: [:each | each name] }; } Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  12. 12. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  13. 13. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  14. 14. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  15. 15. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; }
  16. 16. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } • Variables Verhalten erfordert eigene (anonyme) Klasse • Incomplete Library Smell • Statische Typisierung erzwingt viele gemeinsame Interfaces • Unvorhergesehenes Veränderung => Neukompilierung
  17. 17. Die Rettung naht: Dynamische Skriptsprachen • Scripting • Dynamik
  18. 18. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus
  19. 19. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus List<Person> people = new ArrayList<Person>(); people.add(new Person(quot;Dierkquot;)); ... List<Person> sorted = (List<Person>) Eval.x(people, quot;x.sort {it.name}quot; );
  20. 20. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus List<Person> people = new ArrayList<Person>(); people.add(new Person(quot;Dierkquot;)); ... List<Person> sorted = (List<Person>) Eval.x(people, quot;x.sort {it.name}quot; );
  21. 21. Dynamik • Dynamische Typisierung • Closures • Meta-Programmierung
  22. 22. Dynamische Typisierung aka „Duck Typing“ def sortByName(unsorted) { unsorted.sort {it.name} } def people = [ new Student(quot;Johannesquot;), new Person(quot;Dierkquot;) ] def sorted = sortByName(people) assert sorted[0].name == quot;Dierkquot; assert sorted[1].name == quot;Johannesquot;
  23. 23. Closures (1) Programmlogik als vollwertiges Objekt def sorter = { unsorted -> unsorted.sort {it.name} } def sorted = sorter(people) //oder so: def sorted = sorter.call(people)
  24. 24. Closures (2) • Iteration als typischer Anwendungsfall
  25. 25. Closures (2) • Iteration als typischer Anwendungsfall def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;] def auswahl = namen.findAll {name -> name.contains quot;nquot;} assert auswahl == [quot;Johannesquot;, quot;Frankquot;]
  26. 26. Closures (2) • Iteration als typischer Anwendungsfall def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;] def auswahl = namen.findAll {name -> name.contains quot;nquot;} assert auswahl == [quot;Johannesquot;, quot;Frankquot;] List<String> auswahl = new ArrayList<String>(); for (String name : namen) { if (name.contains(quot;nquot;)) { auswahl.add(name); } } Äquivalenter Java Code
  27. 27. Meta-Programmierung • Erweiterung existierender Klassen • Hinzufügen von Methoden zur Laufzeit • Erweiterung / Veränderung der Sprache durch Verwendung eines „Meta Object Protocol“
  28. 28. Meta Object Protocol „A metaobject protocol (MOP) is an interpreter of the semantics of a program that is open and extensible“ (Wikipedia) class MyObject { def prop void setProperty(String name, value) { prop = value } def getProperty(String name) { prop } } def obj = new MyObject() obj.firstName = quot;Johannesquot; obj.lastName = quot;Linkquot; assert obj.firstName == quot;Linkquot;
  29. 29. Meta Object Protocol „A metaobject protocol (MOP) is an interpreter of the semantics of a program that is open and extensible“ (Wikipedia) Class.metaClass.'static'.create = { Object[] args -> delegate.metaClass.invokeConstructor(*args) } assert new ArrayList() == ArrayList.create() assert new HashMap() == HashMap.create() assert new Integer(42) == Integer.create(42) assert new Dimension(1,1) == Dimension.create(1,1)
  30. 30. Vorteile / Nachteile dynamischer Skriptsprachen • Vorteile: • Weniger Code • Weniger Duplikation • Verständlichere Abstraktionen • Mehr Deployment-Optionen
  31. 31. Vorteile / Nachteile dynamischer Skriptsprachen • Vorteile: • Weniger Code • Weniger Duplikation • Verständlichere Abstraktionen • Mehr Deployment-Optionen • Nachteile: • Erschwerte statische Codeanalyse • Schlechtere Performance
  32. 32. Welche Skriptsprachen gibt es? • Verbreiteste Skriptsprachen: Perl, PHP, Python, Ruby, JavaScript • Mehr als 200 verschiedene Sprachen allein auf der Java VM: Groovy, JRuby, Scala, Bistro ...
  33. 33. Groovy in der Sprachlandschaft Text (c) Dierk König
  34. 34. Groovy
  35. 35. Groovy • Volle Objekt- Orientierung ohne primitive Typen
  36. 36. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung
  37. 37. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung • Closures
  38. 38. Groovy • Volle Objekt- Orientierung ohne primitive Typen • Optionale statische Typisierung • Closures • Listen und Maps als Literale
  39. 39. Groovy • Volle Objekt- • Volle Integration Orientierung ohne mit der Java- primitive Typen Plattform • Optionale statische • Generics Typisierung • Annotations • Closures • Security-Model • Listen und Maps als Literale
  40. 40. Groovy • Volle Objekt- • Volle Integration Orientierung ohne mit der Java- primitive Typen Plattform • Optionale statische • Generics Typisierung • Annotations • Closures • Security-Model • Listen und Maps • Wird (immer) in als Literale echten Bytecode kompiliert
  41. 41. Groovy - Vereinfachte Syntax System.out.println(quot;Hello World!quot;); //Java style println 'Hello, World!' def vorname = 'Stefan' println quot;$vorname, ich hol' den Wagen.quot; String lang = quot;quot;quot;Du, ${vorname}, der Wagen steht eine Zeile weiter.quot;quot;quot; assert 0.5 == 1/2 def printSize(obj) { print obj?.size() } printSize(null) -> null
  42. 42. Reguläre Ausdrücke assert (quot;Hello World!quot; =~ /Hello/) // Find-Operator assert (quot;Hello World!quot; ==~ /Hellob.*/) // Match-Operator def pattern = ~/.*ll.*/ // java.util.regex.Pattern.compile(quot;.*ll.*quot;) assert [quot;halloquot;, quot;helloquot;, quot;holaquot;].grep(pattern) == [quot;halloquot;, quot;helloquot;] def coded = quot;Hallo, JUG Cologne!quot;.replaceAll(/w+/){ match -> match.size() } assert coded == quot;5, 3 7!quot;
  43. 43. Listen, ... def leer = [] def voll = [1, 2, 'JUGC'] assert voll + voll == voll * 2 assert voll[0] == 1 assert voll[0..1] == [1, 2] voll[0..1] = [0, 1, 2, 3] assert voll == [0, 1, 2, 3, 'JUGC'] assert voll[2..-1] == [2, 3, 'JUGC']
  44. 44. ... Maps und Ranges def leer = [:] def voll = [a: 1, b: 2] assert voll['a'] == 1 assert voll.a == 1 voll.a = 2 assert voll == [a: 2, b: 2] def inclusive = 'a'..'z' inclusive.each {c -> print c} def exclusive = 0..<10 for (i in exclusive) {print i}
  45. 45. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot;
  46. 46. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot; johannes.kinder += new Person(name: quot;Jannekquot;) johannes.kinder += new Person(name: quot;Niklasquot;) assert johannes.kinder.size() == 2 assert johannes.kinder[0].name == quot;Jannekquot;
  47. 47. Groovy Beans & GPath class Person { def name def kinder = [] } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot; johannes.kinder += new Person(name: quot;Jannekquot;) johannes.kinder += new Person(name: quot;Niklasquot;) assert johannes.kinder.size() == 2 assert johannes.kinder[0].name == quot;Jannekquot; assert johannes.kinder.name == [quot;Jannekquot;, quot;Niklasquot;] assert johannes.kinder.kinder*.size() == [0, 0]
  48. 48. Groovy -Closures def to = quot;JUGSquot; def say = { msg -> msg + quot;, $toquot; } assert say(quot;Halloquot;) == quot;Hallo, JUGSquot; to = quot;JUG Colognequot; assert say(quot;Halloquot;) == quot;Hallo, JUG Colognequot; (1..10).each { println it } [a:1, b:2].each { key, value -> println quot;key: $key, value: $valuequot; }
  49. 49. Java VM <-> Groovy
  50. 50. Java VM <-> Groovy • Groovy-Klassen können beliebig auf Java-Klassen zugreifen • und umgekehrt!
  51. 51. Java VM <-> Groovy • Groovy-Klassen können beliebig auf Java-Klassen zugreifen • und umgekehrt! • Es werden immer Klassen im Bytecode erzeugt • Egal ob Scripts oder Klassen • Egal ob vorkompiliert oder zur Laufzeit
  52. 52. Vorkompilierter Groovy-Code • groovyc -> *.class files • groovyc -jointCompilation behebt Henne-Ei-Problem • Auslieferung meist als JAR • groovy-all-x.y.z.jar mitausliefern
  53. 53. Dynamische Evaluation zur Laufzeit
  54. 54. Dynamische Evaluation zur Laufzeit • Eval.x(users, quot;x.grep{ it.salary -> 100000 }.address.townquot;); // me, x(), xy(), xyz()
  55. 55. 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)
  56. 56. 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
  57. 57. 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!)
  58. 58. 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)
  59. 59. 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
  60. 60. Dynamik & Metaprogrammierung • Dynamischer Methodenaufruf und Hooks • Kategorien • Methoden zur Laufzeit hinzufügen
  61. 61. Methodenaufrufe in Java und Groovy In Java: In Groovy: • Zur Übersetzungszeit • Zur Ausführungszeit wird festgelegt, welche wird dynamisch Methode ermittelt, auf welcher wie auf einen Vererbungshierarchie Methodenaufruf aufgerufen wird reagiert wird • Zur Ausführungszeit wird dynamisch ermittelt, wie auf einen Property- Zugriff reagiert wird
  62. 62. Dynamischer Aufruf class X { def x = new X() def a = 1 def methodName, propName def b = 2 def foo () { methodName = 'foo' 3 assert 3 == x.quot;$methodNamequot;() } } propName = 'a' assert 1 == x.quot;$propNamequot; propName = 'b' assert 2 == x.quot;$propNamequot;
  63. 63. methodMissing() class PrintMissingMethods { def methodMissing(String name, args) { println quot;missing $name with $argsquot; args.size() } } x = new PrintMissingMethods() assert 2 == x.foo(1,2) -> missing foo with {1, 2} assert 3 == x.bar('just', 'a', 'test') -> missing bar with {quot;justquot;, quot;aquot;, quot;testquot;}
  64. 64. Kategorien class FooCategory { • Kategorie: Klasse static def foo(List self, arg) { mit statischen self + [arg] Methoden } • 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(...) { ... }
  65. 65. Methoden zur Laufzeit hinzufügen String.metaClass.upperCaseCount = { -> • Sogenannte (delegate =~ /[A-Z]/).size() ExpandoMetaClass } • Methode definieren: assert 1 == quot;Onequot;.upperCaseCount() Property der assert 2 == quot;TWoquot;.upperCaseCount() Metaklasse auf eine assert 3 == quot;ThReEquot;.upperCaseCount() Closure setzen, fertig! Integer.metaClass.'static'. answerToEverything = { -> 42 } • Auch assert 42 == Integer.answerToEverything() Klassenmethoden können definiert werden ExpandoMetaClass.enableGlobally() Object.metaClass.tate = { -> 42 } • Auch Vererbung assert 42 == new X().tate() funktioniert
  66. 66. Was gibt es noch? • XML-Support eingebaut • Builder-Konzept (z.B. SwingBuilder) • Nahtlose Ant-Integration • Testen leicht gemacht • Web-Applikationen mit Grails (= Spring + Hibernate + Groovy) • ...
  67. 67. Wie entwickle ich Groovy-Programme? • groovysh • groovyConsole • IDE-Support • IDEA IntelliJ • Eclipse • NetBeans
  68. 68. Einsatzmuster für Scripting (von Dierk König) • Alleskleber • Weiches Herz • Kluge Anpassung • Endoskopische Operation • Grenzenlose Offenheit • Heinzelmännchen • Prototyp
  69. 69. Einsatzmuster: Alleskleber • Applikationen aus bestehenden Komponenten zusammenbauen • Java ist gut geeignet für stabile Infrastruktur: Middleware, Frameworks, Widget Sets, Services • Scripting ist gut geeignet für flexible View- und Controller-Schichten (z.B. Grails)
  70. 70. Alleskleber Demo: RSS Reader • Zusammenbau von XML Parser, Java Networking und Swing Widget Bibliothek, um einen Standard-RSS Feed darzustellen
  71. 71. Einsatzmuster: Weiches Herz • Fachliche Modelle auslagern bei vorgegebenem Java-Applikationsgerüst • Fachlichen Erkenntnisfortschritt ermöglichen: Entitäten, Beziehungen und Verhalten bleiben durch Scripting flexibel • Verhaltensänderung zur Laufzeit
  72. 72. 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 }
  73. 73. 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); BigDecimal bonus = (BigDecimal) shell.evaluate(script);
  74. 74. Einsatzmuster: Kluge Anpassung • Konfigurationen mit Ausführungs-Logik als Ersatz für XML-Konfigurationen • Mit Referenzen, Schleifen, Bedingungen, Vererbung, Ausführungslogik, Umgebungsermittlung, ... • Typischer Anwendungsfall für domänen- spezifische Sprachen (DSLs) • Veränderungen durch den Experten
  75. 75. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m
  76. 76. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m class Meter { def meter Meter(meter) { this.meter = meter } def plus(kilometer) { new Meter(meter + kilometer.meter) } boolean equals(other) { this.meter == other.meter } } class Kilometer { def meter Kilometer(kilometer) { meter = kilometer * 1000 } } class Distance { static def getM(distance) { new Meter(distance) } static def getKm(distance) { new Kilometer(distance) } }
  77. 77. DSL-Beispiel (von Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m class Meter { def meter assert werteAus('5002 m == 2000 m + 3 km + 2 m') Meter(meter) { this.meter = meter } def plus(kilometer) { def werteAus(String anweisung) { new Meter(meter + kilometer.meter) } Eval.me( boolean equals(other) { anweisung.replaceAll(quot; (m|km)quot;, { } this.meter == other.meter } alle, einheit -> quot;.${einheit}quot; class Kilometer { })) def meter Kilometer(kilometer) { } meter = kilometer * 1000 } } class Distance { static def getM(distance) { new Meter(distance) } static def getKm(distance) { new Kilometer(distance) } }
  78. 78. Einsatzmuster: 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 schaffen, z.B. in einem speziellen Servlet • Unglaublich wertvoll für Produkt-Support, Fehleranalyse, Hot-Fixes, Notfälle
  79. 79. Endoskopische Operation: im Servlet
  80. 80. Endoskopische Operation: im Servlet Probleme mit der Datenbank Verbindung? def ds = Config.dataSource ds.connection = new DebugConnection(ds.connection)
  81. 81. 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)
  82. 82. Einsatzmuster: Grenzenlose Offenheit • Jede Zeile Code wird änderbar • Manchmal sind die vorgesehenen Variationspunkte nicht ausreichend • Einfache Änderungen ohne langwieriges Setup für Kompilation und Deployment • Perl, PHP, Python, etc. machen es vor
  83. 83. Einsatzmuster: Heinzelmännchen • Repetitive Aufgaben automatisieren • Automatisierter Build, kontinuierliche Integration, Deployment, Installationen, Server-Überwachung, Reports, Statistiken, Erzeugen von Dokumentation, funktionale Tests uvm. • Anwendungen mit Ant, Maven und Co.
  84. 84. Heinzelmännchen: Mail schicken def users = [ [name:'Johannes', email:'jl@johanneslink.net'], [name:'Teilnehmer', email:'wer@wo.net']] def ant = new groovy.util.AntBuilder() for (user in users) { ant.mail(mailhost: 'smtp.googlemail.com', mailport: '465', ssl: 'true', user: quot;$mailUserquot;, password: quot;$passwordquot;, subject: 'Vortrag ist bald fertig') { from(address: 'johannes.link@googlemail.com') to(address: user.email) message( quot;quot;quot; Hallo ${user.name}, Der Vortrag ist fast fertig: ${new Date().toGMTString()} quot;quot;quot; ) } }
  85. 85. Einsatzmuster: 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 / C#
  86. 86. Weitere Informationen • http://groovy.codehaus.org/ • http://grails.codehaus.org/ • Dierk König et al: „Groovy in Action“
  87. 87. Zusammenfassung • Die Programmiersprache Java hat Einschränkungen: • Anpassungen zur Laufzeit • Präzision im Ausdruck • Erweiterbarkeit der Sprache • Groovy als dynamische Skriptsprache ist in diesen Punkten flexibler und mächtiger • Groovys Ziel ist die best mögliche Integration in die Java-Plattform • Es existieren typische Einsatzmuster
  88. 88. Fragen und Anmerkungen? http://www.slideshare.net/jlink/ mehr-dynamik-mit-groovy/

×