GroovyDomainSpecific    Guillaume Laforge            Groovy Project Manager            SpringSource / VMwareLanguages     ...
ГИЙОМЛАФОРЖ
Guillaume Laforge•   Groovy Project Manager at VMware    •Initiator of the Grails framework    •Creator of the Gaelyk     ...
IntroductionDefinition, Examples, Goals, Pros & Cons                                          4
Domain-Specific Languages    •   Wikipedia definition{                                                                }    ...
Technical examplesGlade                                     XSLT<?xml version="1.0"?>                      <?xml version="...
Antimalaria drug             Insurance policy risk        HR skills representationresistance simulation        calculation...
Goals of DSLs•   Use a more expressive language than a general-purpose one•   Share a common metaphor of understanding    ...
Pros and cons Pros                                             Cons •   Domain experts can help, validate,           •   L...
Groovy provides...•   A flexible and malleable syntax    •scripts, native syntax constructs (list, map, ranges), closures, ...
Let’s get started!                     11
Your mission:   build a DSL for                  a Mars robot
We need a robot! class!Robot!{}                   14
It should move... class!Robot!{ !!!!void)move()!{} }                      15
..in a direction! class!Robot!{ !!!!void)move(String!dir)!{} }                                16
More explicit direction class!Robot!{ !!!!void)move(Direction!dir)!{} } enum!Direction!{ !!!!left,!right,!forward,!backwar...
Now how can we control it?import)static)mars.Direction.*;import)mars.Robot;public)class)Command!{))))public)static)void)ma...
Now how can we control it?import)static)mars.Direction.*;import)mars.Robot;public)class)Command!{))))public)static)void)ma...
Now how can we control it?))))))))))))))))))))))))))))))—import)static)mars.Direction.*;)))))))))))))))))—import)mars.Robo...
Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot!!!!!!!!def))!robot!=)new!Rob...
Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot                Optional typi...
Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot                   Optional t...
Integration
GroovyShell to the rescue                            21
GroovyShell to the rescue                 def$shell%=$new%GroovyShell()                 shell.evaluate(                 %%...
GroovyShell to the rescue                       def$shell%=$new%GroovyShell()                       shell.evaluate(  integ...
GroovyShell to the rescue                        def$shell%=$new%GroovyShell()                        shell.evaluate(   in...
GroovyShell to the rescue                        def$shell%=$new%GroovyShell()                        shell.evaluate(   in...
Integration mechanisms•   Different solutions available:    •Groovy’s own mechanisms     •  GroovyScriptEngine, Eval,     ...
Integration mechanisms•   Different solutions available:    •Groovy’s own mechanisms     •  GroovyScriptEngine, Eval,     ...
What’s wrong with our DSL?       import)static)mars.Direction.*       import)mars.Robot       def)robot!=)new!Robot()     ...
What’s wrong with our DSL?       Can’t we hide      those imports?       import)static)mars.Direction.*       import)mars....
What’s wrong with our DSL?       Can’t we hide      those imports?       import)static)mars.Direction.*       import)mars....
What’s wrong with our DSL?        Can’t we hide       those imports?         import)static)mars.Direction.*         import...
I’m sorry Dave,you can’t do that!
I’m sorry Dave,you can’t do that!
What we really want is...                !move!left!                              25
Let’s inject a robot!•   We can pass data in / out of scripts through the Binding    •it’s basically just like a map of va...
Let’s inject a robot!•   We can pass data in / out of scripts through the Binding    •it’s basically just like a map of va...
Let’s inject a robot!•   We can pass data in / out of scripts through the Binding    •it’s basically just like a map of va...
Better?      import)static)mars.Direction.*      robot.move!left                                       27
Better?Robot import  removed               import)static)mars.Direction.*               robot.move!left                   ...
Better?Robot import  removed               import)static)mars.Direction.*               robot.move!left                   ...
How to inject the direction?•   Using the binding...                  def)binding!=)new!Binding([                  !!!!rob...
How to inject the direction?                                                Fragile in case of                            ...
How to inject the direction?•   Using the binding...                  def)binding!=)new!Binding([                  !!!!rob...
How to inject the direction?•   Using compiler customizers...•   Let’s have a look at them                                ...
Compilation customizers•   Ability to apply some customization    to the Groovy compilation process•   Three available cus...
Imports customizer new!GroovyShell(new!Binding([robot:!new)Robot()])) !!!!.evaluate("import!static!Direction.*n"!+ !!!!!!!...
Imports customizer                                  Cheat with string                                concatenation? Bad! n...
Imports customizer new!GroovyShell(new!Binding([robot:!new)Robot()])) !!!!.evaluate("import!static!Direction.*n"!+ !!!!!!!...
Imports customizer def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStati...
AST transformation customizer def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() impor...
AST transformation customizer    def!configuration!=!new!CompilerConfiguration()    !    def!imports!=!new!ImportCustomize...
Secure the onboardtrajectory calculator
Secure AST customizer                       Idea: Secure the rocket’s onboard trajectory                       calculation...
Secure AST customizer...secure.with!{  //!disallow!closure!creation  closuresAllowed!=!false!  //!disallow!method!definiti...
Secure AST customizer                                  Disallow closures...                                 and methodssec...
Secure AST customizer                                     Disallow closures...                                    and meth...
Secure AST customizer...   //%language%tokens%allowed   tokensWhitelist%=%[      PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER...
Secure AST customizer                          You can build a subset of                                                  ...
Secure AST customizer                          You can build a subset of                                                  ...
Secure AST customizer•   Ready to evaluate our flight equations!           def%config%=%new%CompilerConfiguration()        ...
Back to our robot...            robot.move)left                              40
Back to our robot...              Still need to get rid              of the robot prefix!            robot.move)left      ...
Can we remove it?
Can we remove it?                    да !
How to remove the ‘robot’?•   Instead of calling the move() method on the robot    instance, we should be able to call the...
Inject a closure in the binding      def$robot%=%new%Robot()      binding%=$new%Binding([      %%%%robot:%robot,      %%%%...
Inject a closure in the binding      def$robot%=%new%Robot()      binding%=$new%Binding([      %%%%robot:%robot,      %%%%...
Define a base script class       abstract)class!RobotBaseScriptClass!!!       !!!!!!!extends!Script!{       !!!!void!move(...
Define a base script class            abstract)class!RobotBaseScriptClass!!!            !!!!!!!extends!Script!{           ...
Define a base script class            abstract)class!RobotBaseScriptClass!!!            !!!!!!!extends!Script!{           ...
Configure the base script classdef)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass          ...
Configure the base script classdef)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass          ...
Ready for lift off!   %%move%left
Beep, beep...yes but how do you define the speed?     ...beep...
Oh no!
What we could do now is...         move!left,!at:!3.km/h                                 49
What we could do now is...                 Mix of named and                normal parameters         move!left,!at:!3.km/h...
What we could do now is...                 Mix of named and                normal parameters         move!left,!at:!3.km/h...
Adding properties to numbers•   We need to:    •   define units, distance and speed    •   have a nice notation for them   ...
Unit enum and Distance classenum$DistanceUnit%{%%%%centimeter%(cm,%%%%0.01),%%%%meter%%%%%%(%m,%%%%1),%%%%%kilometer%%(km,...
Unit enum and Distance class                                          @TupleConstructor%enum$DistanceUnit%{               ...
Different techniques•   To add dynamic methods or properties,    there are several approaches at your disposal:    • Expan...
Using ExpandoMetaClass   Number.metaClass.getCm%=%{%f>%   %%%%new%Distance(delegate,%Unit.centimeter)%   }   Number.metaCl...
Using ExpandoMetaClass    Add that tointegration.groovy       Number.metaClass.getCm%=%{%f>%       %%%%new%Distance(delega...
Using ExpandoMetaClass    Add that tointegration.groovy       Number.metaClass.getCm%=%{%f>%       %%%%new%Distance(delega...
Using ExpandoMetaClass    Add that tointegration.groovy                                     Usage in                      ...
Distance okay, but speed?•   For distance, we just added a property access after the number,    but we now need to divide ...
Distance okay, but speed?•   For distance, we just added a property access after the number,    but we now need to divide ...
Distance okay, but speed?•   For distance, we just added a property access after the number,    but we now need to divide ...
First, let’s look at timeenum$TimeUnit%{%%%%hour%%%%%%(h,%%%3600),%%%%minute%%%%(min,%%%60),%%%%%kilometer%(s,%%%%%%1)%%%%...
First, let’s look at time                 @TupleConstructor%                                          class%Duration%{enum...
Inject the ‘h’ hour constant in the binding       def)binding!=)new!Binding([       !!!!robot:!new!Robot(),       !!!!*:!D...
Now at (light!) speed       @TupleConstructor)       class)Speed){       ))))Distance)distance       ))))Duration)duration...
Operator overloading a%+%b%%//%a.plus(b) a%f%b%%//%a.minus(b)          •       Currency amounts a%*%b%%//%a.multiply(b)   ...
Operator overloading•   Update the Distance class with a div() method    following the naming convetion for operators     ...
Operator overloading•   Update the Distance class with a div() method    following the naming convetion for operators     ...
Equivalence of notation•   Those two notations are actually equivalent:                                2.km/h             ...
Equivalence of notation•   Those two notations are actually equivalent:                                2.km/h             ...
Named parameters usage       move!left,!at:!3.km/h                               61
Named parameters usage       move!left,!at:!3.km/h          Normal         parameter                               61
Named parameters usage       move!left,!at:!3.km/h          Normal          Named         parameter       parameter       ...
Named parameters usage       move!left,!at:!3.km/h             Normal              Named            parameter           pa...
Named parameters usage          move!left,!at:!3.km/h               Normal              Named              parameter      ...
Named parameters usage          move!left,!at:!3.km/h               Normal              Named              parameter      ...
Named parameters usage       move!left,!at:!3.km/h                               62
Named parameters usage        move!left,!at:!3.km/h      Can we get rid of        the comma?                              ...
Named parameters usage        move!left,!at:!3.km/h      Can we get rid of   What about the        the comma?          col...
Command chains•   A grammar improvement in Groovy 1.8 allowing you    to drop dots & parens when chaining method calls    ...
Command chains       %move%left%%at%3.km/h%                                64
Command chains       Alternation of       method names       %move%left%%at%3.km/h%                                64
Command chains       Alternation of       method names       %move%left%%at%3.km/h%                     and parameters    ...
Command chains       %move%left%%at%3.km/h%                                64
Command chains       Equivalent to:       %%%%%(%%%%).%%(%%%%%%)       %move%left%%at%3.km/h%                             ...
Look  Ma!No  par ens, no dots!
Command chains          //%Java%fluent%API%approach          class%Robot%{          %%%%...          $$$$def%move(Directio...
Command chains   def)move(Direction)dir)){   ))))[at:){)Speed)speed)F>   ))))))))))))...   ))))))))}]   ))))}]   }        ...
Command chains   def)move(Direction)dir)){   ))))[at:){)Speed)speed)F>   ))))))))))))...             Nested maps   )))))))...
Command chains   def)move(Direction)dir)){   ))))[at:){)Speed)speed)F>   ))))))))))))...                 Nested maps   )))...
Command chains                 68
Command chains   //%methods%with%multiple%arguments%(commas)                                                 68
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor                  ...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   //%leverage%nam...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   %%%%(%%%%%%).%%...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   %%%%(%%%%%%).%%...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   %%%%(%%%%%%).%%...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   %%%%(%%%%%%).%%...
Command chains   //%methods%with%multiple%arguments%(commas)   take%coffee%%with%sugar,%milk%%and%liquor   %%%%(%%%%%%).%%...
Final result               69
Final result          move!forward!at!3.km/h                                   69
move forward at 3.km/h
move forward at 3.km/h     Yes! We did it!
What about security   and safety?
Security and safety     JVM Security Managers     SecureASTCustomizer            Sandboxing   Controlling scripts executio...
Play it safe in a sandbox
Playing it safe...•   You have to think carefully about    what DSL users are allowed to do with your DSL•   Forbid things...
Security Managers•   Groovy is just a language leaving on the JVM,    so you have access to the usual Security Managers me...
SecureASTCustomizer      def!secure!=!new!SecureASTCustomizer()      secure.with!{         //!disallow!closure!creation   ...
Controlling code execution•   Your application may run user’s code    •what if the code runs in infinite loops or for too l...
@ThreadInterrupt  @ThreadInterrupt  import%groovy.transform.ThreadInterrupt%  %  while%(true)%{  %%%%//%Any%extraterestria...
@ThreadInterrupt    @ThreadInterrupt    import%groovy.transform.ThreadInterrupt%    %    while%(true)%{{   %%%%if%(Thread....
@TimedInterrupt                @TimedInterrupt(10)                import!groovy.transform.TimedInterrupt!                !...
@ConditionalInterrupt•       Specify your own condition to be inserted        at the start of method and closure bodies   ...
Using compilation customizers•   In our previous three examples, the usage of the interrupts were explicit,    and users h...
What have we learnt?                       82
Groovy Power!™•   A flexible and malleable syntax    • scripts vs classes, optional typing, colons and parens•   Groovy off...
Groovy Power!™                         Groovy is a                                       great fit for                    ...
And there’s more!•   We haven’t dived into...    •How to implement your own control structures with the help of closures  ...
Thank you!                                   ge                          e   Lafor lopment             Gui llaum ovy Deve ...
Questions & AnswersGot questions,    really?                      86
Questions & Answers                      I might have                        answers!Got questions,    really?            ...
Image credits•   Pills: http://www.we-ew.com/wp-content/uploads/2011/01/plan-b-pills.jpg•   Chains: http://2.bp.blogspot.c...
Going to Mars with Groovy Domain-Specific Languages
Prochain SlideShare
Chargement dans…5
×

Going to Mars with Groovy Domain-Specific Languages

58 332 vues

Publié le

Practical example of implementing and evolving a simple DSL in Groovy, to drive a robot rover on the planet Mars.

Publié dans : Technologie
12 commentaires
88 j’aime
Statistiques
Remarques
  • Very interesting analysis of CET 2016, must read for CET Aspirants http://catking.in/2016/09/30/exam-analysis-mh-cet-2016/ #TargetJBIMS #JBIMSorNothing #CET2017
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • Woohoo, guys just came across some IIM A personal interview experiences http://catking.in/2016/12/20/iim-ahmedabad-personal-interview-experiences/ #TargetIIM #CAT2017 #IIMorNothing
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • If you are aiming high in life, these stories will definitely motivate you to take a big leap http://catking.in/2015/07/22/inspiring-stories/ #TargetIIM #TargetJBIMS #CET2017 #CAT2017
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • My dear, How are you today? i will like to be your friend My name is Sheikha Ghunaim , am a 43 years old divorcee. Please write to me in my email ( sheikhaghunaim2@hotmail.com ). im honest and open mind single woman. im going to tell more when i see your response. Regards Sheikha.
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
  • This is real take it serious, who will believe that a herb can cure herpes, i navel believe that this will work i have spend a lot when getting drugs from the hospital to keep me healthy, what i was waiting for is death because i was broke, one day i hard about this great man who is well know of HIV and cancer cure, i decided to email him, unknowingly to me that this will be the end of the herpes in my body, he prepare the herb for me, and give me instruction on how to take it, at the end of the one month, he told me to go to the hospital for a check up, and i went, surprisingly after the test the doctor confirm me negative, i thought it was a joke, i went to other hospital was also negative, then i took my friend who was also herpes positive to the Dr Agumagu, after the treatment she was also confirm negative . He also have the herb to cure cancer. please i want every one with this virus to be free, that is why am dropping his email address, agumaguspelltemple@outlook.com or agumaguspelltemple@gmail.com do email him he is a great man. the government is also interested in this DR, thank you for saving my life, and I promise I will always testify for your good work.call his number +233200116937.
       Répondre 
    Voulez-vous vraiment ?  Oui  Non
    Votre message apparaîtra ici
Aucun téléchargement
Vues
Nombre de vues
58 332
Sur SlideShare
0
Issues des intégrations
0
Intégrations
2 692
Actions
Partages
0
Téléchargements
577
Commentaires
12
J’aime
88
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Going to Mars with Groovy Domain-Specific Languages

  1. GroovyDomainSpecific Guillaume Laforge Groovy Project Manager SpringSource / VMwareLanguages @glaforge 1
  2. ГИЙОМЛАФОРЖ
  3. Guillaume Laforge• Groovy Project Manager at VMware •Initiator of the Grails framework •Creator of the Gaelyk and Caelyf toolkits• Co-author of Groovy in Action• Follow me on... •My blog: http://glaforge.appspot.com •Twitter: @glaforge •Google+: http://gplus.to/glaforge 3
  4. IntroductionDefinition, Examples, Goals, Pros & Cons 4
  5. Domain-Specific Languages • Wikipedia definition{ } A Domain-Specific Language is a programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular problem domain. • In contrast to General Purprose Languages • Also known as: fluent / human interfaces, language oriented programming, little or mini languages, macros, business natural languages... 5
  6. Technical examplesGlade XSLT<?xml version="1.0"?> <?xml version="1.0"?><GTK-Interface> <xsl:stylesheetversion="1.0"<widget> xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <class>GtkWindow</class> <xsl:output method="xml"/> <name>HelloWindow</name> <xsl:template match="*"> <border_width>5</border_width> <Signal> <xsl:element name="{name()}"> Regex <xsl:for-each select="@*"> <name>destroy</name> <handler>gtk_main_quit</handler> <xsl:element name="{name()}"> <xsl:value-of select="."/> "x.z?z{1,3}y" </Signal> <title>Hello</title> </xsl:element> <type>GTK_WINDOW_TOPLEVEL</type> </xsl:for-each> <position>GTK_WIN_POS_NONE</position> <xsl:apply-templates select="*|text()"/> <allow_shrink>True</allow_shrink> </xsl:element> <allow_grow>True</allow_grow> </xsl:template> <auto_shrink>False</auto_shrink> </xsl:stylesheet> <widget> <class>GtkButton</class> <name>Hello World</name> <can_focus>True</can_focus> fetchmail <label>Hello World</label> # Poll this site first each cycle. </widget> poll pop.provider.net proto pop3</widget> user "jsmith" with pass "secret1" is "smith" here</GTK-Interface> user jones with pass "secret2" is "jjones" here with options keep SQL # Poll this site second, unless Lord Voldemort zaps us first. poll billywig.hogwarts.com with proto imap: user harry_potter with pass "floo" is harry_potter here SELECT * FROM TABLE # Poll this site third in the cycle. WHERE NAME LIKE %SMI # Password will be fetched from ~/.netrc ORDER BY NAME poll mailhost.net with proto imap: user esr is esr here
  7. Antimalaria drug Insurance policy risk HR skills representationresistance simulation calculation engine Nuclear safety simulationsMarket data feeds analysis Loan acceptance rules engine
  8. Goals of DSLs• Use a more expressive language than a general-purpose one• Share a common metaphor of understanding between developers and subject matter experts• Have domain experts help with the design of the business logic of an application• Avoid cluttering business code with too much boilerplate technical code thanks to a clean separation• Let business rules have their own lifecycle 8
  9. Pros and cons Pros Cons • Domain experts can help, validate, • Learning cost vs. limited applicability modify, and often develop DSL programs • Cost of designing, implementing & maintaining DSLs as well as tools/IDEs • Somewhat self-documenting • Attaining proper scope • Enhance quality, productivity, • Trade-offs between domain specificity reliability, maintainability, portability, and general purpose language reusability constructs • Safety; as long as the language • Efficiency cost constructs are safe, any DSL sentence can be considered safe • Proliferation of similar non-standard DSLs 9
  10. Groovy provides...• A flexible and malleable syntax •scripts, native syntax constructs (list, map, ranges), closures, less punctuation...• Compile-time and runtime meta-programming •metaclasses, AST transformations •also operator overloading• The ability to easily integrate into Java / Spring apps •also security and safety 10
  11. Let’s get started! 11
  12. Your mission: build a DSL for a Mars robot
  13. We need a robot! class!Robot!{} 14
  14. It should move... class!Robot!{ !!!!void)move()!{} } 15
  15. ..in a direction! class!Robot!{ !!!!void)move(String!dir)!{} } 16
  16. More explicit direction class!Robot!{ !!!!void)move(Direction!dir)!{} } enum!Direction!{ !!!!left,!right,!forward,!backward } 17
  17. Now how can we control it?import)static)mars.Direction.*;import)mars.Robot;public)class)Command!{))))public)static)void)main(String[]!args)!{!!!!!!!!Robot!robot!=)new!Robot();!!!!!!!!robot.move(left);!!!!}} 18
  18. Now how can we control it?import)static)mars.Direction.*;import)mars.Robot;public)class)Command!{))))public)static)void)main(String[]!args)!{!!!!!!!!Robot!robot!=)new!Robot();!!!!!!!!robot.move(left);!!!!}} Syntactical noise! 18
  19. Now how can we control it?))))))))))))))))))))))))))))))—import)static)mars.Direction.*;)))))))))))))))))—import)mars.Robot;——————————————————————public)class)Command!{))))————————————————————————————————————————))))public)static)void)main(String[]!args)!{))))))))—————))))))))))))))))))))—!!!!!!!!Robot!robot!=)new!Robot();))))))))))))))))))—))))——!!!!!!!!robot.move(left);))))—!!!!}—} Syntactical noise! 18
  20. Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left 19
  21. Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot Optional typing!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left 19
  22. Scripts vs ClassesOptional semicolons & parensimport)static)mars.Direction.*import)mars.Robot Optional typing!!!!!!!!def))!robot!=)new!Robot()!!!!!!!!robot.move!left But I don’t want to compile a script for every command! 19
  23. Integration
  24. GroovyShell to the rescue 21
  25. GroovyShell to the rescue def$shell%=$new%GroovyShell() shell.evaluate( %%%%new%File("command.groovy") ) 21
  26. GroovyShell to the rescue def$shell%=$new%GroovyShell() shell.evaluate( integration.groovy %%%%new%File("command.groovy") ) 21
  27. GroovyShell to the rescue def$shell%=$new%GroovyShell() shell.evaluate( integration.groovy %%%%new%File("command.groovy") )import$static$mars.Direction.*import$mars.Robotdef$robot%=$new%Robot()robot.move%left 21
  28. GroovyShell to the rescue def$shell%=$new%GroovyShell() shell.evaluate( integration.groovy %%%%new%File("command.groovy") )import$static$mars.Direction.*import$mars.Robot command.groovydef$robot%=$new%Robot()robot.move%left 21
  29. Integration mechanisms• Different solutions available: •Groovy’s own mechanisms • GroovyScriptEngine, Eval, GroovyClassLoader, GroovyShell •Java 6: javax.script.* / JSR-223 • Groovy provides a JSR-223 implementation •Spring’s lang namespace• Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard... 22
  30. Integration mechanisms• Different solutions available: •Groovy’s own mechanisms • GroovyScriptEngine, Eval, GroovyClassLoader, GroovyShell •Java 6: javax.script.* / JSR-223 • Groovy provides a JSR-223 implementation •Spring’s lang namespace• Groovy provides the highest level of flexibility and customization, but JSR-223 is a standard... 22
  31. What’s wrong with our DSL? import)static)mars.Direction.* import)mars.Robot def)robot!=)new!Robot() robot.move!left 23
  32. What’s wrong with our DSL? Can’t we hide those imports? import)static)mars.Direction.* import)mars.Robot def)robot!=)new!Robot() robot.move!left 23
  33. What’s wrong with our DSL? Can’t we hide those imports? import)static)mars.Direction.* import)mars.Robot def)robot!=)new!Robot() robot.move!left Can’t we inject the robot? 23
  34. What’s wrong with our DSL? Can’t we hide those imports? import)static)mars.Direction.* import)mars.Robot def)robot!=)new!Robot() robot.move!left Can’t we inject Do we really need to the robot? repeat ‘robot’? 23
  35. I’m sorry Dave,you can’t do that!
  36. I’m sorry Dave,you can’t do that!
  37. What we really want is... !move!left! 25
  38. Let’s inject a robot!• We can pass data in / out of scripts through the Binding •it’s basically just like a map of variable name keys and their associated values 26
  39. Let’s inject a robot!• We can pass data in / out of scripts through the Binding •it’s basically just like a map of variable name keys and their associated values def)binding!=)new!Binding([ !!!!robot:!new!Robot() ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) 26
  40. Let’s inject a robot!• We can pass data in / out of scripts through the Binding •it’s basically just like a map of variable name keys and their associated values integration.groovy def)binding!=)new!Binding([ !!!!robot:!new!Robot() ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) 26
  41. Better? import)static)mars.Direction.* robot.move!left 27
  42. Better?Robot import removed import)static)mars.Direction.* robot.move!left 27
  43. Better?Robot import removed import)static)mars.Direction.* robot.move!left Robot injected, no ‘new’ needed 27
  44. How to inject the direction?• Using the binding... def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!left:!!!!!Direction.left, !!!!right:!!!!Direction.right, !!!!backward:!Direction.backward, !!!!forward:!!Direction.forward ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) 28
  45. How to inject the direction? Fragile in case of new directions!• Using the binding... def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!left:!!!!!Direction.left, !!!!right:!!!!Direction.right, !!!!backward:!Direction.backward, !!!!forward:!!Direction.forward ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) 28
  46. How to inject the direction?• Using the binding... def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!*:!Direction.values() !!!!!!!!!!!!.collectEntries!{ !!!!!!!!!!!!!!!![(it.name()):!it] !!!!!!!!!!!!} ]) def)shell!=)new!GroovyShell(binding) shell.evaluate( !!!!new!File("command.groovy") ) 29
  47. How to inject the direction?• Using compiler customizers...• Let’s have a look at them 30
  48. Compilation customizers• Ability to apply some customization to the Groovy compilation process• Three available customizers •ImportCustomizer: add transparent imports •ASTTransformationCustomizer: injects an AST transform •SecureASTCustomizer: restrict the groovy language to an allowed subset• But you can implement your own 31
  49. Imports customizer new!GroovyShell(new!Binding([robot:!new)Robot()])) !!!!.evaluate("import!static!Direction.*n"!+ !!!!!!!!!!!!!!"robot.move!left") 32
  50. Imports customizer Cheat with string concatenation? Bad! new!GroovyShell(new!Binding([robot:!new)Robot()])) !!!!.evaluate("import!static!Direction.*n"!+ !!!!!!!!!!!!!!"robot.move!left") 32
  51. Imports customizer new!GroovyShell(new!Binding([robot:!new)Robot()])) !!!!.evaluate("import!static!Direction.*n"!+ !!!!!!!!!!!!!!"robot.move!left") 32
  52. Imports customizer def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStaticStar(mars.Direction.name) configuration.addCompilationCustomizers(imports)! ! new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!! ! !!!!!!!!!!!!!!!!configuration) !!!!.evaluate("robot.move!left")!!!!!! 33
  53. AST transformation customizer def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStaticStar(mars.Direction.name) configuration.addCompilationCustomizers(imports, !!!!!!!!!!!!!new!ASTTransformationCustomizer(Log)) ! new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!! ! !!!!!!!!!!!!!!!!configuration) !!!!.evaluate("robot.move!left"!+!"n" !!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!! 34
  54. AST transformation customizer def!configuration!=!new!CompilerConfiguration() ! def!imports!=!new!ImportCustomizer() imports.addStaticStar(mars.Direction.name) configuration.addCompilationCustomizers(imports, !!!!!!!!!!!!!new!ASTTransformationCustomizer(Log)) ! new!GroovyShell(new!Binding([robot:!new)Robot()]),!!!!!!! ! !!!!!!!!!!!!!!!!configuration) !!!!.evaluate("robot.move!left"!+!"n" !!!!!!!!!!!!!!"log.info!‘Robot!moved’")!!!!!!!!!!!@Log injects a logger in scripts and classes 34
  55. Secure the onboardtrajectory calculator
  56. Secure AST customizer Idea: Secure the rocket’s onboard trajectory calculation system by allowing only math expressions to be evaluated by the calculator• Let’s setup our environment •an import customizer to import java.lang.Math.* •prepare a secure AST customizerdef%imports%=%new%ImportCustomizer().addStaticStars(java.lang.Math)def%secure%=%new%SecureASTCustomizer() 36
  57. Secure AST customizer...secure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions methodDefinitionAllowed!=!false!! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=![java.lang.Math]... 37
  58. Secure AST customizer Disallow closures... and methodssecure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions methodDefinitionAllowed!=!false!! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=![java.lang.Math]... 37
  59. Secure AST customizer Disallow closures... and methodssecure.with!{ //!disallow!closure!creation closuresAllowed!=!false! //!disallow!method!definitions Black / white list methodDefinitionAllowed!=!false! imports! //!empty!white!list!=>!forbid!imports importsWhitelist!=![]! staticImportsWhitelist!=![] //!only!allow!the!java.lang.Math.*!static!import staticStarImportsWhitelist!=![java.lang.Math]... 37
  60. Secure AST customizer... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL ]% //%types%allowed%to%be%used%(including%primitive%types) constantTypesClassesWhiteList%=%[ Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ]% //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}... 38
  61. Secure AST customizer You can build a subset of the Groovy syntax!... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL ]% //%types%allowed%to%be%used%(including%primitive%types) constantTypesClassesWhiteList%=%[ Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ]% //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}... 38
  62. Secure AST customizer You can build a subset of the Groovy syntax!... //%language%tokens%allowed tokensWhitelist%=%[ PLUS,%MINUS,%MULTIPLY,%DIVIDE,%MOD,%POWER,%PLUS_PLUS,%MINUS_MINUS,% COMPARE_EQUAL,%COMPARE_NOT_EQUAL,%COMPARE_LESS_THAN,%COMPARE_LESS_THAN_EQUAL,% COMPARE_GREATER_THAN,%COMPARE_GREATER_THAN_EQUAL ]% //%types%allowed%to%be%used%(including%primitive%types) Black / white list constantTypesClassesWhiteList%=%[ usage of classes Integer,%Float,%Long,%Double,%BigDecimal,% Integer.TYPE,%Long.TYPE,%Float.TYPE,%Double.TYPE ]% //%classes%who%are%allowed%to%be%receivers%of%method%calls receiversClassesWhiteList%=%[% Math,%Integer,%Float,%Double,%Long,%BigDecimal%]}... 38
  63. Secure AST customizer• Ready to evaluate our flight equations! def%config%=%new%CompilerConfiguration() config.addCompilationCustomizers(imports,%secure) def%shell%=%new%GroovyShell(config) % shell.evaluate%cos%PI/3• But the following would have failed: shell.evaluate%System.exit(0) 39
  64. Back to our robot... robot.move)left 40
  65. Back to our robot... Still need to get rid of the robot prefix! robot.move)left 40
  66. Can we remove it?
  67. Can we remove it? да !
  68. How to remove the ‘robot’?• Instead of calling the move() method on the robot instance, we should be able to call the move() method directly from within the script• Two approaches: • Inject a ‘move’ closure in the • Use a base script class with a ‘move’ method delegating to the binding with a method pointer robot 42
  69. Inject a closure in the binding def$robot%=%new%Robot() binding%=$new%Binding([ %%%%robot:%robot, %%%%*:%Direction.values() %%%%%%%%%%%%.collectEntries%{ %%%%%%%%%%%%%%%%[(it.name()):%it] %%%%%%%%%%%%}, %%%%move:%robot.&move ]) 43
  70. Inject a closure in the binding def$robot%=%new%Robot() binding%=$new%Binding([ %%%%robot:%robot, %%%%*:%Direction.values() %%%%%%%%%%%%.collectEntries%{ %%%%%%%%%%%%%%%%[(it.name()):%it] %%%%%%%%%%%%}, %%%%move:%robot.&move ]) Method pointer (a closure) on robot’s move instance method 43
  71. Define a base script class abstract)class!RobotBaseScriptClass!!! !!!!!!!extends!Script!{ !!!!void!move(Direction!dir)!{ !!!!!!!!def)robot!=!this.binding.robot !!!!!!!!robot.move!dir !!!!} } 44
  72. Define a base script class abstract)class!RobotBaseScriptClass!!! !!!!!!!extends!Script!{ !!!!void!move(Direction!dir)!{ !!!!!!!!def)robot!=!this.binding.robot !!!!!!!!robot.move!dir !!!!} }The move() method isnow at the script level 44
  73. Define a base script class abstract)class!RobotBaseScriptClass!!! !!!!!!!extends!Script!{ !!!!void!move(Direction!dir)!{ !!!!!!!!def)robot!=!this.binding.robot !!!!!!!!robot.move!dir !!!!} }The move() method is Access the robot throughnow at the script level the script’s binding 44
  74. Configure the base script classdef)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass 45
  75. Configure the base script classdef)conf)=)new)CompilerConfiguration()conf.scriptBaseClass)=)RobotBaseScriptClass Scripts evaluated with this configuration will inherit from that class 45
  76. Ready for lift off! %%move%left
  77. Beep, beep...yes but how do you define the speed? ...beep...
  78. Oh no!
  79. What we could do now is... move!left,!at:!3.km/h 49
  80. What we could do now is... Mix of named and normal parameters move!left,!at:!3.km/h 49
  81. What we could do now is... Mix of named and normal parameters move!left,!at:!3.km/h How to add a km property to numbers? 49
  82. Adding properties to numbers• We need to: • define units, distance and speed • have a nice notation for them • that’s where we add properties to numbers! 50
  83. Unit enum and Distance classenum$DistanceUnit%{%%%%centimeter%(cm,%%%%0.01),%%%%meter%%%%%%(%m,%%%%1),%%%%%kilometer%%(km,%1000)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%Unit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}%%%%String%toString()%{%abbreviation%}%} 51
  84. Unit enum and Distance class @TupleConstructor%enum$DistanceUnit%{ class%Distance%{%%%%centimeter%(cm,%%%%0.01), %%%%double%amount%%%%%meter%%%%%%(%m,%%%%1),% %%%%DistanceUnit%unit%%%%kilometer%%(km,%1000)%%%%% %%%%String%toString()%{%%%%%String%abbreviation %%%%%%%%"$amount%$unit"%%%%%double%multiplier %%%%}%%%%% }%%%%Unit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}%%%%String%toString()%{%abbreviation%}%} 51
  85. Different techniques• To add dynamic methods or properties, there are several approaches at your disposal: • ExpandoMetaClass • custom MetaClass • Categories• Let’s have a look at the ExpandoMetaClass 52
  86. Using ExpandoMetaClass Number.metaClass.getCm%=%{%f>% %%%%new%Distance(delegate,%Unit.centimeter)% } Number.metaClass.getM%=%{%f>% %%%%new%Distance(delegate,%Unit.meter)% } Number.metaClass.getKm%=%{%f>% %%%%new%Distance(delegate,%Unit.kilometer)% } 53
  87. Using ExpandoMetaClass Add that tointegration.groovy Number.metaClass.getCm%=%{%f>% %%%%new%Distance(delegate,%Unit.centimeter)% } Number.metaClass.getM%=%{%f>% %%%%new%Distance(delegate,%Unit.meter)% } Number.metaClass.getKm%=%{%f>% %%%%new%Distance(delegate,%Unit.kilometer)% } 53
  88. Using ExpandoMetaClass Add that tointegration.groovy Number.metaClass.getCm%=%{%f>% %%%%new%Distance(delegate,%Unit.centimeter)% } Number.metaClass.getM%=%{%f>% %%%%new%Distance(delegate,%Unit.meter)% } Number.metaClass.getKm%=%{%f>% %%%%new%Distance(delegate,%Unit.kilometer)% } ‘delegate’ is the current number 53
  89. Using ExpandoMetaClass Add that tointegration.groovy Usage in your DSLs Number.metaClass.getCm%=%{%f>% %%%%new%Distance(delegate,%Unit.centimeter)% } 40.cm! Number.metaClass.getM%=%{%f>% %%%%new%Distance(delegate,%Unit.meter)% 3.5.m } 4.km Number.metaClass.getKm%=%{%f>% %%%%new%Distance(delegate,%Unit.kilometer)% } ‘delegate’ is the current number 53
  90. Distance okay, but speed?• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time 2.km/h 54
  91. Distance okay, but speed?• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time The div() method on Distance 2.km/h 54
  92. Distance okay, but speed?• For distance, we just added a property access after the number, but we now need to divide (‘div’) by the time The div() method on Distance 2.km/h An h duration instance in the binding 54
  93. First, let’s look at timeenum$TimeUnit%{%%%%hour%%%%%%(h,%%%3600),%%%%minute%%%%(min,%%%60),%%%%%kilometer%(s,%%%%%%1)%%%%%%%%%String%abbreviation%%%%double%multiplier%%%%%%%%TimeUnit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}%%%%String%toString()%{%abbreviation%}%} 55
  94. First, let’s look at time @TupleConstructor% class%Duration%{enum$TimeUnit%{ %%%%double%amount%%%%%hour%%%%%%(h,%%%3600), %%%%TimeUnit%unit%%%%minute%%%%(min,%%%60),%%%%%kilometer%(s,%%%%%%1)% %%%%String%toString()%{%%%%% %%%%%%%%"$amount%$unit"%%%%%String%abbreviation %%%%}%%%%%double%multiplier }%%%%%%%%TimeUnit(String%abbr,%double%mult)%{%%%%%%%%this.abbreviation%=%abbr%%%%%%%%this.multiplier%=%mult%%%%%}%%%%String%toString()%{%abbreviation%}%} 55
  95. Inject the ‘h’ hour constant in the binding def)binding!=)new!Binding([ !!!!robot:!new!Robot(), !!!!*:!Direction.values() !!!!!!!!!!!!.collectEntries!{ !!!!!!!!!!!!!!!![(it.name()):!it] !!!!!!!!!!!!}, !!!!h:!new!Duration(1,!TimeUnit.hour) ]) 56
  96. Now at (light!) speed @TupleConstructor) class)Speed){ ))))Distance)distance ))))Duration)duration ))))String)toString()){) ))))))))"$distance/$duration") ))))}) } 57
  97. Operator overloading a%+%b%%//%a.plus(b) a%f%b%%//%a.minus(b) • Currency amounts a%*%b%%//%a.multiply(b) • 15.euros + 10.dollars a%/%b%%//%a.div(b) a%%%b%%//%a.modulo(b) • Distance handling a%**%b%//%a.power(b) • 10.km - 10.m a%|%b%%//%a.or(b) a%&%b%%//%a.and(b) • Workflow, concurrency a%^%b%%//%a.xor(b) • taskA | taskB & taskC a[b]%%%//%a.getAt(b) a%<<%b%//%a.leftShift(b) • Credit an account a%>>%b%//%a.rightShift(b) +a%%%%%//%a.unaryPlus() • account << 10.dollars account += 10.dollars fa%%%%%//%a.unaryMinus() account.credit 10.dollars ~a%%%%%//%a.bitwiseNegate() 58
  98. Operator overloading• Update the Distance class with a div() method following the naming convetion for operators class%Distance%{ %%%%... %%%%Speed%div(Duration%t)%{ %%%%%%%%new%Speed(this,%t) %%%%} %%%%... } 59
  99. Operator overloading• Update the Distance class with a div() method following the naming convetion for operators class%Distance%{ %%%%... %%%%Speed%div(Duration%t)%{ %%%%%%%%new%Speed(this,%t) %%%%} %%%%... } Optional return 59
  100. Equivalence of notation• Those two notations are actually equivalent: 2.km/h 2.getKm().div(h) 60
  101. Equivalence of notation• Those two notations are actually equivalent: 2.km/h This one might be slightly more verbose! 2.getKm().div(h) 60
  102. Named parameters usage move!left,!at:!3.km/h 61
  103. Named parameters usage move!left,!at:!3.km/h Normal parameter 61
  104. Named parameters usage move!left,!at:!3.km/h Normal Named parameter parameter 61
  105. Named parameters usage move!left,!at:!3.km/h Normal Named parameter parameter Will call: def!take(Map!m,!Direction!q) 61
  106. Named parameters usage move!left,!at:!3.km/h Normal Named parameter parameter Will call: def!take(Map!m,!Direction!q) All named parameters go into the map argument 61
  107. Named parameters usage move!left,!at:!3.km/h Normal Named parameter parameter Will call: def!take(Map!m,!Direction!q) All named parameters go Positional parameters into the map argument come afterwards 61
  108. Named parameters usage move!left,!at:!3.km/h 62
  109. Named parameters usage move!left,!at:!3.km/h Can we get rid of the comma? 62
  110. Named parameters usage move!left,!at:!3.km/h Can we get rid of What about the the comma? colon too? 62
  111. Command chains• A grammar improvement in Groovy 1.8 allowing you to drop dots & parens when chaining method calls • an extended version of top-level statements like println• Less dots, less parens allow you to •write more readable business rules •in almost plain English sentences • (or any language, of course) 63
  112. Command chains %move%left%%at%3.km/h% 64
  113. Command chains Alternation of method names %move%left%%at%3.km/h% 64
  114. Command chains Alternation of method names %move%left%%at%3.km/h% and parameters (even named ones) 64
  115. Command chains %move%left%%at%3.km/h% 64
  116. Command chains Equivalent to: %%%%%(%%%%).%%(%%%%%%) %move%left%%at%3.km/h% 64
  117. Look Ma!No par ens, no dots!
  118. Command chains //%Java%fluent%API%approach class%Robot%{ %%%%... $$$$def%move(Direction%dir)%{ %%%%%%%%this.dir%=%dir %%%%%%%%return%this %%%%} %%%%def%at(Speed%speed)%{ %%%%%%%%this.speed%=%speed %%%%%%%%return%this %%%%} %%%%... } 66
  119. Command chains def)move(Direction)dir)){ ))))[at:){)Speed)speed)F> ))))))))))))... ))))))))}] ))))}] } 67
  120. Command chains def)move(Direction)dir)){ ))))[at:){)Speed)speed)F> ))))))))))))... Nested maps ))))))))}] and closures ))))}] } 67
  121. Command chains def)move(Direction)dir)){ ))))[at:){)Speed)speed)F> ))))))))))))... Nested maps ))))))))}] and closures ))))}] } Usage in your DSLs move%left%at%3.km/h 67
  122. Command chains 68
  123. Command chains //%methods%with%multiple%arguments%(commas) 68
  124. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor 68
  125. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation 68
  126. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good 68
  127. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures 68
  128. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} 68
  129. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens 68
  130. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names 68
  131. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names //%possible%with%an%odd%number%of%terms 68
  132. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names //%possible%with%an%odd%number%of%terms deploy%left%%arm 68
  133. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names //%possible%with%an%odd%number%of%terms deploy%left%%arm 68
  134. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good %%%%%(%%%%%%%%%%%).%%%%%%(%%%%) //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} //%zerofarg%methods%require%parens select%all%%unique()%from%names //%possible%with%an%odd%number%of%terms deploy%left%%arm 68
  135. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good %%%%%(%%%%%%%%%%%).%%%%%%(%%%%) //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} %%%%%(%%).%%%%(%%).%%%%(%%) //%zerofarg%methods%require%parens select%all%%unique()%from%names //%possible%with%an%odd%number%of%terms deploy%left%%arm 68
  136. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good %%%%%(%%%%%%%%%%%).%%%%%%(%%%%) //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} %%%%%(%%).%%%%(%%).%%%%(%%) //%zerofarg%methods%require%parens select%all%%unique()%from%names %%%%%%(%%%).%%%%%%%%.%%%%(%%%%%) //%possible%with%an%odd%number%of%terms deploy%left%%arm 68
  137. Command chains //%methods%with%multiple%arguments%(commas) take%coffee%%with%sugar,%milk%%and%liquor %%%%(%%%%%%).%%%%(%%%%%%%%%%%).%%%(%%%%%%) //%leverage%namedfargs%as%punctuation check%that:%vodka%%tastes%good %%%%%(%%%%%%%%%%%).%%%%%%(%%%%) //%closure%parameters%for%new%control%structures given%{}%%when%{}%%then%{} %%%%%(%%).%%%%(%%).%%%%(%%) //%zerofarg%methods%require%parens select%all%%unique()%from%names %%%%%%(%%%).%%%%%%%%.%%%%(%%%%%) //%possible%with%an%odd%number%of%terms deploy%left%%arm %%%%%%(%%%%). 68
  138. Final result 69
  139. Final result move!forward!at!3.km/h 69
  140. move forward at 3.km/h
  141. move forward at 3.km/h Yes! We did it!
  142. What about security and safety?
  143. Security and safety JVM Security Managers SecureASTCustomizer Sandboxing Controlling scripts execution 72
  144. Play it safe in a sandbox
  145. Playing it safe...• You have to think carefully about what DSL users are allowed to do with your DSL• Forbid things which are not allowed •leverage the JVM’s Security Managers • this might have an impact on performance •use a Secure AST compilation customizer • not so easy to think about all possible cases •avoid long running scripts with *Interrupt transformations 74
  146. Security Managers• Groovy is just a language leaving on the JVM, so you have access to the usual Security Managers mechanism • Nothing Groovy specific here • Please check the documentation on Security Managers and how to design policy files 75
  147. SecureASTCustomizer def!secure!=!new!SecureASTCustomizer() secure.with!{ //!disallow!closure!creation !!!closuresAllowed!=!false! //!disallow!method!definitions !!!methodDefinitionAllowed!=!false! //!empty!white!list!=>!forbid!certain!imports !!!importsWhitelist!=![...]! !!!staticImportsWhitelist!=![...] //!only!allow!some!static!import !!!staticStarImportsWhitelist!=![...] //!language!tokens!allowed !!!!tokensWhitelist!=![...] //!types!allowed!to!be!used !!!constantTypesClassesWhiteList!=![...] //!classes!who!are!allowed!to!be!receivers!of!method!calls !!!receiversClassesWhiteList!=![...] } def!config!=!new!CompilerConfiguration() config.addCompilationCustomizers(secure) def!shell!=!new!GroovyShell(config) 76
  148. Controlling code execution• Your application may run user’s code •what if the code runs in infinite loops or for too long? •what if the code consumes too many resources?• 3 new transforms at your rescue • @ThreadInterrupt: adds Thread#isInterrupted checks so your executing thread stops when interrupted • @TimedInterrupt: adds checks in method and closure bodies to verify it’s run longer than expected • @ConditionalInterrupt: adds checks with your own conditional logic to break out from the user code 77
  149. @ThreadInterrupt @ThreadInterrupt import%groovy.transform.ThreadInterrupt% % while%(true)%{ %%%%//%Any%extraterestrial%around? } 78
  150. @ThreadInterrupt @ThreadInterrupt import%groovy.transform.ThreadInterrupt% % while%(true)%{{ %%%%if%(Thread.currentThread.isInterrupted()) %%%%%%%%throw$new%InterruptedException() } %%%%//%Any%extraterestrial%around? } 78
  151. @TimedInterrupt @TimedInterrupt(10) import!groovy.transform.TimedInterrupt! ! while!(true)!{ !!!!move!left !!!!//!circle!forever }• InterruptedException thrown when checks indicate code ran longer than desired 79
  152. @ConditionalInterrupt• Specify your own condition to be inserted at the start of method and closure bodies • check for available resources, number of times run, etc.• Leverages closure annotation parameters from Groovy 1.8 @ConditionalInterrupt({$battery.level$<$O.1$}) import%groovy.transform.ConditionalInterrupt 100.times%{%%%% %%%%move%forward%at%10.km/h } 80
  153. Using compilation customizers• In our previous three examples, the usage of the interrupts were explicit, and users had to type them • if they want to deplete the battery of your robot, they won’t use interrupts, so you have to impose interrupts yourself• With compilation customizers you can inject those interrupts thanks to the ASTTransformationCustomizer 81
  154. What have we learnt? 82
  155. Groovy Power!™• A flexible and malleable syntax • scripts vs classes, optional typing, colons and parens• Groovy offers useful dynamic features for DSLs • operator overloading, ExpandoMetaClass• Can write almost plain natural language sentences • for readable, concise and expressive DSLs• Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox 83
  156. Groovy Power!™ Groovy is a great fit for DSLs!• A flexible and malleable syntax • scripts vs classes, optional typing, colons and parens• Groovy offers useful dynamic features for DSLs • operator overloading, ExpandoMetaClass• Can write almost plain natural language sentences • for readable, concise and expressive DSLs• Groovy DSLs are easy to integrate, and can be secured to run safely in your own sandbox 83
  157. And there’s more!• We haven’t dived into... •How to implement your own control structures with the help of closures •How to create Groovy « builders » •How to hijack the Groovy syntax to develop our own language extensions with AST Transformations •Source preprocessing for custom syntax •How to use the other dynamic metaprogramming techniques available •How to improve error reporting with customizers •IDE support with DSL descriptors (GDSL and DSLD) 84
  158. Thank you! ge e Lafor lopment Gui llaum ovy Deve Head of Gro om @ gmail.c laforge rge Email: g @glafo o/glaforg e Twitter : http://gplus.t spot.com : G oogle+ //glaforge.app p: B log: htt 85
  159. Questions & AnswersGot questions, really? 86
  160. Questions & Answers I might have answers!Got questions, really? 86
  161. Image credits• Pills: http://www.we-ew.com/wp-content/uploads/2011/01/plan-b-pills.jpg• Chains: http://2.bp.blogspot.com/-GXDVqUYSCa0/TVdBsON4tdI/AAAAAAAAAW4/EgJOUmAxB28/s1600/breaking-chains5_copy9611.jpg• Russian flag: http://good-wallpapers.com/pictures/4794/Russian%20Flag.jpg• Space odissey: http://dearjesus.files.wordpress.com/2010/04/2001_a_space_odyssey_1.jpg• HAL red: http://2.bp.blogspot.com/-yjsyPxUFicY/TcazwAltOaI/AAAAAAAAAho/GVT7wGhnrUM/s1600/2001-a-space-odyssey-HAL.jpg• Back in time: http://4.bp.blogspot.com/-Pt44Dk9J2EM/TrQx9YNmVcI/AAAAAAAAAk4/ivWw9Lja05k/s1600/clocky.jpg• USSR Space posters: http://www.flickr.com/photos/justinvg• Russian General: http://rickrozoff.files.wordpress.com/2012/02/general-nikolai-makarov.jpg• Rocket: http://blog.al.com/breaking/2009/03/soyuz_launch.jpg• Progress capsule: http://www.spacedaily.com/images/progress-ocean-desk-1024.jpg• Buran: http://www.buran.fr/mriya-antonov/Photos//050-Exhibition%20au%20Bourget%20avec%20Bourane-Airshow%20with%20Buran%20at%20Le%20Bourget-1134884.jpg• Man in space: http://vintagespace.files.wordpress.com/2010/11/voskhod-2_leonov.jpg• Sputnik 2: http://launiusr.files.wordpress.com/2010/06/sputnik2.jpg• Lunakod: http://www.astr.ua.edu/keel/space/lunakhod_moscow.jpg• Sandbox: http://www.turnbacktogod.com/wp-content/uploads/2008/09/sandbox.jpg• Repair: http://www.oneangels.com/wp-content/uploads/2012/03/repair1.jpg• Mars rover: http://wallpapers.free-review.net/wallpapers/49/Mars_rover%2C_Mars_-_03.jpg• Mars rover 2: http://www.universetoday.com/wp-content/uploads/2011/06/551038main_pia14156-43_946-710.jpg• Thumb: http://www.wpclipart.com/sign_language/thumbs_up_large.png.html• Night sky: http://www.aplf-planetariums.info/galeries/ciel_profond/2004-07-01-Voie_Lactee_Scorpion-Jean-Luc_PUGLIESI.jpg• Obama yes we can: http://www.dessinemoiunboulon.net/wp-content/uploads/2009/01/obama-yes-we-can_04-nov-08.jpg• Hook: http://winningware.com/blog/wp-content/uploads/2009/12/FishHookXSmall.jpg• HP 48 GX: http://calculators.torensma.net/files/images/hewlett-packard_hp-48g.jpg• Omer: http://www.irmin.com/wallpaper/TV/Homer%20Simpson%20Oh%20No.jpg• Cadenat: http://acsgsecurite.com/upl/site/cadenat.png 87

×