Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,14 @@ public void accept(CommunicatorEvents events) {
synchronized public void sendCall(String uniqueId, String action, Request request) {
Object call = makeCall(uniqueId, action, packPayload(request));
try {
if (request.transactionRelated() && transactionQueue.size() > 0) {
if(radio.isClosed()) {
logger.warn("Not connected: storing request to queue");
if (request.transactionRelated()) {
transactionQueue.add(call);
} else {
events.onError(uniqueId, "Not connected", "The request couldn't be send due to the lack of connection", request);
}
} else if (request.transactionRelated() && transactionQueue.size() > 0) {
transactionQueue.add(call);
processTransactionQueue();
} else {
Expand Down
375 changes: 320 additions & 55 deletions ocpp-common/src/main/java/eu/chargetime/ocpp/utilities/MoreObjects.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@

/*
* Copyright (C) 2014 The Guava Authors
*
* Modified by Evgeny Pakhomov <eugene.pakhomov@ubitricity.com>
*
* Changes:
* * Cut Guava specific annotations
* * Ticker abstraction replaced with direct System.nanoTime() call
* * Platform dependency removed and formatCompact4Digits method moved to this class
* * Preconditions dependency removed and checkState method moved to this class
* * References to Guava versions in methods JavaDoc are cut as it won't be relevant
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
Expand Down Expand Up @@ -186,4 +194,4 @@ private static String abbreviate(TimeUnit unit) {
private static String formatCompact4Digits(double value) {
return String.format(Locale.ROOT, "%.4g", value);
}
}
}
42 changes: 40 additions & 2 deletions ocpp-v1_6/src/main/java/eu/chargetime/ocpp/JSONClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
import eu.chargetime.ocpp.feature.profile.Profile;
import eu.chargetime.ocpp.model.Confirmation;
import eu.chargetime.ocpp.model.Request;

import eu.chargetime.ocpp.wss.BaseWssSocketBuilder;
import eu.chargetime.ocpp.wss.WssSocketBuilder;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.util.concurrent.CompletionStage;
Expand Down Expand Up @@ -67,8 +68,45 @@ public JSONClient(ClientCoreProfile coreProfile, String identity) {
featureRepository.addFeatureProfile(coreProfile);
}

/**
* Application composite root for a json client.
* The core feature profile is required as a minimum.
*
* @param coreProfile implementation of the core feature profile.
* @param identity if set, will append identity to url.
* @param wssSocketBuilder to build {@link java.net.Socket} to support wss://.
*/
public JSONClient(ClientCoreProfile coreProfile, String identity, WssSocketBuilder wssSocketBuilder) {
this(coreProfile, identity);
enableWSS(wssSocketBuilder);
}

// To ensure the exposed API is backward compatible
public void enableWSS(SSLContext sslContext) throws IOException {
transmitter.enableWSS(sslContext);
WssSocketBuilder wssSocketBuilder =
BaseWssSocketBuilder.builder().sslSocketFactory(sslContext.getSocketFactory());
enableWSS(wssSocketBuilder);
}

/**
* Enables WSS connection to the endpoint.
* The {@code wssSocketBuilder} must be initialized at that step
* (as required parameters set might vary depending on implementation the {@link eu.chargetime.ocpp.wss.WssSocketBuilder#verify()} is used to ensure initialization).
*
* @param wssSocketBuilder builder to provide SSL socket
* @return instance of {@link JSONClient}
* @throws IllegalStateException in case if the client is already connected
* @throws IllegalStateException in case {@code wssSocketBuilder} not initialized properly
*/
public JSONClient enableWSS(WssSocketBuilder wssSocketBuilder) {
wssSocketBuilder.verify();
transmitter.enableWSS(wssSocketBuilder);
return this;
}

public void setPingInterval(int interval) {
// Set ping interval in seconds
transmitter.setPingInterval(interval);
}

@Override
Expand Down
43 changes: 41 additions & 2 deletions ocpp-v1_6/src/main/java/eu/chargetime/ocpp/JSONServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ of this software and associated documentation files (the "Software"), to deal
import eu.chargetime.ocpp.feature.profile.ServerCoreProfile;
import eu.chargetime.ocpp.model.Confirmation;
import eu.chargetime.ocpp.model.Request;
import eu.chargetime.ocpp.wss.BaseWssFactoryBuilder;
import eu.chargetime.ocpp.wss.WssFactoryBuilder;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.CompletionStage;

Expand All @@ -42,6 +45,7 @@ public class JSONServer implements IServerAPI {

/**
* The core feature profile is required as a minimum.
* The constructor creates WS-ready server.
*
* @param coreProfile implementation of the core feature profile.
*/
Expand All @@ -53,8 +57,43 @@ public JSONServer(ServerCoreProfile coreProfile) {
featureRepository.addFeatureProfile(coreProfile);
}

public void enableWSS(SSLContext sslContext) {
listener.enableWSS(sslContext);
/**
* The core feature profile is required as a minimum.
* The constructor creates WSS-ready server.
*
* @param coreProfile implementation of the core feature profile.
* @param wssFactoryBuilder to build {@link org.java_websocket.WebSocketServerFactory} to support wss://.
*/
public JSONServer(ServerCoreProfile coreProfile, WssFactoryBuilder wssFactoryBuilder) {
this(coreProfile);
enableWSS(wssFactoryBuilder);
}

// To ensure the exposed API is backward compatible
public void enableWSS(SSLContext sslContext) throws IOException {
WssFactoryBuilder builder = BaseWssFactoryBuilder.builder().sslContext(sslContext);
enableWSS(builder);
}

/**
* Enables server to accept WSS connections.
* The {@code wssFactoryBuilder} must be initialized at that step
* (as required parameters set might vary depending on implementation the {@link eu.chargetime.ocpp.wss.WssFactoryBuilder#verify()} is used to ensure initialization).
*
* @param wssFactoryBuilder builder to provide WebSocketServerFactory
* @return instance of {@link JSONServer}
* @throws IllegalStateException in case if the server is already connected
* @throws IllegalStateException in case {@code wssFactoryBuilder} not initialized properly
*/
public JSONServer enableWSS(WssFactoryBuilder wssFactoryBuilder) {
wssFactoryBuilder.verify();
listener.enableWSS(wssFactoryBuilder);
return this;
}

public void setPingInterval(int interval) {
// Set ping interval in seconds
listener.setPingInterval(interval);
}

@Override
Expand Down
33 changes: 29 additions & 4 deletions ocpp-v1_6/src/main/java/eu/chargetime/ocpp/WebSocketListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ of this software and associated documentation files (the "Software"), to deal
*/

import eu.chargetime.ocpp.model.SessionInformation;

import eu.chargetime.ocpp.wss.WssFactoryBuilder;
import org.java_websocket.WebSocket;
import org.java_websocket.drafts.Draft;
import org.java_websocket.drafts.Draft_6455;
Expand All @@ -48,7 +48,11 @@ public class WebSocketListener implements Listener {
private static final Logger logger = LoggerFactory.getLogger(WebSocketListener.class);
private final IServerSessionFactory sessionFactory;

// In seconds
private int pingInterval = 60;

private WebSocketServer server;
private WssFactoryBuilder wssFactoryBuilder;
private HashMap<WebSocket, WebSocketReceiver> sockets;
private volatile boolean closed = true;
private boolean handleRequestAsync;
Expand Down Expand Up @@ -107,12 +111,31 @@ public void onStart() {

}
};

if(wssFactoryBuilder != null) {
server.setWebSocketFactory(wssFactoryBuilder.build());
}

server.setConnectionLostTimeout(pingInterval);

server.start();
closed = false;
}

public void enableWSS(SSLContext sslContext) {
server.setWebSocketFactory(new DefaultSSLWebSocketServerFactory(sslContext));
public void enableWSS(WssFactoryBuilder wssFactoryBuilder) {
if(server != null) {
throw new IllegalStateException("Cannot enable WSS on already running server");
}

this.wssFactoryBuilder = wssFactoryBuilder;
}

public void setPingInterval(int interval) {
this.pingInterval = pingInterval;

if(server != null) {
server.setConnectionLostTimeout(interval);
}
}

@Override
Expand All @@ -127,7 +150,9 @@ public void close() {
server.stop(1);

} catch (InterruptedException e) {
logger.info("close() failed", e);
logger.error("Failed to close listener", e);
} finally {
server = null;
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
package eu.chargetime.ocpp;/*
package eu.chargetime.ocpp;
/*
ChargeTime.eu - Java-OCA-OCPP

MIT License
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ of this software and associated documentation files (the "Software"), to deal
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

*/

import eu.chargetime.ocpp.wss.WssSocketBuilder;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.exceptions.WebsocketNotConnectedException;
Expand All @@ -54,16 +54,21 @@ public class WebSocketTransmitter implements Transmitter
{
private static final Logger logger = LoggerFactory.getLogger(WebSocketTransmitter.class);

public static final String WSS_SCHEME = "wss";
// In seconds
private int pingInterval = 60;
private volatile boolean closed = true;
private WebSocketClient client;
private WssSocketBuilder wssSocketBuilder;

public WebSocketTransmitter() {
}

@Override
public void connect(String uri, RadioEvents events) {
Draft_6455 draft = new Draft_6455(Collections.<IExtension>emptyList(), Collections.<IProtocol>singletonList(new Protocol("ocpp1.6")));
client = new WebSocketClient(URI.create(uri), draft) {
final URI resource = URI.create(uri);
Draft_6455 draft = new Draft_6455(Collections.<IExtension>emptyList(), Collections.<IProtocol>singletonList(new Protocol("ocpp1.6")));
client = new WebSocketClient(resource, draft) {
@Override
public void onOpen(ServerHandshake serverHandshake)
{
Expand Down Expand Up @@ -93,6 +98,24 @@ public void onError(Exception ex)
}
}
};

if(WSS_SCHEME.equals(resource.getScheme())) {

if(wssSocketBuilder == null) {
throw new IllegalStateException("wssSocketBuilder must be set to support " + WSS_SCHEME + " scheme");
}

try {
client.setSocket(wssSocketBuilder
.uri(resource)
.build());
} catch (IOException ex) {
logger.error("SSL socket creation failed", ex);
}
}

client.setConnectionLostTimeout(pingInterval);

try {
client.connectBlocking();
closed = false;
Expand All @@ -101,19 +124,35 @@ public void onError(Exception ex)
}
}

public void enableWSS(SSLContext sslContext) throws IOException {
SSLSocketFactory factory = sslContext.getSocketFactory();
client.setSocket(factory.createSocket());
public void enableWSS(WssSocketBuilder wssSocketBuilder) {

if(client != null) {
throw new IllegalStateException("Cannot enable WSS on already connected client");
}

this.wssSocketBuilder = wssSocketBuilder;
}

public void setPingInterval(int interval) {
this.pingInterval = pingInterval;

if(client != null) {
client.setConnectionLostTimeout(interval);
}
}

@Override
public void disconnect()
{
if(client == null) {
return;
}
try {
client.closeBlocking();
} catch (Exception ex) {
logger.info("client.closeBlocking() failed", ex);
} finally {
client = null;
closed = true;
}
}
Expand Down
Loading