SlideShare a Scribd company logo
1 of 44
Using Grails to power
your Electric Car
Small Intro
● Marco Pas (1973)
› Education in Chemistry and then
moved to Transportation & Logistics
to finally IT.. what is next?
● Software Engineer
● Burgundian lifestyle
Wikipedia tells us :
'enjoyment of life, good food,and extravagant spectacle'
Agenda
● What the heck am I trying to solve!!
● How on earth did we solve it?
● What are our plans for the future?
Disclaimer....
Electric Cars vs Electric Vehicles
Convention Fueling != Electric Vehicle Charging
● EV Charging Challenges:
› Impossible to store & forward electricity
› Charge often (Limited Range)
› Time to charge (from minutes to hours)
› Compatibility (plugs, charging cables)
Not kidding... !!
Range Anxiety Reducer :)
Public EV Chargers in numbers
● 2011: EU 12.000
● 2020: EU 660.000
2011 2020
Denmark 280 5.000
Germany 1.900 150.000
Italy 1.300 125.000
Netherlands 1.700 32.000
United Kingdom 703 122.000
EV Chargers in the wild
Charging Process
Back OfficeValidation / Verification
● Is the card valid?
● Electricity pricing?
● How much can I charge?
● Who is the customer?
● Did you make a reservation?
● ….
Stakeholders involved in EV Charging
How to manage
all those
(different kind of)
Chargers?
Stakeholders?
Processes?
Requirements
● Implement a platform that enables EV Infra management:
› To monitor a Charge Point (CP) network
› Supports remote management
› Track charging sessions
● Including charge authorization &
transaction storage
› Multi-tenancy
› 3rd
party integration using Web Services (SOAP / REST)
Schematic overview of a Charge Point
Open Charge Point Protocol (OCPP)
● Open protocol between charging stations and a managing central
system aka back office
› Asynchronous
› Based on SOAP (v1.2)
› Working group with support from all manufacturers!
Agenda
● What the heck am I trying to solve!!
● How on earth did we solve it?
● What are our plans for the future?
Release 1.0
!
! SOAP ~ Contract First with Grails was not that easy, so we moved to a pure JAVA/Spring OCPP application
Jackson JSON Mapper
public class JsonMapper extends ObjectMapper {
public JsonMapper() {
super();
/**
* De-Serialization options JSON -> OBJECT
*/
// - ignore unknown fields - otherwise the construction of the object will fail!
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// - make it possible to also construct empty objects
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
/**
* Serialization options OBJECT -> JSON
*/
// properties with non-null values are to be included in the resulting JSON
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
}
Jackson JSON Mapper
● JSON → Object
● Object → JSON
resources.groovy
beans = {
// a preconfigured Jackson JSON mapper with defaults
jsonMapper(JsonMapper){}
}
def jsonContent = “{'name': 'John Doe'}”
Person person = jsonMapper.readValue(jsonContent, Person.class)
Person person = new Person(name: 'John Doe')
def jsonContent = jsonMapper.valueToTree(person)
Theming support
● Login-Logout & user configurable themes
● Using Spring Security Core Plugin
Config.groovy
// make sure we can act on security events
grails.plugins.springsecurity.useSecurityEventListener = true
// executed when a user succesfully authenticates into the application
grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx →
// .. code intentionally emitted .. //
session.theme = “MyNameOfTheTheme”
}
page.gsp
<g:if test="${session?.theme == null}">
<% session.theme="${grailsApplication.config.default.theme}"%>
</g:if>
<r:require module="${session?.theme}"/>
<g:external uri="/css/themes/${session?.theme - "theme_"}/images/favicon.ico"/>
Chargepoint Overview
Pool Overview
Nokia Maps – Heat Map
Technical Debt
● Client was very happy but.... shame on us:
› Tightly coupled
› Poor test coverage
› Spring project & Grails project
› Adding functional value is just to much fun!
● But... ready for round 2..
› Thanks to Grails we could refactor with great ease and speed!
Release 2.0
● Guidelines:
› Focus on creating a modular platform
› Test Driven Development
› Use Grails for everything!!
› Minimize the use of plugins!!!
Grails CXF Plugin
● WSDL
› Contract First & Code First
● Wire Interceptors
› Logging, Security
● Support for versioning
@GrailsCxfEndpoint(address='/myCustomSoapService/v2/')
Annotated example
@GrailsCxfEndpoint(
address='/centralsystem/ocpp/v1/5',
wsdl = 'wsdl/ocpp_15_centralsystem.wsdl',
expose = EndpointType.JAX_WS_WSDL,
soap12 = true,
inInterceptors = ["logSoapInboundInterceptor", "setReplyToSOAPHeaderInInterceptor"],
outInterceptors = ["logSoapOutboundInterceptor"])
@WebService(
name = "CentralSystemService",
targetNamespace = "urn://Ocpp/Cs/2012/06/",
serviceName = "CentralSystemService",
portName = "CentralSystemServiceSoap12"
)
@GZIP
class CentralSystemOcpp15Service implements CentralSystemService {
// ... code intentionally omitted
// ... contains the methods that needs to be implemented due to the 'implements'
}
Demo
● Create a contract first webservice using Grails CXF plugin
› Source WSDL: CustomerService.wsdl
› Steps:
● Create grails project
● Install CXF plugin
● Use WSDL2JAVA to generate web service implementation
● Create Grails service that implements the web service interface
● Test using SOAPUI
AMQP - Advanced Message Queuing Protocol
● Asynchronous and synchronous message exchange
› Enables modular platform architecture
RabbitMQ – an AMQP implementation
● Grails RabbitMQ Plugin
› High-level abstraction for sending and receiving messages
› Fallback to Spring Template
class MessageReceiveService {
static rabbitQueue = 'helloQ'
void handleMessage(message) {
// handle message…
}
}
class MessageSendController {
def sendMessage = {
rabbitSend 'helloQ', 'Hello!'
}
}
RabbitMQ Synchronous
class MessageSendController {
def rabbitTemplate // use the Spring rabbitTemplate directly
def sendMessage = {
def response = rabbitTemplate.convertSendAndReceive 'helloQ', 'Hello World'
println response
}
}
class MessageReceiveService {
static rabbitQueue = [queues: 'helloQ', messageConverterBean: '']
void handleMessage(Message message) {
// determine the reply queue
def returnQueue = message.messageProperties.replyTo
// return the response to temporary return queue..
rabbitSend returnQueue, 'Hello there'
}
}
Demo
● Send and Consume a message via RabbitMQ
› Steps:
● Install RabbitMQ plugin
● Configure Grails app to use RabbitMQ
● Create code to publish and consume a message
Testing
● Functional & Unit Testing
› Build-Test-Data
› Spock
● Load & Performane Testing
› BadBoy / Apache JMeter
Some stuff we have used
● Grails Plugins
› Spring Security
› Export
› RabbitMQ
› CXF
› Fixture
› Spock
› Build-Test-Data
● Non-Plugins
› Twitter BootStrap
› Jackson JSON
Agenda
● What the heck am I trying to solve!!
● How on earth did we solve it?
● What are our plans for the future?
Release 3.0
● Additional protocol implementation in JSON
› Eliminating the verbosity of SOAP!
› To ([<MessageTypeId>, “<UniqueId>”, “<Action>”, {<Payload>}])
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:cp="urn://Ocpp/Cp/2012/06/" xmlns:cs="urn://Ocpp/Cs/2012/06/"
xmlns:imp="urn://iMOVE/Cp/2011/09/" xmlns:ims="urn://iMOVE/Cs/2011/09/">
<SOAP-ENV:Header>
<wsa5:MessageID>940</wsa5:MessageID>
<wsa5:From>
<wsa5:Address>http://127.0.0.1:1234</wsa5:Address>
</wsa5:From>
<wsa5:ReplyTo SOAP-ENV:mustUnderstand="true">
<wsa5:Address>http://127.0.0.1:1234</wsa5:Address>
</wsa5:ReplyTo>
<wsa5:To SOAP-ENV:mustUnderstand="true">http://www.starwarsrules.com/services/centralsystem/ocpp/v1/5</wsa5:To>
<wsa5:Action SOAP-ENV:mustUnderstand="true">/Heartbeat</wsa5:Action>
<cs:chargeBoxIdentity SOAP-ENV:mustUnderstand="true">CHARGER_001_1234</cs:chargeBoxIdentity>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:heartbeatRequest />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
[2, “19223201”, “HeartBeat”, {“”}]
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:cp="urn://Ocpp/Cp/2012/06/" xmlns:cs="urn://Ocpp/Cs/2012/06/"
xmlns:imp="urn://iMOVE/Cp/2011/09/" xmlns:ims="urn://iMOVE/Cs/2011/09/">
<SOAP-ENV:Header>
<wsa5:MessageID>940</wsa5:MessageID>
<wsa5:From>
<wsa5:Address>http://127.0.0.1:1234</wsa5:Address>
</wsa5:From>
<wsa5:ReplyTo SOAP-ENV:mustUnderstand="true">
<wsa5:Address>http://127.0.0.1:1234</wsa5:Address>
</wsa5:ReplyTo>
<wsa5:To SOAP-ENV:mustUnderstand="true">http://www.starwarsrules.com/services/centralsystem/ocpp/v1/5</wsa5:To>
<wsa5:Action SOAP-ENV:mustUnderstand="true">/Heartbeat</wsa5:Action>
<cs:chargeBoxIdentity SOAP-ENV:mustUnderstand="true">CHARGER_001_1234</cs:chargeBoxIdentity>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<cs:heartbeatRequest />
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Release 3.0
● Using WebSockets for full-duplex communication
WebSockets
● Defines an API establishing a "socket" connections between a
client and a server
› Providing full-duplex communication
channel over a single TCP
connection
› HTTP upgrade by
Protocol Negotiation
› Firewall friendly! (port 80)
› No reconnect handling or guaranteed
message delivery
WebSocket handshake
● Client Request
● Server Response
GET /mychat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat
Sec-WebSocket-Version: 13
Origin: http://example.com
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
WebSocket API Hooks
Vertx.io
● Asynchronous Application Development
› Polyglot, Simplicity, Scalability, Concurrency
› Distributed Event Bus
› WebSocket support
● Verticles
Server.groovy
vertx.createHttpServer().requestHandler { req ->
req.response.headers().put("Content-Type", "text/html; charset-UTF-8");
req.response.end("<html><body><h1>Hello from vert.x!</h1></body></html>");
}.listen(8080)
vertx run Server.groovy
vertx run Server.groovy -instances 4
Thank you!!
http://twitter.com/marcopas
marco.pas@ihomer.nl
http://www.linkedin.com/in/marcopas

