Skip to content

Commit 4859ecd

Browse files
authored
Merge pull request #239 from ubitricity/master
Add OCPP 2.0.1 and multi-protocol support
2 parents 62353f4 + 2e1fcd8 commit 4859ecd

File tree

455 files changed

+59043
-160
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

455 files changed

+59043
-160
lines changed

OCPP-J/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>eu.chargetime.ocpp</groupId>
88
<artifactId>OCPP-J</artifactId>
9-
<version>1.0.2</version>
9+
<version>1.2.0</version>
1010
<packaging>jar</packaging>
1111

1212
<name>Java-OCA-OCPP OCPP-J</name>
@@ -50,7 +50,7 @@
5050
<dependency>
5151
<groupId>eu.chargetime.ocpp</groupId>
5252
<artifactId>common</artifactId>
53-
<version>1.0.2</version>
53+
<version>1.2.0</version>
5454
</dependency>
5555
<dependency>
5656
<groupId>com.google.code.gson</groupId>

OCPP-J/src/main/java/eu/chargetime/ocpp/JSONCommunicator.java

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@
44
import eu.chargetime.ocpp.model.CallErrorMessage;
55
import eu.chargetime.ocpp.model.CallMessage;
66
import eu.chargetime.ocpp.model.CallResultMessage;
7-
import eu.chargetime.ocpp.model.Message;
87
import eu.chargetime.ocpp.model.Exclude;
9-
8+
import eu.chargetime.ocpp.model.Message;
109
import java.lang.reflect.Type;
1110
import java.time.ZonedDateTime;
1211
import java.time.format.DateTimeFormatter;
@@ -79,6 +78,16 @@ public JSONCommunicator(Radio radio) {
7978
super(radio);
8079
}
8180

81+
/**
82+
* Handle required injections.
83+
*
84+
* @param radio instance of the {@link Radio}.
85+
* @param enableTransactionQueue true if transaction queue should be enabled.
86+
*/
87+
public JSONCommunicator(Radio radio, boolean enableTransactionQueue) {
88+
super(radio, enableTransactionQueue);
89+
}
90+
8291
private static class ZonedDateTimeSerializer
8392
implements JsonSerializer<ZonedDateTime>, JsonDeserializer<ZonedDateTime> {
8493

@@ -101,17 +110,18 @@ public ZonedDateTime deserialize(
101110
static {
102111
GsonBuilder builder = new GsonBuilder();
103112
builder.registerTypeAdapter(ZonedDateTime.class, new ZonedDateTimeSerializer());
104-
builder.addSerializationExclusionStrategy(new ExclusionStrategy() {
105-
@Override
106-
public boolean shouldSkipClass(Class<?> clazz) {
107-
return false;
108-
}
109-
110-
@Override
111-
public boolean shouldSkipField(FieldAttributes field) {
112-
return field.getAnnotation(Exclude.class) != null;
113-
}
114-
});
113+
builder.addSerializationExclusionStrategy(
114+
new ExclusionStrategy() {
115+
@Override
116+
public boolean shouldSkipClass(Class<?> clazz) {
117+
return false;
118+
}
119+
120+
@Override
121+
public boolean shouldSkipField(FieldAttributes field) {
122+
return field.getAnnotation(Exclude.class) != null;
123+
}
124+
});
115125

116126
gson = builder.disableHtmlEscaping().create();
117127
}
@@ -147,26 +157,35 @@ protected Message parse(Object json) {
147157
Message message;
148158
JsonParser parser = new JsonParser();
149159
JsonArray array = parser.parse(json.toString()).getAsJsonArray();
150-
151-
if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALL) {
152-
message = new CallMessage();
153-
message.setAction(array.get(INDEX_CALL_ACTION).getAsString());
154-
message.setPayload(array.get(INDEX_CALL_PAYLOAD).toString());
155-
} else if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALLRESULT) {
156-
message = new CallResultMessage();
157-
message.setPayload(array.get(INDEX_CALLRESULT_PAYLOAD).toString());
158-
} else if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALLERROR) {
159-
message = new CallErrorMessage();
160-
((CallErrorMessage) message).setErrorCode(array.get(INDEX_CALLERROR_ERRORCODE).getAsString());
161-
((CallErrorMessage) message)
162-
.setErrorDescription(array.get(INDEX_CALLERROR_DESCRIPTION).getAsString());
163-
((CallErrorMessage) message).setRawPayload(array.get(INDEX_CALLERROR_PAYLOAD).toString());
164-
} else {
165-
logger.error("Unknown message type of message: {}", json.toString());
166-
throw new IllegalArgumentException("Unknown message type");
160+
String messageId = "-1";
161+
162+
try {
163+
messageId = array.get(INDEX_UNIQUEID).getAsString();
164+
if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALL) {
165+
message = new CallMessage();
166+
message.setAction(array.get(INDEX_CALL_ACTION).getAsString());
167+
message.setPayload(array.get(INDEX_CALL_PAYLOAD).toString());
168+
} else if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALLRESULT) {
169+
message = new CallResultMessage();
170+
message.setPayload(array.get(INDEX_CALLRESULT_PAYLOAD).toString());
171+
} else if (array.get(INDEX_MESSAGEID).getAsInt() == TYPENUMBER_CALLERROR) {
172+
message = new CallErrorMessage();
173+
((CallErrorMessage) message).setErrorCode(array.get(INDEX_CALLERROR_ERRORCODE).getAsString());
174+
((CallErrorMessage) message)
175+
.setErrorDescription(array.get(INDEX_CALLERROR_DESCRIPTION).getAsString());
176+
((CallErrorMessage) message).setRawPayload(array.get(INDEX_CALLERROR_PAYLOAD).toString());
177+
} else {
178+
logger.error("Unknown message type of message: {}", json.toString());
179+
sendCallError(messageId, null, "MessageTypeNotSupported", null);
180+
return null;
181+
}
182+
} catch (Exception e) {
183+
logger.error("Exception while parsing message: {}", json.toString());
184+
sendCallError(messageId, null, "RpcFrameworkError", e.getMessage());
185+
return null;
167186
}
168187

