Upload
ivan-lopez-martin
View
1.301
Download
3
Embed Size (px)
Citation preview
Fullstack Groovy developer
Iván López@ilopmar
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
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
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!
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
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?
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
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
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
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
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
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
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
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
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
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
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>
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)}
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)}
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)}
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 }}
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 }}
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>
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
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
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?)
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) } } } }
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) } } } }
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}
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}
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) } } } }
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
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
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
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
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
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>" } }}
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>"}
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() }}
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 }}
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>
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() } } } }}
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
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
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
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
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() }}
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))
...
}
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
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)
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', "") }}
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
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
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'
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
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,...
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'}
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
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[]-->
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
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
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...”
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
https://github.com/lmivan
Iván López
http://bit.ly/feedback-groovy
Thanks!Any questions?