More Related Content

What's hot

Node.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceNode.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceTimur Shemsedinov
 
Groovy And Grails JUG Padova
Groovy And Grails JUG PadovaGroovy And Grails JUG Padova
Groovy And Grails JUG PadovaJohn Leach
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloadedcbeyls
 
Web components with java by Haijian Wang
Web components with java by Haijian WangWeb components with java by Haijian Wang
Web components with java by Haijian WangGWTcon
 
Qt and QML performance tips & tricks for Qt 4.7
Qt and QML performance tips & tricks for Qt 4.7Qt and QML performance tips & tricks for Qt 4.7
Qt and QML performance tips & tricks for Qt 4.7Pasi Kellokoski
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejugrobbiev
 
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013Raimundas Banevičius
 
Best Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIBest Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIICS
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new buildIgor Khotin
 
QThreads: Are You Using Them Wrong?
QThreads: Are You Using Them Wrong? QThreads: Are You Using Them Wrong?
QThreads: Are You Using Them Wrong? ICS
 
Java Concurrency and Asynchronous
Java Concurrency and AsynchronousJava Concurrency and Asynchronous
Java Concurrency and AsynchronousLifan Yang
 
"Node.js threads for I/O-bound tasks", Timur Shemsedinov
"Node.js threads for I/O-bound tasks", Timur Shemsedinov"Node.js threads for I/O-bound tasks", Timur Shemsedinov
"Node.js threads for I/O-bound tasks", Timur ShemsedinovFwdays
 
