SpringOne 2GX 2015 - Fullstack Groovy developer

63
Fullstack Groovy developer Iván López @ilopmar

Transcript of SpringOne 2GX 2015 - Fullstack Groovy developer

Page 1: SpringOne 2GX 2015 - Fullstack Groovy developer

Fullstack Groovy developer

Iván López@ilopmar

Page 2: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 2

Hello!

@ilopmar

http://greachconf.com@madridgug

I'm Iván López

Page 3: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 3

Thank you very much!

Q&A

Page 4: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 4

Just kidding!

Page 5: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 5

Page 6: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 6

What's a fullstack developer?

Page 7: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 7

Fullstack developer

Backend language

Javascript Mobile app

HTML

Page 8: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 8

Page 9: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 9

Polaromatic

Page 10: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 10

Page 11: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 11

1. Demo

Page 12: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 12

2. Application flow

Page 13: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 13

Page 14: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 14

3. Backend

Page 15: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 15

Page 16: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 16

Polaromatic● Spring Boot

● Core App

● Spring MVC

● Spring Integration Flow

Page 17: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 17

Spring Integration Flow<file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/>

<chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/></chain>

Page 18: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 18

Spring Integration Flow

File Service

<file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/>

<chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/></chain>

Photo preprocessFile(File file) { def pr = new PolaroidRequest(file) this.preprocessFile(pr)}

Page 19: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 19

Spring Integration Flow

File ServicePhoto preprocessFile(File file) { def pr = new PolaroidRequest(file) this.preprocessFile(pr)}

Page 20: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 20

Spring Integration Flow

File ServicePhoto preprocessFile(File file) { def pr = new PolaroidRequest(file) this.preprocessFile(pr)}

Photo preprocessFile(PolaroidRequest polaroidRequest) { String outputFile = File.createTempFile("output", ".png").path

return new Photo(input: polaroidRequest.inputFile.absolutePath, output: outputFile, text: polaroidRequest.text)}

Page 21: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 21

Image converterclass ImageConverterService {

private static final String DEFAULT_CAPTION = "#LearningSpringBoot with Polaromatic\\n" Random rnd = new Random()

Photo applyEffect(Photo photo) { log.debug "Applying effect to file: ${photo.input}..." def inputFile = photo.input def outputFile = photo.output

double polaroidRotation = rnd.nextInt(6).toDouble() String caption = photo.text ?: DEFAULT_CAPTION

def op = new IMOperation() op.addImage(inputFile) op.thumbnail(300, 300) .set("caption", caption) .gravity("center") .pointsize(20) .background("black") .polaroid(rnd.nextBoolean() ? polaroidRotation : -polaroidRotation) .addImage(outputFile) def command = new ConvertCmd() command.run(op)

photo }}

Page 22: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 22

Metrics

class MetricsService {

static final String PHOTO_COUNTER_METRICS_FLICKR = "polaromatized.photos.flickr" static final String PHOTO_COUNTER_METRICS_ANDROID = "polaromatized.photos.android"

@Autowired CounterService counterService

Photo updateMetrics(Photo photo) {

if (photo.text) { counterService.increment(PHOTO_COUNTER_METRICS_ANDROID) } else { counterService.increment(PHOTO_COUNTER_METRICS_FLICKR) }

photo }}

Page 23: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 23

Metrics

class MetricsService {

static final String PHOTO_COUNTER_METRICS_FLICKR = "polaromatized.photos.flickr" static final String PHOTO_COUNTER_METRICS_ANDROID = "polaromatized.photos.android"

@Autowired CounterService counterService

Photo updateMetrics(Photo photo) {

if (photo.text) { counterService.increment(PHOTO_COUNTER_METRICS_ANDROID) } else { counterService.increment(PHOTO_COUNTER_METRICS_FLICKR) }

photo }}

<chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/></chain>

Page 24: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 24

Metrics

Page 25: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 25

Page 26: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 26

FlickrDownloader● Spring Boot CLI

● Download Flickr Interesting pictures

● Jsoup, GPars

● 55 lines of Groovy code (microservice?)

Page 27: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 27

FlickrDownloader@Slf4j@EnableScheduling@Grab('org.jsoup:jsoup:1.8.1')@Grab('commons-io:commons-io:2.4')@Grab('org.codehaus.gpars:gpars:1.2.1')class FlickrDownloader {

static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days"

static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR)

@Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl)

FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }

Page 28: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 28

FlickrDownloader@Slf4j@EnableScheduling@Grab('org.jsoup:jsoup:1.8.1')@Grab('commons-io:commons-io:2.4')@Grab('org.codehaus.gpars:gpars:1.2.1')class FlickrDownloader {

static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days"

static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR)

@Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl)

FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }

Page 29: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 29

FlickrDownloader@Slf4j@EnableScheduling@Grab('org.jsoup:jsoup:1.8.1')@Grab('commons-io:commons-io:2.4')@Grab('org.codehaus.gpars:gpars:1.2.1')class FlickrDownloader {

static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days"

static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR)

@Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl)

FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }

