using grails to power your electric car

44
Using Grails to power your Electric Car

Upload: gr8conf

Post on 10-May-2015

1.083 views

Category:

Technology


5 download

TRANSCRIPT

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 lifestyleWikipedia 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 eventsgrails.plugins.springsecurity.useSecurityEventListener = true

// executed when a user succesfully authenticates into the applicationgrails.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")

@GZIPclass 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 communicationchannel 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.1Host: server.example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==Sec-WebSocket-Protocol: chatSec-WebSocket-Version: 13Origin: http://example.com

HTTP/1.1 101 Switching ProtocolsUpgrade: websocketConnection: UpgradeSec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=Sec-WebSocket-Protocol: chat

WebSocket API Hooks

Vertx.io

● Asynchronous Application Development

› Polyglot, Simplicity, Scalability, Concurrency

› Distributed Event Bus

› WebSocket support

● VerticlesServer.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

[email protected]

http://www.linkedin.com/in/marcopas