Paug paris 2011
Paug paris 2011Paug paris 2011
Paug paris 2011sekond0
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developersTricode (part of Dept)
 

What's hot (20)

SWT Tech Sharing: Node.js + Redis
SWT Tech Sharing: Node.js + RedisSWT Tech Sharing: Node.js + Redis
SWT Tech Sharing: Node.js + Redis
 
Node.js for enterprise - JS Conference
Node.js for enterprise - JS ConferenceNode.js for enterprise - JS Conference
Node.js for enterprise - JS Conference
 
Hands on the Gradle
Hands on the GradleHands on the Gradle
Hands on the Gradle
 
Groovy And Grails JUG Padova
Groovy And Grails JUG PadovaGroovy And Grails JUG Padova
Groovy And Grails JUG Padova
 
Training javascript 2012 hcmut
Training javascript 2012 hcmutTraining javascript 2012 hcmut
Training javascript 2012 hcmut
 
Revealing ALLSTOCKER
Revealing ALLSTOCKERRevealing ALLSTOCKER
Revealing ALLSTOCKER
 
Android Loaders : Reloaded
Android Loaders : ReloadedAndroid Loaders : Reloaded
Android Loaders : Reloaded
 
Web components with java by Haijian Wang
Web components with java by Haijian WangWeb components with java by Haijian Wang
Web components with java by Haijian Wang
 
