SlideShare uma empresa Scribd logo
1 de 50
Baixar para ler offline
Alexander (Sascha) Klein
codecentric AG
vert.x with Groovy
Simplifying non-blocking code
codecentric AG
Alexander Klein, 2014-06-03
vert.x with Groovy – Simpliyfing non-blocking code
codecentric AG
Why using vert.x ?
CC BY 2.0 > http://www.flickr.com/photos/girliemac/6509400997
codecentric AG
Alexander (Sascha) Klein
Principal Consultant
codecentric AG in Stuttgart
Germany
Groovy, JavaFX, UI / UX
Griffon committer
alexander.klein@codecentric.de
@saschaklein
http://gplus.to/karfunkel
codecentric AG
vert.x
Framework to write polyglot, highly concurrent applications
Similar to Node.js
Asynchronous, non-blocking API
Polyglot (Java, JavaScript, Groovy, Ruby, Python and others)
codecentric AG
Architecture
Client Background
Threadpool
Worker-Verticle
Worker-Verticle
Worker-Verticle
Event Loop
Verticle
Verticle
Verticle
Event Bus
Request
Response
delegating
long-running tasks
non-blocking blocking
codecentric AG
Yoke
Middleware framework for vert.x
Currently only Java, JavaScript and Groovy supported
Many helpful implementations
Request body and Cookie parser
Static file server
Request Router
Virtual host support
Templateengines
and more ...
codecentric AG
Calculating CRC32's for a directory
Read directory entries
Read file properties for each entry
Determine if entry is a directory
Handle directories recursively
Read file
Calculate CRC32 via worker verticle
codecentric AG
Classic vert.x/yoke code
container.deployWorkerVerticle 'CRC.groovy', [:]
GRouter router = new GRouter()
router.get("/crc") { GYokeRequest request ->
request.response.chunked = true
request.response.contentType = 'text/plain'
this.crc('/home/aklein/tmp/ConfigParser', request)
}
router.get("/") { GYokeRequest request, Handler next ->
request.response.render 'web/index.gsp', next
}
codecentric AG
Classic vert.x/yoke code
def yoke = new GYoke(vertx, container)
yoke.engine new GroovyTemplateEngine()
yoke.use(router)
yoke.use new Static("web", 24 * 60 * 60 * 1000, true, false)
yoke.use { request ->
request.response.statusCode = 404
request.response.statusMessage = 'Not Found'
request.response.contentType = 'text/plain'
request.response.end('404 - Not Found')
}
yoke.listen(8080)
codecentric AG
Classic vert.x/yoke code
def crc(String baseDir, GYokeRequest request) {
EventBus bus = vertx.eventBus
FileSystem fs = vertx.fileSystem
fs.readDir(baseDir) { AsyncResult<String[]> rs ->
if (rs.succeeded) {
String[] paths = rs.result
paths.each { String path ->
fs.props(path) { AsyncResult<FileProps> rs1 ->
if (rs1.succeeded) {
FileProps props = rs1.result
if (props.directory) {
crc(path, request)
} else {
fs.readFile(path) { AsyncResult<Buffer> rs2 ->
if (rs2.succeeded) {
Buffer content = rs2.result
bus.send("create.crc", content) { Message result ->
if (result.body().status == 'error') {
request.response.statusCode = 500
request.response.statusMessage = "Error processing file " +
"$path: ${result.body().message}: ${result.body().error} n" +
"${result.body().stacktrace}"
request.response.end()
} else {
request.response.write "$path = ${result.body().message}n"
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read file $path"
request.response.end()
}
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read properties for $path"
request.response.end()
}
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read $baseDir"
request.response.end()
}
}
}
codecentric AG
Preparing gradle build
Download from: http://github.com/vert-x/vertx-gradle-template
build.gradle
provided "com.jetdrone:yoke:$yokeVersion@jar" // (optional for using yoke)
gradle.properties
groovyVersion=2.2.1
yokeVersion=1.0.13 // (optional for using yoke)
codecentric AG
Preparing gradle build
gradle/vertx.gradle
task startMod(dependsOn: copyMod, description: 'Run the module', type: JavaExec) {
classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath
main = 'org.vertx.java.platform.impl.cli.Starter'
args(['runmod', moduleName])
args runModArgs.split("s+")
// jvmArgs "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"
systemProperties([
"vertx.clusterManagerFactory": "org.vertx.java.spi.cluster.impl.hazelcast.HazelcastClusterManagerFactory",
"vertx.mods" : "$projectDir/build/mods"
])
}
codecentric AG
Classic vert.x/yoke code
def crc(String baseDir, GYokeRequest request) {
EventBus bus = vertx.eventBus
FileSystem fs = vertx.fileSystem
fs.readDir(baseDir) { AsyncResult<String[]> rs ->
if (rs.succeeded) {
String[] paths = rs.result
paths.each { String path ->
fs.props(path) { AsyncResult<FileProps> rs1 ->
if (rs1.succeeded) {
FileProps props = rs1.result
if (props.directory) {
crc(path, request)
} else {
fs.readFile(path) { AsyncResult<Buffer> rs2 ->
if (rs2.succeeded) {
Buffer content = rs2.result
bus.send("create.crc", content) { Message result ->
if (result.body().status == 'error') {
request.response.statusCode = 500
request.response.statusMessage = "Error processing file " +
"$path: ${result.body().message}: ${result.body().error} n" +
"${result.body().stacktrace}"
request.response.end()
} else {
request.response.write "$path = ${result.body().message}n"
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read file $path"
request.response.end()
}
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read properties for $path"
request.response.end()
}
}
}
} else {
request.response.statusCode = 500
request.response.statusMessage = "Failed to read $baseDir"
request.response.end()
}
}
}
codecentric AG
Compress Errorhandling - Method
request.response.statusCode = 500
request.response.statusMessage = "Failed to read file $path"
request.response.end()
------------------------------------------------------------------------------------------------------------------------------------------------------------------
def end(YokeResponse response, int statusCode, String statusMessage = null) {
response.statusCode = statusCode
if(statusMessage)
response.statusMessage = statusMessage
response.end()
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
end request.response, 500, "Failed to read file $path"
codecentric AG
Compress Errorhandling - Dynamic Mixins
class YokeExtension {
static String end(YokeResponse self, Integer statusCode, String statusMessage = null) {
self.statusCode = statusCode
if (statusMessage)
self.statusMessage = statusMessage
self.end()
}
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
YokeResponse.mixin(YokeExtension)
request.response.end 500, "Failed to read file $path"
codecentric AG
Compress Errorhandling - Static Mixins (vert.x 2.1)
class YokeExtension {
static String end(YokeResponse self, Integer statusCode, String statusMessage = null) {
...
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
compilerConfiguration.groovy:
customizer = { org.codehaus.groovy.control.CompilerConfiguration config ->
config.addCompilationCustomizers(
new ASTTransformationCustomizer(Mixin, value: YokeExtension) )
return config
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
request.response.end 500, "Failed to read file $path"
codecentric AG
Compress Errorhandling - Module Extension (vert.x 2.1)
class YokeExtension {
static String end(YokeResponse self, Integer statusCode, String statusMessage = null) {
...
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
META-INF/services/org.codehaus.groovy.runtime.ExtensionModule:
moduleName = vertx-module
moduleVersion = 1.0
extensionClasses = de.codecentric.vertx.YokeExtension
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
build.gradle:
repositories {
mavenLocal()
}
dependencies {
compile "de.codecentric:vertx-extension:1.0.0-SNAPSHOT@jar"
}
codecentric AG
After YokeResponse enhancement
def crc(String baseDir, GYokeRequest request) {
EventBus bus = vertx.eventBus
FileSystem fs = vertx.fileSystem
fs.readDir(baseDir) { AsyncResult<String[]> rs ->
if (rs.succeeded) {
String[] paths = rs.result
paths.each { String path ->
fs.props(path) { AsyncResult<FileProps> rs1 ->
if (rs1.succeeded) {
FileProps props = rs1.result
if (props.directory) {
crc(path, request)
} else {
fs.readFile(path) { AsyncResult<Buffer> rs2 ->
if (rs2.succeeded) {
Buffer content = rs2.result
bus.send("create.crc", content) { Message result ->
if (result.body().status == 'error') {
request.response.end 500, "Error processing file " +
"$path: ${result.body().message}: ${result.body().error} n" +
"${result.body().stacktrace}"
} else
request.response.write "$path = ${result.body().message}n"
}
} else
request.response.end 500, "Failed to read file $path"
}
}
} else
request.response.end 500, "Failed to read properties for $path"
}
}
} else
request.response.end 500, "Failed to read $baseDir“
}
}
codecentric AG
Bus communication
if (rs2.succeeded) {
Buffer content = rs2.result
bus.send("create.crc", content) { Message result ->
if (result.body().status == 'error') {
request.response.end 500, "Error processing file " +
"$path: ${result.body().message}: ${result.body().error} n" +
"${result.body().stacktrace}"
} else
request.response.write "$path = ${result.body().message}n"
}
} else
request.response.end 500, "Failed to read file $path"
codecentric AG
Worker Module
EventBus bus = vertx.eventBus
bus.registerHandler('create.crc') { Message msg ->
try {
Buffer buffer = new Buffer(msg.body())
CRC32 crc = new CRC32()
int start = 0, end, length = buffer.length
while (start < length) {
end = Math.min(start + 1024, length)
crc.update(buffer.getBytes(start, end))
start = end
}
msg.reply([status: 'ok', message: crc.value ])
} catch (e) {
StringWriter sw = new StringWriter()
e.printStackTrace(sw.newPrintWriter())
msg.reply([status: 'error', message: 'Failure creating crc', error: e.message, stacktrace: sw.toString()])
}
}
codecentric AG
Standardizing bus communication – Worker
bus.registerHandler('create.crc') { Message msg ->
try { ...
msg.reply([status: 'ok', message: crc.value ])
} catch (e) {
StringWriter sw = new StringWriter()
e.printStackTrace(sw.newPrintWriter())
msg.reply([status: 'error', message: 'Failure creating crc', error: e.message, stacktrace: sw.toString()])
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bus.registerHandler('create.crc') { Message msg ->
try { ...
msg.replySuccess(crc.value)
} catch (e) {
msg.replyFailure('Failure creating crc', e)
}
}
codecentric AG
Standardizing bus communication - Module
class MessageExtension {
static final String OK = 'ok'
static final String ERROR = 'error'
static void replySuccess(Message self, message) {
self.reply([status: OK, message: message])
}
static void replyFailure(Message self, Throwable e) {
replyFailure(self, null, e)
}
static void replyFailure(Message self, String msg,
Throwable e = null) {
def message = [status: ERROR]
if (msg)
message.message = msg
if (e) {
message.error = e.message
StringWriter sw = new StringWriter()
e.printStackTrace(sw.newPrintWriter())
message.stacktrace = sw.toString()
}
self.reply(message)
}
codecentric AG
Standardizing bus communication - Module
static String getStacktrace(Message self) {
self.body().stacktrace
}
static String getError(Message self) {
self.body().error
}
static def getMessage(Message self) {
return self.body().message
}
...
codecentric AG
Standardizing bus communication – Caller
bus.send("create.crc", content) { Message result ->
if (result.body().status == 'error')
request.response.end 500,
"Error processing file $path: ${result.body().message}: ${result.body().error} n $result.body().stacktrace}"
else
request.response.write "$path = ${result.body().message}n"
}
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
bus.send("create.crc", content) { Message result ->
if (result)
request.response.write "$path = ${result.message}n"
else
request.response.end 500, "Error processing file $path: $result.logMessage"
}
codecentric AG
Standardizing bus communication - Module
static boolean isSucceeded(Message self) {
def result = self.body()
if (result instanceof Map) {
return result.status == OK
} else
return false
}
static boolean asBoolean(Message self) {
return self.isSucceeded()
}
static String getLogMessage(Message self) {
return self.getError() ? "${self.getMessage()}: ${self.getError()} n${self.getStacktrace()}" : self.getMessage()
}
...
codecentric AG
Streamlining AsyncResult API
static boolean asBoolean(AsyncResult self) {
return self.isSucceeded()
}
static String getStacktrace(AsyncResult self) {
if (!self.cause)
return ''
StringWriter sw = new StringWriter()
PrintWriter pw = sw.newPrintWriter()
self.cause.printStackTrace(pw)
return sw.toString()
}
static String getError(AsyncResult self) {
return self.cause ? self.cause.message : ''
}
static def getMessage(AsyncResult self) {
return self.result
}
static String getLogMessage(AsyncResult self) {
return self.getError() ? self.getMessage() +
": ${self.getError()} n${self.getStacktrace()}" :
self.getMessage()
}
codecentric AG
With standardized bus communication
def crc(String baseDir, GYokeRequest request) {
EventBus bus = vertx.eventBus
FileSystem fs = vertx.fileSystem
fs.readDir(baseDir) { AsyncResult<String[]> rs ->
if (rs) {
String[] paths = rs.result
paths.each { String path ->
fs.props(path) { AsyncResult<FileProps> rs1 ->
if (rs1) {
FileProps props = rs1.result
if (props.directory) {
crc(path, request)
} else {
fs.readFile(path) { AsyncResult<Buffer> rs2 ->
if (rs2) {
Buffer content = rs2.result
bus.send("create.crc", content) { Message result ->
if (result) {
request.response.write "$path = ${result.message}n"
} else
request.response.end 500, "Error processing file $path:" +
result.logMessage
} else
request.response.end 500, "Failed to read file $path"
}
}
} else
request.response.end 500, "Failed to read properties for $path"
}
}
} else
request.response.end 500, "Failed to read $baseDir“
}
}
codecentric AG
Handler chains
Event-based programming often results in multiple, stacked Handlers / Closures
Difficult to read
Order of commands from left to right / outside to inside
Horizontal scrolling because of indentation
Hard to find the begining of a logical part
Difficult to test
Loops are difficult or impossible to implement
When is the for loop finished to send the .end()?
codecentric AG
Closure Chaining - Syntax
chain { next -> next() }, { next -> next(10) }, { input, next -> println input }
chain ( 10, { input, next -> next(input) }, { input, next -> println input } )
chain 10, { input, next -> next(input) }, { input, next -> println input }
------------------------------------------------------------------------------------------------------------------------------------------------------------------
chain { next -> next() } { next -> next(10) } { input, next -> println input }
chain (10) { input, next -> next(input) } { input, next -> println input }
chain (10) { input, next ->
next(input)
} {
input, next -> println input
}
codecentric AG
Closure Chaining – Module
class StructureExtension {
static void chain(final Object self, def arguments, Closure... actions) {
if (arguments instanceof Closure) {
actions = [arguments, *actions] as Closure[]
arguments = null
}
if (!actions)
throw new IllegalArgumentException("One or more arguments of type groovy.lang.Closure required")
_chain(arguments, actions.iterator())
}
...
chain{} …
chain(arg)
chain(arg) {} ...
codecentric AG
Closure Chaining – Module
static void chain(final Object self, Object... arguments) {
if (!arguments.any { it instanceof Closure })
throw new IllegalArgumentException("One or more arguments of type groovy.lang.Closure required")
int i; def actions = []
for (i = arguments.size() - 1; i >= 0; i--) {
if (arguments[i] instanceof Closure)
actions.add(0, arguments[i])
else
break
}
_chain(arguments[0..i], actions.iterator())
}
...
chain()
chain(arg1, arg2, ...)
chain(arg1, arg2, ...) {} …
codecentric AG
Closure Chaining – Module
private static void _chain(final Object arguments, final Iterator<Closure> actions) {
if (actions) {
def action = actions.next()
if (arguments != null) {
action = action.curry(arguments as Object[])
}
action.call { Object[] args ->
_chain(args, actions)
}
}
}
...
codecentric AG
Looping - Syntax
[1,2,3].loop { element, next -> next() }
[a:1, b:2, c:3].loop { key, value, next -> next() }
[1,2,3].loop { element, next ->
next()
} {
// called after the last iteration
}
codecentric AG
Looping – Module
static void loop(final Object[] array, final Closure action) { loop(array, action, {} }
static void loop(final Object[] array, final Closure action, final Closure next) { _loop(array?.iterator(), action, next) }
static void loop(final Collection collection, final Closure action) { loop(collection, action, {} }
static void loop(final Collection collection, final Closure action, final Closure next) {
_loop(collection.iterator(), action, next)
}
static void loop(final Map map, final Closure action) { loop(map, action, {} }
static void loop(final Map map, final Closure action, final Closure next) { _loop(map.iterator(), action, next) }
...
codecentric AG
Looping – Module
private static void _loop(final Iterator<?> iterator, final Closure action, Closure next = {}) {
if(iterator) {
def element = iterator.next()
def nextAction
if (iterator)
nextAction = StructureExtension.&_loop.curry(iterator, action, next)
else
nextAction = next
if (element instanceof Map.Entry)
action.call(element.key, element.value, nextAction)
else
action.call(element, nextAction)
} else next.call()
}
codecentric AG
With chaining and looping
def crc(String baseDir, GYokeRequest request, Closure nextCrc = null) {
FileSystem fs = vertx.fileSystem
chain { nextChain -> // Read directory
fs.readDir(baseDir) { AsyncResult<String[]> rs ->
if (rs) nextChain(rs.result as List)
else request.response.end 500, "Failed to read $baseDir"
}
} { List paths, nextChain -> // Loop over files
paths.loop { String path, nextLoop ->
chain { next -> // Read file properties
fs.props(path) { AsyncResult<FileProps> rs ->
if (rs) next(rs.result)
else request.response.end 500, "Failed to read properties for $path"
}
} { FileProps props, next -> // Check for directory
if (props.directory) crc(path, request, nextLoop)
else next()
}
{ next -> // Read file
fs.readFile(path) { AsyncResult<Buffer> rs ->
if (rs) next(rs.result)
else request.response.end 500, "Failed to read file $path"
}
} { Buffer content, next -> // Call module to calculate crc
bus.send("create.crc", content) { Message result ->
if (result) {
request.response.write "$path = ${result.message}n"
nextLoop()
} else request.response.end 500, "Error processing file $path"
}
}
}
}
}
codecentric AG
Adding .end() after the loop
{ Buffer content, next -> // Call module to calculate crc
Vertx.eventBus.send("create.crc", content) { Message result ->
if (result) {
request.response.write "$path = ${result.message}n"
nextLoop()
} else request.response.end 500, "Error processing file $path"
}
}
} { // finish everything up after loop
if (nextCrc) nextCrc()
else request.response.end()
}
}
}
codecentric AG
Using a template engine
router.get("/crc") { GYokeRequest request ->
request.context.files = [:]
...
def crc(String baseDir, GYokeRequest request, Closure nextCrc = null) {
request.context.files[baseDir] = null
...
{ Buffer content, next -> // Call module to calculate crc
Vertx.eventBus.send("create.crc", content) { Message result ->
if (result) {
request.context.files[path] = result.message
nextLoop()
} else request.response.end 500, "Error processing file $path"
}
}
}
...
} { // finish everything up after loop
if (nextCrc) nextCrc()
else
request.response.render('web/crc.gsp',
files: request.context.files)
}
}
}
codecentric AG
Accessing the context - !!! Hack Alert !!!
class YokeExtension {
...
static Context getContext(YokeRequest self) {
// Reflection because context is a private field of the super class for GYokeRequest
Field field = YokeRequest.getDeclaredField('context')
field.accessible = true
return (Context) field.get(self)
}
static Context getContext(YokeResponse self) {
// Reflection because context is a private field of the super class for GYokeResponse
Field field = YokeResponse.getDeclaredField('context')
field.accessible = true
return (Context) field.get(self)
}
codecentric AG
Adding custom context for rendering
static void render(GYokeResponse self, Map<String, Object> context, String template) { render(self, context, template, null, null) }
static void render(GYokeResponse self, Map<String, Object> context, String template, Closure next) {
render(self, context, template, null, next)
}
static void render(GYokeResponse self, Map<String, Object> context, String template, String layoutTemplate) {
render(self, context, template, layoutTemplate, null)
}
static void render(GYokeResponse self, Map<String, Object> context, String template, String layoutTemplate, Closure next) {
Map<String, Object> oldContext = getContext(self).clone()
getContext(self).clear()
getContext(self).putAll(context)
if (next)
self.render(template, layoutTemplate, next)
else
self.render(template, layoutTemplate)
getContext(self).clear()
getContext(self).putAll(oldContext)
}
codecentric AG
The template
<html>
<head>
<title>CRC</title>
</head>
<body>
<ul>
<% def data = files.sort { a, b -> a.key <=> b.key }
data.each { k, v ->
if (v != null) { %>
<li>${k} = ${v}</li>
<% } else { %>
<li>${k}</li>
<% } %>
<% } %>
</ul>
</body>
</html>
codecentric AG
Smoothen all up with a custom BaseScriptClass
abstract class VerticleScript extends Script {
Vertx getVertx() {
return binding.vertx
}
void setVertx(Vertx vertx) {
binding.vertx = vertx
}
Container getContainer() {
return binding.container
}
void setContainer(Container container) {
binding.container = container
}
EventBus getBus() {
vertx.eventBus
}
SharedData getSharedData() {
vertx.sharedData
}
Logger getLog() {
container.logger
}
Map<String, Object> getConfig() {
container.config
}
Map<String, String> getEnv() {
container.env
}
codecentric AG
Using the BaseScriptClass (vert.x 2.1)
Global usage:
compilerConfiguration.groovy:
customizer = { org.codehaus.groovy.control.CompilerConfiguration config ->
config.scriptBaseClass = 'de.codecentric.vertx.VerticleScript'
return config
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Local usage per Script:
@groovy.transform.BaseScript de.codecentric.vertx.VerticleScript verticleScript
codecentric AG
API to smoothen MongoDB usage
def db(String address, Map message, Closure success = null, Closure failure = null) {
bus.send(address, message) { Message result ->
Map reply = result.body()
if (reply.status == 'ok') {
if (success) {
if (success.maximumNumberOfParameters == 2) success(reply, result)
else success(reply)
}
} else {
if (failure) {
if (failure.maximumNumberOfParameters == 2) failure(reply, result)
else failure(result)
}
}
}
}
codecentric AG
API to smoothen MongoDB usage
def save(String address, String collection, Map document, Closure success = null, Closure failure = null) {
db(address,
[action: 'save', collection: collection, document: document, write_concern: 'SAFE'],
success, failure)
}
def update(String address, String collection, Map criteria, Map update, Closure success=null, Closure failure=null) {
db(address, [action: 'update', collection: collection, criteria: criteria, objNew: update, write_concern: 'SAFE'],
success, failure)
}
def delete(String address, String collection, Map matcher, Closure success = null, Closure failure = null) {
db(address, [action: 'delete', collection: collection, matcher: matcher], success, failure)
}
def read(String address, String collection, Map matcher, Closure success = null, Closure failure = null) {
db(address, [action: 'findone', collection: collection, matcher: matcher,], success, failure)
}
codecentric AG
API to smoothen MongoDB usage
def exists(String address, String collection, Map matcher, Closure success = null, Closure failure = null) {
def command = [action: 'find', collection: collection, matcher: matcher, batch_size: 100]
db(address, command, success) { Map reply, Message result ->
if (reply.status == 'more-exist') {
if (success.maximumNumberOfParameters == 2)
success(reply, result)
else
success(result)
} else {
if (failure.maximumNumberOfParameters == 2)
failure(reply, result)
else
failure(result)
}
}
}
codecentric AG
API to smoothen MongoDB usage
def query(String address, String collection, Map matcher,
Map options, Closure success, Closure failure) {
int max = options.max ?: -1
int offset = options.offset ?: -1
Map orderby = options.orderby ?: null
Map keys = options.keys ?: null
def data = []
def queryHandler
queryHandler = { Map reply, Message result ->
if (reply.status == 'more-exist') {
data.addAll reply.results
result.reply([:], queryHandler)
} else if (reply.status == 'ok') {
data.addAll reply.results
success(data)
} else if (reply.status == 'ok') {
data.addAll reply.results
success(data)
} else if (failure.maximumNumberOfParameters == 2) {
failure(reply, result)
} else failure(result)
}
def command = [ action: 'find', collection: collection,
matcher : matcher, batch_size: 100]
if (max >= 0) command.max = max
if (offset >= 0) command.offset = offset
if (orderby) command.orderby = orderby
if (keys) command.keys = keys
db(address, command, queryHandler, queryHandler)
}
codecentric AG
API to smoothen MongoDB usage
def query(String address, String collection, Map matcher, Closure success) {
query(address, collection, matcher, [:], success, null)
}
def query(String address, String collection, Map matcher, Closure success, Closure failure) {
query(address, collection, matcher, [:], success, failure)
}
def query(String address, String collection, Map matcher, Map options, Closure success) {
query(address, collection, matcher, options, success, null)
}
codecentric AG
Questions?
Alexander (Sascha) Klein
codecentric AG
Curiestr. 2
70563 Stuttgart
tel +49 (0) 711.674 00 - 328
fax +49 (0) 172.529 40 20
alexander.klein@codecentric.de
@saschaklein
www.codecentric.de
blog.codecentric.de
03.06.14 50

Mais conteúdo relacionado

Mais procurados

Advanced Data Modeling with Apache Cassandra
Advanced Data Modeling with Apache CassandraAdvanced Data Modeling with Apache Cassandra
Advanced Data Modeling with Apache CassandraDataStax Academy
 
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...PROIDEA
 
Forget the Web
Forget the WebForget the Web
Forget the WebRemy Sharp
 
Webinar: Architecting Secure and Compliant Applications with MongoDB
Webinar: Architecting Secure and Compliant Applications with MongoDBWebinar: Architecting Secure and Compliant Applications with MongoDB
Webinar: Architecting Secure and Compliant Applications with MongoDBMongoDB
 
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...MongoDB
 
Seattle C* Meetup: Hardening cassandra for compliance or paranoia
Seattle C* Meetup: Hardening cassandra for compliance or paranoiaSeattle C* Meetup: Hardening cassandra for compliance or paranoia
Seattle C* Meetup: Hardening cassandra for compliance or paranoiazznate
 
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...DataStax Academy
 
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...Andrey Devyatkin
 
Creating Reusable Puppet Profiles
Creating Reusable Puppet ProfilesCreating Reusable Puppet Profiles
Creating Reusable Puppet ProfilesBram Vogelaar
 
Static Typing in Vault
Static Typing in VaultStatic Typing in Vault
Static Typing in VaultGlynnForrest
 
What I learned from FluentConf and then some
What I learned from FluentConf and then someWhat I learned from FluentConf and then some
What I learned from FluentConf and then someOhad Kravchick
 
Meetup cassandra sfo_jdbc
Meetup cassandra sfo_jdbcMeetup cassandra sfo_jdbc
Meetup cassandra sfo_jdbczznate
 
Ground Control to Nomad Job Dispatch
Ground Control to Nomad Job DispatchGround Control to Nomad Job Dispatch
Ground Control to Nomad Job DispatchMichael Lange
 
Incrementalism: An Industrial Strategy For Adopting Modern Automation
Incrementalism: An Industrial Strategy For Adopting Modern AutomationIncrementalism: An Industrial Strategy For Adopting Modern Automation
Incrementalism: An Industrial Strategy For Adopting Modern AutomationSean Chittenden
 
Integrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteIntegrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteBram Vogelaar
 
Creating PostgreSQL-as-a-Service at Scale
Creating PostgreSQL-as-a-Service at ScaleCreating PostgreSQL-as-a-Service at Scale
Creating PostgreSQL-as-a-Service at ScaleSean Chittenden
 
bootstrapping containers with confd
bootstrapping containers with confdbootstrapping containers with confd
bootstrapping containers with confdm_richardson
 

Mais procurados (20)

Advanced Data Modeling with Apache Cassandra
Advanced Data Modeling with Apache CassandraAdvanced Data Modeling with Apache Cassandra
Advanced Data Modeling with Apache Cassandra
 
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...
DevOpsDays Warsaw 2015: Running High Performance And Fault Tolerant Elasticse...
 
Forget the Web
Forget the WebForget the Web
Forget the Web
 
Webinar: Architecting Secure and Compliant Applications with MongoDB
Webinar: Architecting Secure and Compliant Applications with MongoDBWebinar: Architecting Secure and Compliant Applications with MongoDB
Webinar: Architecting Secure and Compliant Applications with MongoDB
 
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...
Securing MongoDB to Serve an AWS-Based, Multi-Tenant, Security-Fanatic SaaS A...
 
Seattle C* Meetup: Hardening cassandra for compliance or paranoia
Seattle C* Meetup: Hardening cassandra for compliance or paranoiaSeattle C* Meetup: Hardening cassandra for compliance or paranoia
Seattle C* Meetup: Hardening cassandra for compliance or paranoia
 
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
Beyond the Query: A Cassandra + Solr + Spark Love Triangle Using Datastax Ent...
 
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...
2020-02-20 - HashiTalks 2020 - HashiCorp Vault configuration as code via Hash...
 
Creating Reusable Puppet Profiles
Creating Reusable Puppet ProfilesCreating Reusable Puppet Profiles
Creating Reusable Puppet Profiles
 
Advanced Cassandra
Advanced CassandraAdvanced Cassandra
Advanced Cassandra
 
Unity Makes Strength
Unity Makes StrengthUnity Makes Strength
Unity Makes Strength
 
Static Typing in Vault
Static Typing in VaultStatic Typing in Vault
Static Typing in Vault
 
Node.js
Node.jsNode.js
Node.js
 
What I learned from FluentConf and then some
What I learned from FluentConf and then someWhat I learned from FluentConf and then some
What I learned from FluentConf and then some
 
Meetup cassandra sfo_jdbc
Meetup cassandra sfo_jdbcMeetup cassandra sfo_jdbc
Meetup cassandra sfo_jdbc
 
Ground Control to Nomad Job Dispatch
Ground Control to Nomad Job DispatchGround Control to Nomad Job Dispatch
Ground Control to Nomad Job Dispatch
 
Incrementalism: An Industrial Strategy For Adopting Modern Automation
Incrementalism: An Industrial Strategy For Adopting Modern AutomationIncrementalism: An Industrial Strategy For Adopting Modern Automation
Incrementalism: An Industrial Strategy For Adopting Modern Automation
 
Integrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suiteIntegrating icinga2 and the HashiCorp suite
Integrating icinga2 and the HashiCorp suite
 
Creating PostgreSQL-as-a-Service at Scale
Creating PostgreSQL-as-a-Service at ScaleCreating PostgreSQL-as-a-Service at Scale
Creating PostgreSQL-as-a-Service at Scale
 
bootstrapping containers with confd
bootstrapping containers with confdbootstrapping containers with confd
bootstrapping containers with confd
 

Destaque

vert.x - asynchronous event-driven web applications on the JVM
vert.x - asynchronous event-driven web applications on the JVMvert.x - asynchronous event-driven web applications on the JVM
vert.x - asynchronous event-driven web applications on the JVMjbandi
 
빠르게훓어보는 Node.js와 Vert.x
빠르게훓어보는 Node.js와 Vert.x빠르게훓어보는 Node.js와 Vert.x
빠르게훓어보는 Node.js와 Vert.xTerry Cho
 
Creating polyglot and scalable applications on the jvm using Vert.x
Creating polyglot and scalable applications on the jvm using Vert.xCreating polyglot and scalable applications on the jvm using Vert.x
Creating polyglot and scalable applications on the jvm using Vert.xJettro Coenradie
 
Vert.x
Vert.x Vert.x
Vert.x ymtech
 
Vert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingVert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingAlex Derkach
 
vert.x 소개 및 개발 실습
vert.x 소개 및 개발 실습vert.x 소개 및 개발 실습
vert.x 소개 및 개발 실습John Kim
 
Vert.x v3 - high performance polyglot application toolkit
Vert.x v3 - high performance  polyglot application toolkitVert.x v3 - high performance  polyglot application toolkit
Vert.x v3 - high performance polyglot application toolkitSages
 
SockJS Intro
SockJS IntroSockJS Intro
SockJS IntroNgoc Dao
 
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기Kim Hunmin
 
기술적 변화를 이끌어가기
기술적 변화를 이끌어가기기술적 변화를 이끌어가기
기술적 변화를 이끌어가기Jaewoo Ahn
 
Reactive Polyglot Microservices with OpenShift and Vert.x
Reactive Polyglot Microservices with OpenShift and Vert.xReactive Polyglot Microservices with OpenShift and Vert.x
Reactive Polyglot Microservices with OpenShift and Vert.xReactivesummit
 
RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015Ben Lesh
 
vert.x 3.1 - be reactive on the JVM but not only in Java
vert.x 3.1 - be reactive on the JVM but not only in Javavert.x 3.1 - be reactive on the JVM but not only in Java
vert.x 3.1 - be reactive on the JVM but not only in JavaClément Escoffier
 

Destaque (18)

vert.x - asynchronous event-driven web applications on the JVM
vert.x - asynchronous event-driven web applications on the JVMvert.x - asynchronous event-driven web applications on the JVM
vert.x - asynchronous event-driven web applications on the JVM
 
빠르게훓어보는 Node.js와 Vert.x
빠르게훓어보는 Node.js와 Vert.x빠르게훓어보는 Node.js와 Vert.x
빠르게훓어보는 Node.js와 Vert.x
 
Creating polyglot and scalable applications on the jvm using Vert.x
Creating polyglot and scalable applications on the jvm using Vert.xCreating polyglot and scalable applications on the jvm using Vert.x
Creating polyglot and scalable applications on the jvm using Vert.x
 
Vert.x
Vert.xVert.x
Vert.x
 
Vert.x
Vert.x Vert.x
Vert.x
 
Vert.x 3
Vert.x 3Vert.x 3
Vert.x 3
 
Vert.x devoxx london 2013
Vert.x devoxx london 2013Vert.x devoxx london 2013
Vert.x devoxx london 2013
 
Vert.x
Vert.xVert.x
Vert.x
 
Vert.x – The problem of real-time data binding
Vert.x – The problem of real-time data bindingVert.x – The problem of real-time data binding
Vert.x – The problem of real-time data binding
 
Production ready Vert.x
Production ready Vert.xProduction ready Vert.x
Production ready Vert.x
 
vert.x 소개 및 개발 실습
vert.x 소개 및 개발 실습vert.x 소개 및 개발 실습
vert.x 소개 및 개발 실습
 
Vert.x v3 - high performance polyglot application toolkit
Vert.x v3 - high performance  polyglot application toolkitVert.x v3 - high performance  polyglot application toolkit
Vert.x v3 - high performance polyglot application toolkit
 
SockJS Intro
SockJS IntroSockJS Intro
SockJS Intro
 
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기
 
기술적 변화를 이끌어가기
기술적 변화를 이끌어가기기술적 변화를 이끌어가기
기술적 변화를 이끌어가기
 
Reactive Polyglot Microservices with OpenShift and Vert.x
Reactive Polyglot Microservices with OpenShift and Vert.xReactive Polyglot Microservices with OpenShift and Vert.x
Reactive Polyglot Microservices with OpenShift and Vert.x
 
RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015RxJS and Reactive Programming - Modern Web UI - May 2015
RxJS and Reactive Programming - Modern Web UI - May 2015
 
vert.x 3.1 - be reactive on the JVM but not only in Java
vert.x 3.1 - be reactive on the JVM but not only in Javavert.x 3.1 - be reactive on the JVM but not only in Java
vert.x 3.1 - be reactive on the JVM but not only in Java
 

Semelhante a Vert.x using Groovy - Simplifying non-blocking code

Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)James Titcumb
 
Quick trip around the Cosmos - Things every astronaut supposed to know
Quick trip around the Cosmos - Things every astronaut supposed to knowQuick trip around the Cosmos - Things every astronaut supposed to know
Quick trip around the Cosmos - Things every astronaut supposed to knowRafał Hryniewski
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesLindsay Holmwood
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)James Titcumb
 
Infrastructure-as-code: bridging the gap between Devs and Ops
Infrastructure-as-code: bridging the gap between Devs and OpsInfrastructure-as-code: bridging the gap between Devs and Ops
Infrastructure-as-code: bridging the gap between Devs and OpsMykyta Protsenko
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extremeyinonavraham
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Agile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collectionAgile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collectionJoEllen Carter
 
Going Offline with Gears And GWT
Going Offline with Gears And GWTGoing Offline with Gears And GWT
Going Offline with Gears And GWTtom.peck
 
Elk-slides-pdf.pdf
Elk-slides-pdf.pdfElk-slides-pdf.pdf
Elk-slides-pdf.pdfHello244729
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVCAlive Kuo
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020Matt Raible
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)James Titcumb
 
Deploying configurable frontend web application containers
Deploying configurable frontend web application containersDeploying configurable frontend web application containers
Deploying configurable frontend web application containersJosé Moreira
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsIván López Martín
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
 
ELK: a log management framework
ELK: a log management frameworkELK: a log management framework
ELK: a log management frameworkGiovanni Bechis
 

Semelhante a Vert.x using Groovy - Simplifying non-blocking code (20)

Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
Kicking off with Zend Expressive and Doctrine ORM (Sunshine PHP 2017)
 
Quick trip around the Cosmos - Things every astronaut supposed to know
Quick trip around the Cosmos - Things every astronaut supposed to knowQuick trip around the Cosmos - Things every astronaut supposed to know
Quick trip around the Cosmos - Things every astronaut supposed to know
 
Burn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websitesBurn down the silos! Helping dev and ops gel on high availability websites
Burn down the silos! Helping dev and ops gel on high availability websites
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
 
Frontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and HowFrontend Servers and NGINX: What, Where and How
Frontend Servers and NGINX: What, Where and How
 
Infrastructure-as-code: bridging the gap between Devs and Ops
Infrastructure-as-code: bridging the gap between Devs and OpsInfrastructure-as-code: bridging the gap between Devs and Ops
Infrastructure-as-code: bridging the gap between Devs and Ops
 
Taking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the ExtremeTaking Jenkins Pipeline to the Extreme
Taking Jenkins Pipeline to the Extreme
 
Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On Steroids
 
Agile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collectionAgile Testing Days 2018 - API Fundamentals - postman collection
Agile Testing Days 2018 - API Fundamentals - postman collection
 
Going Offline with Gears And GWT
Going Offline with Gears And GWTGoing Offline with Gears And GWT
Going Offline with Gears And GWT
 
Elk-slides-pdf.pdf
Elk-slides-pdf.pdfElk-slides-pdf.pdf
Elk-slides-pdf.pdf
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 202010 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
10 Excellent Ways to Secure Spring Boot Applications - Okta Webinar 2020
 
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
Kicking off with Zend Expressive and Doctrine ORM (PHP Srbija 2017)
 
Deploying configurable frontend web application containers
Deploying configurable frontend web application containersDeploying configurable frontend web application containers
Deploying configurable frontend web application containers
 
Greach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut ConfigurationsGreach 2019 - Creating Micronaut Configurations
Greach 2019 - Creating Micronaut Configurations
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
ELK: a log management framework
ELK: a log management frameworkELK: a log management framework
ELK: a log management framework
 

Mais de sascha_klein

Groovy on the shell
Groovy on the shellGroovy on the shell
Groovy on the shellsascha_klein
 
GroovyFX - groove JavaFX Gr8Conf EU 2017
GroovyFX - groove JavaFX Gr8Conf EU 2017GroovyFX - groove JavaFX Gr8Conf EU 2017
GroovyFX - groove JavaFX Gr8Conf EU 2017sascha_klein
 
Bob the Builder - Gr8Conf EU 2017
Bob the Builder - Gr8Conf EU 2017Bob the Builder - Gr8Conf EU 2017
Bob the Builder - Gr8Conf EU 2017sascha_klein
 
GroovyFX - Groove JavaFX
GroovyFX - Groove JavaFXGroovyFX - Groove JavaFX
GroovyFX - Groove JavaFXsascha_klein
 
Using Groovy with Jenkins
Using Groovy with JenkinsUsing Groovy with Jenkins
Using Groovy with Jenkinssascha_klein
 
Introduction to Graphics- and UI-Design
Introduction to Graphics- and UI-DesignIntroduction to Graphics- and UI-Design
Introduction to Graphics- and UI-Designsascha_klein
 
Groovy on the shell
Groovy on the shellGroovy on the shell
Groovy on the shellsascha_klein
 
Groovy on the Shell
Groovy on the ShellGroovy on the Shell
Groovy on the Shellsascha_klein
 

Mais de sascha_klein (10)

DSL101
DSL101DSL101
DSL101
 
Groovy on the shell
Groovy on the shellGroovy on the shell
Groovy on the shell
 
GroovyFX - groove JavaFX Gr8Conf EU 2017
GroovyFX - groove JavaFX Gr8Conf EU 2017GroovyFX - groove JavaFX Gr8Conf EU 2017
GroovyFX - groove JavaFX Gr8Conf EU 2017
 
Bob the Builder - Gr8Conf EU 2017
Bob the Builder - Gr8Conf EU 2017Bob the Builder - Gr8Conf EU 2017
Bob the Builder - Gr8Conf EU 2017
 
GroovyFX - Groove JavaFX
GroovyFX - Groove JavaFXGroovyFX - Groove JavaFX
GroovyFX - Groove JavaFX
 
Using Groovy with Jenkins
Using Groovy with JenkinsUsing Groovy with Jenkins
Using Groovy with Jenkins
 
Introduction to Graphics- and UI-Design
Introduction to Graphics- and UI-DesignIntroduction to Graphics- and UI-Design
Introduction to Graphics- and UI-Design
 
Android on Groovy
Android on GroovyAndroid on Groovy
Android on Groovy
 
Groovy on the shell
Groovy on the shellGroovy on the shell
Groovy on the shell
 
Groovy on the Shell
Groovy on the ShellGroovy on the Shell
Groovy on the Shell
 

Último

Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...Health
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 

Último (20)

Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
+971565801893>>SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHAB...
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 

Vert.x using Groovy - Simplifying non-blocking code

  • 1. Alexander (Sascha) Klein codecentric AG vert.x with Groovy Simplifying non-blocking code
  • 2. codecentric AG Alexander Klein, 2014-06-03 vert.x with Groovy – Simpliyfing non-blocking code
  • 3. codecentric AG Why using vert.x ? CC BY 2.0 > http://www.flickr.com/photos/girliemac/6509400997
  • 4. codecentric AG Alexander (Sascha) Klein Principal Consultant codecentric AG in Stuttgart Germany Groovy, JavaFX, UI / UX Griffon committer alexander.klein@codecentric.de @saschaklein http://gplus.to/karfunkel
  • 5. codecentric AG vert.x Framework to write polyglot, highly concurrent applications Similar to Node.js Asynchronous, non-blocking API Polyglot (Java, JavaScript, Groovy, Ruby, Python and others)
  • 6. codecentric AG Architecture Client Background Threadpool Worker-Verticle Worker-Verticle Worker-Verticle Event Loop Verticle Verticle Verticle Event Bus Request Response delegating long-running tasks non-blocking blocking
  • 7. codecentric AG Yoke Middleware framework for vert.x Currently only Java, JavaScript and Groovy supported Many helpful implementations Request body and Cookie parser Static file server Request Router Virtual host support Templateengines and more ...
  • 8. codecentric AG Calculating CRC32's for a directory Read directory entries Read file properties for each entry Determine if entry is a directory Handle directories recursively Read file Calculate CRC32 via worker verticle
  • 9. codecentric AG Classic vert.x/yoke code container.deployWorkerVerticle 'CRC.groovy', [:] GRouter router = new GRouter() router.get("/crc") { GYokeRequest request -> request.response.chunked = true request.response.contentType = 'text/plain' this.crc('/home/aklein/tmp/ConfigParser', request) } router.get("/") { GYokeRequest request, Handler next -> request.response.render 'web/index.gsp', next }
  • 10. codecentric AG Classic vert.x/yoke code def yoke = new GYoke(vertx, container) yoke.engine new GroovyTemplateEngine() yoke.use(router) yoke.use new Static("web", 24 * 60 * 60 * 1000, true, false) yoke.use { request -> request.response.statusCode = 404 request.response.statusMessage = 'Not Found' request.response.contentType = 'text/plain' request.response.end('404 - Not Found') } yoke.listen(8080)
  • 11. codecentric AG Classic vert.x/yoke code def crc(String baseDir, GYokeRequest request) { EventBus bus = vertx.eventBus FileSystem fs = vertx.fileSystem fs.readDir(baseDir) { AsyncResult<String[]> rs -> if (rs.succeeded) { String[] paths = rs.result paths.each { String path -> fs.props(path) { AsyncResult<FileProps> rs1 -> if (rs1.succeeded) { FileProps props = rs1.result if (props.directory) { crc(path, request) } else { fs.readFile(path) { AsyncResult<Buffer> rs2 -> if (rs2.succeeded) { Buffer content = rs2.result bus.send("create.crc", content) { Message result -> if (result.body().status == 'error') { request.response.statusCode = 500 request.response.statusMessage = "Error processing file " + "$path: ${result.body().message}: ${result.body().error} n" + "${result.body().stacktrace}" request.response.end() } else { request.response.write "$path = ${result.body().message}n" } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read file $path" request.response.end() } } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read properties for $path" request.response.end() } } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read $baseDir" request.response.end() } } }
  • 12. codecentric AG Preparing gradle build Download from: http://github.com/vert-x/vertx-gradle-template build.gradle provided "com.jetdrone:yoke:$yokeVersion@jar" // (optional for using yoke) gradle.properties groovyVersion=2.2.1 yokeVersion=1.0.13 // (optional for using yoke)
  • 13. codecentric AG Preparing gradle build gradle/vertx.gradle task startMod(dependsOn: copyMod, description: 'Run the module', type: JavaExec) { classpath = sourceSets.main.compileClasspath + sourceSets.main.runtimeClasspath main = 'org.vertx.java.platform.impl.cli.Starter' args(['runmod', moduleName]) args runModArgs.split("s+") // jvmArgs "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005" systemProperties([ "vertx.clusterManagerFactory": "org.vertx.java.spi.cluster.impl.hazelcast.HazelcastClusterManagerFactory", "vertx.mods" : "$projectDir/build/mods" ]) }
  • 14. codecentric AG Classic vert.x/yoke code def crc(String baseDir, GYokeRequest request) { EventBus bus = vertx.eventBus FileSystem fs = vertx.fileSystem fs.readDir(baseDir) { AsyncResult<String[]> rs -> if (rs.succeeded) { String[] paths = rs.result paths.each { String path -> fs.props(path) { AsyncResult<FileProps> rs1 -> if (rs1.succeeded) { FileProps props = rs1.result if (props.directory) { crc(path, request) } else { fs.readFile(path) { AsyncResult<Buffer> rs2 -> if (rs2.succeeded) { Buffer content = rs2.result bus.send("create.crc", content) { Message result -> if (result.body().status == 'error') { request.response.statusCode = 500 request.response.statusMessage = "Error processing file " + "$path: ${result.body().message}: ${result.body().error} n" + "${result.body().stacktrace}" request.response.end() } else { request.response.write "$path = ${result.body().message}n" } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read file $path" request.response.end() } } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read properties for $path" request.response.end() } } } } else { request.response.statusCode = 500 request.response.statusMessage = "Failed to read $baseDir" request.response.end() } } }
  • 15. codecentric AG Compress Errorhandling - Method request.response.statusCode = 500 request.response.statusMessage = "Failed to read file $path" request.response.end() ------------------------------------------------------------------------------------------------------------------------------------------------------------------ def end(YokeResponse response, int statusCode, String statusMessage = null) { response.statusCode = statusCode if(statusMessage) response.statusMessage = statusMessage response.end() } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ end request.response, 500, "Failed to read file $path"
  • 16. codecentric AG Compress Errorhandling - Dynamic Mixins class YokeExtension { static String end(YokeResponse self, Integer statusCode, String statusMessage = null) { self.statusCode = statusCode if (statusMessage) self.statusMessage = statusMessage self.end() } } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ YokeResponse.mixin(YokeExtension) request.response.end 500, "Failed to read file $path"
  • 17. codecentric AG Compress Errorhandling - Static Mixins (vert.x 2.1) class YokeExtension { static String end(YokeResponse self, Integer statusCode, String statusMessage = null) { ... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ compilerConfiguration.groovy: customizer = { org.codehaus.groovy.control.CompilerConfiguration config -> config.addCompilationCustomizers( new ASTTransformationCustomizer(Mixin, value: YokeExtension) ) return config } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ request.response.end 500, "Failed to read file $path"
  • 18. codecentric AG Compress Errorhandling - Module Extension (vert.x 2.1) class YokeExtension { static String end(YokeResponse self, Integer statusCode, String statusMessage = null) { ... ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ META-INF/services/org.codehaus.groovy.runtime.ExtensionModule: moduleName = vertx-module moduleVersion = 1.0 extensionClasses = de.codecentric.vertx.YokeExtension ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ build.gradle: repositories { mavenLocal() } dependencies { compile "de.codecentric:vertx-extension:1.0.0-SNAPSHOT@jar" }
  • 19. codecentric AG After YokeResponse enhancement def crc(String baseDir, GYokeRequest request) { EventBus bus = vertx.eventBus FileSystem fs = vertx.fileSystem fs.readDir(baseDir) { AsyncResult<String[]> rs -> if (rs.succeeded) { String[] paths = rs.result paths.each { String path -> fs.props(path) { AsyncResult<FileProps> rs1 -> if (rs1.succeeded) { FileProps props = rs1.result if (props.directory) { crc(path, request) } else { fs.readFile(path) { AsyncResult<Buffer> rs2 -> if (rs2.succeeded) { Buffer content = rs2.result bus.send("create.crc", content) { Message result -> if (result.body().status == 'error') { request.response.end 500, "Error processing file " + "$path: ${result.body().message}: ${result.body().error} n" + "${result.body().stacktrace}" } else request.response.write "$path = ${result.body().message}n" } } else request.response.end 500, "Failed to read file $path" } } } else request.response.end 500, "Failed to read properties for $path" } } } else request.response.end 500, "Failed to read $baseDir“ } }
  • 20. codecentric AG Bus communication if (rs2.succeeded) { Buffer content = rs2.result bus.send("create.crc", content) { Message result -> if (result.body().status == 'error') { request.response.end 500, "Error processing file " + "$path: ${result.body().message}: ${result.body().error} n" + "${result.body().stacktrace}" } else request.response.write "$path = ${result.body().message}n" } } else request.response.end 500, "Failed to read file $path"
  • 21. codecentric AG Worker Module EventBus bus = vertx.eventBus bus.registerHandler('create.crc') { Message msg -> try { Buffer buffer = new Buffer(msg.body()) CRC32 crc = new CRC32() int start = 0, end, length = buffer.length while (start < length) { end = Math.min(start + 1024, length) crc.update(buffer.getBytes(start, end)) start = end } msg.reply([status: 'ok', message: crc.value ]) } catch (e) { StringWriter sw = new StringWriter() e.printStackTrace(sw.newPrintWriter()) msg.reply([status: 'error', message: 'Failure creating crc', error: e.message, stacktrace: sw.toString()]) } }
  • 22. codecentric AG Standardizing bus communication – Worker bus.registerHandler('create.crc') { Message msg -> try { ... msg.reply([status: 'ok', message: crc.value ]) } catch (e) { StringWriter sw = new StringWriter() e.printStackTrace(sw.newPrintWriter()) msg.reply([status: 'error', message: 'Failure creating crc', error: e.message, stacktrace: sw.toString()]) } } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bus.registerHandler('create.crc') { Message msg -> try { ... msg.replySuccess(crc.value) } catch (e) { msg.replyFailure('Failure creating crc', e) } }
  • 23. codecentric AG Standardizing bus communication - Module class MessageExtension { static final String OK = 'ok' static final String ERROR = 'error' static void replySuccess(Message self, message) { self.reply([status: OK, message: message]) } static void replyFailure(Message self, Throwable e) { replyFailure(self, null, e) } static void replyFailure(Message self, String msg, Throwable e = null) { def message = [status: ERROR] if (msg) message.message = msg if (e) { message.error = e.message StringWriter sw = new StringWriter() e.printStackTrace(sw.newPrintWriter()) message.stacktrace = sw.toString() } self.reply(message) }
  • 24. codecentric AG Standardizing bus communication - Module static String getStacktrace(Message self) { self.body().stacktrace } static String getError(Message self) { self.body().error } static def getMessage(Message self) { return self.body().message } ...
  • 25. codecentric AG Standardizing bus communication – Caller bus.send("create.crc", content) { Message result -> if (result.body().status == 'error') request.response.end 500, "Error processing file $path: ${result.body().message}: ${result.body().error} n $result.body().stacktrace}" else request.response.write "$path = ${result.body().message}n" } ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bus.send("create.crc", content) { Message result -> if (result) request.response.write "$path = ${result.message}n" else request.response.end 500, "Error processing file $path: $result.logMessage" }
  • 26. codecentric AG Standardizing bus communication - Module static boolean isSucceeded(Message self) { def result = self.body() if (result instanceof Map) { return result.status == OK } else return false } static boolean asBoolean(Message self) { return self.isSucceeded() } static String getLogMessage(Message self) { return self.getError() ? "${self.getMessage()}: ${self.getError()} n${self.getStacktrace()}" : self.getMessage() } ...
  • 27. codecentric AG Streamlining AsyncResult API static boolean asBoolean(AsyncResult self) { return self.isSucceeded() } static String getStacktrace(AsyncResult self) { if (!self.cause) return '' StringWriter sw = new StringWriter() PrintWriter pw = sw.newPrintWriter() self.cause.printStackTrace(pw) return sw.toString() } static String getError(AsyncResult self) { return self.cause ? self.cause.message : '' } static def getMessage(AsyncResult self) { return self.result } static String getLogMessage(AsyncResult self) { return self.getError() ? self.getMessage() + ": ${self.getError()} n${self.getStacktrace()}" : self.getMessage() }
  • 28. codecentric AG With standardized bus communication def crc(String baseDir, GYokeRequest request) { EventBus bus = vertx.eventBus FileSystem fs = vertx.fileSystem fs.readDir(baseDir) { AsyncResult<String[]> rs -> if (rs) { String[] paths = rs.result paths.each { String path -> fs.props(path) { AsyncResult<FileProps> rs1 -> if (rs1) { FileProps props = rs1.result if (props.directory) { crc(path, request) } else { fs.readFile(path) { AsyncResult<Buffer> rs2 -> if (rs2) { Buffer content = rs2.result bus.send("create.crc", content) { Message result -> if (result) { request.response.write "$path = ${result.message}n" } else request.response.end 500, "Error processing file $path:" + result.logMessage } else request.response.end 500, "Failed to read file $path" } } } else request.response.end 500, "Failed to read properties for $path" } } } else request.response.end 500, "Failed to read $baseDir“ } }
  • 29. codecentric AG Handler chains Event-based programming often results in multiple, stacked Handlers / Closures Difficult to read Order of commands from left to right / outside to inside Horizontal scrolling because of indentation Hard to find the begining of a logical part Difficult to test Loops are difficult or impossible to implement When is the for loop finished to send the .end()?
  • 30. codecentric AG Closure Chaining - Syntax chain { next -> next() }, { next -> next(10) }, { input, next -> println input } chain ( 10, { input, next -> next(input) }, { input, next -> println input } ) chain 10, { input, next -> next(input) }, { input, next -> println input } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ chain { next -> next() } { next -> next(10) } { input, next -> println input } chain (10) { input, next -> next(input) } { input, next -> println input } chain (10) { input, next -> next(input) } { input, next -> println input }
  • 31. codecentric AG Closure Chaining – Module class StructureExtension { static void chain(final Object self, def arguments, Closure... actions) { if (arguments instanceof Closure) { actions = [arguments, *actions] as Closure[] arguments = null } if (!actions) throw new IllegalArgumentException("One or more arguments of type groovy.lang.Closure required") _chain(arguments, actions.iterator()) } ... chain{} … chain(arg) chain(arg) {} ...
  • 32. codecentric AG Closure Chaining – Module static void chain(final Object self, Object... arguments) { if (!arguments.any { it instanceof Closure }) throw new IllegalArgumentException("One or more arguments of type groovy.lang.Closure required") int i; def actions = [] for (i = arguments.size() - 1; i >= 0; i--) { if (arguments[i] instanceof Closure) actions.add(0, arguments[i]) else break } _chain(arguments[0..i], actions.iterator()) } ... chain() chain(arg1, arg2, ...) chain(arg1, arg2, ...) {} …
  • 33. codecentric AG Closure Chaining – Module private static void _chain(final Object arguments, final Iterator<Closure> actions) { if (actions) { def action = actions.next() if (arguments != null) { action = action.curry(arguments as Object[]) } action.call { Object[] args -> _chain(args, actions) } } } ...
  • 34. codecentric AG Looping - Syntax [1,2,3].loop { element, next -> next() } [a:1, b:2, c:3].loop { key, value, next -> next() } [1,2,3].loop { element, next -> next() } { // called after the last iteration }
  • 35. codecentric AG Looping – Module static void loop(final Object[] array, final Closure action) { loop(array, action, {} } static void loop(final Object[] array, final Closure action, final Closure next) { _loop(array?.iterator(), action, next) } static void loop(final Collection collection, final Closure action) { loop(collection, action, {} } static void loop(final Collection collection, final Closure action, final Closure next) { _loop(collection.iterator(), action, next) } static void loop(final Map map, final Closure action) { loop(map, action, {} } static void loop(final Map map, final Closure action, final Closure next) { _loop(map.iterator(), action, next) } ...
  • 36. codecentric AG Looping – Module private static void _loop(final Iterator<?> iterator, final Closure action, Closure next = {}) { if(iterator) { def element = iterator.next() def nextAction if (iterator) nextAction = StructureExtension.&_loop.curry(iterator, action, next) else nextAction = next if (element instanceof Map.Entry) action.call(element.key, element.value, nextAction) else action.call(element, nextAction) } else next.call() }
  • 37. codecentric AG With chaining and looping def crc(String baseDir, GYokeRequest request, Closure nextCrc = null) { FileSystem fs = vertx.fileSystem chain { nextChain -> // Read directory fs.readDir(baseDir) { AsyncResult<String[]> rs -> if (rs) nextChain(rs.result as List) else request.response.end 500, "Failed to read $baseDir" } } { List paths, nextChain -> // Loop over files paths.loop { String path, nextLoop -> chain { next -> // Read file properties fs.props(path) { AsyncResult<FileProps> rs -> if (rs) next(rs.result) else request.response.end 500, "Failed to read properties for $path" } } { FileProps props, next -> // Check for directory if (props.directory) crc(path, request, nextLoop) else next() } { next -> // Read file fs.readFile(path) { AsyncResult<Buffer> rs -> if (rs) next(rs.result) else request.response.end 500, "Failed to read file $path" } } { Buffer content, next -> // Call module to calculate crc bus.send("create.crc", content) { Message result -> if (result) { request.response.write "$path = ${result.message}n" nextLoop() } else request.response.end 500, "Error processing file $path" } } } } }
  • 38. codecentric AG Adding .end() after the loop { Buffer content, next -> // Call module to calculate crc Vertx.eventBus.send("create.crc", content) { Message result -> if (result) { request.response.write "$path = ${result.message}n" nextLoop() } else request.response.end 500, "Error processing file $path" } } } { // finish everything up after loop if (nextCrc) nextCrc() else request.response.end() } } }
  • 39. codecentric AG Using a template engine router.get("/crc") { GYokeRequest request -> request.context.files = [:] ... def crc(String baseDir, GYokeRequest request, Closure nextCrc = null) { request.context.files[baseDir] = null ... { Buffer content, next -> // Call module to calculate crc Vertx.eventBus.send("create.crc", content) { Message result -> if (result) { request.context.files[path] = result.message nextLoop() } else request.response.end 500, "Error processing file $path" } } } ... } { // finish everything up after loop if (nextCrc) nextCrc() else request.response.render('web/crc.gsp', files: request.context.files) } } }
  • 40. codecentric AG Accessing the context - !!! Hack Alert !!! class YokeExtension { ... static Context getContext(YokeRequest self) { // Reflection because context is a private field of the super class for GYokeRequest Field field = YokeRequest.getDeclaredField('context') field.accessible = true return (Context) field.get(self) } static Context getContext(YokeResponse self) { // Reflection because context is a private field of the super class for GYokeResponse Field field = YokeResponse.getDeclaredField('context') field.accessible = true return (Context) field.get(self) }
  • 41. codecentric AG Adding custom context for rendering static void render(GYokeResponse self, Map<String, Object> context, String template) { render(self, context, template, null, null) } static void render(GYokeResponse self, Map<String, Object> context, String template, Closure next) { render(self, context, template, null, next) } static void render(GYokeResponse self, Map<String, Object> context, String template, String layoutTemplate) { render(self, context, template, layoutTemplate, null) } static void render(GYokeResponse self, Map<String, Object> context, String template, String layoutTemplate, Closure next) { Map<String, Object> oldContext = getContext(self).clone() getContext(self).clear() getContext(self).putAll(context) if (next) self.render(template, layoutTemplate, next) else self.render(template, layoutTemplate) getContext(self).clear() getContext(self).putAll(oldContext) }
  • 42. codecentric AG The template <html> <head> <title>CRC</title> </head> <body> <ul> <% def data = files.sort { a, b -> a.key <=> b.key } data.each { k, v -> if (v != null) { %> <li>${k} = ${v}</li> <% } else { %> <li>${k}</li> <% } %> <% } %> </ul> </body> </html>
  • 43. codecentric AG Smoothen all up with a custom BaseScriptClass abstract class VerticleScript extends Script { Vertx getVertx() { return binding.vertx } void setVertx(Vertx vertx) { binding.vertx = vertx } Container getContainer() { return binding.container } void setContainer(Container container) { binding.container = container } EventBus getBus() { vertx.eventBus } SharedData getSharedData() { vertx.sharedData } Logger getLog() { container.logger } Map<String, Object> getConfig() { container.config } Map<String, String> getEnv() { container.env }
  • 44. codecentric AG Using the BaseScriptClass (vert.x 2.1) Global usage: compilerConfiguration.groovy: customizer = { org.codehaus.groovy.control.CompilerConfiguration config -> config.scriptBaseClass = 'de.codecentric.vertx.VerticleScript' return config } ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Local usage per Script: @groovy.transform.BaseScript de.codecentric.vertx.VerticleScript verticleScript
  • 45. codecentric AG API to smoothen MongoDB usage def db(String address, Map message, Closure success = null, Closure failure = null) { bus.send(address, message) { Message result -> Map reply = result.body() if (reply.status == 'ok') { if (success) { if (success.maximumNumberOfParameters == 2) success(reply, result) else success(reply) } } else { if (failure) { if (failure.maximumNumberOfParameters == 2) failure(reply, result) else failure(result) } } } }
  • 46. codecentric AG API to smoothen MongoDB usage def save(String address, String collection, Map document, Closure success = null, Closure failure = null) { db(address, [action: 'save', collection: collection, document: document, write_concern: 'SAFE'], success, failure) } def update(String address, String collection, Map criteria, Map update, Closure success=null, Closure failure=null) { db(address, [action: 'update', collection: collection, criteria: criteria, objNew: update, write_concern: 'SAFE'], success, failure) } def delete(String address, String collection, Map matcher, Closure success = null, Closure failure = null) { db(address, [action: 'delete', collection: collection, matcher: matcher], success, failure) } def read(String address, String collection, Map matcher, Closure success = null, Closure failure = null) { db(address, [action: 'findone', collection: collection, matcher: matcher,], success, failure) }
  • 47. codecentric AG API to smoothen MongoDB usage def exists(String address, String collection, Map matcher, Closure success = null, Closure failure = null) { def command = [action: 'find', collection: collection, matcher: matcher, batch_size: 100] db(address, command, success) { Map reply, Message result -> if (reply.status == 'more-exist') { if (success.maximumNumberOfParameters == 2) success(reply, result) else success(result) } else { if (failure.maximumNumberOfParameters == 2) failure(reply, result) else failure(result) } } }
  • 48. codecentric AG API to smoothen MongoDB usage def query(String address, String collection, Map matcher, Map options, Closure success, Closure failure) { int max = options.max ?: -1 int offset = options.offset ?: -1 Map orderby = options.orderby ?: null Map keys = options.keys ?: null def data = [] def queryHandler queryHandler = { Map reply, Message result -> if (reply.status == 'more-exist') { data.addAll reply.results result.reply([:], queryHandler) } else if (reply.status == 'ok') { data.addAll reply.results success(data) } else if (reply.status == 'ok') { data.addAll reply.results success(data) } else if (failure.maximumNumberOfParameters == 2) { failure(reply, result) } else failure(result) } def command = [ action: 'find', collection: collection, matcher : matcher, batch_size: 100] if (max >= 0) command.max = max if (offset >= 0) command.offset = offset if (orderby) command.orderby = orderby if (keys) command.keys = keys db(address, command, queryHandler, queryHandler) }
  • 49. codecentric AG API to smoothen MongoDB usage def query(String address, String collection, Map matcher, Closure success) { query(address, collection, matcher, [:], success, null) } def query(String address, String collection, Map matcher, Closure success, Closure failure) { query(address, collection, matcher, [:], success, failure) } def query(String address, String collection, Map matcher, Map options, Closure success) { query(address, collection, matcher, options, success, null) }
  • 50. codecentric AG Questions? Alexander (Sascha) Klein codecentric AG Curiestr. 2 70563 Stuttgart tel +49 (0) 711.674 00 - 328 fax +49 (0) 172.529 40 20 alexander.klein@codecentric.de @saschaklein www.codecentric.de blog.codecentric.de 03.06.14 50