SlideShare une entreprise Scribd logo
1  sur  71
Télécharger pour lire hors ligne
by Andrés Viedma
scripts
with
Restless Java lover
Software dinosaur
more than 20 years nagging
Working at
Usual suspect of MadridGUG
and MadridJUG
Arquitecture at
Service
DB
TService
TuentiNg
DBs
tuenti-ng
Micro serviceTService
Micro serviceTService
Micro serviceTService
Arquitecture at
Service
DB
TService
TuentiNg
DBs
tuenti-ng
Micro serviceTService
Micro serviceTService
Micro serviceTService
PHP Script
About Groovy
● Dynamic Language, prepared for scripting
● Runs in the JVM
o Lots of Java libraries
o Can use the code of our Java services
● Source code “almost” compatible with Java
o Main difference: == operator means equals()
o If you make your script in Java, it’ll WORK
● Other “cool” features, mainly inspired by Python
Arquitecture at
Service
DB
TService
TuentiNg
DBs
tuenti-ng
Micro serviceTService
Micro serviceTService
Micro serviceTService
Arquitecture at
Service
DB
TService
TuentiNg
DBs
tuenti-ng
Micro serviceTService
Micro serviceTService
Micro serviceTService
Groovy Script
Arquitecture at
Service
DB
TService
TuentiNg
DBs
tuenti-ng
Micro serviceTService
Micro serviceTService
Micro serviceTService
Groovy Script
Mix your Production code
with direct accesses to the
DB, config, TServices...
Hello World (Java, but works also as
Groovy)
import utils.*;
World world = new World();
world.setId("mongo");
world.setName("Mongo");
System.out.println("Hello " +
world.getName() + "!");
package utils;
public class World {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
$GRSCRIPTS/helloworld.groovy $GRSCRIPTS/utils/World.groovy
Hello World (Groovy style)
def world = new World(id: "mongo", name: "Mongo")
println "Hello ${world.name}!"
class World {
String id
String name
}
$GRSCRIPTS/helloworld.groovy
$ cd $GRSCRIPTS
$ groovy helloworld.groovy
Hello Mongo!
$
Hello World (Groovy style)
def world = new World(id: "mongo", name: "Mongo")
println "Hello ${world.name}!"
class World {
String id
String name
}
$GRSCRIPTS/helloworld.groovy
$ cd $GRSCRIPTS
$ groovy helloworld.groovy
Hello Mongo!
$
Hello World (Groovy style)
def world = new World(id: "mongo", name: "Mongo")
println "Hello ${world.name}!"
class World {
String id
String name
}
$GRSCRIPTS/helloworld.groovy
$ cd $GRSCRIPTS
$ groovy helloworld.groovy
Hello Mongo!
$
Hello World (Groovy style)
def world = new World(id: "mongo", name: "Mongo")
println "Hello ${world.name}!"
class World {
String id
String name
}
$GRSCRIPTS/helloworld.groovy
$ cd $GRSCRIPTS
$ groovy helloworld.groovy
Hello Mongo!
$
Closures / collections
def worlds = [
new World(id: "mongo", name: "Mongo"),
new World(id: "mars", name: "Mars"),
new World(id: "wonderland", name: "Wonderland")
] as ArrayList
def heroesByWorld = [
mongo: ["Flash Gordon", "Prince Barin"],
mars: ["John Carter"],
wonderland: ["Alice", "Queen of Hearts"]
]
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
println "*** World: ${world.name}"
def heroList = worldEntry.value
heroList.each { hero -> println hero }
}
Closures / collections
def worlds = [
new World(id: "mongo", name: "Mongo"),
new World(id: "mars", name: "Mars"),
new World(id: "wonderland", name: "Wonderland")
] as ArrayList
def heroesByWorld = [
mongo: ["Flash Gordon", "Prince Barin"],
mars: ["John Carter"],
wonderland: ["Alice", "Queen of Hearts"]
]
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
println "*** World: ${world.name}"
def heroList = worldEntry.value
heroList.each { hero -> println hero }
}
Closures / collections
def worlds = [
new World(id: "mongo", name: "Mongo"),
new World(id: "mars", name: "Mars"),
new World(id: "wonderland", name: "Wonderland")
] as ArrayList
def heroesByWorld = [
mongo: ["Flash Gordon", "Prince Barin"],
mars: ["John Carter"],
wonderland: ["Alice", "Queen of Hearts"]
]
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
println "*** World: ${world.name}"
def heroList = worldEntry.value
heroList.each { hero -> println hero }
}
Closures / collections
def worlds = [
new World(id: "mongo", name: "Mongo"),
new World(id: "mars", name: "Mars"),
new World(id: "wonderland", name: "Wonderland")
] as ArrayList
def heroesByWorld = [
mongo: ["Flash Gordon", "Prince Barin"],
mars: ["John Carter"],
wonderland: ["Alice", "Queen of Hearts"]
]
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
println "*** World: ${world.name}"
def heroList = worldEntry.value
heroList.each { hero -> println hero }
}
Closures / collections
def worlds = [
new World(id: "mongo", name: "Mongo"),
new World(id: "mars", name: "Mars"),
new World(id: "wonderland", name: "Wonderland")
] as ArrayList
def heroesByWorld = [
mongo: ["Flash Gordon", "Prince Barin"],
mars: ["John Carter"],
wonderland: ["Alice", "Queen of Hearts"]
]
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
println "*** World: ${world.name}"
def heroList = worldEntry.value
heroList.each { hero -> println hero }
}
Functions and scope of variables
def worlds = [ … ]
def heroesByWorld = [ … ]
eachWorld { world, heroes ->
println "*** World: ${world.name}"
heroes.each { hero -> println hero }
}
void eachWorld(Closure closure) {
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
def heroList = worldEntry.value
closure(world, heroList)
}
}
Functions and scope of variables
def worlds = [ … ]
def heroesByWorld = [ … ]
eachWorld { world, heroes ->
println "*** World: ${world.name}"
heroes.each { hero -> println hero }
}
void eachWorld(Closure closure) {
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
def heroList = worldEntry.value
closure(world, heroList)
}
}
Functions and scope of variables
def worlds = [ … ]
def heroesByWorld = [ … ]
eachWorld { world, heroes ->
println "*** World: ${world.name}"
heroes.each { hero -> println hero }
}
void eachWorld(Closure closure) {
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
def heroList = worldEntry.value
closure(world, heroList)
}
}
Functions and scope of variables
def worlds = [ … ]
def heroesByWorld = [ … ]
eachWorld { world, heroes ->
println "*** World: ${world.name}"
heroes.each { hero -> println hero }
}
void eachWorld(Closure closure) {
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
def heroList = worldEntry.value
closure(world, heroList)
}
}
Functions and scope of variables
def worlds = [ … ]
def heroesByWorld = [ … ]
eachWorld { world, heroes ->
println "*** World: ${world.name}"
heroes.each { hero -> println hero }
}
void eachWorld(Closure closure) {
heroesByWorld.each { worldEntry ->
def worldId = worldEntry.key
def world = worlds.find { it.id == worldId }
def heroList = worldEntry.value
closure(world, heroList)
}
}
● worlds = [ … ]
● @Field def worlds = [ … ]
● @Field List<World> worlds = [ … ]
Grape: libraries from Maven repos
@Grab(group='org.apache.commons', module='commons-email', version='1.3.3')
import org.apache.commons.mail.*
def usr, pwd, toAddress = [ … ]
println "Creating email object"
Email email = new SimpleEmail(
hostName: "smtp.googlemail.com",
smtpPort: 465,
authenticator: new DefaultAuthenticator(usr, pwd),
SSLOnConnect: true,
from: usr,
subject: "Groovy mail!",
msg: "You're hot and you know it ... :-)"
)
email.addTo(toAddress);
println "Sending email..."
email.send()
println "OK"
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<resolvers>
<chain name="downloadGrapes">
<filesystem name="cachedGrapes">
<ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-
[revision].xml"/>
<artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/
[type]s/[artifact]-[revision].[ext]"/>
</filesystem>
<ibiblio name="codehaus" root="http://repository.codehaus.org/"
m2compatible="true"/>
<ibiblio name="ibiblio" m2compatible="true"/>
<ibiblio name="java.net2" root="http://download.java.net/maven/2/"
m2compatible="true"/>
</chain>
</resolvers>
</ivysettings>
Grape: default config
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<resolvers>
<chain name="downloadGrapes">
<filesystem name="cachedGrapes">
<ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-
[revision].xml"/>
<artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/
[type]s/[artifact]-[revision].[ext]"/>
</filesystem>
<ibiblio name="codehaus" root="http://repository.codehaus.org/"
m2compatible="true"/>
<ibiblio name="ibiblio" m2compatible="true"/>
<ibiblio name="java.net2" root="http://download.java.net/maven/2/"
m2compatible="true"/>
</chain>
</resolvers>
</ivysettings>
Grape: default config
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<resolvers>
<chain name="downloadGrapes">
<filesystem name="cachedGrapes">
<ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-
[revision].xml"/>
<artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/
[type]s/[artifact]-[revision].[ext]"/>
</filesystem>
<ibiblio name="codehaus" root="http://repository.codehaus.org/"
m2compatible="true"/>
<ibiblio name="ibiblio" m2compatible="true"/>
<ibiblio name="java.net2" root="http://download.java.net/maven/2/"
m2compatible="true"/>
</chain>
</resolvers>
</ivysettings>
Grape: default config
Grape: add your repository
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<credentials host="nexus.xxx.xxx"
realm="Sonatype Nexus Repository Manager"
username="xxxx" passwd="xxxx"/>
<property name="nexus-root"
value="http://nexus.xxx.xxx/content/groups/public/"/>
<resolvers>
<chain name="downloadGrapes">
<ibiblio name="nexus" root="${nexus-root}" m2compatible="true" />
(...)
</chain>
</resolvers>
</ivysettings>
Grape: add your repository
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<credentials host="nexus.xxx.xxx"
realm="Sonatype Nexus Repository Manager"
username="xxxx" passwd="xxxx"/>
<property name="nexus-root"
value="http://nexus.xxx.xxx/content/groups/public/"/>
<resolvers>
<chain name="downloadGrapes">
<ibiblio name="nexus" root="${nexus-root}" m2compatible="true" />
(...)
</chain>
</resolvers>
</ivysettings>
Grape: updatable snapshots
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<credentials host="nexus.xxx.xxx"
realm="Sonatype Nexus Repository Manager"
username="xxxx" passwd="xxxx"/>
<property name="nexus-root"
value="http://nexus.xxx.xxx/content/groups/public/"/>
<resolvers>
<ibiblio name="downloadGrapes" root="${nexus-root}"
m2compatible="true" />
</resolvers>
</ivysettings>
Grape: updatable snapshots
<ivysettings>
<settings defaultResolver="downloadGrapes"/>
<credentials host="nexus.xxx.xxx"
realm="Sonatype Nexus Repository Manager"
username="xxxx" passwd="xxxx"/>
<property name="nexus-root"
value="http://nexus.xxx.xxx/content/groups/public/"/>
<resolvers>
<ibiblio name="downloadGrapes" root="${nexus-root}"
m2compatible="true" />
</resolvers>
</ivysettings>
Databases: Sql object
@Grab('mysql:mysql-connector-java')
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging",
"tuenti_developer", "lalala",
"com.mysql.jdbc.Driver")
sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE
def version = 2
def newVersion = 3
def type = "BUNDLEDEF"
sql.eachRow("""select * from charging_element_definition
where version = ${version} and element_type = ${type}"""
) { row ->
if (row.element_id.startsWith("PG0.")) {
println "Bundle ${row.element_id} version ${row.version}" +
" to ${newVersion}"
row.version = newVersion
}
}
Databases: Sql object
@Grab('mysql:mysql-connector-java')
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging",
"tuenti_developer", "lalala",
"com.mysql.jdbc.Driver")
sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE
def version = 2
def newVersion = 3
def type = "BUNDLEDEF"
sql.eachRow("""select * from charging_element_definition
where version = ${version} and element_type = ${type}"""
) { row ->
if (row.element_id.startsWith("PG0.")) {
println "Bundle ${row.element_id} version ${row.version}" +
" to ${newVersion}"
row.version = newVersion
}
}
Databases: Sql object
@Grab('mysql:mysql-connector-java')
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging",
"tuenti_developer", "lalala",
"com.mysql.jdbc.Driver")
sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE
def version = 2
def newVersion = 3
def type = "BUNDLEDEF"
sql.eachRow("""select * from charging_element_definition
where version = ${version} and element_type = ${type}"""
) { row ->
if (row.element_id.startsWith("PG0.")) {
println "Bundle ${row.element_id} version ${row.version}" +
" to ${newVersion}"
row.version = newVersion
}
}
Databases: Sql object
@Grab('mysql:mysql-connector-java')
@GrabConfig(systemClassLoader=true)
import groovy.sql.Sql
def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging",
"tuenti_developer", "lalala",
"com.mysql.jdbc.Driver")
sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE
def version = 2
def newVersion = 3
def type = "BUNDLEDEF"
sql.eachRow("""select * from charging_element_definition
where version = ${version} and element_type = ${type}"""
) { row ->
if (row.element_id.startsWith("PG0.")) {
println "Bundle ${row.element_id} version ${row.version}" +
" to ${newVersion}"
row.version = newVersion
}
}
Script arguments: CliBuilder
def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY')
cli.with {
h longOpt:'help', 'Usage information'
p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080'
d longOpt:'dir', argName:'directory', args:1, 'Default is .'
}
def opts = cli.parse(args)
if(!opts) return
if(opts.help) {
cli.usage()
return
}
def directory = opts.d
def port = opts.port
(...)
Script arguments: CliBuilder
def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY')
cli.with {
h longOpt:'help', 'Usage information'
p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080'
d longOpt:'dir', argName:'directory', args:1, 'Default is .'
}
def opts = cli.parse(args)
if(!opts) return
if(opts.help) {
cli.usage()
return
}
def directory = opts.d
def port = opts.port
(...)
Script arguments: CliBuilder
def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY')
cli.with {
h longOpt:'help', 'Usage information'
p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080'
d longOpt:'dir', argName:'directory', args:1, 'Default is .'
}
def opts = cli.parse(args)
if(!opts) return
if(opts.help) {
cli.usage()
return
}
def directory = opts.d
def port = opts.port
(...)
Create your own utility classes
Grapes in reusable files
import utils.*
PlatformLibs.load()
(...)
package utils
@Grab('commons-logging:commons-logging:1.1.3')
@Grab('org.apache.logging.log4j:log4j-api:2.1')
@Grab('...')
(...)
class PlatformLibs {
static void load() {}
}
(Script) utils/PlatformLibs.groovy
“Clean” Services Clients
import utils.*
TServiceClient subscriptionService = new TServiceClient(
base: "http://xxxxx/SubscriptionService/")
def statusData = subscriptionService.getSubscriptionStatus([id: 80644970])
println "Result of the call: ${statusData}"
println "Subscription status: ${statusData.status}"
● Generic, equivalent to CURLs
● Using dynamic Groovy features
● Methods of the service are used transparently as if it
were a “real” client interface
“Clean” clients trick
@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-
builder', version='0.7')
(...)
class TServiceClient {
(...)
def methodMissing(String name, args) {
def jsonResult = jsonCall(name, args)
(...)
}
String jsonCall(String name, args) {
def http = getHttpClient()
def json = http.request(POST, JSON) { req ->
body = [
"jsonrpc": "2.0",
"id": callId,
"method": interface + "." + version + "." + name,
"params": [
"params": args,
"gid": gid,
"rid": rid
]
]
}
return json
}
}
“Clean” clients trick
@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-
builder', version='0.7')
(...)
class TServiceClient {
(...)
def methodMissing(String name, args) {
def jsonResult = jsonCall(name, args)
(...)
}
String jsonCall(String name, args) {
def http = getHttpClient()
def json = http.request(POST, JSON) { req ->
body = [
"jsonrpc": "2.0",
"id": callId,
"method": interface + "." + version + "." + name,
"params": [
"params": args,
"gid": gid,
"rid": rid
]
]
}
return json
}
}
Classes for named access to the
environment
import utils.*
import groovy.sql.*
def chargingService = TuentiEnv.jsc.prod.charging
def balanceData = chargingService.getBalance([id: 80644970], "es")
Sql chargingDb = TuentiEnv.jsc.prod.charging.sql
● Easy named access to:
o Databases
o Service clients
o For every environment
Environment helper
package utils
@GrabConfig(systemClassLoader=true, initContextClassLoader=true)
@Grab('mysql:mysql-connector-java')
@GrabExclude('xml-apis:xml-apis')
import groovy.sql.Sql
class TuentiEnv {
(... properties with common configuration ...)
static void initConsole() {
Object.metaClass.tu = TuentiEnv.metaClass
Object.metaClass.sim = TuentiEnv.simfonics
Object.metaClass.jsc = TuentiEnv.jsc
(...)
Object.metaClass.pretty = { obj ->
(new groovy.json.JsonBuilder(obj)).toPrettyString() }
Object.metaClass.tservice = { String base, String
iface = null ->
return new TServiceClient(base: base,
iface: iface)
}
}
}
Environment helper
package utils
@GrabConfig(systemClassLoader=true, initContextClassLoader=true)
@Grab('mysql:mysql-connector-java')
@GrabExclude('xml-apis:xml-apis')
import groovy.sql.Sql
class TuentiEnv {
(... properties with common configuration ...)
static void initConsole() {
Object.metaClass.tu = TuentiEnv.metaClass
Object.metaClass.sim = TuentiEnv.simfonics
Object.metaClass.jsc = TuentiEnv.jsc
(...)
Object.metaClass.pretty = { obj ->
(new groovy.json.JsonBuilder(obj)).toPrettyString() }
Object.metaClass.tservice = { String base, String
iface = null ->
return new TServiceClient(base: base,
iface: iface)
}
}
}
Environment helper
package utils
@GrabConfig(systemClassLoader=true, initContextClassLoader=true)
@Grab('mysql:mysql-connector-java')
@GrabExclude('xml-apis:xml-apis')
import groovy.sql.Sql
class TuentiEnv {
(... properties with common configuration ...)
static void initConsole() {
Object.metaClass.tu = TuentiEnv.metaClass
Object.metaClass.sim = TuentiEnv.simfonics
Object.metaClass.jsc = TuentiEnv.jsc
(...)
Object.metaClass.pretty = { obj ->
(new groovy.json.JsonBuilder(obj)).toPrettyString() }
Object.metaClass.tservice = { String base, String
iface = null ->
return new TServiceClient(base: base,
iface: iface)
}
}
}
Services Console: easily test your
services
aviedma@dev6:~$ groovysh
Groovy Shell (2.2.2, JVM: 1.6.0_26)
Type ':help' or ':h' for help.
---------------------------------------------------------------------
groovy:000> utils.TuentiEnv.initConsole()
===> null
groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es")
===> [amount:[amountInMillieuros:0], isAvailable:true]
groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id:
80644970])
===> {
"isAvailable": true,
"lastUpdateTime": 1423501862,
"status": "active"
}
groovy:000>
Services Console: easily test your
services
aviedma@dev6:~$ groovysh
Groovy Shell (2.2.2, JVM: 1.6.0_26)
Type ':help' or ':h' for help.
---------------------------------------------------------------------
groovy:000> utils.TuentiEnv.initConsole()
===> null
groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es")
===> [amount:[amountInMillieuros:0], isAvailable:true]
groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id:
80644970])
===> {
"isAvailable": true,
"lastUpdateTime": 1423501862,
"status": "active"
}
groovy:000>
Services Console: easily test your
services
aviedma@dev6:~$ groovysh
Groovy Shell (2.2.2, JVM: 1.6.0_26)
Type ':help' or ':h' for help.
---------------------------------------------------------------------
groovy:000> utils.TuentiEnv.initConsole()
===> null
groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es")
===> [amount:[amountInMillieuros:0], isAvailable:true]
groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id:
80644970])
===> {
"isAvailable": true,
"lastUpdateTime": 1423501862,
"status": "active"
}
groovy:000>
Tracking scripts execution
import utils.*
TuScript.track("Say hello to the world”)
println "Hello world!"
(...)
● A single line at the beginning of the script
o Logs start-end time and duration of the run (even if it
fails or is killed)
o Without changes in the scripts, it can be used to
register the script execution for monitoring
Tracking scripts execution
class TuScript {
public static void track(String description) {
if (metadata != null) {
finishCurrentScript()
} else {
addShutdownHook { finishCurrentScript() }
captureSignal("INT")
captureSignal("TERM")
}
metadata = new ScriptMetadata(description: description)
logScriptStart()
}
public static void finishCurrentScript() {
if (metadata != null) {
logScriptEnd()
}
metadata = null
}
private static void captureSignal(String signal) {
def oldHandler = Signal.handle(new Signal(signal), [handle: { sig ->
logSignal(signal)
if (oldHandler) oldHandler.handle(sig)
}] as SignalHandler);
}
(...)
Tracking scripts execution
class TuScript {
public static void track(String description) {
if (metadata != null) {
finishCurrentScript()
} else {
addShutdownHook { finishCurrentScript() }
captureSignal("INT")
captureSignal("TERM")
}
metadata = new ScriptMetadata(description: description)
logScriptStart()
}
public static void finishCurrentScript() {
if (metadata != null) {
logScriptEnd()
}
metadata = null
}
private static void captureSignal(String signal) {
def oldHandler = Signal.handle(new Signal(signal), [handle: { sig ->
logSignal(signal)
if (oldHandler) oldHandler.handle(sig)
}] as SignalHandler);
}
(...)
Tracking scripts execution
class TuScript {
public static void track(String description) {
if (metadata != null) {
finishCurrentScript()
} else {
addShutdownHook { finishCurrentScript() }
captureSignal("INT")
captureSignal("TERM")
}
metadata = new ScriptMetadata(description: description)
logScriptStart()
}
public static void finishCurrentScript() {
if (metadata != null) {
logScriptEnd()
}
metadata = null
}
private static void captureSignal(String signal) {
def oldHandler = Signal.handle(new Signal(signal), [handle: { sig ->
logSignal(signal)
if (oldHandler) oldHandler.handle(sig)
}] as SignalHandler);
}
(...)
Split execution in steps
sql.eachRow("""
<loooooong SQL>
""") { row ->
processRow(row)
}
void processRow(row) {
println "${row.id}: ${row.name} ${row.surname}"
(... lots and lots of processing ...)
}
Split execution in steps
sql.eachRow("""
<loooooong SQL>
""") { row ->
processRow(row)
}
void processRow(row) {
println "${row.id}: ${row.name} ${row.surname}"
(... lots and lots of processing ...)
}
Split execution in steps
void step1(String file) {
Dump dump = new Dump(file)
dump.withWriter(fieldNames) { out ->
sql.eachRow("""
<loooooong SQL>
""") { row ->
out.insert(row)
}
}
}
void step2(String file) {
Dump dump = new Dump(file)
dump.eachRow { out ->
processRow(row)
}
}
void processRow(row) {
println "${row.id}: ${row.name} ${row.surname}"
(... lots and lots of processing ...)
}
Split execution in steps
void step1(String file) {
Dump dump = new Dump(file)
dump.withWriter(fieldNames) { out ->
sql.eachRow("""
<loooooong SQL>
""") { row ->
out.insert(row)
}
}
}
void step2(String file) {
Dump dump = new Dump(file)
dump.eachRow { out ->
processRow(row)
}
}
void processRow(row) {
println "${row.id}: ${row.name} ${row.surname}"
(... lots and lots of processing ...)
}
Split execution in steps
void step1(String file) {
Dump dump = new Dump(file)
dump.withWriter(fieldNames) { out ->
sql.eachRow("""
<loooooong SQL>
""") { row ->
out.insert(row)
}
}
}
void step2(String file) {
Dump dump = new Dump(file)
dump.eachRow { out ->
processRow(row)
}
}
void processRow(row) {
println "${row.id}: ${row.name} ${row.surname}"
(... lots and lots of processing ...)
}
Same processing code, no changes needed
Running Shell commands
def process = 'ls /home/andres'.execute()
def procOutput = new InputStreamReader(process.in)
procOutput.eachLine { line ->
println line
}
process.waitFor()
println "** Return code: ${process.exitValue()}"
Running Shell commands
def process = 'ls /home/andres'.execute()
def procOutput = new InputStreamReader(process.in)
procOutput.eachLine { line ->
println line
}
process.waitFor()
println "** Return code: ${process.exitValue()}"
Running Shell commands
def process = 'ls /home/andres'.execute()
def procOutput = new InputStreamReader(process.in)
procOutput.eachLine { line ->
println line
}
process.waitFor()
println "** Return code: ${process.exitValue()}"
def process = 'echo "Hola caracola"'.execute()
println process.text
def process = ['echo', 'Hola caracola'].execute()
Running Shell commands
def process = 'ls /home/andres'.execute()
def procOutput = new InputStreamReader(process.in)
procOutput.eachLine { line ->
println line
}
process.waitFor()
println "** Return code: ${process.exitValue()}"
def process = 'echo "Hola caracola"'.execute()
println process.text
def process = ['echo', 'Hola caracola'].execute()
def process = 'ls /home/andres/*'.execute()
def process = ['sh', '-c', 'ls /home/andres/*'].execute()
Running Shell commands
def process = 'ls /home/andres'.execute()
def procOutput = new InputStreamReader(process.in)
procOutput.eachLine { line ->
println line
}
process.waitFor()
println "** Return code: ${process.exitValue()}"
def process = 'echo "Hola caracola"'.execute()
println process.text
def process = ['echo', 'Hola caracola'].execute()
def process = 'ls /home/andres/*'.execute()
def process = ['sh', '-c', 'ls /home/andres/*'].execute()
def process = 'ls'.execute()
def process = 'ls'.execute([], new File('/home/andres'))
Running Shell commands
class Shell {
File currentDir = new File('.')
final Map environment = [:]
Process run(String command) {
return ['sh', '-c', command].execute(
environment.collect { "${it.key}=${it.value}" },
currentDir)
}
String runAndGet(String command) {
def proc = run(command)
proc.waitFor()
return proc.text
}
}
Shell shell = new Shell(currentDir: new File("/home/andres/temp"))
shell.environment["GREETINGS"] = "Hi!"
print shell.runAndGet('echo $GREETINGS')
print shell.runAndGet("ls i*")
print shell.runAndGet('echo "Hola caracola"')
Running Shell commands
class Shell {
File currentDir = new File('.')
final Map environment = [:]
Process run(String command) {
return ['sh', '-c', command].execute(
environment.collect { "${it.key}=${it.value}" },
currentDir)
}
String runAndGet(String command) {
def proc = run(command)
proc.waitFor()
return proc.text
}
}
Shell shell = new Shell(currentDir: new File("/home/andres/temp"))
shell.environment["GREETINGS"] = "Hi!"
print shell.runAndGet('echo $GREETINGS')
print shell.runAndGet("ls i*")
print shell.runAndGet('echo "Hola caracola"')
Thanks!
Questions?

Contenu connexe

Tendances

Contando uma história com O.O.
Contando uma história com O.O.Contando uma história com O.O.
Contando uma história com O.O.Vagner Zampieri
 
PostgreSQLからMongoDBへ
PostgreSQLからMongoDBへPostgreSQLからMongoDBへ
PostgreSQLからMongoDBへBasuke Suzuki
 
Solr & Lucene @ Etsy by Gregg Donovan
Solr & Lucene @ Etsy by Gregg DonovanSolr & Lucene @ Etsy by Gregg Donovan
Solr & Lucene @ Etsy by Gregg DonovanGregg Donovan
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHPTaras Kalapun
 
ElasticSearch at berlinbuzzwords 2010
ElasticSearch at berlinbuzzwords 2010ElasticSearch at berlinbuzzwords 2010
ElasticSearch at berlinbuzzwords 2010Elasticsearch
 
MongoDB Online Conference: Introducing MongoDB 2.2
MongoDB Online Conference: Introducing MongoDB 2.2MongoDB Online Conference: Introducing MongoDB 2.2
MongoDB Online Conference: Introducing MongoDB 2.2MongoDB
 
DataMapper @ RubyEnRails2009
DataMapper @ RubyEnRails2009DataMapper @ RubyEnRails2009
DataMapper @ RubyEnRails2009Dirkjan Bussink
 
NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法Tomohiro Nishimura
 
Andreas Roth - GraphQL erfolgreich im Backend einsetzen
Andreas Roth - GraphQL erfolgreich im Backend einsetzenAndreas Roth - GraphQL erfolgreich im Backend einsetzen
Andreas Roth - GraphQL erfolgreich im Backend einsetzenDevDay Dresden
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APISix Apart KK
 
Introduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genIntroduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genMongoDB
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway ichikaway
 
Inside MongoDB: the Internals of an Open-Source Database
Inside MongoDB: the Internals of an Open-Source DatabaseInside MongoDB: the Internals of an Open-Source Database
Inside MongoDB: the Internals of an Open-Source DatabaseMike Dirolf
 
Webinar: Replication and Replica Sets
Webinar: Replication and Replica SetsWebinar: Replication and Replica Sets
Webinar: Replication and Replica SetsMongoDB
 

Tendances (20)

Contando uma história com O.O.
Contando uma história com O.O.Contando uma história com O.O.
Contando uma história com O.O.
 
Solr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene EuroconSolr @ Etsy - Apache Lucene Eurocon
Solr @ Etsy - Apache Lucene Eurocon
 
PostgreSQLからMongoDBへ
PostgreSQLからMongoDBへPostgreSQLからMongoDBへ
PostgreSQLからMongoDBへ
 
Solr & Lucene @ Etsy by Gregg Donovan
Solr & Lucene @ Etsy by Gregg DonovanSolr & Lucene @ Etsy by Gregg Donovan
Solr & Lucene @ Etsy by Gregg Donovan
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 
Living with garbage
Living with garbageLiving with garbage
Living with garbage
 
ElasticSearch at berlinbuzzwords 2010
ElasticSearch at berlinbuzzwords 2010ElasticSearch at berlinbuzzwords 2010
ElasticSearch at berlinbuzzwords 2010
 
PhoneGap: Local Storage
PhoneGap: Local StoragePhoneGap: Local Storage
PhoneGap: Local Storage
 
MongoDB Online Conference: Introducing MongoDB 2.2
MongoDB Online Conference: Introducing MongoDB 2.2MongoDB Online Conference: Introducing MongoDB 2.2
MongoDB Online Conference: Introducing MongoDB 2.2
 
DataMapper @ RubyEnRails2009
DataMapper @ RubyEnRails2009DataMapper @ RubyEnRails2009
DataMapper @ RubyEnRails2009
 
Potential Friend Finder
Potential Friend FinderPotential Friend Finder
Potential Friend Finder
 
NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法NoSQL を Ruby で実践するための n 個の方法
NoSQL を Ruby で実践するための n 個の方法
 
PHP and MySQL
PHP and MySQLPHP and MySQL
PHP and MySQL
 
Andreas Roth - GraphQL erfolgreich im Backend einsetzen
Andreas Roth - GraphQL erfolgreich im Backend einsetzenAndreas Roth - GraphQL erfolgreich im Backend einsetzen
Andreas Roth - GraphQL erfolgreich im Backend einsetzen
 
MTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new APIMTDDC 2010.2.5 Tokyo - Brand new API
MTDDC 2010.2.5 Tokyo - Brand new API
 
Mongo db for c# developers
Mongo db for c# developersMongo db for c# developers
Mongo db for c# developers
 
Introduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10genIntroduction to the new official C# Driver developed by 10gen
Introduction to the new official C# Driver developed by 10gen
 
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
Tips of CakePHP and MongoDB - Cakefest2011 ichikaway
 
Inside MongoDB: the Internals of an Open-Source Database
Inside MongoDB: the Internals of an Open-Source DatabaseInside MongoDB: the Internals of an Open-Source Database
Inside MongoDB: the Internals of an Open-Source Database
 
Webinar: Replication and Replica Sets
Webinar: Replication and Replica SetsWebinar: Replication and Replica Sets
Webinar: Replication and Replica Sets
 

Similaire à Groovy scripts with Groovy

2013-03-23 - NoSQL Spartakiade
2013-03-23 - NoSQL Spartakiade2013-03-23 - NoSQL Spartakiade
2013-03-23 - NoSQL SpartakiadeJohannes Hoppe
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapHoward Lewis Ship
 
Mongoskin - Guilin
Mongoskin - GuilinMongoskin - Guilin
Mongoskin - GuilinJackson Tian
 
MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !Sébastien Prunier
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
 
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014Puppet
 
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...MongoDB
 
Модерни езици за програмиране за JVM (2011)
Модерни езици за програмиране за JVM (2011)Модерни езици за програмиране за JVM (2011)
Модерни езици за програмиране за JVM (2011)Bozhidar Batsov
 
Webinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev TeamsWebinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev TeamsMongoDB
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistenceHugo Hamon
 
js+ts fullstack typescript with react and express.pdf
js+ts fullstack typescript with react and express.pdfjs+ts fullstack typescript with react and express.pdf
js+ts fullstack typescript with react and express.pdfNuttavutThongjor1
 
fullstack typescript with react and express.pdf
fullstack typescript with react and express.pdffullstack typescript with react and express.pdf
fullstack typescript with react and express.pdfNuttavutThongjor1
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopIntroduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopSteven Francia
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Tsuyoshi Yamamoto
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodJeremy Kendall
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB
 
"Powerful Analysis with the Aggregation Pipeline (Tutorial)"
"Powerful Analysis with the Aggregation Pipeline (Tutorial)""Powerful Analysis with the Aggregation Pipeline (Tutorial)"
"Powerful Analysis with the Aggregation Pipeline (Tutorial)"MongoDB
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Codestasimus
 

Similaire à Groovy scripts with Groovy (20)

2013-03-23 - NoSQL Spartakiade
2013-03-23 - NoSQL Spartakiade2013-03-23 - NoSQL Spartakiade
2013-03-23 - NoSQL Spartakiade
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Modern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter BootstrapModern Application Foundations: Underscore and Twitter Bootstrap
Modern Application Foundations: Underscore and Twitter Bootstrap
 
Mongoskin - Guilin
Mongoskin - GuilinMongoskin - Guilin
Mongoskin - Guilin
 
MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !MongoDB Aggregation Framework in action !
MongoDB Aggregation Framework in action !
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014
Absolute Beginners Guide to Puppet Through Types - PuppetConf 2014
 
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
[MongoDB.local Bengaluru 2018] Tutorial: Pipeline Power - Doing More with Mon...
 
Модерни езици за програмиране за JVM (2011)
Модерни езици за програмиране за JVM (2011)Модерни езици за програмиране за JVM (2011)
Модерни езици за програмиране за JVM (2011)
 
Webinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev TeamsWebinar: General Technical Overview of MongoDB for Dev Teams
Webinar: General Technical Overview of MongoDB for Dev Teams
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
ts+js
ts+jsts+js
ts+js
 
js+ts fullstack typescript with react and express.pdf
js+ts fullstack typescript with react and express.pdfjs+ts fullstack typescript with react and express.pdf
js+ts fullstack typescript with react and express.pdf
 
fullstack typescript with react and express.pdf
fullstack typescript with react and express.pdffullstack typescript with react and express.pdf
fullstack typescript with react and express.pdf
 
Introduction to MongoDB and Hadoop
Introduction to MongoDB and HadoopIntroduction to MongoDB and Hadoop
Introduction to MongoDB and Hadoop
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
Php 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the GoodPhp 102: Out with the Bad, In with the Good
Php 102: Out with the Bad, In with the Good
 
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
MongoDB .local San Francisco 2020: Aggregation Pipeline Power++
 
"Powerful Analysis with the Aggregation Pipeline (Tutorial)"
"Powerful Analysis with the Aggregation Pipeline (Tutorial)""Powerful Analysis with the Aggregation Pipeline (Tutorial)"
"Powerful Analysis with the Aggregation Pipeline (Tutorial)"
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 

Dernier

Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Angel Borroy López
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROmotivationalword821
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 

Dernier (20)

Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
Alfresco TTL#157 - Troubleshooting Made Easy: Deciphering Alfresco mTLS Confi...
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
How To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTROHow To Manage Restaurant Staff -BTRESTRO
How To Manage Restaurant Staff -BTRESTRO
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 

Groovy scripts with Groovy

  • 2. Restless Java lover Software dinosaur more than 20 years nagging Working at Usual suspect of MadridGUG and MadridJUG
  • 3.
  • 4.
  • 5.
  • 8. About Groovy ● Dynamic Language, prepared for scripting ● Runs in the JVM o Lots of Java libraries o Can use the code of our Java services ● Source code “almost” compatible with Java o Main difference: == operator means equals() o If you make your script in Java, it’ll WORK ● Other “cool” features, mainly inspired by Python
  • 12. Mix your Production code with direct accesses to the DB, config, TServices...
  • 13. Hello World (Java, but works also as Groovy) import utils.*; World world = new World(); world.setId("mongo"); world.setName("Mongo"); System.out.println("Hello " + world.getName() + "!"); package utils; public class World { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } $GRSCRIPTS/helloworld.groovy $GRSCRIPTS/utils/World.groovy
  • 14. Hello World (Groovy style) def world = new World(id: "mongo", name: "Mongo") println "Hello ${world.name}!" class World { String id String name } $GRSCRIPTS/helloworld.groovy $ cd $GRSCRIPTS $ groovy helloworld.groovy Hello Mongo! $
  • 15. Hello World (Groovy style) def world = new World(id: "mongo", name: "Mongo") println "Hello ${world.name}!" class World { String id String name } $GRSCRIPTS/helloworld.groovy $ cd $GRSCRIPTS $ groovy helloworld.groovy Hello Mongo! $
  • 16. Hello World (Groovy style) def world = new World(id: "mongo", name: "Mongo") println "Hello ${world.name}!" class World { String id String name } $GRSCRIPTS/helloworld.groovy $ cd $GRSCRIPTS $ groovy helloworld.groovy Hello Mongo! $
  • 17. Hello World (Groovy style) def world = new World(id: "mongo", name: "Mongo") println "Hello ${world.name}!" class World { String id String name } $GRSCRIPTS/helloworld.groovy $ cd $GRSCRIPTS $ groovy helloworld.groovy Hello Mongo! $
  • 18. Closures / collections def worlds = [ new World(id: "mongo", name: "Mongo"), new World(id: "mars", name: "Mars"), new World(id: "wonderland", name: "Wonderland") ] as ArrayList def heroesByWorld = [ mongo: ["Flash Gordon", "Prince Barin"], mars: ["John Carter"], wonderland: ["Alice", "Queen of Hearts"] ] heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } println "*** World: ${world.name}" def heroList = worldEntry.value heroList.each { hero -> println hero } }
  • 19. Closures / collections def worlds = [ new World(id: "mongo", name: "Mongo"), new World(id: "mars", name: "Mars"), new World(id: "wonderland", name: "Wonderland") ] as ArrayList def heroesByWorld = [ mongo: ["Flash Gordon", "Prince Barin"], mars: ["John Carter"], wonderland: ["Alice", "Queen of Hearts"] ] heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } println "*** World: ${world.name}" def heroList = worldEntry.value heroList.each { hero -> println hero } }
  • 20. Closures / collections def worlds = [ new World(id: "mongo", name: "Mongo"), new World(id: "mars", name: "Mars"), new World(id: "wonderland", name: "Wonderland") ] as ArrayList def heroesByWorld = [ mongo: ["Flash Gordon", "Prince Barin"], mars: ["John Carter"], wonderland: ["Alice", "Queen of Hearts"] ] heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } println "*** World: ${world.name}" def heroList = worldEntry.value heroList.each { hero -> println hero } }
  • 21. Closures / collections def worlds = [ new World(id: "mongo", name: "Mongo"), new World(id: "mars", name: "Mars"), new World(id: "wonderland", name: "Wonderland") ] as ArrayList def heroesByWorld = [ mongo: ["Flash Gordon", "Prince Barin"], mars: ["John Carter"], wonderland: ["Alice", "Queen of Hearts"] ] heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } println "*** World: ${world.name}" def heroList = worldEntry.value heroList.each { hero -> println hero } }
  • 22. Closures / collections def worlds = [ new World(id: "mongo", name: "Mongo"), new World(id: "mars", name: "Mars"), new World(id: "wonderland", name: "Wonderland") ] as ArrayList def heroesByWorld = [ mongo: ["Flash Gordon", "Prince Barin"], mars: ["John Carter"], wonderland: ["Alice", "Queen of Hearts"] ] heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } println "*** World: ${world.name}" def heroList = worldEntry.value heroList.each { hero -> println hero } }
  • 23. Functions and scope of variables def worlds = [ … ] def heroesByWorld = [ … ] eachWorld { world, heroes -> println "*** World: ${world.name}" heroes.each { hero -> println hero } } void eachWorld(Closure closure) { heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } def heroList = worldEntry.value closure(world, heroList) } }
  • 24. Functions and scope of variables def worlds = [ … ] def heroesByWorld = [ … ] eachWorld { world, heroes -> println "*** World: ${world.name}" heroes.each { hero -> println hero } } void eachWorld(Closure closure) { heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } def heroList = worldEntry.value closure(world, heroList) } }
  • 25. Functions and scope of variables def worlds = [ … ] def heroesByWorld = [ … ] eachWorld { world, heroes -> println "*** World: ${world.name}" heroes.each { hero -> println hero } } void eachWorld(Closure closure) { heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } def heroList = worldEntry.value closure(world, heroList) } }
  • 26. Functions and scope of variables def worlds = [ … ] def heroesByWorld = [ … ] eachWorld { world, heroes -> println "*** World: ${world.name}" heroes.each { hero -> println hero } } void eachWorld(Closure closure) { heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } def heroList = worldEntry.value closure(world, heroList) } }
  • 27. Functions and scope of variables def worlds = [ … ] def heroesByWorld = [ … ] eachWorld { world, heroes -> println "*** World: ${world.name}" heroes.each { hero -> println hero } } void eachWorld(Closure closure) { heroesByWorld.each { worldEntry -> def worldId = worldEntry.key def world = worlds.find { it.id == worldId } def heroList = worldEntry.value closure(world, heroList) } } ● worlds = [ … ] ● @Field def worlds = [ … ] ● @Field List<World> worlds = [ … ]
  • 28. Grape: libraries from Maven repos @Grab(group='org.apache.commons', module='commons-email', version='1.3.3') import org.apache.commons.mail.* def usr, pwd, toAddress = [ … ] println "Creating email object" Email email = new SimpleEmail( hostName: "smtp.googlemail.com", smtpPort: 465, authenticator: new DefaultAuthenticator(usr, pwd), SSLOnConnect: true, from: usr, subject: "Groovy mail!", msg: "You're hot and you know it ... :-)" ) email.addTo(toAddress); println "Sending email..." email.send() println "OK"
  • 29. <ivysettings> <settings defaultResolver="downloadGrapes"/> <resolvers> <chain name="downloadGrapes"> <filesystem name="cachedGrapes"> <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy- [revision].xml"/> <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ [type]s/[artifact]-[revision].[ext]"/> </filesystem> <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/> </chain> </resolvers> </ivysettings> Grape: default config
  • 30. <ivysettings> <settings defaultResolver="downloadGrapes"/> <resolvers> <chain name="downloadGrapes"> <filesystem name="cachedGrapes"> <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy- [revision].xml"/> <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ [type]s/[artifact]-[revision].[ext]"/> </filesystem> <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/> </chain> </resolvers> </ivysettings> Grape: default config
  • 31. <ivysettings> <settings defaultResolver="downloadGrapes"/> <resolvers> <chain name="downloadGrapes"> <filesystem name="cachedGrapes"> <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy- [revision].xml"/> <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ [type]s/[artifact]-[revision].[ext]"/> </filesystem> <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/> <ibiblio name="ibiblio" m2compatible="true"/> <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/> </chain> </resolvers> </ivysettings> Grape: default config
  • 32. Grape: add your repository <ivysettings> <settings defaultResolver="downloadGrapes"/> <credentials host="nexus.xxx.xxx" realm="Sonatype Nexus Repository Manager" username="xxxx" passwd="xxxx"/> <property name="nexus-root" value="http://nexus.xxx.xxx/content/groups/public/"/> <resolvers> <chain name="downloadGrapes"> <ibiblio name="nexus" root="${nexus-root}" m2compatible="true" /> (...) </chain> </resolvers> </ivysettings>
  • 33. Grape: add your repository <ivysettings> <settings defaultResolver="downloadGrapes"/> <credentials host="nexus.xxx.xxx" realm="Sonatype Nexus Repository Manager" username="xxxx" passwd="xxxx"/> <property name="nexus-root" value="http://nexus.xxx.xxx/content/groups/public/"/> <resolvers> <chain name="downloadGrapes"> <ibiblio name="nexus" root="${nexus-root}" m2compatible="true" /> (...) </chain> </resolvers> </ivysettings>
  • 34. Grape: updatable snapshots <ivysettings> <settings defaultResolver="downloadGrapes"/> <credentials host="nexus.xxx.xxx" realm="Sonatype Nexus Repository Manager" username="xxxx" passwd="xxxx"/> <property name="nexus-root" value="http://nexus.xxx.xxx/content/groups/public/"/> <resolvers> <ibiblio name="downloadGrapes" root="${nexus-root}" m2compatible="true" /> </resolvers> </ivysettings>
  • 35. Grape: updatable snapshots <ivysettings> <settings defaultResolver="downloadGrapes"/> <credentials host="nexus.xxx.xxx" realm="Sonatype Nexus Repository Manager" username="xxxx" passwd="xxxx"/> <property name="nexus-root" value="http://nexus.xxx.xxx/content/groups/public/"/> <resolvers> <ibiblio name="downloadGrapes" root="${nexus-root}" m2compatible="true" /> </resolvers> </ivysettings>
  • 36. Databases: Sql object @Grab('mysql:mysql-connector-java') @GrabConfig(systemClassLoader=true) import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging", "tuenti_developer", "lalala", "com.mysql.jdbc.Driver") sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE def version = 2 def newVersion = 3 def type = "BUNDLEDEF" sql.eachRow("""select * from charging_element_definition where version = ${version} and element_type = ${type}""" ) { row -> if (row.element_id.startsWith("PG0.")) { println "Bundle ${row.element_id} version ${row.version}" + " to ${newVersion}" row.version = newVersion } }
  • 37. Databases: Sql object @Grab('mysql:mysql-connector-java') @GrabConfig(systemClassLoader=true) import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging", "tuenti_developer", "lalala", "com.mysql.jdbc.Driver") sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE def version = 2 def newVersion = 3 def type = "BUNDLEDEF" sql.eachRow("""select * from charging_element_definition where version = ${version} and element_type = ${type}""" ) { row -> if (row.element_id.startsWith("PG0.")) { println "Bundle ${row.element_id} version ${row.version}" + " to ${newVersion}" row.version = newVersion } }
  • 38. Databases: Sql object @Grab('mysql:mysql-connector-java') @GrabConfig(systemClassLoader=true) import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging", "tuenti_developer", "lalala", "com.mysql.jdbc.Driver") sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE def version = 2 def newVersion = 3 def type = "BUNDLEDEF" sql.eachRow("""select * from charging_element_definition where version = ${version} and element_type = ${type}""" ) { row -> if (row.element_id.startsWith("PG0.")) { println "Bundle ${row.element_id} version ${row.version}" + " to ${newVersion}" row.version = newVersion } }
  • 39. Databases: Sql object @Grab('mysql:mysql-connector-java') @GrabConfig(systemClassLoader=true) import groovy.sql.Sql def sql = Sql.newInstance("jdbc:mysql://localhost:3306/simfonics_charging", "tuenti_developer", "lalala", "com.mysql.jdbc.Driver") sql.resultSetConcurrency = java.sql.ResultSet.CONCUR_UPDATABLE def version = 2 def newVersion = 3 def type = "BUNDLEDEF" sql.eachRow("""select * from charging_element_definition where version = ${version} and element_type = ${type}""" ) { row -> if (row.element_id.startsWith("PG0.")) { println "Bundle ${row.element_id} version ${row.version}" + " to ${newVersion}" row.version = newVersion } }
  • 40. Script arguments: CliBuilder def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY') cli.with { h longOpt:'help', 'Usage information' p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080' d longOpt:'dir', argName:'directory', args:1, 'Default is .' } def opts = cli.parse(args) if(!opts) return if(opts.help) { cli.usage() return } def directory = opts.d def port = opts.port (...)
  • 41. Script arguments: CliBuilder def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY') cli.with { h longOpt:'help', 'Usage information' p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080' d longOpt:'dir', argName:'directory', args:1, 'Default is .' } def opts = cli.parse(args) if(!opts) return if(opts.help) { cli.usage() return } def directory = opts.d def port = opts.port (...)
  • 42. Script arguments: CliBuilder def cli = new CliBuilder(usage:'simpleHtmlServer -p PORT -d DIRECTORY') cli.with { h longOpt:'help', 'Usage information' p longOpt:'port',argName:'port', args:1, type:Number.class,'Def is 8080' d longOpt:'dir', argName:'directory', args:1, 'Default is .' } def opts = cli.parse(args) if(!opts) return if(opts.help) { cli.usage() return } def directory = opts.d def port = opts.port (...)
  • 43. Create your own utility classes
  • 44. Grapes in reusable files import utils.* PlatformLibs.load() (...) package utils @Grab('commons-logging:commons-logging:1.1.3') @Grab('org.apache.logging.log4j:log4j-api:2.1') @Grab('...') (...) class PlatformLibs { static void load() {} } (Script) utils/PlatformLibs.groovy
  • 45. “Clean” Services Clients import utils.* TServiceClient subscriptionService = new TServiceClient( base: "http://xxxxx/SubscriptionService/") def statusData = subscriptionService.getSubscriptionStatus([id: 80644970]) println "Result of the call: ${statusData}" println "Subscription status: ${statusData.status}" ● Generic, equivalent to CURLs ● Using dynamic Groovy features ● Methods of the service are used transparently as if it were a “real” client interface
  • 46. “Clean” clients trick @Grab(group='org.codehaus.groovy.modules.http-builder', module='http- builder', version='0.7') (...) class TServiceClient { (...) def methodMissing(String name, args) { def jsonResult = jsonCall(name, args) (...) } String jsonCall(String name, args) { def http = getHttpClient() def json = http.request(POST, JSON) { req -> body = [ "jsonrpc": "2.0", "id": callId, "method": interface + "." + version + "." + name, "params": [ "params": args, "gid": gid, "rid": rid ] ] } return json } }
  • 47. “Clean” clients trick @Grab(group='org.codehaus.groovy.modules.http-builder', module='http- builder', version='0.7') (...) class TServiceClient { (...) def methodMissing(String name, args) { def jsonResult = jsonCall(name, args) (...) } String jsonCall(String name, args) { def http = getHttpClient() def json = http.request(POST, JSON) { req -> body = [ "jsonrpc": "2.0", "id": callId, "method": interface + "." + version + "." + name, "params": [ "params": args, "gid": gid, "rid": rid ] ] } return json } }
  • 48. Classes for named access to the environment import utils.* import groovy.sql.* def chargingService = TuentiEnv.jsc.prod.charging def balanceData = chargingService.getBalance([id: 80644970], "es") Sql chargingDb = TuentiEnv.jsc.prod.charging.sql ● Easy named access to: o Databases o Service clients o For every environment
  • 49. Environment helper package utils @GrabConfig(systemClassLoader=true, initContextClassLoader=true) @Grab('mysql:mysql-connector-java') @GrabExclude('xml-apis:xml-apis') import groovy.sql.Sql class TuentiEnv { (... properties with common configuration ...) static void initConsole() { Object.metaClass.tu = TuentiEnv.metaClass Object.metaClass.sim = TuentiEnv.simfonics Object.metaClass.jsc = TuentiEnv.jsc (...) Object.metaClass.pretty = { obj -> (new groovy.json.JsonBuilder(obj)).toPrettyString() } Object.metaClass.tservice = { String base, String iface = null -> return new TServiceClient(base: base, iface: iface) } } }
  • 50. Environment helper package utils @GrabConfig(systemClassLoader=true, initContextClassLoader=true) @Grab('mysql:mysql-connector-java') @GrabExclude('xml-apis:xml-apis') import groovy.sql.Sql class TuentiEnv { (... properties with common configuration ...) static void initConsole() { Object.metaClass.tu = TuentiEnv.metaClass Object.metaClass.sim = TuentiEnv.simfonics Object.metaClass.jsc = TuentiEnv.jsc (...) Object.metaClass.pretty = { obj -> (new groovy.json.JsonBuilder(obj)).toPrettyString() } Object.metaClass.tservice = { String base, String iface = null -> return new TServiceClient(base: base, iface: iface) } } }
  • 51. Environment helper package utils @GrabConfig(systemClassLoader=true, initContextClassLoader=true) @Grab('mysql:mysql-connector-java') @GrabExclude('xml-apis:xml-apis') import groovy.sql.Sql class TuentiEnv { (... properties with common configuration ...) static void initConsole() { Object.metaClass.tu = TuentiEnv.metaClass Object.metaClass.sim = TuentiEnv.simfonics Object.metaClass.jsc = TuentiEnv.jsc (...) Object.metaClass.pretty = { obj -> (new groovy.json.JsonBuilder(obj)).toPrettyString() } Object.metaClass.tservice = { String base, String iface = null -> return new TServiceClient(base: base, iface: iface) } } }
  • 52. Services Console: easily test your services aviedma@dev6:~$ groovysh Groovy Shell (2.2.2, JVM: 1.6.0_26) Type ':help' or ':h' for help. --------------------------------------------------------------------- groovy:000> utils.TuentiEnv.initConsole() ===> null groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es") ===> [amount:[amountInMillieuros:0], isAvailable:true] groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id: 80644970]) ===> { "isAvailable": true, "lastUpdateTime": 1423501862, "status": "active" } groovy:000>
  • 53. Services Console: easily test your services aviedma@dev6:~$ groovysh Groovy Shell (2.2.2, JVM: 1.6.0_26) Type ':help' or ':h' for help. --------------------------------------------------------------------- groovy:000> utils.TuentiEnv.initConsole() ===> null groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es") ===> [amount:[amountInMillieuros:0], isAvailable:true] groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id: 80644970]) ===> { "isAvailable": true, "lastUpdateTime": 1423501862, "status": "active" } groovy:000>
  • 54. Services Console: easily test your services aviedma@dev6:~$ groovysh Groovy Shell (2.2.2, JVM: 1.6.0_26) Type ':help' or ':h' for help. --------------------------------------------------------------------- groovy:000> utils.TuentiEnv.initConsole() ===> null groovy:000> jsc.prod.charging.getBalance([id: 80644970], "es") ===> [amount:[amountInMillieuros:0], isAvailable:true] groovy:000> pretty jsc.prod.subscription.getSubscriptionStatus([id: 80644970]) ===> { "isAvailable": true, "lastUpdateTime": 1423501862, "status": "active" } groovy:000>
  • 55. Tracking scripts execution import utils.* TuScript.track("Say hello to the world”) println "Hello world!" (...) ● A single line at the beginning of the script o Logs start-end time and duration of the run (even if it fails or is killed) o Without changes in the scripts, it can be used to register the script execution for monitoring
  • 56. Tracking scripts execution class TuScript { public static void track(String description) { if (metadata != null) { finishCurrentScript() } else { addShutdownHook { finishCurrentScript() } captureSignal("INT") captureSignal("TERM") } metadata = new ScriptMetadata(description: description) logScriptStart() } public static void finishCurrentScript() { if (metadata != null) { logScriptEnd() } metadata = null } private static void captureSignal(String signal) { def oldHandler = Signal.handle(new Signal(signal), [handle: { sig -> logSignal(signal) if (oldHandler) oldHandler.handle(sig) }] as SignalHandler); } (...)
  • 57. Tracking scripts execution class TuScript { public static void track(String description) { if (metadata != null) { finishCurrentScript() } else { addShutdownHook { finishCurrentScript() } captureSignal("INT") captureSignal("TERM") } metadata = new ScriptMetadata(description: description) logScriptStart() } public static void finishCurrentScript() { if (metadata != null) { logScriptEnd() } metadata = null } private static void captureSignal(String signal) { def oldHandler = Signal.handle(new Signal(signal), [handle: { sig -> logSignal(signal) if (oldHandler) oldHandler.handle(sig) }] as SignalHandler); } (...)
  • 58. Tracking scripts execution class TuScript { public static void track(String description) { if (metadata != null) { finishCurrentScript() } else { addShutdownHook { finishCurrentScript() } captureSignal("INT") captureSignal("TERM") } metadata = new ScriptMetadata(description: description) logScriptStart() } public static void finishCurrentScript() { if (metadata != null) { logScriptEnd() } metadata = null } private static void captureSignal(String signal) { def oldHandler = Signal.handle(new Signal(signal), [handle: { sig -> logSignal(signal) if (oldHandler) oldHandler.handle(sig) }] as SignalHandler); } (...)
  • 59. Split execution in steps sql.eachRow(""" <loooooong SQL> """) { row -> processRow(row) } void processRow(row) { println "${row.id}: ${row.name} ${row.surname}" (... lots and lots of processing ...) }
  • 60. Split execution in steps sql.eachRow(""" <loooooong SQL> """) { row -> processRow(row) } void processRow(row) { println "${row.id}: ${row.name} ${row.surname}" (... lots and lots of processing ...) }
  • 61. Split execution in steps void step1(String file) { Dump dump = new Dump(file) dump.withWriter(fieldNames) { out -> sql.eachRow(""" <loooooong SQL> """) { row -> out.insert(row) } } } void step2(String file) { Dump dump = new Dump(file) dump.eachRow { out -> processRow(row) } } void processRow(row) { println "${row.id}: ${row.name} ${row.surname}" (... lots and lots of processing ...) }
  • 62. Split execution in steps void step1(String file) { Dump dump = new Dump(file) dump.withWriter(fieldNames) { out -> sql.eachRow(""" <loooooong SQL> """) { row -> out.insert(row) } } } void step2(String file) { Dump dump = new Dump(file) dump.eachRow { out -> processRow(row) } } void processRow(row) { println "${row.id}: ${row.name} ${row.surname}" (... lots and lots of processing ...) }
  • 63. Split execution in steps void step1(String file) { Dump dump = new Dump(file) dump.withWriter(fieldNames) { out -> sql.eachRow(""" <loooooong SQL> """) { row -> out.insert(row) } } } void step2(String file) { Dump dump = new Dump(file) dump.eachRow { out -> processRow(row) } } void processRow(row) { println "${row.id}: ${row.name} ${row.surname}" (... lots and lots of processing ...) } Same processing code, no changes needed
  • 64. Running Shell commands def process = 'ls /home/andres'.execute() def procOutput = new InputStreamReader(process.in) procOutput.eachLine { line -> println line } process.waitFor() println "** Return code: ${process.exitValue()}"
  • 65. Running Shell commands def process = 'ls /home/andres'.execute() def procOutput = new InputStreamReader(process.in) procOutput.eachLine { line -> println line } process.waitFor() println "** Return code: ${process.exitValue()}"
  • 66. Running Shell commands def process = 'ls /home/andres'.execute() def procOutput = new InputStreamReader(process.in) procOutput.eachLine { line -> println line } process.waitFor() println "** Return code: ${process.exitValue()}" def process = 'echo "Hola caracola"'.execute() println process.text def process = ['echo', 'Hola caracola'].execute()
  • 67. Running Shell commands def process = 'ls /home/andres'.execute() def procOutput = new InputStreamReader(process.in) procOutput.eachLine { line -> println line } process.waitFor() println "** Return code: ${process.exitValue()}" def process = 'echo "Hola caracola"'.execute() println process.text def process = ['echo', 'Hola caracola'].execute() def process = 'ls /home/andres/*'.execute() def process = ['sh', '-c', 'ls /home/andres/*'].execute()
  • 68. Running Shell commands def process = 'ls /home/andres'.execute() def procOutput = new InputStreamReader(process.in) procOutput.eachLine { line -> println line } process.waitFor() println "** Return code: ${process.exitValue()}" def process = 'echo "Hola caracola"'.execute() println process.text def process = ['echo', 'Hola caracola'].execute() def process = 'ls /home/andres/*'.execute() def process = ['sh', '-c', 'ls /home/andres/*'].execute() def process = 'ls'.execute() def process = 'ls'.execute([], new File('/home/andres'))
  • 69. Running Shell commands class Shell { File currentDir = new File('.') final Map environment = [:] Process run(String command) { return ['sh', '-c', command].execute( environment.collect { "${it.key}=${it.value}" }, currentDir) } String runAndGet(String command) { def proc = run(command) proc.waitFor() return proc.text } } Shell shell = new Shell(currentDir: new File("/home/andres/temp")) shell.environment["GREETINGS"] = "Hi!" print shell.runAndGet('echo $GREETINGS') print shell.runAndGet("ls i*") print shell.runAndGet('echo "Hola caracola"')
  • 70. Running Shell commands class Shell { File currentDir = new File('.') final Map environment = [:] Process run(String command) { return ['sh', '-c', command].execute( environment.collect { "${it.key}=${it.value}" }, currentDir) } String runAndGet(String command) { def proc = run(command) proc.waitFor() return proc.text } } Shell shell = new Shell(currentDir: new File("/home/andres/temp")) shell.environment["GREETINGS"] = "Hi!" print shell.runAndGet('echo $GREETINGS') print shell.runAndGet("ls i*") print shell.runAndGet('echo "Hola caracola"')