Qt and QML performance tips & tricks for Qt 4.7
Qt and QML performance tips & tricks for Qt 4.7Qt and QML performance tips & tricks for Qt 4.7
Qt and QML performance tips & tricks for Qt 4.7
 
Enterprise Guice 20090217 Bejug
Enterprise Guice 20090217 BejugEnterprise Guice 20090217 Bejug
Enterprise Guice 20090217 Bejug
 
mvcExpress training course : part1
mvcExpress training course : part1mvcExpress training course : part1
mvcExpress training course : part1
 
Mvc express presentation
Mvc express presentationMvc express presentation
Mvc express presentation
 
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
The Next Step in AS3 Framework Evolution - FITC Amsterdam 2013
 
Best Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part IIIBest Practices in Qt Quick/QML - Part III
Best Practices in Qt Quick/QML - Part III
 
Gradle - time for a new build
Gradle - time for a new buildGradle - time for a new build
Gradle - time for a new build
 
QThreads: Are You Using Them Wrong?
QThreads: Are You Using Them Wrong? QThreads: Are You Using Them Wrong?
QThreads: Are You Using Them Wrong?
 
Java Concurrency and Asynchronous
Java Concurrency and AsynchronousJava Concurrency and Asynchronous
Java Concurrency and Asynchronous
 
"Node.js threads for I/O-bound tasks", Timur Shemsedinov
"Node.js threads for I/O-bound tasks", Timur Shemsedinov"Node.js threads for I/O-bound tasks", Timur Shemsedinov
"Node.js threads for I/O-bound tasks", Timur Shemsedinov
 
Paug paris 2011
Paug paris 2011Paug paris 2011
Paug paris 2011
 
The world of gradle - an introduction for developers
The world of gradle  - an introduction for developersThe world of gradle  - an introduction for developers
The world of gradle - an introduction for developers
 