private List extractPhotosFromFlickr() { Document doc = Jsoup.connect(FLICKER_INTERESTING_URL).get() Elements images = doc.select("img.pc_img")

def photos = images .listIterator() .collect { it.attr('src').replace('_m.jpg', '_b.jpg') }

photos}

Page 30: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 30

FlickrDownloader@Slf4j@EnableScheduling@Grab('org.jsoup:jsoup:1.8.1')@Grab('commons-io:commons-io:2.4')@Grab('org.codehaus.gpars:gpars:1.2.1')class FlickrDownloader {

static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days"

static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR)

@Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl)

FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }

private File download(String url) { def tempFile = File.createTempFile('flickr_downloader', '') tempFile << url.toURL().bytes

tempFile}

Page 31: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 31

FlickrDownloader@Slf4j@EnableScheduling@Grab('org.jsoup:jsoup:1.8.1')@Grab('commons-io:commons-io:2.4')@Grab('org.codehaus.gpars:gpars:1.2.1')class FlickrDownloader {

static final String FLICKER_INTERESTING_URL = "https://www.flickr.com/explore/interesting/7days"

static final String WORK_DIR = "./work" final File workDir = new File(WORK_DIR)

@Scheduled(fixedRate = 30000L) void downloadFlickrInteresting() { def photos = extractPhotosFromFlickr() withPool { photos.eachParallel { photoUrl -> log.info "Downloading photo ${photoUrl}" def tempFile = download(photoUrl)

FileUtils.moveFileToDirectory(tempFile, workDir, true) } } } }

Page 32: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 32

FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader2015-08-31 21:56:11.354 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader2015-08-31 21:56:11.375 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.527 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader2015-08-31 21:56:11.537 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.612 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.693 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader

2015-08-31 22:02:17.019 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:19.451 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:21.661 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:22.079 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:22.877 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:23.392 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:23.749 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:24.250 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:24.695 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader

Page 33: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 33

FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.139 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader2015-08-31 21:56:11.354 INFO 16447 --- [111617-worker-1] polaromatic.FlickrDownloader2015-08-31 21:56:11.375 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.527 INFO 16447 --- [111617-worker-3] polaromatic.FlickrDownloader2015-08-31 21:56:11.537 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.612 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader2015-08-31 21:56:11.693 INFO 16447 --- [111617-worker-2] polaromatic.FlickrDownloader

2015-08-31 22:02:17.019 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:19.451 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:21.661 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:22.079 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:22.877 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:23.392 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:23.749 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:24.250 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader2015-08-31 22:02:24.695 INFO 9872 --- [pool-1-thread-1] polaromatic.FlickrDownloader

Page 34: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 34

4. Frontend

Page 35: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 35

Page 36: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 36

Frontend● MarkupTemplatEngine (HTML)

● Websockets

● Grooscript

Page 37: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 37

HTMLyieldUnescaped '<!DOCTYPE html>'

html { head { title "Polaromatic"

link(rel: 'stylesheet', href: '/css/app.css') link(rel: 'stylesheet', href: '/css/gh-fork-ribbon.css')

['webjars/sockjs-client/0.3.4-1/sockjs.min.js', 'webjars/stomp-websocket/2.3.1-1/stomp.min.js', 'webjars/jquery/2.1.3/jquery.min.js', 'webjars/handlebars/2.0.0-1/handlebars.min.js', 'js/Connection.js'] .each { yieldUnescaped "<script src='$it'></script>" } }}

Page 38: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 38

HTMLbody { ...

div(id: 'header') { div(class: 'center') { a(href: 'https://github.com/lmivan/contest', target: 'blank') { img(src: 'images/polaromatic-logo.png') } p('Polaromatic') span('Powered by Spring Boot') } } div(id: 'timeline', class: 'center')}

script(id: 'photo-template', type: 'text/x-handlebars-template') { div(class: 'photo-cover') { div(class: 'photo', style: 'visibility:hidden; height:0') { img(src: '{{image}}') } }}

yieldUnescaped "<script>Connection().start()</script>"}

Page 39: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 39

Websockets

@Configuration@EnableWebSocketMessageBrokerclass WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Override void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker '/notifications' }

@Override void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint('/polaromatic').withSockJS() }}

Page 40: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 40

Websockets

class BrowserPushService {

@Autowired SimpMessagingTemplate template

Photo pushToBrowser(Photo photo) { log.debug "Pushing file to browser: ${photo.output}"

String imageB64 = new File(photo.output).bytes.encodeBase64().toString()

template.convertAndSend "/notifications/photo", imageB64

return photo }}

Page 41: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 41

Websockets

class BrowserPushService {

@Autowired SimpMessagingTemplate template

Photo pushToBrowser(Photo photo) { log.debug "Pushing file to browser: ${photo.output}"

String imageB64 = new File(photo.output).bytes.encodeBase64().toString()

template.convertAndSend "/notifications/photo", imageB64

return photo }}

<chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <service-activator ref="imageConverterService" method="applyEffect"/> <service-activator ref="browserPushService" method="pushToBrowser"/> <service-activator ref="metricsService" method="updateMetrics"/> <service-activator ref="fileService" method="deleteTempFiles"/></chain>

