Skip to content

Commit 16d2051

Browse files
committed
Added web service for client to receive requests.
Finished SOAPCommunicator parse method. Still needs to handle error messages.
1 parent fb2b115 commit 16d2051

File tree

17 files changed

+2457
-54
lines changed

17 files changed

+2457
-54
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public Feature findFeatureByRequest(Request request) {
7777
@Override
7878
public void handleConfirmation(String uniqueId, Confirmation confirmation) {
7979
getPromise(uniqueId).complete(confirmation);
80+
removePromise(uniqueId);
8081
}
8182

8283
@Override
@@ -88,6 +89,7 @@ public Confirmation handleRequest(Request request) {
8889
@Override
8990
public void handleError(String uniqueId, String errorCode, String errorDescription, Object payload) {
9091
getPromise(uniqueId).completeExceptionally(new CallErrorException(errorCode, errorCode, payload));
92+
removePromise(uniqueId);
9193
}
9294

9395
@Override

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public interface CommunicatorEvents {
3939
* @param id unique id used to identify the original request.
4040
* @param payload raw payload.
4141
*/
42-
void onCallResult(String id, String payload);
42+
void onCallResult(String id, Object payload);
4343

4444
/**
4545
* Handle call.
@@ -50,7 +50,7 @@ public interface CommunicatorEvents {
5050
* @param action action name used to identify the feature.
5151
* @param payload raw payload.
5252
*/
53-
void onCall(String id, String action, String payload);
53+
void onCall(String id, String action, Object payload);
5454

5555
/**
5656
* Handle call error.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,13 @@ protected CompletableFuture<Confirmation> getPromise(String uniqueId) {
122122
return promises.get(uniqueId);
123123
}
124124

125+
/**
126+
* Remove stored call back {@link CompletableFuture}.
127+
*
128+
* @param uniqueId identification for the {@link Request}
129+
*/
130+
protected void removePromise(String uniqueId) {
131+
promises.remove(uniqueId);
132+
}
133+
125134
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ of this software and associated documentation files (the "Software"), to deal
2626
*/
2727

2828
public interface Listener {
29-
void open(String hostname, int port, String path, ListenerEvents listenerEvents);
29+
void open(String hostname, int port, ListenerEvents listenerEvents);
3030

3131
void close();
3232
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public Server(Listener listener) {
6161
*/
6262
public void open(String hostname, int port, ServerEvents serverEvents) {
6363

64-
listener.open(hostname, port, null, session -> {
64+
listener.open(hostname, port, session -> {
6565
session.accept(new SessionEvents() {
6666
@Override
6767
public Feature findFeatureByAction(String action) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public void accept(SessionEvents eventHandler) {
112112

113113
private class CommunicatorEventHandler implements CommunicatorEvents {
114114
@Override
115-
public void onCallResult(String id, String payload) {
115+
public void onCallResult(String id, Object payload) {
116116
try {
117117
Confirmation confirmation = communicator.unpackPayload(payload, getConfirmationType(id));
118118
if (confirmation.validate()) {
@@ -135,7 +135,7 @@ public void onCallResult(String id, String payload) {
135135
}
136136

137137
@Override
138-
public void onCall(String id, String action, String payload) {
138+
public void onCall(String id, String action, Object payload) {
139139
Feature feature = events.findFeatureByAction(action);
140140
if (feature == null) {
141141
communicator.sendCallError(id, "NotImplemented", "Requested Action is not known by receiver");

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ of this software and associated documentation files (the "Software"), to deal
3232
*/
3333
public class Message {
3434
private String id;
35-
private String payload;
35+
private Object payload;
3636

3737
/**
3838
* Get unique id for message.
@@ -57,16 +57,16 @@ public void setId(String id) {
5757
*
5858
* @return payload.
5959
*/
60-
public String getPayload() {
60+
public Object getPayload() {
6161
return payload;
6262
}
6363

6464
/**
6565
* Attach payload to message.
6666
*
67-
* @param payload String, payload.
67+
* @param payload payload object.
6868
*/
69-
public void setPayload(String payload) {
69+
public void setPayload(Object payload) {
7070
this.payload = payload;
7171
}
7272
}

ocpp-common/src/test/java/eu/chargetime/ocpp/test/ServerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public void setup() {
6666
doReturn(request.getClass()).when(feature).getRequestType();
6767
doReturn(TestConfirmation.class).when(feature).getConfirmationType();
6868
when(feature.getAction()).thenReturn(null);
69-
doAnswer(invocation -> listenerEvents = invocation.getArgumentAt(3, ListenerEvents.class)).when(listener).open(anyString(), anyInt(), any(), any());
69+
doAnswer(invocation -> listenerEvents = invocation.getArgumentAt(2, ListenerEvents.class)).when(listener).open(anyString(), anyInt(), any());
7070
doAnswer(invocation -> sessionEvents = invocation.getArgumentAt(0, SessionEvents.class)).when(session).accept(any());
7171

7272
server = new Server(listener) {

ocpp-v1_6/src/main/java/eu/chargetime/ocpp/SOAPClient.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,23 @@ of this software and associated documentation files (the "Software"), to deal
2424
SOFTWARE.
2525
*/
2626

27+
import com.sun.net.httpserver.HttpServer;
2728
import eu.chargetime.ocpp.feature.profile.ClientCoreProfile;
2829

30+
import javax.xml.soap.SOAPMessage;
31+
import java.io.IOException;
32+
import java.net.InetSocketAddress;
2933
import java.net.URL;
34+
import java.util.concurrent.ExecutionException;
3035

3136
public class SOAPClient extends Client {
3237

38+
final private String WSDL_CHARGE_POINT = "eu/chargetime/ocpp/OCPP_ChargePointService_1.6.wsdl";
39+
3340
private SOAPCommunicator communicator;
41+
private WebServiceTransmitter transmitter;
42+
private URL callback;
43+
3444
/**
3545
* The core feature profile is required.
3646
* The client will use the information taken from the callback parameter to open a HTTP based Web Service.
@@ -40,23 +50,58 @@ public class SOAPClient extends Client {
4050
* @param coreProfile implementation of the core feature profile.
4151
*/
4252
public SOAPClient(String chargeBoxIdentity, URL callback, ClientCoreProfile coreProfile) {
43-
this(new SOAPCommunicator(chargeBoxIdentity, callback.toString(), new WebServiceTransmitter()));
53+
this(chargeBoxIdentity, callback, new WebServiceTransmitter());
54+
this.callback = callback;
4455
addFeatureProfile(coreProfile);
4556
}
4657

58+
private SOAPClient(String chargeBoxIdentity, URL callback, WebServiceTransmitter transmitter) {
59+
this(new SOAPCommunicator(chargeBoxIdentity, callback.toString(), transmitter));
60+
this.transmitter = transmitter;
61+
}
62+
4763
private SOAPClient(SOAPCommunicator communicator) {
4864
super(new Session(communicator, new Queue()));
4965
this.communicator = communicator;
5066
}
5167

5268
/**
5369
* Connect to server and set To header.
70+
* Client opens a WebService for incoming requests.
5471
*
5572
* @param uri url and port of the server
5673
*/
5774
@Override
5875
public void connect(String uri) {
5976
communicator.setToUrl(uri);
6077
super.connect(uri);
78+
openWS();
79+
}
80+
81+
private int getPort() {
82+
return callback.getPort() == -1 ? 8000 : callback.getPort();
83+
}
84+
85+
private void openWS() {
86+
try {
87+
HttpServer server = HttpServer.create(new InetSocketAddress(callback.getHost(), getPort()), 0);
88+
server.createContext("/", new WSHttpHandler(WSDL_CHARGE_POINT, message -> {
89+
SOAPMessage soapMessage = null;
90+
try {
91+
soapMessage = transmitter.relay(message).get();
92+
} catch (InterruptedException e) {
93+
e.printStackTrace();
94+
} catch (ExecutionException e) {
95+
e.printStackTrace();
96+
}
97+
return soapMessage;
98+
}));
99+
server.setExecutor(java.util.concurrent.Executors.newCachedThreadPool());
100+
server.start();
101+
} catch (IOException e) {
102+
e.printStackTrace();
103+
}
61104
}
105+
106+
62107
}

ocpp-v1_6/src/main/java/eu/chargetime/ocpp/SOAPCommunicator.java

Lines changed: 99 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ of this software and associated documentation files (the "Software"), to deal
2424
SOFTWARE.
2525
*/
2626

27+
import eu.chargetime.ocpp.model.CallMessage;
28+
import eu.chargetime.ocpp.model.CallResultMessage;
2729
import eu.chargetime.ocpp.model.Message;
2830
import org.w3c.dom.Document;
31+
import org.w3c.dom.NodeList;
2932

3033
import javax.xml.bind.JAXBContext;
3134
import javax.xml.bind.JAXBException;
@@ -38,6 +41,16 @@ of this software and associated documentation files (the "Software"), to deal
3841
public class SOAPCommunicator extends Communicator {
3942

4043

44+
private static final String HEADER_ACTION = "Action";
45+
private static final String HEADER_MESSAGEID = "MessageID";
46+
private static final String HEADER_RELATESTO = "RelatesTo";
47+
private static final String HEADER_FROM = "From";
48+
private static final String HEADER_REPLYTO = "ReplyTo";
49+
private static final String HEADER_REPLYTO_ADDRESS = "Address";
50+
private static final String HEADER_TO = "To";
51+
private static final String HEADER_CHARGEBOXIDENTITY = "chargeBoxIdentity";
52+
53+
4154
private final String chargeBoxIdentity;
4255
private final String fromUrl;
4356
private String toUrl;
@@ -104,38 +117,38 @@ private Object createMessage(String uniqueId, String action, Document payload, b
104117
String namespace = "http://schemas.xmlsoap.org/ws/2004/08/addressing";
105118

106119
// Set chargeBoxIdentity
107-
SOAPHeaderElement chargeBoxIdentityHeader = soapHeader.addHeaderElement(soapFactory.createName("chargeBoxIdentity", "cs", "urn://Ocpp/Cs/2015/10/"));
120+
SOAPHeaderElement chargeBoxIdentityHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_CHARGEBOXIDENTITY, "cs", "urn://Ocpp/Cs/2015/10/"));
108121
chargeBoxIdentityHeader.setMustUnderstand(true);
109122
chargeBoxIdentityHeader.setValue(chargeBoxIdentity);
110123

111124
// Set Action
112-
SOAPHeaderElement actionHeader = soapHeader.addHeaderElement(soapFactory.createName("Action", prefix, namespace));
125+
SOAPHeaderElement actionHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_ACTION, prefix, namespace));
113126
actionHeader.setMustUnderstand(true);
114127
actionHeader.setValue(String.format("/%s", action));
115128

116129
// Set MessageID
117-
SOAPHeaderElement messageIDHeader = soapHeader.addHeaderElement(soapFactory.createName("MessageID", prefix, namespace));
130+
SOAPHeaderElement messageIDHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_MESSAGEID, prefix, namespace));
118131
messageIDHeader.setMustUnderstand(true);
119132
messageIDHeader.setValue(uniqueId);
120133

121134
// Set RelatesTo
122135
if (isResponse) {
123-
SOAPHeaderElement relatesToHeader = soapHeader.addHeaderElement(soapFactory.createName("RelatesTo", prefix, namespace));
136+
SOAPHeaderElement relatesToHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_RELATESTO, prefix, namespace));
124137
relatesToHeader.setValue(uniqueId);
125138
}
126139

127140
// Set From
128-
SOAPHeaderElement fromHeader = soapHeader.addHeaderElement(soapFactory.createName("From", prefix, namespace));
141+
SOAPHeaderElement fromHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_FROM, prefix, namespace));
129142
fromHeader.setValue(fromUrl);
130143

131144
// Set ReplyTo
132-
SOAPHeaderElement replyToHeader = soapHeader.addHeaderElement(soapFactory.createName("ReplyTo", prefix, namespace));
145+
SOAPHeaderElement replyToHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_REPLYTO, prefix, namespace));
133146
replyToHeader.setMustUnderstand(true);
134-
SOAPElement addressElement = replyToHeader.addChildElement(soapFactory.createName("Address", prefix, namespace));
147+
SOAPElement addressElement = replyToHeader.addChildElement(soapFactory.createName(HEADER_REPLYTO_ADDRESS, prefix, namespace));
135148
addressElement.setValue("http://www.w3.org/2005/08/addressing/anonymous");
136149

137150
// Set To
138-
SOAPHeaderElement toHeader = soapHeader.addHeaderElement(soapFactory.createName("To", prefix, namespace));
151+
SOAPHeaderElement toHeader = soapHeader.addHeaderElement(soapFactory.createName(HEADER_TO, prefix, namespace));
139152
toHeader.setMustUnderstand(true);
140153
toHeader.setValue(toUrl);
141154

@@ -154,7 +167,84 @@ protected Object makeCallError(String uniqueId, String errorCode, String errorDe
154167

155168
@Override
156169
protected Message parse(Object message) {
157-
return null;
170+
Message output = null;
171+
SOAPParser soapParser = new SOAPParser((SOAPMessage) message);
172+
173+
if (soapParser.isAddressedToMe())
174+
output = soapParser.parseMessage();
175+
176+
return output;
177+
}
178+
179+
private class SOAPParser {
180+
181+
private SOAPHeader soapHeader;
182+
private SOAPMessage soapMessage;
183+
184+
public SOAPParser(SOAPMessage message) {
185+
try {
186+
soapMessage = message;
187+
soapHeader = message.getSOAPHeader();
188+
} catch (SOAPException e) {
189+
e.printStackTrace();
190+
}
191+
}
192+
193+
public Message parseMessage() {
194+
Message output = null;
195+
try {
196+
197+
String relatesTo = getElementValue(HEADER_REPLYTO);
198+
if (relatesTo != null && "".equals(relatesTo)) {
199+
output = parseResult();
200+
} else {
201+
output = parseCall();
202+
}
203+
output.setPayload(soapMessage.getSOAPBody().extractContentAsDocument());
204+
205+
} catch (SOAPException e) {
206+
e.printStackTrace();
207+
}
208+
return output;
209+
}
210+
211+
public boolean isAddressedToMe() {
212+
String to = getElementValue(HEADER_TO);
213+
String cbIdentity = getElementValue(HEADER_CHARGEBOXIDENTITY);
214+
return fromUrl.equals(to) && chargeBoxIdentity.equals(cbIdentity);
215+
}
216+
217+
private CallResultMessage parseResult() {
218+
CallResultMessage message = new CallResultMessage();
219+
220+
String id = getElementValue(HEADER_REPLYTO);
221+
message.setId(id);
222+
223+
return message;
224+
}
225+
226+
private CallMessage parseCall() {
227+
CallMessage message = new CallMessage();
228+
229+
String action = getElementValue(HEADER_ACTION);
230+
if (action != null && "".equals(action))
231+
message.setAction(action.substring(1));
232+
233+
String id = getElementValue(HEADER_MESSAGEID);
234+
message.setId(id);
235+
236+
return message;
237+
}
238+
239+
private String getElementValue(String tagName) {
240+
String value = null;
241+
NodeList elements = soapHeader.getElementsByTagName(tagName);
242+
243+
if (elements.getLength() > 0)
244+
value = elements.item(0).getNodeValue();
245+
246+
return value;
247+
}
158248
}
159249

160250
public String getToUrl() {

0 commit comments

Comments
 (0)