Similar to Using Grails to power your electric car

Micronaut: A new way to build microservices
Micronaut: A new way to build microservicesMicronaut: A new way to build microservices
Micronaut: A new way to build microservicesLuram Archanjo
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Ran Mizrahi
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Ran Mizrahi
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...GITS Indonesia
 
Deep dive into Android async operations
Deep dive into Android async operationsDeep dive into Android async operations
Deep dive into Android async operationsMateusz Grzechociński
 
node.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoonnode.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang YoonJesang Yoon
 
Nodejs web service for starters
Nodejs web service for startersNodejs web service for starters
Nodejs web service for startersBruce Li
 
PyCon 2016: Personalised emails with Spark and Python
PyCon 2016:  Personalised emails  with Spark and PythonPyCon 2016:  Personalised emails  with Spark and Python
PyCon 2016: Personalised emails with Spark and PythonTomas Sirny
 
Testing and validating spark programs - Strata SJ 2016
Testing and validating spark programs - Strata SJ 2016Testing and validating spark programs - Strata SJ 2016
Testing and validating spark programs - Strata SJ 2016Holden Karau
 
Ob1k presentation at Java.IL
Ob1k presentation at Java.ILOb1k presentation at Java.IL
Ob1k presentation at Java.ILEran Harel
 
Java gpu computing
Java gpu computingJava gpu computing
Java gpu computingArjan Lamers
 
Profiling & Testing with Spark
Profiling & Testing with SparkProfiling & Testing with Spark
Profiling & Testing with SparkRoger Rafanell Mas
 
Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Aleksander Piotrowski
 
Eclipse IoT Talk (Montreal JUG)
Eclipse IoT Talk (Montreal JUG)Eclipse IoT Talk (Montreal JUG)
Eclipse IoT Talk (Montreal JUG)Mike Milinkovich
 

Similar to Using Grails to power your electric car (20)

