Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Using Grails to power your Electric Car

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest. →

Using Grails to power your Electric Car

Avatar for Marco Pas

Marco Pas

May 22, 2013

More Decks by Marco Pas

Other Decks in Programming

Transcript

  1. 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'
  2. Agenda • What the heck am I trying to solve!!

    • How on earth did we solve it? • What are our plans for the future?
  3. 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)
  4. 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
  5. Charging Process Back Office Validation / Verification • Is the

    card valid? • Electricity pricing? • How much can I charge? • Who is the customer? • Did you make a reservation? • ….
  6. 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)
  7. 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!
  8. Agenda • What the heck am I trying to solve!!

    • How on earth did we solve it? • What are our plans for the future?
  9. Release 1.0 ! ! SOAP ~ Contract First with Grails

    was not that easy, so we moved to a pure JAVA/Spring OCPP application
  10. 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); } }
  11. 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)
  12. 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"/>
  13. 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!
  14. Release 2.0 • Guidelines: › Focus on creating a modular

    platform › Test Driven Development › Use Grails for everything!! › Minimize the use of plugins!!!
  15. Grails CXF Plugin • WSDL › Contract First & Code

    First • Wire Interceptors › Logging, Security • Support for versioning @GrailsCxfEndpoint(address='/myCustomSoapService/v2/')
  16. 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' }
  17. 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
  18. AMQP - Advanced Message Queuing Protocol • Asynchronous and synchronous

    message exchange › Enables modular platform architecture
  19. 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!' } }
  20. 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' } }
  21. 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
  22. Testing • Functional & Unit Testing › Build-Test-Data › Spock

    • Load & Performane Testing › BadBoy / Apache JMeter
  23. Some stuff we have used • Grails Plugins › Spring

    Security › Export › RabbitMQ › CXF › Fixture › Spock › Build-Test-Data • Non-Plugins › Twitter BootStrap › Jackson JSON
  24. Agenda • What the heck am I trying to solve!!

    • How on earth did we solve it? • What are our plans for the future?
  25. 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>
  26. 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
  27. 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
  28. 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