SlideShare uma empresa Scribd logo
1 de 66
W-JAX Workshop
   Von Java zu Groovy

        Dierk König             Johannes Link             Tammo Freese
dierk.koenig@canoo.com   business@johanneslink.net   business@tammofreese.de
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
Herzlich Willkommen!

                            Johannes Link
                            • Unabhängiger Softwarecoach
                            • johanneslink.net
                            • Autor: Softwaretests mit Java




© 2007 by Dierk König, Tammo Freese & Johannes Link
Herzlich Willkommen!

                            Tammo Freese
                            • Freiberuflicher Diplom-Informatiker
                            • Extreme Programmer (Ruby/Java/...)
                            • http://tammofreese.de




© 2007 by Dierk König, Tammo Freese & Johannes Link
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
Groovy in der Sprachlandschaft




© 2007 by Dierk König, Tammo Freese & Johannes Link
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
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
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
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
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
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
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
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
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
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
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
Demo II

•     Erweitere Person um 'tags'
•     Schreibe alle tags
•     Entferne Doppler
•     Sortiere nach Taglänge




© 2007 by Dierk König, Tammo Freese & Johannes Link
Ü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
Integration von Groovy
in Java
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
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
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
Dynamisches Groovy mit
Metaprogrammierung
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
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
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
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
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
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
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
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
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
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
Meta-Übungen




© 2007 by Dierk König, Tammo Freese & Johannes Link
Einfacher Testen mit Groovy
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
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
Attrappen im Test

      TestCase                                        ClassUnderTest



                                                      <<interface>>
                                                       Collaborator




                         <<replacement>>                     RealCollaborator
                           Collaborator
                             Attrappe


© 2007 by Dierk König, Tammo Freese & Johannes Link
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
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
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
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
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
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
Ü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
Einsatz-Patterns für Groovy
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
#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
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
#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
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
#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
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
#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
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
#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
#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
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
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
#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
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
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
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
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
Offene Fragen




© 2007 by Dierk König, Tammo Freese & Johannes Link

Mais conteúdo relacionado

Semelhante a Von Java Zu Groovy

Genügend gute Gründe, wieso Ruby besser als PHP ist
Genügend gute Gründe, wieso Ruby besser als PHP istGenügend gute Gründe, wieso Ruby besser als PHP ist
Genügend gute Gründe, wieso Ruby besser als PHP istDaniel Spangenberg
 
Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
Von Automaten zu Programmen–Parsergeneratoren und AttributgrammatikenVon Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
Von Automaten zu Programmen–Parsergeneratoren und AttributgrammatikenTim Furche
 
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"DevDay Dresden
 
2008 02 01 Zeller
2008 02 01 Zeller2008 02 01 Zeller
2008 02 01 ZellerCHOOSE
 
Let’s groove with Groovy
Let’s groove with GroovyLet’s groove with Groovy
Let’s groove with GroovyThorsten Kamann
 
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011JavaFX - 9. JUGR Stammtisch - 5. Mai 2011
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011Reto Zahner
 
Production-ready Infrastruktur in 3 Wochen
Production-ready Infrastruktur in 3 WochenProduction-ready Infrastruktur in 3 Wochen
Production-ready Infrastruktur in 3 WochenAndré Goliath
 
JsUnconf 2014
JsUnconf 2014JsUnconf 2014
JsUnconf 2014emrox
 
Microservices mit Rust
Microservices mit RustMicroservices mit Rust
Microservices mit RustJens Siebert
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeFrank Müller
 
Backend-Services mit Rust
Backend-Services mit RustBackend-Services mit Rust
Backend-Services mit RustJens Siebert
 
Typ-sichere DSLs
Typ-sichere DSLsTyp-sichere DSLs
Typ-sichere DSLsWerner Keil
 
An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to RubyJonathan Weiss
 
Automatisierte Linux Administration mit (R)?ex
Automatisierte Linux Administration mit (R)?ex Automatisierte Linux Administration mit (R)?ex
Automatisierte Linux Administration mit (R)?ex Jan Gehring
 

Semelhante a Von Java Zu Groovy (17)

jBPM & Drools
jBPM & DroolsjBPM & Drools
jBPM & Drools
 
Genügend gute Gründe, wieso Ruby besser als PHP ist
Genügend gute Gründe, wieso Ruby besser als PHP istGenügend gute Gründe, wieso Ruby besser als PHP ist
Genügend gute Gründe, wieso Ruby besser als PHP ist
 
Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
Von Automaten zu Programmen–Parsergeneratoren und AttributgrammatikenVon Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
 
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"
Dev Day 2019: Mirko Zeibig – "Hallo " <> "Elixir"
 
