Skip to content

Commit 9fe3b79

Browse files
authored
Merge pull request #215 from dimaa6/172-async-execution
Asynchronous execution
2 parents cfff07b + b6c0b59 commit 9fe3b79

File tree

71 files changed

+293
-93
lines changed

Some content is hidden

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

71 files changed

+293
-93
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import eu.chargetime.ocpp.model.CallMessage;
66
import eu.chargetime.ocpp.model.CallResultMessage;
77
import eu.chargetime.ocpp.model.Message;
8+
import eu.chargetime.ocpp.model.Exclude;
9+
810
import java.lang.reflect.Type;
911
import java.time.ZonedDateTime;
1012
import java.time.format.DateTimeFormatter;
@@ -99,6 +101,18 @@ public ZonedDateTime deserialize(
99101
static {
100102
GsonBuilder builder = new GsonBuilder();
101103
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+
});
115+
102116
gson = builder.disableHtmlEscaping().create();
103117
}
104118

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ public Confirmation handleRequest(Request request) throws UnsupportedFeatureExce
9696
}
9797
}
9898

99+
@Override
100+
public boolean asyncCompleteRequest(String uniqueId, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException {
101+
return session.completePendingPromise(uniqueId, confirmation);
102+
}
103+
99104
@Override
100105
public void handleError(
101106
String uniqueId, String errorCode, String errorDescription, Object payload) {
@@ -165,4 +170,8 @@ public CompletableFuture<Confirmation> send(Request request)
165170
public UUID getSessionId() {
166171
return this.session.getSessionId();
167172
}
173+
174+
public boolean asyncCompleteRequest(String uniqueId, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException {
175+
return session.completePendingPromise(uniqueId, confirmation);
176+
}
168177
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.chargetime.ocpp;
22

3+
import eu.chargetime.ocpp.model.Confirmation;
34
import eu.chargetime.ocpp.model.Request;
45
import java.util.UUID;
56

@@ -39,5 +40,7 @@ public interface ISession {
3940

4041
void sendRequest(String action, Request payload, String uuid);
4142

43+
boolean completePendingPromise(String id, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException;
44+
4245
void close();
4346
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,8 @@ public RequestDispatcher(PromiseFulfiller fulfiller) {
3838
this.fulfiller = fulfiller;
3939
}
4040

41-
public CompletableFuture<Confirmation> handleRequest(Request request) {
42-
CompletableFuture<Confirmation> promise = new CompletableFuture<>();
41+
public void handleRequest(CompletableFuture<Confirmation> promise, Request request) {
4342
fulfiller.fulfill(promise, eventHandler, request);
44-
return promise;
4543
}
4644

4745
public void setEventHandler(SessionEvents eventHandler) {

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ public Confirmation handleRequest(Request request)
126126
}
127127
}
128128

129+
@Override
130+
public boolean asyncCompleteRequest(String uniqueId, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException {
131+
return session.completePendingPromise(uniqueId, confirmation);
132+
}
133+
129134
@Override
130135
public void handleError(
131136
String uniqueId, String errorCode, String errorDescription, Object payload) {
@@ -219,6 +224,29 @@ public CompletableFuture<Confirmation> send(UUID sessionIndex, Request request)
219224
return promise;
220225
}
221226

227+
/**
228+
* Indicate completion of a pending request.
229+
*
230+
* @param sessionIndex Session index of the client.
231+
* @param uniqueId the unique id used for the original {@link Request}.
232+
* @param confirmation the {@link Confirmation} to the original {@link Request}.
233+
* @return a boolean indicating if pending request was found.
234+
* @throws NotConnectedException Thrown if session with passed sessionIndex is not found
235+
*/
236+
public boolean asyncCompleteRequest(UUID sessionIndex, String uniqueId, Confirmation confirmation) throws NotConnectedException, UnsupportedFeatureException, OccurenceConstraintException {
237+
ISession session = sessions.get(sessionIndex);
238+
239+
if (session == null) {
240+
logger.warn("Session not found by index: {}", sessionIndex);
241+
242+
// No session found means client disconnected and request should be cancelled
243+
throw new NotConnectedException();
244+
}
245+
246+
return session.completePendingPromise(uniqueId, confirmation);
247+
}
248+
249+
222250
public boolean isSessionOpen(UUID sessionIndex) {
223251
return sessions.containsKey(sessionIndex);
224252
}

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

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ of this software and associated documentation files (the "Software"), to deal
3232
import eu.chargetime.ocpp.utilities.MoreObjects;
3333
import java.util.Optional;
3434
import java.util.UUID;
35+
import java.util.Map;
36+
import java.util.HashMap;
37+
import java.util.AbstractMap;
3538
import java.util.concurrent.CompletableFuture;
3639
import org.slf4j.Logger;
3740
import org.slf4j.LoggerFactory;
@@ -50,6 +53,7 @@ public class Session implements ISession {
5053
private final RequestDispatcher dispatcher;
5154
private final IFeatureRepository featureRepository;
5255
private SessionEvents events;
56+
private final Map<String, AbstractMap.SimpleImmutableEntry<String, CompletableFuture<Confirmation>>> pendingPromises = new HashMap<>();
5357

5458
/**
5559
* Handles required injections.
@@ -198,9 +202,12 @@ public synchronized void onCall(String id, String action, Object payload) {
198202
try {
199203
Request request =
200204
communicator.unpackPayload(payload, featureOptional.get().getRequestType());
205+
request.setOcppMessageId(id);
201206
if (request.validate()) {
202-
CompletableFuture<Confirmation> promise = dispatcher.handleRequest(request);
207+
CompletableFuture<Confirmation> promise = new CompletableFuture<>();
203208
promise.whenComplete(new ConfirmationHandler(id, action, communicator));
209+
addPendingPromise(id, action, promise);
210+
dispatcher.handleRequest(promise, request);
204211
} else {
205212
communicator.sendCallError(
206213
id, action, "OccurenceConstraintViolation", OCCURENCE_CONSTRAINT_VIOLATION);
@@ -231,6 +238,36 @@ public void onConnected() {
231238
}
232239
}
233240

241+
private void addPendingPromise(String id, String action, CompletableFuture<Confirmation> promise) {
242+
synchronized (pendingPromises) {
243+
pendingPromises.put(id, new AbstractMap.SimpleImmutableEntry<>(action, promise));
244+
}
245+
}
246+
247+
@Override
248+
public boolean completePendingPromise(String id, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException {
249+
AbstractMap.SimpleImmutableEntry<String, CompletableFuture<Confirmation>> promiseAction = null;
250+
// synchronization prevents from confirming one promise more than once, as we remove found promise
251+
synchronized (pendingPromises) {
252+
promiseAction = pendingPromises.get(id);
253+
if (promiseAction == null) return false;
254+
// remove promise from store
255+
pendingPromises.remove(id);
256+
}
257+
// check confirmation type, it has to correspond to original request type
258+
Optional<Feature> featureOptional = featureRepository.findFeature(promiseAction.getKey());
259+
if (featureOptional.isPresent()) {
260+
if (!featureOptional.get().getConfirmationType().isInstance(confirmation)) {
261+
throw new OccurenceConstraintException();
262+
}
263+
} else {
264+
logger.debug("Feature for confirmation with id: {} not found in session: {}", id, this);
265+
throw new UnsupportedFeatureException("Error with getting confirmation type by request id = " + id);
266+
}
267+
promiseAction.getValue().complete(confirmation);
268+
return true;
269+
}
270+
234271
@Override
235272
public boolean equals(Object o) {
236273
if (this == o) return true;

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ public interface SessionEvents {
4949
*/
5050
Confirmation handleRequest(Request request) throws UnsupportedFeatureException;
5151

52+
/**
53+
* Completes a pending request {@link Request}.
54+
*
55+
* @param uniqueId the unique id used for the {@link Request}.
56+
* @param confirmation the {@link Confirmation} to the {@link Request}.
57+
* @return a boolean indicating if pending request was found.
58+
*/
59+
boolean asyncCompleteRequest(String uniqueId, Confirmation confirmation) throws UnsupportedFeatureException, OccurenceConstraintException;
60+
5261
/**
5362
* Handle a error to a {@link Request}.
5463
*

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ public void fulfill(
3939
CompletableFuture<Confirmation> promise, SessionEvents eventHandler, Request request) {
4040
try {
4141
Confirmation conf = eventHandler.handleRequest(request);
42-
promise.complete(conf);
42+
// Confirmation may be null, in this case asynchronous execution is assumed
43+
if (conf != null) {
44+
eventHandler.asyncCompleteRequest(request.getOcppMessageId(), conf);
45+
}
4346
} catch (Exception ex) {
4447
logger.warn("fulfillPromis() failed", ex);
4548
promise.completeExceptionally(ex);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package eu.chargetime.ocpp.model;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.FIELD)
10+
public @interface Exclude {}

ocpp-common/src/main/java/eu/chargetime/ocpp/model/Request.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ of this software and associated documentation files (the "Software"), to deal
3030
/** Interface used to flag a model as Request payload. */
3131
public interface Request extends Validatable {
3232
boolean transactionRelated();
33+
String getOcppMessageId();
34+
void setOcppMessageId(String id);
3335
}

0 commit comments

Comments
 (0)