This document discusses using Grails to develop an electric vehicle charging platform. It describes how Grails was used to implement the Open Charge Point Protocol (OCPP) for communication between charging stations and a backend system. Future plans include adding additional protocol support using JSON and WebSockets for full-duplex communication. Testing and performance testing were important aspects, and plugins like RabbitMQ and CXF were leveraged. Vert.x is discussed as an option for asynchronous programming.
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?
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)
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)
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"/>
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
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
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