169-
message.setId(array.get(INDEX_UNIQUEID).getAsString());
188+
message.setId(messageId);
170189

171190
return message;
172191
}

OCPP-J/src/main/java/eu/chargetime/ocpp/JSONConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class JSONConfiguration {
3636
public static final String PING_INTERVAL_PARAMETER = "PING_INTERVAL";
3737
public static final String USERNAME_PARAMETER = "USERNAME";
3838
public static final String PASSWORD_PARAMETER = "PASSWORD";
39+
public static final String CONNECT_NON_BLOCKING_PARAMETER = "CONNECT_NON_BLOCKING";
3940
public static final String CONNECT_TIMEOUT_IN_MS_PARAMETER = "CONNECT_TIMEOUT_IN_MS";
4041
public static final String WEBSOCKET_WORKER_COUNT = "WEBSOCKET_WORKER_COUNT";
4142

OCPP-J/src/main/java/eu/chargetime/ocpp/WebSocketTransmitter.java

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,24 @@ public void onError(Exception ex) {
134134

135135
configure();
136136

137-
logger.debug("Trying to connect to: {}", resource);
137+
boolean isNonBlocking = isNonBlockingParameterSet();
138138

139-
try {
140-
client.connectBlocking();
141-
closed = false;
142-
} catch (Exception ex) {
143-
logger.warn("client.connectBlocking() failed", ex);
139+
logger.debug("Trying to connect to: {}{}", resource, isNonBlocking ? "" : " [blocking]");
140+
141+
if (isNonBlocking) {
142+
try {
143+
client.connect();
144+
closed = false;
145+
} catch (Exception ex) {
146+
logger.warn("client.connect() failed", ex);
147+
}
148+
} else {
149+
try {
150+
client.connectBlocking();
151+
closed = false;
152+
} catch (Exception ex) {
153+
logger.warn("client.connectBlocking() failed", ex);
154+
}
144155
}
145156
}
146157

@@ -175,16 +186,37 @@ public void disconnect() {
175186
if (client == null) {
176187
return;
177188
}
178-
try {
179-
client.closeBlocking();
180-
} catch (Exception ex) {
181-
logger.info("client.closeBlocking() failed", ex);
182-
} finally {
183-
client = null;
184-
closed = true;
189+
190+
boolean isNonBlocking = isNonBlockingParameterSet();
191+
192+
logger.debug("Disconnecting{}", isNonBlocking ? "" : " [blocking]");
193+
194+
if (isNonBlocking) {
195+
try {
196+
client.close();
197+
} catch (Exception ex) {
198+
logger.info("client.close() failed", ex);
199+
} finally {
200+
client = null;
201+
closed = true;
202+
}
203+
} else {
204+
try {
205+
client.closeBlocking();
206+
} catch (Exception ex) {
207+
logger.info("client.closeBlocking() failed", ex);
208+
} finally {
209+
client = null;
210+
closed = true;
211+
}
185212
}
186213
}
187214

215+
private boolean isNonBlockingParameterSet() {
216+
Object rawParam = configuration.getParameter(JSONConfiguration.CONNECT_NON_BLOCKING_PARAMETER);
217+
return rawParam instanceof Boolean ? (Boolean) rawParam : false;
218+
}
219+
188220
@Override
189221
public void send(Object request) throws NotConnectedException {
190222
if (client == null) {

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ buildscript {
1515

1616
allprojects {
1717
group = 'eu.chargetime.ocpp'
18-
version = '1.1'
18+
version = '1.2'
1919
}
2020

2121
subprojects {

ocpp-common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>eu.chargetime.ocpp</groupId>
88
<artifactId>common</artifactId>
9-
<version>1.0.2</version>
9+
<version>1.2.0</version>
1010

1111
<name>Java-OCA-OCPP common</name>
1212
<description>Implementation of Open Charge-Point Protocol common library.</description>

ocpp-common/src/main/java/eu/chargetime/ocpp/Client.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,20 @@ of this software and associated documentation files (the "Software"), to deal
4444
public class Client {
4545
private static final Logger logger = LoggerFactory.getLogger(Client.class);
4646

47-
private ISession session;
48-
private final IFeatureRepository featureRepository;
47+
private final ISession session;
4948
private final IPromiseRepository promiseRepository;
5049

5150
/**
5251
* Handle required injections.
5352
*
5453
* @param session Inject session object
54+
* @param promiseRepository Inject promise repository
5555
* @see Session
5656
*/
5757
public Client(
5858
ISession session,
59-
IFeatureRepository featureRepository,
6059
IPromiseRepository promiseRepository) {
6160
this.session = session;
62-
this.featureRepository = featureRepository;
6361
this.promiseRepository = promiseRepository;
6462
}
6563

@@ -88,7 +86,7 @@ public void handleConfirmation(String uniqueId, Confirmation confirmation) {
8886

8987
@Override
9088
public Confirmation handleRequest(Request request) throws UnsupportedFeatureException {
91-
Optional<Feature> featureOptional = featureRepository.findFeature(request);
89+
Optional<Feature> featureOptional = session.getFeatureRepository().findFeature(request);
9290
if (featureOptional.isPresent()) {
9391
return featureOptional.get().handleRequest(getSessionId(), request);
9492
} else {
@@ -149,7 +147,7 @@ public void disconnect() {
149147
*/
150148
public CompletableFuture<Confirmation> send(Request request)
151149
throws UnsupportedFeatureException, OccurenceConstraintException {
152-
Optional<Feature> featureOptional = featureRepository.findFeature(request);
150+
Optional<Feature> featureOptional = session.getFeatureRepository().findFeature(request);
153151
if (!featureOptional.isPresent()) {
154152
logger.error("Can't send request: unsupported feature. Payload: {}", request);
155153
throw new UnsupportedFeatureException();

ocpp-common/src/main/java/eu/chargetime/ocpp/Communicator.java

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,20 @@ protected abstract Object makeCallError(
115115
* @param transmitter Injected {@link Transmitter}
116116
*/
117117
public Communicator(Radio transmitter) {
118+
this(transmitter, true);
119+
}
120+
121+
/**
122+
* Handle required injections.
123+
*
124+
* @param transmitter Injected {@link Transmitter}
125+
* @param enableTransactionQueue flag to enable/disable the transaction queue and associated
126+
* processing
127+
*/
128+
public Communicator(Radio transmitter, boolean enableTransactionQueue) {
118129
this.radio = transmitter;
119-
this.transactionQueue = new ArrayDeque<>();
120-
this.retryRunner = new RetryRunner();
130+
this.transactionQueue = enableTransactionQueue ? new ArrayDeque<>() : null;
131+
this.retryRunner = enableTransactionQueue ? new RetryRunner() : null;
121132
this.failedFlag = false;
122133
}
123134

@@ -164,7 +175,7 @@ public synchronized void sendCall(String uniqueId, String action, Request reques
164175

165176
try {
166177
if (radio.isClosed()) {
167-
if (request.transactionRelated()) {
178+
if (request.transactionRelated() && transactionQueue != null) {
168179
logger.warn("Not connected: storing request to queue: {}", request);
169180
transactionQueue.add(call);
170181
} else {
@@ -175,15 +186,17 @@ public synchronized void sendCall(String uniqueId, String action, Request reques
175186
"The request can't be sent due to the lack of connection",
176187
request);
177188
}
178-
} else if (request.transactionRelated() && transactionQueue.size() > 0) {
189+
} else if (request.transactionRelated()
190+
&& transactionQueue != null
191+
&& transactionQueue.size() > 0) {
179192
transactionQueue.add(call);
180193
processTransactionQueue();
181194
} else {
182195
radio.send(call);
183196
}
184197
} catch (NotConnectedException ex) {
185198
logger.warn("sendCall() failed: not connected");
186-
if (request.transactionRelated()) {
199+
if (request.transactionRelated() && transactionQueue != null) {
187200
transactionQueue.add(call);
188201
} else {
189202
events.onError(
@@ -211,7 +224,11 @@ public void sendCallResult(String uniqueId, String action, Confirmation confirma
211224
try {
212225
completedHandler.onConfirmationCompleted();
213226
} catch (Throwable e) {
214-
events.onError(uniqueId, "ConfirmationCompletedHandlerFailed", "The confirmation completed callback handler failed with exception " + e.toString(), confirmation);
227+
events.onError(
228+
uniqueId,
229+
"ConfirmationCompletedHandlerFailed",
230+
"The confirmation completed callback handler failed with exception " + e.toString(),
231+
confirmation);
215232
}
216233
}
217234
} catch (NotConnectedException ex) {
@@ -257,7 +274,7 @@ public void disconnect() {
257274
}
258275

259276
private synchronized void processTransactionQueue() {
260-
if (!retryRunner.isAlive()) {
277+
if (retryRunner != null && !retryRunner.isAlive()) {
261278
if (retryRunner.getState() != Thread.State.NEW) {
262279
retryRunner = new RetryRunner();
263280
}
@@ -315,7 +332,7 @@ public void disconnected() {
315332
*/
316333
private Object getRetryMessage() {
317334
Object result = null;
318-
if (!transactionQueue.isEmpty()) result = transactionQueue.peek();
335+
if (transactionQueue != null && !transactionQueue.isEmpty()) result = transactionQueue.peek();
319336
return result;
320337
}
321338

@@ -329,7 +346,7 @@ private boolean hasFailed() {
329346
}
330347

331348
private void popRetryMessage() {
332-
if (!transactionQueue.isEmpty()) transactionQueue.pop();
349+
if (transactionQueue != null && !transactionQueue.isEmpty()) transactionQueue.pop();
333350
}
334351

335352
/** Will resend transaction related requests. */

ocpp-common/src/main/java/eu/chargetime/ocpp/FeatureRepository.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,23 @@ of this software and associated documentation files (the "Software"), to deal
3636

3737
public class FeatureRepository implements IFeatureRepository {
3838

39+
private final ProtocolVersion protocolVersion;
3940
private final Map<String, Feature> actionMap = new HashMap<>();
4041
private final Map<Class<?>, Feature> classMap = new HashMap<>();
4142

43+
public FeatureRepository() {
44+
this(ProtocolVersion.OCPP1_6);
45+
}
46+
47+
public FeatureRepository(ProtocolVersion protocolVersion) {
48+
this.protocolVersion = protocolVersion;
49+
}
50+
51+
@Override
52+
public ProtocolVersion getProtocolVersion() {
53+
return protocolVersion;
54+
}
55+
4256
/**
4357
* Add {@link Profile} to support a group of features.
4458
*
@@ -89,6 +103,7 @@ public Optional<Feature> findFeature(Object needle) {
89103
@Override
90104
public String toString() {
91105
return MoreObjects.toStringHelper("FeatureRepository")
106+
.add("protocolVersion", protocolVersion)
92107
.add("actionMap", actionMap)
93108
.add("classMap", classMap)
94109
.toString();

0 commit comments

Comments
 (0)