Submit Search
Upload
make builds groovy
•
1 like
•
673 views
G
guest88884d
Follow
ant, groovy, maven and gradle
Read less
Read more
Technology
Report
Share
Report
Share
1 of 67
Download now
Download to read offline
Recommended
Make Your Builds More Groovy
Make Your Builds More Groovy
Paul King
Dynamic Language Practices
Dynamic Language Practices
Paul King
GroovyDSLs
GroovyDSLs
Paul King
Challenges in Maintaining a High Performance Search Engine Written in Java
Challenges in Maintaining a High Performance Search Engine Written in Java
lucenerevolution
ROM Hacking for Fun, Profit & Infinite Lives
ROM Hacking for Fun, Profit & Infinite Lives
Ulisses Albuquerque
Tech Ed09 India Ver M New
Tech Ed09 India Ver M New
rsnarayanan
Wind River Medical Devices
Wind River Medical Devices
Marco Thompson
Pv Android Slides For Posting
Pv Android Slides For Posting
Marco Thompson
Recommended
Make Your Builds More Groovy
Make Your Builds More Groovy
Paul King
Dynamic Language Practices
Dynamic Language Practices
Paul King
GroovyDSLs
GroovyDSLs
Paul King
Challenges in Maintaining a High Performance Search Engine Written in Java
Challenges in Maintaining a High Performance Search Engine Written in Java
lucenerevolution
ROM Hacking for Fun, Profit & Infinite Lives
ROM Hacking for Fun, Profit & Infinite Lives
Ulisses Albuquerque
Tech Ed09 India Ver M New
Tech Ed09 India Ver M New
rsnarayanan
Wind River Medical Devices
Wind River Medical Devices
Marco Thompson
Pv Android Slides For Posting
Pv Android Slides For Posting
Marco Thompson
Final Marco Solekai Coffee 2 For Posting
Final Marco Solekai Coffee 2 For Posting
Marco Thompson
Innovive April 09
Innovive April 09
Marco Thompson
Ultrastar Damon Rubio
Ultrastar Damon Rubio
Marco Thompson
Final Martin Coffee March 4 2010 For Posting
Final Martin Coffee March 4 2010 For Posting
Marco Thompson
Wind River Chumby Motorola Stacatto
Wind River Chumby Motorola Stacatto
Marco Thompson
Solekai Digital Living Pitch
Solekai Digital Living Pitch
Marco Thompson
Linked in training 10.0
Linked in training 10.0
Marco Thompson
VIP Roundtable - Medical Devices
VIP Roundtable - Medical Devices
Marco Thompson
Ipsos&ISC - New media usage summary report 2013
Ipsos&ISC - New media usage summary report 2013
Nikola Jovanovic
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Nikola Jovanovic
Emocionalna inteligencija & Lideri
Emocionalna inteligencija & Lideri
Nikola Jovanovic
Verimatrix Digital Living
Verimatrix Digital Living
Marco Thompson
Rob Hoffman\'s Wind River Slides
Rob Hoffman\'s Wind River Slides
Marco Thompson
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Marco Thompson
How To Make Your Testing More Groovy
How To Make Your Testing More Groovy
Craig Smith
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Novell
Paulking dlp
Paulking dlp
d0nn9n
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
JAX London
Groovy Testing Aug2009
Groovy Testing Aug2009
guest4a266c
Groovy Tutorial
Groovy Tutorial
Paul King
Smalltalk in Enterprise Applications
Smalltalk in Enterprise Applications
ESUG
Agile Testing Practices
Agile Testing Practices
Paul King
More Related Content
Viewers also liked
Final Marco Solekai Coffee 2 For Posting
Final Marco Solekai Coffee 2 For Posting
Marco Thompson
Innovive April 09
Innovive April 09
Marco Thompson
Ultrastar Damon Rubio
Ultrastar Damon Rubio
Marco Thompson
Final Martin Coffee March 4 2010 For Posting
Final Martin Coffee March 4 2010 For Posting
Marco Thompson
Wind River Chumby Motorola Stacatto
Wind River Chumby Motorola Stacatto
Marco Thompson
Solekai Digital Living Pitch
Solekai Digital Living Pitch
Marco Thompson
Linked in training 10.0
Linked in training 10.0
Marco Thompson
VIP Roundtable - Medical Devices
VIP Roundtable - Medical Devices
Marco Thompson
Ipsos&ISC - New media usage summary report 2013
Ipsos&ISC - New media usage summary report 2013
Nikola Jovanovic
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Nikola Jovanovic
Emocionalna inteligencija & Lideri
Emocionalna inteligencija & Lideri
Nikola Jovanovic
Verimatrix Digital Living
Verimatrix Digital Living
Marco Thompson
Rob Hoffman\'s Wind River Slides
Rob Hoffman\'s Wind River Slides
Marco Thompson
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Marco Thompson
Viewers also liked
(14)
Final Marco Solekai Coffee 2 For Posting
Final Marco Solekai Coffee 2 For Posting
Innovive April 09
Innovive April 09
Ultrastar Damon Rubio
Ultrastar Damon Rubio
Final Martin Coffee March 4 2010 For Posting
Final Martin Coffee March 4 2010 For Posting
Wind River Chumby Motorola Stacatto
Wind River Chumby Motorola Stacatto
Solekai Digital Living Pitch
Solekai Digital Living Pitch
Linked in training 10.0
Linked in training 10.0
VIP Roundtable - Medical Devices
VIP Roundtable - Medical Devices
Ipsos&ISC - New media usage summary report 2013
Ipsos&ISC - New media usage summary report 2013
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Nikola Jovanovic - Eh, da mi je neko ovo rekao pre 15 godina.
Emocionalna inteligencija & Lideri
Emocionalna inteligencija & Lideri
Verimatrix Digital Living
Verimatrix Digital Living
Rob Hoffman\'s Wind River Slides
Rob Hoffman\'s Wind River Slides
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Aero & Defense - VIP Coffee with Gene Ray - Wind River Overview
Similar to make builds groovy
How To Make Your Testing More Groovy
How To Make Your Testing More Groovy
Craig Smith
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Novell
Paulking dlp
Paulking dlp
d0nn9n
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
JAX London
Groovy Testing Aug2009
Groovy Testing Aug2009
guest4a266c
Groovy Tutorial
Groovy Tutorial
Paul King
Smalltalk in Enterprise Applications
Smalltalk in Enterprise Applications
ESUG
Agile Testing Practices
Agile Testing Practices
Paul King
Rationalize Android Development with StAnD - Clement Escoffier, akquinet
Rationalize Android Development with StAnD - Clement Escoffier, akquinet
Paris Open Source Summit
groovy and concurrency
groovy and concurrency
Paul King
Continuous Development with Jenkins - Stephen Connolly at PuppetCamp Dublin '12
Continuous Development with Jenkins - Stephen Connolly at PuppetCamp Dublin '12
Puppet
Safe and Reliable Embedded Linux Programming: How to Get There
Safe and Reliable Embedded Linux Programming: How to Get There
AdaCore
Ben Pashkoff - java embedded - 24mai2011
Ben Pashkoff - java embedded - 24mai2011
Agora Group
E-GEN/iCAN
E-GEN/iCAN
teddi22
Groovy Testing Sep2009
Groovy Testing Sep2009
Paul King
Radovan Janecek R E S Tor S O A Pv1
Radovan Janecek R E S Tor S O A Pv1
SOA Symposium
Shannon McFarland OpenStack/Cisco Intro
Shannon McFarland OpenStack/Cisco Intro
Shannon McFarland
Optimizing HTML5 Sites with CQ5/WEM
Optimizing HTML5 Sites with CQ5/WEM
Gabriel Walt
Lean Engineering. Applying Lean Principles to Building Experiences
Lean Engineering. Applying Lean Principles to Building Experiences
Bill Scott
EclipseConEurope2012 SOA - Models As Operational Documentation
EclipseConEurope2012 SOA - Models As Operational Documentation
Marc Dutoo
Similar to make builds groovy
(20)
How To Make Your Testing More Groovy
How To Make Your Testing More Groovy
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Lessons Learned: Novell Open Enterprise Server Upgrades Made Easy
Paulking dlp
Paulking dlp
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
Achieving genuine elastic multitenancy with the Waratek Cloud VM for Java : J...
Groovy Testing Aug2009
Groovy Testing Aug2009
Groovy Tutorial
Groovy Tutorial
Smalltalk in Enterprise Applications
Smalltalk in Enterprise Applications
Agile Testing Practices
Agile Testing Practices
Rationalize Android Development with StAnD - Clement Escoffier, akquinet
Rationalize Android Development with StAnD - Clement Escoffier, akquinet
groovy and concurrency
groovy and concurrency
Continuous Development with Jenkins - Stephen Connolly at PuppetCamp Dublin '12
Continuous Development with Jenkins - Stephen Connolly at PuppetCamp Dublin '12
Safe and Reliable Embedded Linux Programming: How to Get There
Safe and Reliable Embedded Linux Programming: How to Get There
Ben Pashkoff - java embedded - 24mai2011
Ben Pashkoff - java embedded - 24mai2011
E-GEN/iCAN
E-GEN/iCAN
Groovy Testing Sep2009
Groovy Testing Sep2009
Radovan Janecek R E S Tor S O A Pv1
Radovan Janecek R E S Tor S O A Pv1
Shannon McFarland OpenStack/Cisco Intro
Shannon McFarland OpenStack/Cisco Intro
Optimizing HTML5 Sites with CQ5/WEM
Optimizing HTML5 Sites with CQ5/WEM
Lean Engineering. Applying Lean Principles to Building Experiences
Lean Engineering. Applying Lean Principles to Building Experiences
EclipseConEurope2012 SOA - Models As Operational Documentation
EclipseConEurope2012 SOA - Models As Operational Documentation
Recently uploaded
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Victor Rentea
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
ThousandEyes
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
apidays
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Zilliz
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
sudhanshuwaghmare1
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
MIND CTI
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Juan lago vázquez
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
apidays
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
Nanddeep Nachan
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
apidays
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Orbitshub
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
Product Anonymous
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
Overkill Security
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
Khushali Kathiriya
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
Overkill Security
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
debabhi2
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
sammart93
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Safe Software
Recently uploaded
(20)
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Apidays New York 2024 - Accelerating FinTech Innovation by Vasa Krishnan, Fin...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Navigating the Deluge_ Dubai Floods and the Resilience of Dubai International...
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
make builds groovy
1.
© ASERT 2008-2010
Make Your Builds More Groovy Dr Paul King paulk@asert.com.au @paulk_asert ASERT, Australia ESDC 2010 - 1
2.
Topics
Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 2
3.
Build Pain Points...
• Has anyone seen? – Large monolithic balls of mud – Complex usage, assumptions, conventions – Impossible to bend in desired ways – Never been (can't be) refactored/tested – © ASERT 2008-2010 Many manual steps – Environment fragile • different machines, CI vs IDE, dev vs prod vs test ESDC 2010 - 3
4.
...Build Pain Points...
• Require powerful features – Dependency management – Version management – Polyglot compilation – Artifact production and manipulation (jar, war, ...) – Templating (generation of boilerplate text files) © ASERT 2008-2010 – Multifacted testing – Reporting – Quality control (Metrics, code quality, static analysis) – Property management – Infinitely(?) extensible ESDC 2010 - 4
5.
...Build Pain Points
• Useful characteristics – Tool friendly – Cross platform – IDE support, CI support – Refactorable – Testable © ASERT 2008-2010 – Minimal noise (DSL like) – Easy to extend – Conventions – Good documentation – Polyglot friendly ESDC 2010 - 5
6.
Topics
• Build Pain Points Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 6
7.
Build Tools
• Non-exhaustive list – Ant, Maven, EasyAnt – Gant, GMaven, Gradle, Graven (uptake?), Groovy Frontend for Ant (emerge from sandbox?) – Rake, Raven, Buildr – Make, SCons, Waf © ASERT 2008-2010 – MSBuild, Nant • Used by – Developers: NetBeans, Eclipse, Intellij, Command-line – CI: Hudson (Groovy support and console), Team City, CruiseControl, AnthillPro (Groovy support), Bamboo – Deployment Management: Tableaux (Groovy support) – Ad-hoc: batch processing, production applications ESDC 2010 - 7
8.
Pros/Cons of Traditional
Tools • Ant • Maven – Flexible (supports any – Opinionated about convention) conventions – Easy to extend • Mostly a good thing – Wealth of useful tasks – Mostly declarative – Well documented • XML != concise DSL – Numerous plugins © ASERT 2008-2010 – Partially declarative but some scope for – Some easy extension procedural instructions points but some more • XML != prog. language difficult options – Lifecycle is hand-crafted • Some things beyond some teams in your build file – Structured lifecycle – Can use Ivy or Maven Ant tasks for dependency management ESDC 2010 - 8
9.
Enhancing Traditional Tools
• Ant + Groovy • Maven + Groovy – Easy to write the – Easier to extend procedural pieces – More concise syntax – Easier to refactor – Some scope for – Easier to test refactoring – Ease of creating a build © ASERT 2008-2010 DSL – More concise – Better interaction with • Gradle Java – Take the best of both – No impedence worlds and combine mismatch with them developers ESDC 2010 - 9
10.
A Preview Example... ©
ASERT 2008-2010 ESDC 2010 - 10
11.
...A Preview Example...
StringUtils: Vanilla Ant + Ivy <project name="StringUtilsBuild" default="package" <?xml version="1.0" encoding="ISO-8859-1"?> xmlns:ivy="antlib:org.apache.ivy.ant" xmlns="antlib:org.apache.tools.ant"> <target name="clean"> <ivy-module version="1.0"> <delete dir="target"/> <info organisation="org" module="groovycookbook" /> <delete dir="lib"/> <dependencies> </target> <dependency name="junit" rev="4.7" /> <target name="compile" depends="-init-ivy"> </dependencies> <mkdir dir="target/classes"/> </ivy-module> <javac srcdir="src/main" destdir="target/classes"/> </target> <target name="compileTest" depends="compile"> <mkdir dir="target/test-classes"/> <ivysettings> <javac srcdir="src/test" <settings defaultResolver="chained"/> destdir="target/test-classes"> <resolvers> <classpath> <chain name="chained" returnFirst="true"> <pathelement location="target/classes"/> <ibiblio name="ibiblio" /> <fileset dir="lib" includes="*.jar"/> <url name="ibiblio-mirror"> </classpath> </javac> <artifact </target> pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ © ASERT 2008-2010 [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> <target name="test" depends="compileTest"> </url> <mkdir dir="target/test-reports"/> </chain> <junit printsummary="yes" fork="yes" haltonfailure="yes"> </resolvers> <classpath> </ivysettings> <pathelement location="target/classes"/> <pathelement location="target/test-classes"/> <fileset dir="lib" includes="*.jar"/> </classpath> <formatter type="plain"/> <formatter type="xml"/> <batchtest fork="yes" todir="target/test-reports"> <fileset dir="target/test-classes"/> </batchtest> </junit> </target> <target name="package" depends="test"> <jar destfile="target/stringutils-1.0-SNAPSHOT.jar" basedir="target/classes"/> </target> <target name="-init-ivy" depends="-download-ivy"> <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpath="lib/ivy.jar"/> <ivy:settings file="ivysettings.xml"/> <ivy:retrieve/> </target> <target name="-download-ivy"> <property name="ivy.version" value="2.1.0-rc2"/> <mkdir dir="lib"/> <get src="http://repo2.maven.org/maven2/org/apache/ivy/ivy/${ivy.version}/ivy- ${ivy.version}.jar" dest="lib/ivy.jar" usetimestamp="true"/> </target> </project> ESDC 2010 - 11
12.
...A Preview Example...
StringUtils: Groovy's AntBuilder ... import static groovy.xml.NamespaceBuilder.newInstance as namespace def test() { ant = new AntBuilder() compileTest() clean() ant.mkdir dir: 'target/test-reports' doPackage() ant.junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { classpath { def doPackage() { pathelement location: 'target/classes' test() pathelement location: 'target/test-classes' ant.jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', fileset dir: 'lib', includes: '*.jar' basedir: 'target/classes' } } formatter type: 'plain' formatter type: 'xml' private dependencies() { batchtest(todir: 'target/test-reports', fork: 'yes') { def ivy_version = '2.1.0-rc2' fileset dir: 'target/test-classes' def repo = 'http://repo2.maven.org/maven2' } ant.mkdir dir: 'lib' } ant.get dest: 'lib/ivy.jar', } usetimestamp: 'true', src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" ant.taskdef classpath: 'lib/ivy.jar', © ASERT 2008-2010 uri: 'antlib:org.apache.ivy.ant', resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() <?xml version="1.0" encoding="ISO-8859-1"?> } <ivy-module version="1.0"> <info organisation="org" module="groovycookbook" /> def clean() { <dependencies> ant.delete dir: 'target' ant.delete dir: 'lib' <dependency name="junit" rev="4.7" /> } </dependencies> </ivy-module> def compile() { dependencies() ant.mkdir dir: 'target/classes' ant.javac destdir: 'target/classes', srcdir: 'src/main', <ivysettings> includeantruntime: false <settings defaultResolver="chained"/> } <resolvers> <chain name="chained" returnFirst="true"> def compileTest() { <ibiblio name="ibiblio" /> compile() <url name="ibiblio-mirror"> ant.mkdir dir: 'target/test-classes' <artifact ant.javac(destdir: 'target/test-classes', srcdir: 'src/test', pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ includeantruntime: false) { [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> classpath { </url> pathelement location: 'target/classes' </chain> fileset dir: 'lib', includes: '*.jar' </resolvers> } </ivysettings> } } ... ESDC 2010 - 12
13.
...A Preview Example...
StringUtils: Gant ... import static groovy.xml.NamespaceBuilder.newInstance as namespace target(test: '') { target('package': '') { depends 'compileTest' depends 'test' mkdir dir: 'target/test-reports' jar destfile: 'target/stringutils-1.0-SNAPSHOT.jar', junit(printsummary: 'yes', haltonfailure: 'yes', fork: 'yes') { basedir: 'target/classes' classpath { } pathelement location: 'target/classes' pathelement location: 'target/test-classes' target('-download-ivy': '') { fileset dir: 'lib', includes: '*.jar' def ivy_version = '2.1.0-rc2' } def repo = 'http://repo2.maven.org/maven2' formatter type: 'plain' mkdir dir: 'lib' formatter type: 'xml' get dest: 'lib/ivy.jar', batchtest(todir: 'target/test-reports', fork: 'yes') { usetimestamp: 'true', fileset dir: 'target/test-classes' src: "$repo/org/apache/ivy/ivy/$ivy_version/ivy-${ivy_version}.jar" } } } } target(clean: '') { delete dir: 'target' setDefaultTarget 'package' delete dir: 'lib' © ASERT 2008-2010 } target(compile: '') { depends '-init-ivy' mkdir dir: 'target/classes' <?xml version="1.0" encoding="ISO-8859-1"?> javac destdir: 'target/classes', srcdir: 'src/main' <ivy-module version="1.0"> } <info organisation="org" module="groovycookbook" /> <dependencies> target('-init-ivy': '') { depends '-download-ivy' <dependency name="junit" rev="4.7" /> taskdef classpath: 'lib/ivy.jar', </dependencies> uri: 'antlib:org.apache.ivy.ant', </ivy-module> resource: 'org/apache/ivy/ant/antlib.xml' def ivy = namespace(ant, 'antlib:org.apache.ivy.ant') ivy.settings file: 'ivysettings.xml' ivy.retrieve() <ivysettings> } <settings defaultResolver="chained"/> <resolvers> target(compileTest: '') { <chain name="chained" returnFirst="true"> depends 'compile' <ibiblio name="ibiblio" /> mkdir dir: 'target/test-classes' <url name="ibiblio-mirror"> javac(destdir: 'target/test-classes', srcdir: 'src/test') { <artifact classpath { pattern="http://mirrors.ibiblio.org/pub/mirrors/maven2/[organisation]/ pathelement location: 'target/classes' [module]/[branch]/[revision]/[branch]-[revision].[ext]" /> fileset dir: 'lib', includes: '*.jar' </url> } </chain> } </resolvers> } </ivysettings> ... ESDC 2010 - 13
14.
...A Preview Example...
StringUtils: Maven <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.groovycookbook.builds</groupId> <artifactId>stringutils</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>stringutils</name> <url>http://maven.apache.org</url> <dependencies> © ASERT 2008-2010 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <!-- this is a java 1.5 project --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> </project> ESDC 2010 - 14
15.
...A Preview Example
StringUtils: Gradle usePlugin 'java' sourceCompatibility = 1.5 version = '1.0-SNAPSHOT' repositories { © ASERT 2008-2010 mavenCentral() } dependencies { testCompile 'junit:junit:4.7' } ESDC 2010 - 15
16.
Topics
• Build Pain Points • Build Tool Landscape Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools • More Info ESDC 2010 - 16
17.
What is Groovy?
• “Groovy is like a super version of Java. It can leverage Java's enterprise capabilities but also has cool productivity features like closures, DSL support, builders and dynamic typing.” © ASERT 2008-2010 Groovy = Java – boiler plate code + optional dynamic typing + closures + domain specific languages + builders + metaprogramming + GDK library ESDC 2010 - 17
18.
Groovy Goodies Overview
• Fully object oriented • Closures: reusable and assignable pieces of code • Operators can be • GPath: efficient overloaded © ASERT 2008-2010 object navigation • Multimethods • GroovyBeans • Literal declaration for • grep and switch lists (arrays), maps, ranges and regular • Templates, builder, expressions swing, Ant, markup, XML, SQL, XML-RPC, Scriptom, Grails, tests, Mocks ESDC 2010 - 18
19.
Growing Acceptance …
A slow and steady start but now gaining in momentum, maturity and mindshare Now free
20.
… Growing Acceptance
… © ASERT 2008-2010 ESDC 2010 - 20
21.
… Growing Acceptance
… © ASERT 2008-2010 Groovy and Grails downloads: 70-90K per month and growing ESDC 2010 - 21
22.
… Growing Acceptance
… © ASERT 2008-2010 Source: http://www.micropoll.com/akira/mpresult/501697-116746 Source: http://www.grailspodcast.co ESDC 2010 - 22
23.
… Growing Acceptance
… © ASERT 2008-2010 http://www.jroller.com/scolebourne/entry/devoxx_2008_whitebo http://www.java.net ESDC 2010 - 23
24.
… Growing Acceptance ©
ASERT 2006-2010 http://pollpigeon.com/jsf-grails-wicket/r/25665/ ESDC 2010 - 24
25.
… Growing Acceptance
… What alternative JVM language are you using or intending to use © ASERT 2008-2010 http://www.leonardoborges.com/writings ESDC 2010 - 25
26.
… Growing Acceptance
… © ASERT 2008-2010 http://it-republik.de/jaxenter/quickvote/results/1/poll/44 (translated using http://babelfish.yahoo ESDC 2010 - 26
27.
… Growing Acceptance ©
ASERT 2008-2010 ESDC 2010 - 27
28.
The Landscape of
JVM Languages mostly dynamic typing © ASERT 2008-2010 Dynamic features call for dynamic types Java bytecode calls for static types The terms “Java Virtual Machine” and “JVM” mean a Virtual Machine for the Java™ platform. ESDC 2010 - 28
29.
Groovy Starter
System.out.println("Hello, World!"); // optional semicolon, println 'Hello, World!' // System.out, brackets, // main() method, class defn def name = 'Guillaume' // dynamic typing println "$name, I'll get the car." // GString String longer = """${name}, the car is in the next row.""" // multi-line string // with static typing © ASERT 2008-2010 assert 0.5 == 1/2 // BigDecimal equals() def printSize(obj) { // optional duck typing print obj?.size() // safe dereferencing } def pets = ['ant', 'bee', 'cat'] // native list syntax pets.each { pet -> // closure support assert pet < 'dog' // overloading '<' on String } // or: for (pet in pets)... ESDC 2010 - 29
30.
A Better Java...
import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { This code List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { is valid String s = (String) strings.get(i); if (s.length() <= length) { Java and } result.add(s); valid Groovy } return result; © ASERT 2008-2010 } public static void main(String[] args) { List names = new ArrayList(); names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); System.out.println(names); Erase e = new Erase(); Based on an List shortNames = e.removeLongerThan(names, 3); System.out.println(shortNames.size()); example by for (int i = 0; i < shortNames.size(); i++) { Jim Weirich String s = (String) shortNames.get(i); System.out.println(s); & Ted Leung } } } ESDC 2010 - 30
31.
...A Better Java...
import java.util.List; import java.util.ArrayList; class Erase { private List removeLongerThan(List strings, int length) { Do the List result = new ArrayList(); for (int i = 0; i < strings.size(); i++) { semicolons String s = (String) strings.get(i); if (s.length() <= length) { add anything? } result.add(s); And shouldn‟t } we us more return result; © ASERT 2008-2010 } modern list public static void main(String[] args) { List names = new ArrayList(); notation? names.add("Ted"); names.add("Fred"); names.add("Jed"); names.add("Ned"); Why not System.out.println(names); import common Erase e = new Erase(); List shortNames = e.removeLongerThan(names, 3); libraries? System.out.println(shortNames.size()); for (int i = 0; i < shortNames.size(); i++) { String s = (String) shortNames.get(i); System.out.println(s); } } } ESDC 2010 - 31
32.
...A Better Java...
class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) } } return result } public static void main(String[] args) { List names = new ArrayList() © ASERT 2008-2010 names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") System.out.println(names) Erase e = new Erase() List shortNames = e.removeLongerThan(names, 3) System.out.println(shortNames.size()) for (String s in shortNames) { System.out.println(s) } } } ESDC 2010 - 32
33.
...A Better Java...
class Erase { private List removeLongerThan(List strings, int length) { List result = new ArrayList() for (String s in strings) { if (s.length() <= length) { result.add(s) Do we need } } the static types? } return result Must we always have a main public static void main(String[] args) { List names = new ArrayList() method and © ASERT 2008-2010 names.add("Ted"); names.add("Fred") names.add("Jed"); names.add("Ned") class definition? System.out.println(names) Erase e = new Erase() How about List shortNames = e.removeLongerThan(names, 3) improved System.out.println(shortNames.size()) for (String s in shortNames) { consistency? System.out.println(s) } } } ESDC 2010 - 33
34.
...A Better Java...
def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) } } return result } © ASERT 2008-2010 names = new ArrayList() names.add("Ted") names.add("Fred") names.add("Jed") names.add("Ned") System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } ESDC 2010 - 34
35.
...A Better Java...
def removeLongerThan(strings, length) { def result = new ArrayList() for (s in strings) { if (s.size() <= length) { result.add(s) Shouldn‟t we } } have special return result notation for lists? } And special © ASERT 2008-2010 names = new ArrayList() facilities for names.add("Ted") names.add("Fred") list processing? names.add("Jed") Is „return‟ names.add("Ned") needed at end? System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) for (s in shortNames) { System.out.println(s) } ESDC 2010 - 35
36.
...A Better Java...
def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } names = ["Ted", "Fred", "Jed", "Ned"] System.out.println(names) shortNames = removeLongerThan(names, 3) System.out.println(shortNames.size()) shortNames.each{ System.out.println(s) } © ASERT 2008-2010 ESDC 2010 - 36
37.
...A Better Java...
def removeLongerThan(strings, length) { strings.findAll{ it.size() <= length } } Is the method names = ["Ted", "Fred", "Jed", "Ned"] now needed? System.out.println(names) shortNames = removeLongerThan(names, 3) Easier ways to System.out.println(shortNames.size()) use common shortNames.each{ System.out.println(s) } methods? © ASERT 2008-2010 Are brackets required here? ESDC 2010 - 37
38.
...A Better Java...
names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2008-2010 ESDC 2010 - 38
39.
...A Better Java
names = ["Ted", "Fred", "Jed", "Ned"] println names shortNames = names.findAll{ it.size() <= 3 } println shortNames.size() shortNames.each{ println it } © ASERT 2008-2010 [Ted, Fred, Jed, Ned] 3 Ted Jed Ned ESDC 2010 - 39
40.
Topics
• Build Pain Points • Build Tool Landscape • Groovy Intro Ant & friends Calling Groovy from Ant © ASERT 2008-2010 Calling Ant from Groovy Gant • Maven & friends • Gradle • Other Tools • More Info ESDC 2010 - 40
41.
What is Ant?
• Tool to assist automating (build) steps <project name="MyProject" default="dist" basedir="."> <property name="src" location="src"/> <property name="build" location="build"/> © ASERT 2008-2010 <target name="init"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="compile the source"> <javac srcdir="${src}" destdir="${build}"/> </target> </project> ESDC 2010 - 41
42.
Groovy from Ant
• Need groovy jar on your Ant classpath <taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy" classpathref="my.classpath"/> © ASERT 2006-2010 <target name="printXmlFileNamesFromJar"> <zipfileset id="found" src="foobar.jar" includes="**/*.xml"/> <groovy> project.references.found.each { println it.name } </groovy> </target> ESDC 2010 - 42
43.
Groovyc from Ant
• Need groovy jar on your Ant classpath <taskdef name="groovyc" classname="org.codehaus.groovy.ant.Groovyc" classpathref="my.classpath"/> <groovyc srcdir="${testSourceDirectory}" © ASERT 2006-2010 destdir="${testClassesDirectory}"> <classpath> <pathelement path="${mainClassesDirectory}"/> <pathelement path="${testClassesDirectory}"/> <path refid="testPath"/> </classpath> <javac source="1.5" target="1.5" debug="on" /> </groovyc> ESDC 2010 - 43
44.
AntBuilder...
def ant = new AntBuilder() ant.echo("hello") // let's just call one task // create a block of Ant using the builder pattern ant.with { myDir = "target/AntTest/" mkdir(dir: myDir) © ASERT 2006-2010 copy(todir: myDir) { fileset(dir: "src/test") { include(name: "**/*.groovy") } } echo("done") } // now let's do some normal Groovy again file = new File("target/test/AntTest.groovy") assert file.exists() Needs ant.jar on your Groovy classpath ESDC 2010 - 44
45.
...AntBuilder
• Built-in new AntBuilder().with { echo(file:'Temp.java', ''' class Temp { public static void main(String[] args) { System.out.println("Hello"); } © ASERT 2006-2010 } ''') javac(srcdir:'.', includes:'Temp.java', fork:'true') java(classpath:'.', classname:'Temp', fork:'true') echo('Done') } // => // [javac] Compiling 1 source file // [java] Hello // [echo] Done ESDC 2010 - 45
46.
Using AntLibs: Maven
Ant Tasks & AntUnit import static groovy.xml.NamespaceBuilder.newInstance as namespace def ant = new AntBuilder() def mvn = namespace(ant, 'antlib:org.apache.maven.artifact.ant') def antunit = namespace(ant, 'antlib:org.apache.ant.antunit') direct = [groupId:'jfree', artifactId:'jfreechart', version:'1.0.9'] indirect = [groupId:'jfree', artifactId:'jcommon', version:'1.0.12'] // download artifacts mvn.dependencies(filesetId:'artifacts') { dependency(direct) } © ASERT 2006-2010 // print out what we downloaded ant.fileScanner { fileset(refid:'artifacts') }.each { println it } // use AntUnit to confirm expected files were downloaded def prefix = System.properties.'user.home' + '/.m2/repository' [direct, indirect].each { item -> def (g, a, v) = [item.groupId, item.artifactId, item.version] antunit.assertFileExists(file:"$prefix/$g/$a/$v/$a-${v}.jar") } C:Userspaulk.m2repositoryjfreejcommon1.0.12jcommon-1.0.12.jar C:Userspaulk.m2repositoryjfreejfreechart1.0.9jfreechart-1.0.9.jar ESDC 2010 - 46
47.
Builds: Gant
• lightweight façade on Groovy's AntBuilder • target def’ns, pre-defined ‘ant’, operations on predefined objects includeTargets << gant.targets.Clean cleanPattern << [ '**/*~' , '**/*.bak' ] cleanDirectory << 'build' © ASERT 2006-2010 target ( stuff : 'A target to do some stuff.' ) { println ( 'Stuff' ) depends ( clean ) echo ( message : 'A default message from Ant.' ) otherStuff ( ) } target ( otherStuff : 'A target to do some other stuff' ) { println ( 'OtherStuff' ) echo ( message : 'Another message from Ant.' ) clean ( ) } ESDC 2010 - 47
48.
Topics
• Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends Maven & friends © ASERT 2008-2010 Writing plugins in Groovy Building your Groovy project • Gradle • Other Tools • More Info ESDC 2010 - 48
49.
What is Maven?
• Tool to assist automating (build) steps © ASERT 2008-2010 ESDC 2010 - 49
50.
Builds: GMaven...
• Implementing Maven plugins has never been Groovier! • Groovy Mojos – A Simple Groovy Mojo • Building Plugins – Project Definition © ASERT 2006-2010 – Mojo Parameters • Putting More Groove into your Mojo – Using ant, Using fail() • gmaven-archetype-mojo Archetype • gmaven-plugin Packaging ESDC 2010 - 50
51.
...Builds: GMaven...
<plugin> <groupId>org.codehaus.groovy.maven</groupId> <artifactId>gmaven-plugin</artifactId> <executions> <execution> <phase>generate-resources</phase> <goals> <goal>execute</goal> </goals> <configuration> © ASERT 2006-2010 <source> if (project.packaging != 'pom') { log.info('Copying some stuff...') def dir = new File(project.basedir, 'target/classes/META-IN ant.mkdir(dir: dir) ant.copy(todir: dir) { fileset(dir: project.basedir) { include(name: 'LICENSE.txt') include(name: 'NOTICE.txt') } } } </source> </configuration> </execution> </executions> </plugin> ESDC 2010 - 51
52.
...Builds: GMaven...
<plugin> <groupId>org.codehaus.mojo.groovy</groupId> <artifactId>groovy-maven-plugin</artifactId> <executions> <execution> <id>restart-weblogic</id> © ASERT 2006-2010 <phase>pre-integration-test</phase> <goals> <goal>execute</goal> </goals> <configuration> <source> ${pom.basedir}/src/main/script/restartWeblogic.groovy </source> </configuration> </execution> ... ESDC 2010 - 52
53.
...Builds: GMaven...
def domainDir = project.properties['weblogic.domain.easyimage.dir'] stopWebLogic() copyFiles(domainDir) startWebLogic(domainDir) © ASERT 2006-2010 waitForWebLogicStartup() def stopWebLogic() { weblogicServerDir = project.properties['weblogic.server.dir'] adminUrl = project.properties['easyimage.weblogic.admin.t3'] userName = 'weblogic' password = 'weblogic' ant.exec(executable: 'cmd', failonerror: 'false') { arg(line: "/C ${wlsDir}/bin/setWLSEnv.cmd && java ..." ... } ... ESDC 2010 - 53
54.
...Builds: GMaven © ASERT
2006-2010 ESDC 2010 - 54
55.
Topics
• Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 Gradle • Other Tools • More Info ESDC 2010 - 55
56.
What is Gradle?
• Tool to assist automating (build) steps task hello << { println 'Hello world!' } task intro(dependsOn: hello) << { © ASERT 2008-2010 println "I'm Gradle" } > gradle -q intro Hello world! I'm Gradle ESDC 2010 - 56
57.
Gradle Features
• A very flexible general purpose build tool like Ant • Switchable, build-by-convention frameworks a la Maven. But we never lock you in! • Very powerful support for multi-project builds • Very powerful dependency management (based on Apache Ivy) • Full support for your existing Maven or Ivy repository © ASERT 2006-2010 infrastructure • Support for transitive dependency management without the need for remote repositories or pom.xml and ivy.xml files • Ant tasks as first class citizens • Groovy build scripts • A rich domain model for describing your build ESDC 2010 - 57
58.
Gradle Examples © ASERT
2006-2010 ESDC 2010 - 58
59.
Revisiting our Preview
Example Switching to IDE © ASERT 2008-2010 ESDC 2010 - 59
60.
Topics
• Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle Other Tools • More Info ESDC 2010 - 60
61.
Hudson
• Gant Plugin — This plugin allows Hudson to invoke Gant build script as the main build step • Gradle Plugin — This plugin allows Hudson to invoke Gradle build script as the main build step • Grails Plugin — This plugin allows Hudson to invoke Grails tasks as build steps © ASERT 2006-2010 • Hudson CLI and GroovyShell Source: http://weblogs.java.net/blog/kohsuke/archive/2009/05/hudson_cli_and.html ESDC 2010 - 61
62.
Hudson: Groovy Postbuild
Plugin... if (manager.logContains(".*uses or overrides a deprecated API.*")) { manager.addWarningBadge("Thou shalt not use deprecated methods.") manager.createSummary("warning.gif").appendText( "<h1>You have been warned!</h1>", false, false, false, "red") manager.buildUnstable() } © ASERT 2006-2010 Source: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
63.
...Hudson: Groovy Postbuild
Plugin regex = 'src/main/java/(.*).java:[^ ]* (.*) is Sun proprietary API and may be removed in a future release' map = [:] manager.build.logFile.eachMatch(regex) { full, ownClass, sunClass -> map[ownClass.replaceAll("/", ".")] = sunClass } if (map) { manager.createSummary("warning.gif").with { appendText("Classes using Sun proprietary API:<ul>", false) map.each { k, v -> appendText("<li><b>$k</b> - uses $v</li>", false) © ASERT 2006-2010 } appendText("</ul>", false) } } Adapted from: http://wiki.hudson-ci.org/display/HUDSON/Groovy+Postbuild+Plugin
64.
Topics
• Build Pain Points • Build Tool Landscape • Groovy Intro • Ant & friends • Maven & friends © ASERT 2008-2010 • Gradle • Other Tools More Info ESDC 2010 - 64
65.
More Information...
• Ant – http://ant.apache.org – http://groovy.codehaus.org/The+groovy+Ant+Task – http://groovy.codehaus.org/Using+Ant+from+Groovy – http://groovy.codehaus.org/Using+Ant+Libraries+with +AntBuilder © ASERT 2008-2010 – http://gant.codehaus.org/ • Maven – http://maven.apache.org – http://gmaven.codehaus.org • Gradle – http://gradle.org ESDC 2010 - 65
66.
...More Information...
• Groovy Web sites – http://groovy.codehaus.org – http://grails.codehaus.org – http://pleac.sourceforge.net/pleac_groovy (many examples) – http://www.asert.com.au/training/java/GV110.htm (workshop) • Groovy User Mailing list – user@groovy.codehaus.org © ASERT 2006-2010 • Groovy Information portals – http://www.aboutgroovy.org – http://www.groovyblogs.org • Groovy Documentation (1000+ pages) – Getting Started Guide, User Guide, Developer Guide, Testing Guide, Cookbook Examples, Advanced Usage Guide ESDC 2010 - 66
67.
GinA 2ed “ReGinA”
is coming ... © ASERT 2006-2010
Download now