Micronaut: A new way to build microservices
Micronaut: A new way to build microservicesMicronaut: A new way to build microservices
Micronaut: A new way to build microservices
 
Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)Intro to node.js - Ran Mizrahi (27/8/2014)
Intro to node.js - Ran Mizrahi (27/8/2014)
 
Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)Intro to node.js - Ran Mizrahi (28/8/14)
Intro to node.js - Ran Mizrahi (28/8/14)
 
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
Fundamental Node.js (Workshop bersama Front-end Developer GITS Indonesia, War...
 
Deep dive into Android async operations
Deep dive into Android async operationsDeep dive into Android async operations
Deep dive into Android async operations
 
Nodejs
NodejsNodejs
Nodejs
 
node.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoonnode.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoon
 
Nodejs web service for starters
Nodejs web service for startersNodejs web service for starters
Nodejs web service for starters
 
PyCon 2016: Personalised emails with Spark and Python
PyCon 2016:  Personalised emails  with Spark and PythonPyCon 2016:  Personalised emails  with Spark and Python
PyCon 2016: Personalised emails with Spark and Python
 
Testing and validating spark programs - Strata SJ 2016
Testing and validating spark programs - Strata SJ 2016Testing and validating spark programs - Strata SJ 2016
Testing and validating spark programs - Strata SJ 2016
 
Ob1k presentation at Java.IL
Ob1k presentation at Java.ILOb1k presentation at Java.IL
Ob1k presentation at Java.IL
 
Java gpu computing
Java gpu computingJava gpu computing
Java gpu computing
 
Java 9-coding-from-zero-level-v1.0
Java 9-coding-from-zero-level-v1.0Java 9-coding-from-zero-level-v1.0
Java 9-coding-from-zero-level-v1.0
 
Node azure
Node azureNode azure
Node azure
 
Profiling & Testing with Spark
Profiling & Testing with SparkProfiling & Testing with Spark
Profiling & Testing with Spark
 
JS Class 2016
JS Class 2016JS Class 2016
JS Class 2016
 
Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015
 
JS class slides (2016)
JS class slides (2016)JS class slides (2016)
JS class slides (2016)
 
Retour JavaOne 2009
Retour JavaOne 2009Retour JavaOne 2009
Retour JavaOne 2009
 
Eclipse IoT Talk (Montreal JUG)
Eclipse IoT Talk (Montreal JUG)Eclipse IoT Talk (Montreal JUG)
Eclipse IoT Talk (Montreal JUG)
 

Using Grails to power your electric car

  • 1. Using Grails to power your Electric Car
  • 2. Small Intro ● Marco Pas (1973) › Education in Chemistry and then moved to Transportation & Logistics to finally IT.. what is next? ● Software Engineer ● Burgundian lifestyle Wikipedia tells us : 'enjoyment of life, good food,and extravagant spectacle'
  • 3. Agenda ● What the heck am I trying to solve!! ● How on earth did we solve it? ● What are our plans for the future?
  • 5. Electric Cars vs Electric Vehicles
  • 6. Convention Fueling != Electric Vehicle Charging ● EV Charging Challenges: › Impossible to store & forward electricity › Charge often (Limited Range) › Time to charge (from minutes to hours) › Compatibility (plugs, charging cables)
  • 7. Not kidding... !! Range Anxiety Reducer :)
  • 8. Public EV Chargers in numbers ● 2011: EU 12.000 ● 2020: EU 660.000 2011 2020 Denmark 280 5.000 Germany 1.900 150.000 Italy 1.300 125.000 Netherlands 1.700 32.000 United Kingdom 703 122.000
  • 9. EV Chargers in the wild
  • 10. Charging Process Back OfficeValidation / Verification ● Is the card valid? ● Electricity pricing? ● How much can I charge? ● Who is the customer? ● Did you make a reservation? ● ….
  • 12. How to manage all those (different kind of) Chargers? Stakeholders? Processes?
  • 13. Requirements ● Implement a platform that enables EV Infra management: › To monitor a Charge Point (CP) network › Supports remote management › Track charging sessions ● Including charge authorization & transaction storage › Multi-tenancy › 3rd party integration using Web Services (SOAP / REST)
  • 14.
  • 15. Schematic overview of a Charge Point
  • 16. Open Charge Point Protocol (OCPP) ● Open protocol between charging stations and a managing central system aka back office › Asynchronous › Based on SOAP (v1.2) › Working group with support from all manufacturers!
  • 17. Agenda ● What the heck am I trying to solve!! ● How on earth did we solve it? ● What are our plans for the future?
  • 18. Release 1.0 ! ! SOAP ~ Contract First with Grails was not that easy, so we moved to a pure JAVA/Spring OCPP application
  • 19. Jackson JSON Mapper public class JsonMapper extends ObjectMapper { public JsonMapper() { super(); /** * De-Serialization options JSON -> OBJECT */ // - ignore unknown fields - otherwise the construction of the object will fail! this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // - make it possible to also construct empty objects this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); /** * Serialization options OBJECT -> JSON */ // properties with non-null values are to be included in the resulting JSON this.setSerializationInclusion(JsonInclude.Include.NON_NULL); } }
  • 20. Jackson JSON Mapper ● JSON → Object ● Object → JSON resources.groovy beans = { // a preconfigured Jackson JSON mapper with defaults jsonMapper(JsonMapper){} } def jsonContent = “{'name': 'John Doe'}” Person person = jsonMapper.readValue(jsonContent, Person.class) Person person = new Person(name: 'John Doe') def jsonContent = jsonMapper.valueToTree(person)
  • 21. Theming support ● Login-Logout & user configurable themes ● Using Spring Security Core Plugin Config.groovy // make sure we can act on security events grails.plugins.springsecurity.useSecurityEventListener = true // executed when a user succesfully authenticates into the application grails.plugins.springsecurity.onInteractiveAuthenticationSuccessEvent = { e, appCtx → // .. code intentionally emitted .. // session.theme = “MyNameOfTheTheme” } page.gsp <g:if test="${session?.theme == null}"> <% session.theme="${grailsApplication.config.default.theme}"%> </g:if> <r:require module="${session?.theme}"/> <g:external uri="/css/themes/${session?.theme - "theme_"}/images/favicon.ico"/>
  • 24. Nokia Maps – Heat Map
  • 25. Technical Debt ● Client was very happy but.... shame on us: › Tightly coupled › Poor test coverage › Spring project & Grails project › Adding functional value is just to much fun! ● But... ready for round 2.. › Thanks to Grails we could refactor with great ease and speed!
  • 26. Release 2.0 ● Guidelines: › Focus on creating a modular platform › Test Driven Development › Use Grails for everything!! › Minimize the use of plugins!!!
  • 27. Grails CXF Plugin ● WSDL › Contract First & Code First ● Wire Interceptors › Logging, Security ● Support for versioning @GrailsCxfEndpoint(address='/myCustomSoapService/v2/')
  • 28. Annotated example @GrailsCxfEndpoint( address='/centralsystem/ocpp/v1/5', wsdl = 'wsdl/ocpp_15_centralsystem.wsdl', expose = EndpointType.JAX_WS_WSDL, soap12 = true, inInterceptors = ["logSoapInboundInterceptor", "setReplyToSOAPHeaderInInterceptor"], outInterceptors = ["logSoapOutboundInterceptor"]) @WebService( name = "CentralSystemService", targetNamespace = "urn://Ocpp/Cs/2012/06/", serviceName = "CentralSystemService", portName = "CentralSystemServiceSoap12" ) @GZIP class CentralSystemOcpp15Service implements CentralSystemService { // ... code intentionally omitted // ... contains the methods that needs to be implemented due to the 'implements' }
  • 29. Demo ● Create a contract first webservice using Grails CXF plugin › Source WSDL: CustomerService.wsdl › Steps: ● Create grails project ● Install CXF plugin ● Use WSDL2JAVA to generate web service implementation ● Create Grails service that implements the web service interface ● Test using SOAPUI
  • 30. AMQP - Advanced Message Queuing Protocol ● Asynchronous and synchronous message exchange › Enables modular platform architecture
  • 31. RabbitMQ – an AMQP implementation ● Grails RabbitMQ Plugin › High-level abstraction for sending and receiving messages › Fallback to Spring Template class MessageReceiveService { static rabbitQueue = 'helloQ' void handleMessage(message) { // handle message… } } class MessageSendController { def sendMessage = { rabbitSend 'helloQ', 'Hello!' } }
  • 32. RabbitMQ Synchronous class MessageSendController { def rabbitTemplate // use the Spring rabbitTemplate directly def sendMessage = { def response = rabbitTemplate.convertSendAndReceive 'helloQ', 'Hello World' println response } } class MessageReceiveService { static rabbitQueue = [queues: 'helloQ', messageConverterBean: ''] void handleMessage(Message message) { // determine the reply queue def returnQueue = message.messageProperties.replyTo // return the response to temporary return queue.. rabbitSend returnQueue, 'Hello there' } }
  • 33. Demo ● Send and Consume a message via RabbitMQ › Steps: ● Install RabbitMQ plugin ● Configure Grails app to use RabbitMQ ● Create code to publish and consume a message
  • 34.
  • 35. Testing ● Functional & Unit Testing › Build-Test-Data › Spock ● Load & Performane Testing › BadBoy / Apache JMeter
  • 36. Some stuff we have used ● Grails Plugins › Spring Security › Export › RabbitMQ › CXF › Fixture › Spock › Build-Test-Data ● Non-Plugins › Twitter BootStrap › Jackson JSON
  • 37. Agenda ● What the heck am I trying to solve!! ● How on earth did we solve it? ● What are our plans for the future?
  • 38. Release 3.0 ● Additional protocol implementation in JSON › Eliminating the verbosity of SOAP! › To ([<MessageTypeId>, “<UniqueId>”, “<Action>”, {<Payload>}]) <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:cp="urn://Ocpp/Cp/2012/06/" xmlns:cs="urn://Ocpp/Cs/2012/06/" xmlns:imp="urn://iMOVE/Cp/2011/09/" xmlns:ims="urn://iMOVE/Cs/2011/09/"> <SOAP-ENV:Header> <wsa5:MessageID>940</wsa5:MessageID> <wsa5:From> <wsa5:Address>http://127.0.0.1:1234</wsa5:Address> </wsa5:From> <wsa5:ReplyTo SOAP-ENV:mustUnderstand="true"> <wsa5:Address>http://127.0.0.1:1234</wsa5:Address> </wsa5:ReplyTo> <wsa5:To SOAP-ENV:mustUnderstand="true">http://www.starwarsrules.com/services/centralsystem/ocpp/v1/5</wsa5:To> <wsa5:Action SOAP-ENV:mustUnderstand="true">/Heartbeat</wsa5:Action> <cs:chargeBoxIdentity SOAP-ENV:mustUnderstand="true">CHARGER_001_1234</cs:chargeBoxIdentity> </SOAP-ENV:Header> <SOAP-ENV:Body> <cs:heartbeatRequest /> </SOAP-ENV:Body> </SOAP-ENV:Envelope> [2, “19223201”, “HeartBeat”, {“”}] <?xml version="1.0" encoding="UTF-8"?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:cp="urn://Ocpp/Cp/2012/06/" xmlns:cs="urn://Ocpp/Cs/2012/06/" xmlns:imp="urn://iMOVE/Cp/2011/09/" xmlns:ims="urn://iMOVE/Cs/2011/09/"> <SOAP-ENV:Header> <wsa5:MessageID>940</wsa5:MessageID> <wsa5:From> <wsa5:Address>http://127.0.0.1:1234</wsa5:Address> </wsa5:From> <wsa5:ReplyTo SOAP-ENV:mustUnderstand="true"> <wsa5:Address>http://127.0.0.1:1234</wsa5:Address> </wsa5:ReplyTo> <wsa5:To SOAP-ENV:mustUnderstand="true">http://www.starwarsrules.com/services/centralsystem/ocpp/v1/5</wsa5:To> <wsa5:Action SOAP-ENV:mustUnderstand="true">/Heartbeat</wsa5:Action> <cs:chargeBoxIdentity SOAP-ENV:mustUnderstand="true">CHARGER_001_1234</cs:chargeBoxIdentity> </SOAP-ENV:Header> <SOAP-ENV:Body> <cs:heartbeatRequest /> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
  • 39. Release 3.0 ● Using WebSockets for full-duplex communication
  • 40. WebSockets ● Defines an API establishing a "socket" connections between a client and a server › Providing full-duplex communication channel over a single TCP connection › HTTP upgrade by Protocol Negotiation › Firewall friendly! (port 80) › No reconnect handling or guaranteed message delivery
  • 41. WebSocket handshake ● Client Request ● Server Response GET /mychat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat Sec-WebSocket-Version: 13 Origin: http://example.com HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= Sec-WebSocket-Protocol: chat
  • 43. Vertx.io ● Asynchronous Application Development › Polyglot, Simplicity, Scalability, Concurrency › Distributed Event Bus › WebSocket support ● Verticles Server.groovy vertx.createHttpServer().requestHandler { req -> req.response.headers().put("Content-Type", "text/html; charset-UTF-8"); req.response.end("<html><body><h1>Hello from vert.x!</h1></body></html>"); }.listen(8080) vertx run Server.groovy vertx run Server.groovy -instances 4