Page 42: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 42

Websocketsclass Connection { @GsNative def initOn(source, path) {/* var socket = new SockJS(path); return [Handlebars.compile(source), Stomp.over(socket)]; */}

def start() { def source = $("#photo-template").html() def (template, client) = initOn(source, '/polaromatic') client.debug = null

client.connect(gs.toJavascript([:])) { -> client.subscribe('/notifications/photo') { message -> def context = [image: 'data:image/png;base64,' + message.body] def html = template(context) $("#timeline").prepend(html) $("#timeline .photo:first-child img").on("load") { $(this).parent().css(gs.toJavascript(display: 'none', visibility: 'visible', height: 'auto')) $(this).parent().slideDown() } } } }}

Page 43: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 43

5. Android

Page 44: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 44

Page 45: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 45

Android App● Disclaimer: I'm not an Android developer

● Lazybones template (@marioggar)

● Traits, @CompileStatic, AST Transformations,…

● SwissKnife

Page 46: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 46

Page 47: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 47

Android

trait Toastable { @OnUIThread void showToastMessage(String message) { Toast toast = Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT) toast.show() }}

Page 48: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 48

Android

trait Toastable { @OnUIThread void showToastMessage(String message) { Toast toast = Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT) toast.show() }}

@CompileStaticpublic class ShareActivity extends Activity implements Toastable { ...

showToastMessage(getString(R.string.share_ok_msg))

...

}

Page 49: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 49

6. Tests

Page 50: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 50

Tests● Spock Framework

● 0.7 for more than 3 years

● Now 1.0

● JUnit compatible (but way better)

Page 51: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 51

Spockclass BrowserPushServiceSpec extends Specification {

void 'should push a converted photo to the browser'() { given: 'a photo' def output = File.createTempFile("output", "") def photo = new Photo(output: output.path)

and: 'a mocked SimpMessagingTemplate' def mockSimpMessagingTemplate = Mock(SimpMessagingTemplate)

and: 'the push service' def browserPushService = new BrowserPushService(template: mockSimpMessagingTemplate)

when: 'pushing the photo to the browser' browserPushService.pushToBrowser(photo)

then: 'the photo is pushed' 1 * mockSimpMessagingTemplate.convertAndSend('/notifications/photo', "") }}

Page 52: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 52

7. Build tool

Page 53: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 53

Build tool● Gradle

● Multiproject to build backend, documentation and android

Page 54: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 54

Gradle

subprojects { buildscript { repositories { jcenter()

} }

repositories { jcenter() }}

task wrapper(type: Wrapper) { gradleVersion = '2.2.1'}

build.gradle settings.gradle

include 'polaromatic-back'include 'polaromatic-groid'include 'polaromatic-docs'

Page 55: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 55

8. Documentation

Page 56: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 56

Documentation● Asciidoctor (FTW!)

● Gradle plugin

● Backends: html, epub, pdf,...

Page 57: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 57

Asciidoctorbuildscript { dependencies { classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2' }}

apply plugin: 'org.asciidoctor.convert'

asciidoctor { sourceDir 'src/docs' outputDir "${buildDir}/docs"

attributes 'source-highlighter': 'coderay', toc : 'left', icons : 'font'}

Page 58: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 58

Asciidoctor[source,xml,indent=0].src/main/resources/resources.xml----include::{polaromaticBackResources}/resources.xml[tags=appFlow]----<1> Define the integration with the file system<2> Preprocess the file received<3> Apply the Polaroid effect<4> Send the new photo to the browser using Websockets<5> Update the metrics<6> Delete all temporary files

Page 59: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 59

Asciidoctor[source,xml,indent=0].src/main/resources/resources.xml----include::{polaromaticBackResources}/resources.xml[tags=appFlow]----<1> Define the integration with the file system<2> Preprocess the file received<3> Apply the Polaroid effect<4> Send the new photo to the browser using Websockets<5> Update the metrics<6> Delete all temporary files

<!-- tag::appFlow[] --><file:inbound-channel-adapter directory="work" channel="incommingFilesChannel"/> <!--1-->

<chain input-channel="incommingFilesChannel"> <service-activator ref="fileService" method="preprocessFile"/> <!--2--> <service-activator ref="imageConverterService" method="applyEffect"/> <!--3--> <service-activator ref="browserPushService" method="pushToBrowser"/> <!--4--> <service-activator ref="metricsService" method="updateMetrics"/> <!--5--> <service-activator ref="fileService" method="deleteTempFiles"/> <!--6--></chain><!-- end::appFlow[]-->

Page 60: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 60

Asciidoctor

Page 61: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 61

9. Summary

Page 62: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 62

“Groovy, groovy everywhere...”

Page 63: SpringOne 2GX 2015 - Fullstack Groovy developer

Unless otherwise indicated, these slides are © 2013-2015 Pivotal Software, Inc. and licensed under aCreative Commons Attribution-NonCommercial license: http://creativecommons.org/licenses/by-nc/3.0/ 63

@ilopmar

[email protected]

https://github.com/lmivan

Iván López

http://bit.ly/feedback-groovy

Thanks!Any questions?