SlideShare ist ein Scribd-Unternehmen logo
1 von 50
Downloaden Sie, um offline zu lesen
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

Weitere Àhnliche Inhalte

Was ist angesagt?

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
 
Unity Makes Strength
Unity Makes StrengthUnity Makes Strength
Unity Makes StrengthXavier Mertens
 
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
 

Was ist angesagt? (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
 

Andere mochten auch

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
 

Andere mochten auch (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
 

Ähnlich wie 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
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On SteroidsSara Tornincasa
 
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
 
JS everywhere 2011
JS everywhere 2011JS everywhere 2011
JS everywhere 2011Oleg Podsechin
 
[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
 

Ähnlich wie 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
 

Mehr von 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
 
Android on Groovy
Android on GroovyAndroid on Groovy
Android on Groovysascha_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
 

Mehr von 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
 

KĂŒrzlich hochgeladen

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...gurkirankumar98700
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfWilly Marroquin (WillyDevNET)
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfCionsystems
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...harshavardhanraghave
 
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
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE9953056974 Low Rate Call Girls In Saket, Delhi NCR
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....ShaimaaMohamedGalal
 
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
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
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
 
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
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 
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
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 

KĂŒrzlich hochgeladen (20)

Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...
(Genuine) Escort Service Lucknow | Starting â‚č,5K To @25k with A/C đŸ§‘đŸœâ€â€ïžâ€đŸ§‘đŸ» 89...
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Active Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdfActive Directory Penetration Testing, cionsystems.com.pdf
Active Directory Penetration Testing, cionsystems.com.pdf
 
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
Reassessing the Bedrock of Clinical Function Models: An Examination of Large ...
 
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
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Clustering techniques data mining book ....
Clustering techniques data mining book ....Clustering techniques data mining book ....
Clustering techniques data mining book ....
 
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 đŸ”âœ”ïžâœ”ïž
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
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
 
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 ☂
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Vip Call Girls Noida âžĄïž Delhi âžĄïž 9999965857 No Advance 24HRS Live
Vip Call Girls Noida âžĄïž Delhi âžĄïž 9999965857 No Advance 24HRS LiveVip Call Girls Noida âžĄïž Delhi âžĄïž 9999965857 No Advance 24HRS Live
Vip Call Girls Noida âžĄïž Delhi âžĄïž 9999965857 No Advance 24HRS Live
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 
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 ...
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Call Girls In Mukherjee Nagar đŸ“± 9999965857 đŸ€© Delhi đŸ«Š HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar đŸ“±  9999965857  đŸ€© Delhi đŸ«Š HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar đŸ“±  9999965857  đŸ€© Delhi đŸ«Š HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar đŸ“± 9999965857 đŸ€© Delhi đŸ«Š HOT AND SEXY VVIP 🍎 SE...
 

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