2008 02 01 Zeller
2008 02 01 Zeller2008 02 01 Zeller
2008 02 01 Zeller
 
Let’s groove with Groovy
Let’s groove with GroovyLet’s groove with Groovy
Let’s groove with Groovy
 
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011JavaFX - 9. JUGR Stammtisch - 5. Mai 2011
JavaFX - 9. JUGR Stammtisch - 5. Mai 2011
 
Production-ready Infrastruktur in 3 Wochen
Production-ready Infrastruktur in 3 WochenProduction-ready Infrastruktur in 3 Wochen
Production-ready Infrastruktur in 3 Wochen
 
JsUnconf 2014
JsUnconf 2014JsUnconf 2014
JsUnconf 2014
 
Microservices mit Rust
Microservices mit RustMicroservices mit Rust
Microservices mit Rust
 
Go - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare SystemeGo - Googles Sprache für skalierbare Systeme
Go - Googles Sprache für skalierbare Systeme
 
Backend-Services mit Rust
Backend-Services mit RustBackend-Services mit Rust
Backend-Services mit Rust
 
Typ-sichere DSLs
Typ-sichere DSLsTyp-sichere DSLs
Typ-sichere DSLs
 
Ruby on Rails SS09 03
Ruby on Rails SS09 03Ruby on Rails SS09 03
Ruby on Rails SS09 03
 
DSLs in Scala & DB4O
DSLs in Scala & DB4ODSLs in Scala & DB4O
DSLs in Scala & DB4O
 
An Introduction to Ruby
An Introduction to RubyAn Introduction to Ruby
An Introduction to Ruby
 
Automatisierte Linux Administration mit (R)?ex
Automatisierte Linux Administration mit (R)?ex Automatisierte Linux Administration mit (R)?ex
Automatisierte Linux Administration mit (R)?ex
 

Mais de jlink

Mein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-EntwicklerMein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-Entwicklerjlink
 
Agile08: Test Driven Ajax
Agile08: Test Driven AjaxAgile08: Test Driven Ajax
Agile08: Test Driven Ajaxjlink
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Developmentjlink
 
Mehr Dynamik Mit Groovy
Mehr Dynamik Mit GroovyMehr Dynamik Mit Groovy
Mehr Dynamik Mit Groovyjlink
 
Automated Web 2.0 Testing
Automated Web 2.0 TestingAutomated Web 2.0 Testing
Automated Web 2.0 Testingjlink
 
AdvancedTdd
AdvancedTddAdvancedTdd
AdvancedTddjlink
 
XP Day Germany 2006 - Keynote
XP Day Germany 2006 - KeynoteXP Day Germany 2006 - Keynote
XP Day Germany 2006 - Keynotejlink
 
Testgetriebene Softwareentwicklung
Testgetriebene SoftwareentwicklungTestgetriebene Softwareentwicklung
Testgetriebene Softwareentwicklungjlink
 

Mais de jlink (8)

Mein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-EntwicklerMein paralleles Leben als Java-Entwickler
Mein paralleles Leben als Java-Entwickler
 
Agile08: Test Driven Ajax
Agile08: Test Driven AjaxAgile08: Test Driven Ajax
Agile08: Test Driven Ajax
 
Behaviour-Driven Development
Behaviour-Driven DevelopmentBehaviour-Driven Development
Behaviour-Driven Development
 
Mehr Dynamik Mit Groovy
Mehr Dynamik Mit GroovyMehr Dynamik Mit Groovy
Mehr Dynamik Mit Groovy
 
Automated Web 2.0 Testing
Automated Web 2.0 TestingAutomated Web 2.0 Testing
Automated Web 2.0 Testing
 
AdvancedTdd
AdvancedTddAdvancedTdd
AdvancedTdd
 
XP Day Germany 2006 - Keynote
XP Day Germany 2006 - KeynoteXP Day Germany 2006 - Keynote
XP Day Germany 2006 - Keynote
 
Testgetriebene Softwareentwicklung
Testgetriebene SoftwareentwicklungTestgetriebene Softwareentwicklung
Testgetriebene Softwareentwicklung
 

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
  • 35. Meta-Übungen © 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
  • 66. Offene Fragen © 2007 by Dierk König, Tammo Freese & Johannes Link