-
Notifications
You must be signed in to change notification settings - Fork 407
/
CaliforniumServerEndpointsProvider.java
356 lines (309 loc) · 15.2 KB
/
CaliforniumServerEndpointsProvider.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
/*******************************************************************************
* Copyright (c) 2022 Sierra Wireless and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Sierra Wireless - initial API and implementation
*******************************************************************************/
package org.eclipse.leshan.server.californium.endpoint;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.eclipse.californium.core.CoapServer;
import org.eclipse.californium.core.coap.Request;
import org.eclipse.californium.core.coap.Response;
import org.eclipse.californium.core.network.CoapEndpoint;
import org.eclipse.californium.core.observe.NotificationListener;
import org.eclipse.californium.core.server.resources.Resource;
import org.eclipse.californium.elements.config.Configuration;
import org.eclipse.californium.elements.config.Configuration.ModuleDefinitionsProvider;
import org.eclipse.leshan.core.californium.ExceptionTranslator;
import org.eclipse.leshan.core.californium.ObserveUtil;
import org.eclipse.leshan.core.californium.identity.IdentityHandler;
import org.eclipse.leshan.core.californium.identity.IdentityHandlerProvider;
import org.eclipse.leshan.core.endpoint.EndpointUriUtil;
import org.eclipse.leshan.core.endpoint.Protocol;
import org.eclipse.leshan.core.observation.CompositeObservation;
import org.eclipse.leshan.core.observation.Observation;
import org.eclipse.leshan.core.observation.ObservationIdentifier;
import org.eclipse.leshan.core.observation.SingleObservation;
import org.eclipse.leshan.core.peer.LwM2mPeer;
import org.eclipse.leshan.core.response.AbstractLwM2mResponse;
import org.eclipse.leshan.core.response.ObserveCompositeResponse;
import org.eclipse.leshan.core.response.ObserveResponse;
import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.LeshanServer;
import org.eclipse.leshan.server.californium.RootResource;
import org.eclipse.leshan.server.californium.endpoint.coap.CoapServerProtocolProvider;
import org.eclipse.leshan.server.endpoint.LwM2mServerEndpoint;
import org.eclipse.leshan.server.endpoint.LwM2mServerEndpointsProvider;
import org.eclipse.leshan.server.endpoint.ServerEndpointToolbox;
import org.eclipse.leshan.server.observation.LwM2mNotificationReceiver;
import org.eclipse.leshan.server.profile.ClientProfile;
import org.eclipse.leshan.server.request.UplinkRequestReceiver;
import org.eclipse.leshan.server.security.ServerSecurityInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CaliforniumServerEndpointsProvider implements LwM2mServerEndpointsProvider {
// TODO TL : provide a COAP/Californium API ? like previous LeshanServer.coapAPI()
private final Logger LOG = LoggerFactory.getLogger(CaliforniumServerEndpointsProvider.class);
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("Leshan Async Request timeout"));
private final Configuration serverConfig;
private final List<CaliforniumServerEndpointFactory> endpointsFactory;
private final ServerCoapMessageTranslator messagetranslator = new ServerCoapMessageTranslator();
private final List<CaliforniumServerEndpoint> endpoints;
private CoapServer coapServer;
public CaliforniumServerEndpointsProvider() {
this(new Builder().generateDefaultValue());
}
protected CaliforniumServerEndpointsProvider(Builder builder) {
this.serverConfig = builder.serverConfiguration;
this.endpointsFactory = builder.endpointsFactory;
this.endpoints = new ArrayList<CaliforniumServerEndpoint>();
}
@Override
public List<LwM2mServerEndpoint> getEndpoints() {
return Collections.unmodifiableList(endpoints);
}
@Override
public LwM2mServerEndpoint getEndpoint(URI uri) {
for (CaliforniumServerEndpoint endpoint : endpoints) {
if (endpoint.getURI().equals(uri))
return endpoint;
}
return null;
}
@Override
public void createEndpoints(UplinkRequestReceiver requestReceiver, LwM2mNotificationReceiver notificatonReceiver,
ServerEndpointToolbox toolbox, ServerSecurityInfo serverSecurityInfo, LeshanServer server) {
// create server;
coapServer = new CoapServer(serverConfig) {
@Override
protected Resource createRoot() {
return new RootResource();
}
};
// create identity handler provider
IdentityHandlerProvider identityHandlerProvider = new IdentityHandlerProvider();
// create endpoints
for (CaliforniumServerEndpointFactory endpointFactory : endpointsFactory) {
// create Californium endpoint
CoapEndpoint coapEndpoint = endpointFactory.createCoapEndpoint(serverConfig, serverSecurityInfo,
notificatonReceiver, server);
if (coapEndpoint != null) {
// create identity handler and add it to provider
final IdentityHandler identityHandler = endpointFactory.createIdentityHandler();
identityHandlerProvider.addIdentityHandler(coapEndpoint, identityHandler);
// create exception translator;
ExceptionTranslator exceptionTranslator = endpointFactory.createExceptionTranslator();
// create LWM2M endpoint
CaliforniumServerEndpoint lwm2mEndpoint = new CaliforniumServerEndpoint(endpointFactory.getProtocol(),
coapEndpoint, messagetranslator, toolbox, notificatonReceiver, identityHandler,
exceptionTranslator, executor);
endpoints.add(lwm2mEndpoint);
// add Californium endpoint to coap server
coapServer.addEndpoint(coapEndpoint);
// add NotificationListener
coapEndpoint.addNotificationListener(new NotificationListener() {
@Override
public void onNotification(Request coapRequest, Response coapResponse) {
// Get Observation
String regid = coapRequest.getUserContext().get(ObserveUtil.CTX_REGID);
Observation observation = server.getRegistrationStore().getObservation(regid,
new ObservationIdentifier(coapResponse.getToken().getBytes()));
if (observation == null) {
LOG.error("Unexpected error: Unable to find observation with token {} for registration {}",
coapResponse.getToken(), regid);
return;
}
// Get profile
LwM2mPeer client = identityHandler.getIdentity(coapResponse);
ClientProfile profile = toolbox.getProfileProvider().getProfile(client.getIdentity());
// create Observe Response
try {
AbstractLwM2mResponse response = messagetranslator.createObservation(observation,
coapResponse, toolbox, profile);
if (observation instanceof SingleObservation) {
notificatonReceiver.onNotification((SingleObservation) observation, client, profile,
(ObserveResponse) response);
} else if (observation instanceof CompositeObservation) {
notificatonReceiver.onNotification((CompositeObservation) observation, client, profile,
(ObserveCompositeResponse) response);
}
} catch (Exception e) {
notificatonReceiver.onError(observation, client, profile, e);
}
}
});
}
}
// create resources
List<Resource> resources = messagetranslator.createResources(requestReceiver, toolbox, identityHandlerProvider);
coapServer.add(resources.toArray(new Resource[resources.size()]));
}
@Override
public void start() {
coapServer.start();
}
@Override
public void stop() {
coapServer.stop();
}
@Override
public void destroy() {
executor.shutdownNow();
try {
executor.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
LOG.warn("Destroying RequestSender was interrupted.", e);
}
coapServer.destroy();
}
public static class Builder {
private final List<ServerProtocolProvider> protocolProviders;
private Configuration serverConfiguration;
private final List<CaliforniumServerEndpointFactory> endpointsFactory;
public Builder(ServerProtocolProvider... protocolProviders) {
// TODO TL : handle duplicate ?
this.protocolProviders = new ArrayList<ServerProtocolProvider>();
if (protocolProviders.length == 0) {
this.protocolProviders.add(new CoapServerProtocolProvider());
} else {
this.protocolProviders.addAll(Arrays.asList(protocolProviders));
}
this.endpointsFactory = new ArrayList<>();
}
/**
* Create Californium {@link Configuration} with all Module Definitions needed for protocols provided by this
* endpoints provider.
* <p>
* Once, you create the configuration you should use {@link #setConfiguration(Configuration)}
*
* <pre>
* // Create Builder
* CaliforniumServerEndpointsProvider.Builder builder = new CaliforniumServerEndpointsProvider.Builder(
* new CoapServerProtocolProvider(), //
* new CoapsServerProtocolProvider());
*
* // Set custom Californium Configuration :
* Configuration c = builder.createDefaultConfiguration();
* c.set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true);
* c.set(CoapConfig.ACK_TIMEOUT, 1, TimeUnit.SECONDS);
* builder.setConfiguration(c);
* </pre>
*/
public Configuration createDefaultConfiguration() {
// Get all Californium modules
Set<ModuleDefinitionsProvider> moduleProviders = new HashSet<>();
for (ServerProtocolProvider protocolProvider : protocolProviders) {
moduleProviders.addAll(protocolProvider.getModuleDefinitionsProviders());
}
// create Californium Configuration
Configuration configuration = new Configuration(
moduleProviders.toArray(new ModuleDefinitionsProvider[moduleProviders.size()]));
// apply default value
for (ServerProtocolProvider protocolProvider : protocolProviders) {
protocolProvider.applyDefaultValue(configuration);
}
return configuration;
}
/**
* Set {@link Configuration} used by the {@link CoapServer}. It will be shared by all endpoints created by this
* endpoints provider.
* <p>
* {@link Configuration} provided SHOULD be created with {@link #createDefaultConfiguration()}.
* <p>
* It should generally not be used with {@link #setConfiguration(Consumer)}
*/
public Builder setConfiguration(Configuration serverConfiguration) {
this.serverConfiguration = serverConfiguration;
return this;
}
/**
* Create Californium {@link Configuration} with all needed Module Definitions for protocol provided by
* {@link ServerProtocolProvider}s, then apply given consumer to it.
*
* <pre>
* {@code
* endpointsBuilder.setConfiguration(c -> {
* c.set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true);
* c.set(CoapConfig.ACK_TIMEOUT, 1, TimeUnit.SECONDS);
* });
* }
* </pre>
*
* This is like doing :
*
* <pre>
* Configuration c = endpointsBuilder.createDefaultConfiguration();
* c.set(DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true);
* c.set(CoapConfig.ACK_TIMEOUT, 1, TimeUnit.SECONDS);
* endpointsBuilder.setConfiguration(c);
* </pre>
*/
public Builder setConfiguration(Consumer<Configuration> configurationSetter) {
Configuration cfg = createDefaultConfiguration();
configurationSetter.accept(cfg);
// we set config once all is done without exception.
this.serverConfiguration = cfg;
return this;
}
public Builder addEndpoint(String uri) {
return addEndpoint(EndpointUriUtil.createUri(uri));
}
public Builder addEndpoint(URI uri) {
for (ServerProtocolProvider protocolProvider : protocolProviders) {
// TODO TL : validate URI
if (protocolProvider.getProtocol().getUriScheme().equals(uri.getScheme())) {
// TODO TL: handle duplicate addr
endpointsFactory.add(protocolProvider.createDefaultEndpointFactory(uri));
}
}
// TODO TL: handle missing provider for given protocol
return this;
}
public Builder addEndpoint(InetSocketAddress addr, Protocol protocol) {
return addEndpoint(EndpointUriUtil.createUri(protocol.getUriScheme(), addr));
}
public Builder addEndpoint(CaliforniumServerEndpointFactory endpointFactory) {
// TODO TL: handle duplicate addr
endpointsFactory.add(endpointFactory);
return this;
}
protected Builder generateDefaultValue() {
if (serverConfiguration == null) {
serverConfiguration = createDefaultConfiguration();
}
if (endpointsFactory.isEmpty()) {
for (ServerProtocolProvider protocolProvider : protocolProviders) {
// TODO TL : handle duplicates
endpointsFactory.add(protocolProvider
.createDefaultEndpointFactory(protocolProvider.getDefaultUri(serverConfiguration)));
}
}
return this;
}
public CaliforniumServerEndpointsProvider build() {
generateDefaultValue();
return new CaliforniumServerEndpointsProvider(this);
}
}
}