Commit e86af4b677af78d7d1f60cb5914be70f9cffe6b9

Authored by Andrew Shvayka
Committed by GitHub
2 parents 08e517a6 4287d838

Merge pull request #4707 from thingsboard/lwm2m-refactoring

LwM2M Refactoring
Showing 38 changed files with 971 additions and 789 deletions
... ... @@ -72,15 +72,15 @@ public class DefaultTbResourceService implements TbResourceService {
72 72 if (ResourceType.LWM2M_MODEL.equals(resource.getResourceType())) {
73 73 try {
74 74 List<ObjectModel> objectModels =
75   - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
  75 + ddfFileParser.parse(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
76 76 if (!objectModels.isEmpty()) {
77 77 ObjectModel objectModel = objectModels.get(0);
78 78
79   - String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.getVersion();
  79 + String resourceKey = objectModel.id + LWM2M_SEPARATOR_KEY + objectModel.version;
80 80 String name = objectModel.name;
81 81 resource.setResourceKey(resourceKey);
82 82 if (resource.getId() == null) {
83   - resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.getVersion());
  83 + resource.setTitle(name + " id=" + objectModel.id + " v" + objectModel.version);
84 84 }
85 85 resource.setSearchText(resourceKey + LWM2M_SEPARATOR_SEARCH_TEXT + name);
86 86 } else {
... ... @@ -176,7 +176,7 @@ public class DefaultTbResourceService implements TbResourceService {
176 176 try {
177 177 DDFFileParser ddfFileParser = new DDFFileParser(new DefaultDDFFileValidator());
178 178 List<ObjectModel> objectModels =
179   - ddfFileParser.parseEx(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
  179 + ddfFileParser.parse(new ByteArrayInputStream(Base64.getDecoder().decode(resource.getData())), resource.getSearchText());
180 180 if (objectModels.size() == 0) {
181 181 return null;
182 182 } else {
... ...
... ... @@ -60,6 +60,53 @@ import java.util.concurrent.ScheduledExecutorService;
60 60 @DaoSqlTest
61 61 public class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest {
62 62
  63 + protected final String TRANSPORT_CONFIGURATION = "{\n" +
  64 + " \"type\": \"LWM2M\",\n" +
  65 + " \"observeAttr\": {\n" +
  66 + " \"keyName\": {\n" +
  67 + " \"/3_1.0/0/9\": \"batteryLevel\"\n" +
  68 + " },\n" +
  69 + " \"observe\": [],\n" +
  70 + " \"attribute\": [\n" +
  71 + " ],\n" +
  72 + " \"telemetry\": [\n" +
  73 + " \"/3_1.0/0/9\"\n" +
  74 + " ],\n" +
  75 + " \"attributeLwm2m\": {}\n" +
  76 + " },\n" +
  77 + " \"bootstrap\": {\n" +
  78 + " \"servers\": {\n" +
  79 + " \"binding\": \"U\",\n" +
  80 + " \"shortId\": 123,\n" +
  81 + " \"lifetime\": 300,\n" +
  82 + " \"notifIfDisabled\": true,\n" +
  83 + " \"defaultMinPeriod\": 1\n" +
  84 + " },\n" +
  85 + " \"lwm2mServer\": {\n" +
  86 + " \"host\": \"localhost\",\n" +
  87 + " \"port\": 5686,\n" +
  88 + " \"serverId\": 123,\n" +
  89 + " \"serverPublicKey\": \"\",\n" +
  90 + " \"bootstrapServerIs\": false,\n" +
  91 + " \"clientHoldOffTime\": 1,\n" +
  92 + " \"bootstrapServerAccountTimeout\": 0\n" +
  93 + " },\n" +
  94 + " \"bootstrapServer\": {\n" +
  95 + " \"host\": \"localhost\",\n" +
  96 + " \"port\": 5687,\n" +
  97 + " \"serverId\": 111,\n" +
  98 + " \"securityMode\": \"NO_SEC\",\n" +
  99 + " \"serverPublicKey\": \"\",\n" +
  100 + " \"bootstrapServerIs\": true,\n" +
  101 + " \"clientHoldOffTime\": 1,\n" +
  102 + " \"bootstrapServerAccountTimeout\": 0\n" +
  103 + " }\n" +
  104 + " },\n" +
  105 + " \"clientLwM2mSettings\": {\n" +
  106 + " \"clientOnlyObserveAfterConnect\": 1\n" +
  107 + " }\n" +
  108 + "}";
  109 +
63 110 protected DeviceProfile deviceProfile;
64 111 protected ScheduledExecutorService executor;
65 112 protected TbTestWebSocketClient wsClient;
... ...
... ... @@ -22,6 +22,7 @@ import org.junit.Assert;
22 22 import org.junit.Test;
23 23 import org.thingsboard.common.util.JacksonUtil;
24 24 import org.thingsboard.server.common.data.Device;
  25 +import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
25 26 import org.thingsboard.server.common.data.query.EntityData;
26 27 import org.thingsboard.server.common.data.query.EntityDataPageLink;
27 28 import org.thingsboard.server.common.data.query.EntityDataQuery;
... ... @@ -36,7 +37,6 @@ import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate;
36 37 import org.thingsboard.server.service.telemetry.cmd.v2.LatestValueCmd;
37 38 import org.thingsboard.server.transport.lwm2m.client.LwM2MTestClient;
38 39 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
39   -import org.thingsboard.server.common.data.device.credentials.lwm2m.NoSecClientCredentials;
40 40
41 41 import java.util.Collections;
42 42 import java.util.List;
... ... @@ -46,60 +46,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
46 46
47 47 public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
48 48
49   - protected final String TRANSPORT_CONFIGURATION = "{\n" +
50   - " \"type\": \"LWM2M\",\n" +
51   - " \"observeAttr\": {\n" +
52   - " \"keyName\": {\n" +
53   - " \"/3_1.0/0/9\": \"batteryLevel\"\n" +
54   - " },\n" +
55   - " \"observe\": [],\n" +
56   - " \"attribute\": [\n" +
57   - " ],\n" +
58   - " \"telemetry\": [\n" +
59   - " \"/3_1.0/0/9\"\n" +
60   - " ],\n" +
61   - " \"attributeLwm2m\": {}\n" +
62   - " },\n" +
63   - " \"bootstrap\": {\n" +
64   - " \"servers\": {\n" +
65   - " \"binding\": \"UQ\",\n" +
66   - " \"shortId\": 123,\n" +
67   - " \"lifetime\": 300,\n" +
68   - " \"notifIfDisabled\": true,\n" +
69   - " \"defaultMinPeriod\": 1\n" +
70   - " },\n" +
71   - " \"lwm2mServer\": {\n" +
72   - " \"host\": \"localhost\",\n" +
73   - " \"port\": 5685,\n" +
74   - " \"serverId\": 123,\n" +
75   - " \"securityMode\": \"NO_SEC\",\n" +
76   - " \"serverPublicKey\": \"\",\n" +
77   - " \"bootstrapServerIs\": false,\n" +
78   - " \"clientHoldOffTime\": 1,\n" +
79   - " \"bootstrapServerAccountTimeout\": 0\n" +
80   - " },\n" +
81   - " \"bootstrapServer\": {\n" +
82   - " \"host\": \"localhost\",\n" +
83   - " \"port\": 5687,\n" +
84   - " \"serverId\": 111,\n" +
85   - " \"securityMode\": \"NO_SEC\",\n" +
86   - " \"serverPublicKey\": \"\",\n" +
87   - " \"bootstrapServerIs\": true,\n" +
88   - " \"clientHoldOffTime\": 1,\n" +
89   - " \"bootstrapServerAccountTimeout\": 0\n" +
90   - " }\n" +
91   - " },\n" +
92   - " \"clientLwM2mSettings\": {\n" +
93   - " \"clientOnlyObserveAfterConnect\": 1\n" +
94   - " }\n" +
95   - "}";
96   -
97   - private final int port = 5685;
98   - private final Security security = noSec("coap://localhost:" + port, 123);
99   - private final NetworkConfig coapConfig = new NetworkConfig().setString("COAP_PORT", Integer.toString(port));
  49 + private final int PORT = 5685;
  50 + private final Security SECURITY = noSec("coap://localhost:" + PORT, 123);
  51 + private final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT));
  52 + private final String ENDPOINT = "deviceAEndpoint";
100 53
101 54 @NotNull
102   - private Device createDevice(String deviceAEndpoint) throws Exception {
  55 + private Device createDevice() throws Exception {
103 56 Device device = new Device();
104 57 device.setName("Device A");
105 58 device.setDeviceProfileId(deviceProfile.getId());
... ... @@ -114,7 +67,7 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
114 67
115 68 LwM2MCredentials noSecCredentials = new LwM2MCredentials();
116 69 NoSecClientCredentials clientCredentials = new NoSecClientCredentials();
117   - clientCredentials.setEndpoint(deviceAEndpoint);
  70 + clientCredentials.setEndpoint(ENDPOINT);
118 71 noSecCredentials.setClient(clientCredentials);
119 72 deviceCredentials.setCredentialsValue(JacksonUtil.toString(noSecCredentials));
120 73 doPost("/api/device/credentials", deviceCredentials).andExpect(status().isOk());
... ... @@ -125,9 +78,7 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
125 78 public void testConnectAndObserveTelemetry() throws Exception {
126 79 createDeviceProfile(TRANSPORT_CONFIGURATION);
127 80
128   - String deviceAEndpoint = "deviceAEndpoint";
129   -
130   - Device device = createDevice(deviceAEndpoint);
  81 + Device device = createDevice();
131 82
132 83 SingleEntityFilter sef = new SingleEntityFilter();
133 84 sef.setSingleEntity(device.getId());
... ... @@ -144,8 +95,8 @@ public class NoSecLwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
144 95 wsClient.waitForReply();
145 96
146 97 wsClient.registerWaitForUpdate();
147   - LwM2MTestClient client = new LwM2MTestClient(executor, deviceAEndpoint);
148   - client.init(security, coapConfig);
  98 + LwM2MTestClient client = new LwM2MTestClient(executor, ENDPOINT);
  99 + client.init(SECURITY, COAP_CONFIG);
149 100 String msg = wsClient.waitForUpdate();
150 101
151 102 EntityDataUpdate update = mapper.readValue(msg, EntityDataUpdate.class);
... ...
... ... @@ -47,54 +47,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
47 47
48 48 public class X509LwM2MIntegrationTest extends AbstractLwM2MIntegrationTest {
49 49
50   - protected final String TRANSPORT_CONFIGURATION = "{\n" +
51   - " \"type\": \"LWM2M\",\n" +
52   - " \"observeAttr\": {\n" +
53   - " \"keyName\": {\n" +
54   - " \"/3_1.0/0/9\": \"batteryLevel\"\n" +
55   - " },\n" +
56   - " \"observe\": [],\n" +
57   - " \"attribute\": [\n" +
58   - " ],\n" +
59   - " \"telemetry\": [\n" +
60   - " \"/3_1.0/0/9\"\n" +
61   - " ],\n" +
62   - " \"attributeLwm2m\": {}\n" +
63   - " },\n" +
64   - " \"bootstrap\": {\n" +
65   - " \"servers\": {\n" +
66   - " \"binding\": \"UQ\",\n" +
67   - " \"shortId\": 123,\n" +
68   - " \"lifetime\": 300,\n" +
69   - " \"notifIfDisabled\": true,\n" +
70   - " \"defaultMinPeriod\": 1\n" +
71   - " },\n" +
72   - " \"lwm2mServer\": {\n" +
73   - " \"host\": \"localhost\",\n" +
74   - " \"port\": 5686,\n" +
75   - " \"serverId\": 123,\n" +
76   - " \"serverPublicKey\": \"\",\n" +
77   - " \"bootstrapServerIs\": false,\n" +
78   - " \"clientHoldOffTime\": 1,\n" +
79   - " \"bootstrapServerAccountTimeout\": 0\n" +
80   - " },\n" +
81   - " \"bootstrapServer\": {\n" +
82   - " \"host\": \"localhost\",\n" +
83   - " \"port\": 5687,\n" +
84   - " \"serverId\": 111,\n" +
85   - " \"securityMode\": \"NO_SEC\",\n" +
86   - " \"serverPublicKey\": \"\",\n" +
87   - " \"bootstrapServerIs\": true,\n" +
88   - " \"clientHoldOffTime\": 1,\n" +
89   - " \"bootstrapServerAccountTimeout\": 0\n" +
90   - " }\n" +
91   - " },\n" +
92   - " \"clientLwM2mSettings\": {\n" +
93   - " \"clientOnlyObserveAfterConnect\": 1\n" +
94   - " }\n" +
95   - "}";
96   -
97   -
98 50 private final int port = 5686;
99 51 private final NetworkConfig coapConfig = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(port));
100 52 private final String endpoint = "deviceAEndpoint";
... ...
... ... @@ -17,40 +17,37 @@ package org.thingsboard.server.transport.lwm2m.client;
17 17
18 18 import lombok.Data;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.californium.core.network.CoapEndpoint;
20 21 import org.eclipse.californium.core.network.config.NetworkConfig;
21   -import org.eclipse.californium.elements.Connector;
  22 +import org.eclipse.californium.core.observe.ObservationStore;
22 23 import org.eclipse.californium.scandium.DTLSConnector;
23 24 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
24   -import org.eclipse.californium.scandium.dtls.ClientHandshaker;
25   -import org.eclipse.californium.scandium.dtls.DTLSSession;
26   -import org.eclipse.californium.scandium.dtls.HandshakeException;
27   -import org.eclipse.californium.scandium.dtls.Handshaker;
28   -import org.eclipse.californium.scandium.dtls.ResumingClientHandshaker;
29   -import org.eclipse.californium.scandium.dtls.ResumingServerHandshaker;
30   -import org.eclipse.californium.scandium.dtls.ServerHandshaker;
31   -import org.eclipse.californium.scandium.dtls.SessionAdapter;
32 25 import org.eclipse.leshan.client.californium.LeshanClient;
33 26 import org.eclipse.leshan.client.californium.LeshanClientBuilder;
34 27 import org.eclipse.leshan.client.engine.DefaultRegistrationEngineFactory;
35 28 import org.eclipse.leshan.client.object.Security;
36 29 import org.eclipse.leshan.client.object.Server;
37 30 import org.eclipse.leshan.client.observer.LwM2mClientObserver;
  31 +import org.eclipse.leshan.client.resource.DummyInstanceEnabler;
38 32 import org.eclipse.leshan.client.resource.ObjectsInitializer;
39 33 import org.eclipse.leshan.client.servers.ServerIdentity;
  34 +import org.eclipse.leshan.core.LwM2mId;
40 35 import org.eclipse.leshan.core.ResponseCode;
41   -import org.eclipse.leshan.core.californium.DefaultEndpointFactory;
  36 +import org.eclipse.leshan.core.californium.EndpointFactory;
  37 +import org.eclipse.leshan.core.model.InvalidDDFFileException;
42 38 import org.eclipse.leshan.core.model.LwM2mModel;
43 39 import org.eclipse.leshan.core.model.ObjectLoader;
44 40 import org.eclipse.leshan.core.model.ObjectModel;
45 41 import org.eclipse.leshan.core.model.StaticModel;
46 42 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder;
47 43 import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder;
48   -import org.eclipse.leshan.core.request.BindingMode;
49 44 import org.eclipse.leshan.core.request.BootstrapRequest;
50 45 import org.eclipse.leshan.core.request.DeregisterRequest;
51 46 import org.eclipse.leshan.core.request.RegisterRequest;
52 47 import org.eclipse.leshan.core.request.UpdateRequest;
53 48
  49 +import java.io.IOException;
  50 +import java.net.InetSocketAddress;
54 51 import java.util.ArrayList;
55 52 import java.util.List;
56 53 import java.util.concurrent.ScheduledExecutorService;
... ... @@ -67,7 +64,7 @@ public class LwM2MTestClient {
67 64 private final String endpoint;
68 65 private LeshanClient client;
69 66
70   - public void init(Security security, NetworkConfig coapConfig) {
  67 + public void init(Security security, NetworkConfig coapConfig) throws InvalidDDFFileException, IOException {
71 68 String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml"};
72 69 List<ObjectModel> models = new ArrayList<>();
73 70 for (String resourceName : resources) {
... ... @@ -76,82 +73,51 @@ public class LwM2MTestClient {
76 73 LwM2mModel model = new StaticModel(models);
77 74 ObjectsInitializer initializer = new ObjectsInitializer(model);
78 75 initializer.setInstancesForObject(SECURITY, security);
79   - initializer.setInstancesForObject(SERVER, new Server(123, 300, BindingMode.U, false));
  76 + initializer.setInstancesForObject(SERVER, new Server(123, 300));
80 77 initializer.setInstancesForObject(DEVICE, new SimpleLwM2MDevice());
  78 + initializer.setClassForObject(LwM2mId.ACCESS_CONTROL, DummyInstanceEnabler.class);
81 79
82 80 DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder();
83 81 dtlsConfig.setRecommendedCipherSuitesOnly(true);
  82 + dtlsConfig.setClientOnly();
84 83
85 84 DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory();
86 85 engineFactory.setReconnectOnUpdate(false);
87 86 engineFactory.setResumeOnConnect(true);
88 87
89   - DefaultEndpointFactory endpointFactory = new DefaultEndpointFactory(endpoint) {
  88 + EndpointFactory endpointFactory = new EndpointFactory() {
  89 +
90 90 @Override
91   - protected Connector createSecuredConnector(DtlsConnectorConfig dtlsConfig) {
92   -
93   - return new DTLSConnector(dtlsConfig) {
94   - @Override
95   - protected void onInitializeHandshaker(Handshaker handshaker) {
96   - handshaker.addSessionListener(new SessionAdapter() {
97   -
98   - @Override
99   - public void handshakeStarted(Handshaker handshaker) throws HandshakeException {
100   - if (handshaker instanceof ServerHandshaker) {
101   - log.info("DTLS Full Handshake initiated by server : STARTED ...");
102   - } else if (handshaker instanceof ResumingServerHandshaker) {
103   - log.info("DTLS abbreviated Handshake initiated by server : STARTED ...");
104   - } else if (handshaker instanceof ClientHandshaker) {
105   - log.info("DTLS Full Handshake initiated by client : STARTED ...");
106   - } else if (handshaker instanceof ResumingClientHandshaker) {
107   - log.info("DTLS abbreviated Handshake initiated by client : STARTED ...");
108   - }
109   - }
110   -
111   - @Override
112   - public void sessionEstablished(Handshaker handshaker, DTLSSession establishedSession)
113   - throws HandshakeException {
114   - if (handshaker instanceof ServerHandshaker) {
115   - log.info("DTLS Full Handshake initiated by server : SUCCEED, handshaker {}", handshaker);
116   - } else if (handshaker instanceof ResumingServerHandshaker) {
117   - log.info("DTLS abbreviated Handshake initiated by server : SUCCEED, handshaker {}", handshaker);
118   - } else if (handshaker instanceof ClientHandshaker) {
119   - log.info("DTLS Full Handshake initiated by client : SUCCEED, handshaker {}", handshaker);
120   - } else if (handshaker instanceof ResumingClientHandshaker) {
121   - log.info("DTLS abbreviated Handshake initiated by client : SUCCEED, handshaker {}", handshaker);
122   - }
123   - }
124   -
125   - @Override
126   - public void handshakeFailed(Handshaker handshaker, Throwable error) {
127   - /** get cause */
128   - String cause;
129   - if (error != null) {
130   - if (error.getMessage() != null) {
131   - cause = error.getMessage();
132   - } else {
133   - cause = error.getClass().getName();
134   - }
135   - } else {
136   - cause = "unknown cause";
137   - }
138   -
139   - if (handshaker instanceof ServerHandshaker) {
140   - log.info("DTLS Full Handshake initiated by server : FAILED [{}]", cause);
141   - } else if (handshaker instanceof ResumingServerHandshaker) {
142   - log.info("DTLS abbreviated Handshake initiated by server : FAILED [{}]", cause);
143   - } else if (handshaker instanceof ClientHandshaker) {
144   - log.info("DTLS Full Handshake initiated by client : FAILED [{}]", cause);
145   - } else if (handshaker instanceof ResumingClientHandshaker) {
146   - log.info("DTLS abbreviated Handshake initiated by client : FAILED [{}]", cause);
147   - }
148   - }
149   - });
150   - }
151   - };
  91 + public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig,
  92 + ObservationStore store) {
  93 + CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
  94 + builder.setInetSocketAddress(address);
  95 + builder.setNetworkConfig(coapConfig);
  96 + return builder.build();
  97 + }
  98 +
  99 + @Override
  100 + public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig,
  101 + ObservationStore store) {
  102 + CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
  103 + DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig);
  104 +
  105 + // tricks to be able to change psk information on the fly
  106 +// AdvancedPskStore pskStore = dtlsConfig.getAdvancedPskStore();
  107 +// if (pskStore != null) {
  108 +// PskPublicInformation identity = pskStore.getIdentity(null, null);
  109 +// SecretKey key = pskStore
  110 +// .requestPskSecretResult(ConnectionId.EMPTY, null, identity, null, null, null).getSecret();
  111 +// singlePSKStore = new SinglePSKStore(identity, key);
  112 +// dtlsConfigBuilder.setAdvancedPskStore(singlePSKStore);
  113 +// }
  114 + builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build()));
  115 + builder.setNetworkConfig(coapConfig);
  116 + return builder.build();
152 117 }
153 118 };
154 119
  120 +
155 121 LeshanClientBuilder builder = new LeshanClientBuilder(endpoint);
156 122 builder.setLocalAddress("0.0.0.0", 11000);
157 123 builder.setObjects(initializer.createAll());
... ... @@ -246,6 +212,11 @@ public class LwM2MTestClient {
246 212 public void onDeregistrationTimeout(ServerIdentity server, DeregisterRequest request) {
247 213 log.info("ClientObserver ->onDeregistrationTimeout... DeregisterRequest [{}] [{}]", request.getRegistrationId(), request.getRegistrationId());
248 214 }
  215 +
  216 + @Override
  217 + public void onUnexpectedError(Throwable unexpectedError) {
  218 +
  219 + }
249 220 };
250 221 this.client.addObserver(observer);
251 222
... ...
... ... @@ -97,7 +97,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
97 97 }
98 98
99 99 @Override
100   - public WriteResponse write(ServerIdentity identity, int resourceid, LwM2mResource value) {
  100 + public WriteResponse write(ServerIdentity identity, boolean replace, int resourceid, LwM2mResource value) {
101 101 log.info("Write on Device resource /{}/{}/{}", getModel().id, getId(), resourceid);
102 102
103 103 switch (resourceid) {
... ... @@ -112,7 +112,7 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl
112 112 fireResourcesChange(resourceid);
113 113 return WriteResponse.success();
114 114 default:
115   - return super.write(identity, resourceid, value);
  115 + return super.write(identity, replace, resourceid, value);
116 116 }
117 117 }
118 118
... ...
... ... @@ -109,8 +109,8 @@ public class LwM2MTransportBootstrapService {
109 109 /** Create credentials */
110 110 this.setServerWithCredentials(builder);
111 111
112   - /** Set securityStore with new ConfigStore */
113   - builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore);
  112 +// /** Set securityStore with new ConfigStore */
  113 +// builder.setConfigStore(lwM2MInMemoryBootstrapConfigStore);
114 114
115 115 /** SecurityStore */
116 116 builder.setSecurityStore(lwM2MBootstrapSecurityStore);
... ...
... ... @@ -69,7 +69,7 @@ public class LwM2MBootstrapConfig {
69 69 server0.lifetime = servers.getLifetime();
70 70 server0.defaultMinPeriod = servers.getDefaultMinPeriod();
71 71 server0.notifIfDisabled = servers.isNotifIfDisabled();
72   - server0.binding = BindingMode.valueOf(servers.getBinding());
  72 + server0.binding = BindingMode.parse(servers.getBinding());
73 73 configBs.servers.put(0, server0);
74 74 /* Security Configuration (object 0) as defined in LWM2M 1.0.x TS. Bootstrap instance = 0 */
75 75 this.bootstrapServer.setBootstrapServerIs(true);
... ...
... ... @@ -30,7 +30,7 @@ import org.eclipse.leshan.server.security.SecurityInfo;
30 30 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
31 31 import org.springframework.stereotype.Service;
32 32 import org.thingsboard.server.gen.transport.TransportProtos;
33   -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo;
  33 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
34 34 import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
35 35 import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
... ... @@ -40,7 +40,7 @@ import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
40 40 import java.io.IOException;
41 41 import java.security.GeneralSecurityException;
42 42 import java.util.Collections;
43   -import java.util.List;
  43 +import java.util.Iterator;
44 44 import java.util.UUID;
45 45
46 46 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.BOOTSTRAP_SERVER;
... ... @@ -71,8 +71,8 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
71 71 }
72 72
73 73 @Override
74   - public List<SecurityInfo> getAllByEndpoint(String endPoint) {
75   - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
  74 + public Iterator<SecurityInfo> getAllByEndpoint(String endPoint) {
  75 + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(endPoint, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
76 76 if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) {
77 77 /* add value to store from BootstrapJson */
78 78 this.setBootstrapConfigScurityInfo(store);
... ... @@ -88,7 +88,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
88 88 } catch (InvalidConfigurationException e) {
89 89 log.error("", e);
90 90 }
91   - return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo());
  91 + return store.getSecurityInfo() == null ? null : Collections.singletonList(store.getSecurityInfo()).iterator();
92 92 }
93 93 }
94 94 return null;
... ... @@ -96,7 +96,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
96 96
97 97 @Override
98 98 public SecurityInfo getByIdentity(String identity) {
99   - EndpointSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
  99 + TbLwM2MSecurityInfo store = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfoByCredentialsId(identity, LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP);
100 100 if (store.getBootstrapCredentialConfig() != null && store.getSecurityMode() != null) {
101 101 /* add value to store from BootstrapJson */
102 102 this.setBootstrapConfigScurityInfo(store);
... ... @@ -113,7 +113,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
113 113 return null;
114 114 }
115 115
116   - private void setBootstrapConfigScurityInfo(EndpointSecurityInfo store) {
  116 + private void setBootstrapConfigScurityInfo(TbLwM2MSecurityInfo store) {
117 117 /* BootstrapConfig */
118 118 LwM2MBootstrapConfig lwM2MBootstrapConfig = this.getParametersBootstrap(store);
119 119 if (lwM2MBootstrapConfig != null) {
... ... @@ -150,7 +150,7 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore {
150 150 }
151 151 }
152 152
153   - private LwM2MBootstrapConfig getParametersBootstrap(EndpointSecurityInfo store) {
  153 + private LwM2MBootstrapConfig getParametersBootstrap(TbLwM2MSecurityInfo store) {
154 154 try {
155 155 LwM2MBootstrapConfig lwM2MBootstrapConfig = store.getBootstrapCredentialConfig();
156 156 if (lwM2MBootstrapConfig != null) {
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.lwm2m.bootstrap.secure;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.leshan.core.request.BootstrapRequest;
19 20 import org.eclipse.leshan.core.request.Identity;
20 21 import org.eclipse.leshan.server.bootstrap.BootstrapSession;
21 22 import org.eclipse.leshan.server.bootstrap.DefaultBootstrapSession;
... ... @@ -25,7 +26,7 @@ import org.eclipse.leshan.server.security.SecurityChecker;
25 26 import org.eclipse.leshan.server.security.SecurityInfo;
26 27
27 28 import java.util.Collections;
28   -import java.util.List;
  29 +import java.util.Iterator;
29 30
30 31 @Slf4j
31 32 public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSessionManager {
... ... @@ -50,16 +51,17 @@ public class LwM2mDefaultBootstrapSessionManager extends DefaultBootstrapSession
50 51 }
51 52
52 53 @SuppressWarnings("deprecation")
53   - public BootstrapSession begin(String endpoint, Identity clientIdentity) {
  54 + public BootstrapSession begin(BootstrapRequest request, Identity clientIdentity) {
54 55 boolean authorized;
55 56 if (bsSecurityStore != null) {
56   - List<SecurityInfo> securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ? Collections.singletonList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())) : bsSecurityStore.getAllByEndpoint(endpoint);
  57 + Iterator<SecurityInfo> securityInfos = (clientIdentity.getPskIdentity() != null && !clientIdentity.getPskIdentity().isEmpty()) ?
  58 + Collections.singletonList(bsSecurityStore.getByIdentity(clientIdentity.getPskIdentity())).iterator() : bsSecurityStore.getAllByEndpoint(request.getEndpointName());
57 59 log.info("Bootstrap session started securityInfos: [{}]", securityInfos);
58   - authorized = securityChecker.checkSecurityInfos(endpoint, clientIdentity, securityInfos);
  60 + authorized = securityChecker.checkSecurityInfos(request.getEndpointName(), clientIdentity, securityInfos);
59 61 } else {
60 62 authorized = true;
61 63 }
62   - DefaultBootstrapSession session = new DefaultBootstrapSession(endpoint, clientIdentity, authorized);
  64 + DefaultBootstrapSession session = new DefaultBootstrapSession(request, clientIdentity, authorized);
63 65 log.info("Bootstrap session started : {}", session);
64 66 return session;
65 67 }
... ...
... ... @@ -22,16 +22,16 @@ import org.eclipse.leshan.server.security.SecurityInfo;
22 22 import org.springframework.stereotype.Component;
23 23 import org.thingsboard.common.util.JacksonUtil;
24 24 import org.thingsboard.server.common.data.StringUtils;
  25 +import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials;
25 26 import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
  27 +import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials;
  28 +import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials;
26 29 import org.thingsboard.server.common.transport.TransportServiceCallback;
27 30 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
28 31 import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg;
29 32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
30 33 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
31   -import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MClientCredentials;
32 34 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
33   -import org.thingsboard.server.common.data.device.credentials.lwm2m.PSKClientCredentials;
34   -import org.thingsboard.server.common.data.device.credentials.lwm2m.RPKClientCredentials;
35 35 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
36 36 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
37 37
... ... @@ -55,15 +55,15 @@ public class LwM2mCredentialsSecurityInfoValidator {
55 55 private final LwM2mTransportContext context;
56 56 private final LwM2MTransportServerConfig config;
57 57
58   - public EndpointSecurityInfo getEndpointSecurityInfo(String endpoint, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
  58 + public TbLwM2MSecurityInfo getEndpointSecurityInfoByCredentialsId(String credentialsId, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
59 59 CountDownLatch latch = new CountDownLatch(1);
60   - final EndpointSecurityInfo[] resultSecurityStore = new EndpointSecurityInfo[1];
61   - context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(),
  60 + final TbLwM2MSecurityInfo[] resultSecurityStore = new TbLwM2MSecurityInfo[1];
  61 + context.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(credentialsId).build(),
62 62 new TransportServiceCallback<>() {
63 63 @Override
64 64 public void onSuccess(ValidateDeviceCredentialsResponse msg) {
65 65 String credentialsBody = msg.getCredentials();
66   - resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue);
  66 + resultSecurityStore[0] = createSecurityInfo(credentialsId, credentialsBody, keyValue);
67 67 resultSecurityStore[0].setMsg(msg);
68 68 resultSecurityStore[0].setDeviceProfile(msg.getDeviceProfile());
69 69 latch.countDown();
... ... @@ -71,8 +71,8 @@ public class LwM2mCredentialsSecurityInfoValidator {
71 71
72 72 @Override
73 73 public void onError(Throwable e) {
74   - log.trace("[{}] [{}] Failed to process credentials ", endpoint, e);
75   - resultSecurityStore[0] = createSecurityInfo(endpoint, null, null);
  74 + log.trace("[{}] [{}] Failed to process credentials ", credentialsId, e);
  75 + resultSecurityStore[0] = createSecurityInfo(credentialsId, null, null);
76 76 latch.countDown();
77 77 }
78 78 });
... ... @@ -91,8 +91,8 @@ public class LwM2mCredentialsSecurityInfoValidator {
91 91 * @param keyValue -
92 92 * @return SecurityInfo
93 93 */
94   - private EndpointSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
95   - EndpointSecurityInfo result = new EndpointSecurityInfo();
  94 + private TbLwM2MSecurityInfo createSecurityInfo(String endpoint, String jsonStr, LwM2mTransportUtil.LwM2mTypeServer keyValue) {
  95 + TbLwM2MSecurityInfo result = new TbLwM2MSecurityInfo();
96 96 LwM2MCredentials credentials = JacksonUtil.fromString(jsonStr, LwM2MCredentials.class);
97 97 if (credentials != null) {
98 98 if (keyValue.equals(LwM2mTransportUtil.LwM2mTypeServer.BOOTSTRAP)) {
... ... @@ -104,6 +104,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
104 104 result.setEndpoint(endpoint);
105 105 result.setSecurityMode(credentials.getBootstrap().getBootstrapServer().getSecurityMode());
106 106 } else {
  107 + result.setEndpoint(credentials.getClient().getEndpoint());
107 108 switch (credentials.getClient().getSecurityConfigClientMode()) {
108 109 case NO_SEC:
109 110 createClientSecurityInfoNoSec(result);
... ... @@ -125,12 +126,12 @@ public class LwM2mCredentialsSecurityInfoValidator {
125 126 return result;
126 127 }
127 128
128   - private void createClientSecurityInfoNoSec(EndpointSecurityInfo result) {
  129 + private void createClientSecurityInfoNoSec(TbLwM2MSecurityInfo result) {
129 130 result.setSecurityInfo(null);
130 131 result.setSecurityMode(NO_SEC);
131 132 }
132 133
133   - private void createClientSecurityInfoPSK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
  134 + private void createClientSecurityInfoPSK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
134 135 PSKClientCredentials pskConfig = (PSKClientCredentials) clientCredentialsConfig;
135 136 if (StringUtils.isNotEmpty(pskConfig.getIdentity())) {
136 137 try {
... ... @@ -149,7 +150,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
149 150 }
150 151 }
151 152
152   - private void createClientSecurityInfoRPK(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
  153 + private void createClientSecurityInfoRPK(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
153 154 RPKClientCredentials rpkConfig = (RPKClientCredentials) clientCredentialsConfig;
154 155 try {
155 156 if (rpkConfig.getKey() != null) {
... ... @@ -164,7 +165,7 @@ public class LwM2mCredentialsSecurityInfoValidator {
164 165 }
165 166 }
166 167
167   - private void createClientSecurityInfoX509(EndpointSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
  168 + private void createClientSecurityInfoX509(TbLwM2MSecurityInfo result, String endpoint, LwM2MClientCredentials clientCredentialsConfig) {
168 169 result.setSecurityInfo(SecurityInfo.newX509CertInfo(endpoint));
169 170 result.setSecurityMode(X509);
170 171 }
... ...
... ... @@ -27,6 +27,7 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
27 27 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
28 28 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
29 29 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore;
  30 +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
30 31
31 32 @Component
32 33 @RequiredArgsConstructor
... ... @@ -34,7 +35,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2mSecurityStore;
34 35 public class TbLwM2MAuthorizer implements Authorizer {
35 36
36 37 private final TbLwM2MDtlsSessionStore sessionStorage;
37   - private final TbLwM2mSecurityStore securityStore;
  38 + private final TbSecurityStore securityStore;
38 39 private final SecurityChecker securityChecker = new SecurityChecker();
39 40 private final LwM2mClientContext clientContext;
40 41
... ...
... ... @@ -29,22 +29,21 @@ import org.eclipse.californium.scandium.dtls.HandshakeResultHandler;
29 29 import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier;
30 30 import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier;
31 31 import org.eclipse.californium.scandium.util.ServerNames;
  32 +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
32 33 import org.springframework.beans.factory.annotation.Value;
33 34 import org.springframework.stereotype.Component;
34   -import org.springframework.util.StringUtils;
35 35 import org.thingsboard.common.util.JacksonUtil;
36 36 import org.thingsboard.server.common.data.DeviceProfile;
37 37 import org.thingsboard.server.common.data.device.credentials.lwm2m.LwM2MSecurityMode;
  38 +import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
38 39 import org.thingsboard.server.common.msg.EncryptionUtil;
39   -import org.thingsboard.server.common.transport.TransportService;
40   -import org.thingsboard.server.common.transport.TransportServiceCallback;
41 40 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
42 41 import org.thingsboard.server.common.transport.util.SslUtil;
43   -import org.thingsboard.server.gen.transport.TransportProtos;
44 42 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
45 43 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
46 44 import org.thingsboard.server.transport.lwm2m.secure.credentials.LwM2MCredentials;
47   -import org.thingsboard.server.common.data.device.credentials.lwm2m.X509ClientCredentials;
  45 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  46 +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore;
48 47 import org.thingsboard.server.transport.lwm2m.server.store.TbLwM2MDtlsSessionStore;
49 48
50 49 import javax.annotation.PostConstruct;
... ... @@ -57,8 +56,6 @@ import java.security.cert.CertificateNotYetValidException;
57 56 import java.security.cert.X509Certificate;
58 57 import java.util.Arrays;
59 58 import java.util.List;
60   -import java.util.concurrent.CountDownLatch;
61   -import java.util.concurrent.TimeUnit;
62 59
63 60 @Slf4j
64 61 @Component
... ... @@ -66,9 +63,10 @@ import java.util.concurrent.TimeUnit;
66 63 @RequiredArgsConstructor
67 64 public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVerifier {
68 65
69   - private final TransportService transportService;
70 66 private final TbLwM2MDtlsSessionStore sessionStorage;
71 67 private final LwM2MTransportServerConfig config;
  68 + private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator;
  69 + private final TbEditableSecurityStore securityStore;
72 70
73 71 @SuppressWarnings("deprecation")
74 72 private StaticCertificateVerifier staticCertificateVerifier;
... ... @@ -119,48 +117,33 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer
119 117
120 118 String strCert = SslUtil.getCertificateString(cert);
121 119 String sha3Hash = EncryptionUtil.getSha3Hash(strCert);
122   - final ValidateDeviceCredentialsResponse[] deviceCredentialsResponse = new ValidateDeviceCredentialsResponse[1];
123   - CountDownLatch latch = new CountDownLatch(1);
124   - transportService.process(TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(sha3Hash).build(),
125   - new TransportServiceCallback<>() {
126   - @Override
127   - public void onSuccess(ValidateDeviceCredentialsResponse msg) {
128   - if (!StringUtils.isEmpty(msg.getCredentials())) {
129   - deviceCredentialsResponse[0] = msg;
130   - }
131   - latch.countDown();
132   - }
133   -
134   - @Override
135   - public void onError(Throwable e) {
136   - log.error(e.getMessage(), e);
137   - latch.countDown();
138   - }
139   - });
140   - if (latch.await(10, TimeUnit.SECONDS)) {
141   - ValidateDeviceCredentialsResponse msg = deviceCredentialsResponse[0];
142   - if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) {
143   - LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class);
144   - if(!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)){
145   - continue;
146   - }
147   - X509ClientCredentials config = (X509ClientCredentials) credentials.getClient();
148   - String certBody = config.getCert();
149   - String endpoint = config.getEndpoint();
150   - if (strCert.equals(certBody)) {
151   - x509CredentialsFound = true;
152   - DeviceProfile deviceProfile = msg.getDeviceProfile();
153   - if (msg.hasDeviceInfo() && deviceProfile != null) {
154   - sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg));
155   - break;
  120 + TbLwM2MSecurityInfo securityInfo = securityInfoValidator.getEndpointSecurityInfoByCredentialsId(sha3Hash, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
  121 + ValidateDeviceCredentialsResponse msg = securityInfo != null ? securityInfo.getMsg() : null;
  122 + if (msg != null && org.thingsboard.server.common.data.StringUtils.isNotEmpty(msg.getCredentials())) {
  123 + LwM2MCredentials credentials = JacksonUtil.fromString(msg.getCredentials(), LwM2MCredentials.class);
  124 + if (!credentials.getClient().getSecurityConfigClientMode().equals(LwM2MSecurityMode.X509)) {
  125 + continue;
  126 + }
  127 + X509ClientCredentials config = (X509ClientCredentials) credentials.getClient();
  128 + String certBody = config.getCert();
  129 + String endpoint = config.getEndpoint();
  130 + if (strCert.equals(certBody)) {
  131 + x509CredentialsFound = true;
  132 + DeviceProfile deviceProfile = msg.getDeviceProfile();
  133 + if (msg.hasDeviceInfo() && deviceProfile != null) {
  134 + sessionStorage.put(endpoint, new TbX509DtlsSessionInfo(cert.getSubjectX500Principal().getName(), msg));
  135 + try {
  136 + securityStore.put(securityInfo);
  137 + } catch (NonUniqueSecurityInfoException e) {
  138 + log.trace("Failed to add security info: {}", securityInfo, e);
156 139 }
157   - } else {
158   - log.trace("[{}][{}] Certificate mismatch. Expected: {}, Actual: {}", endpoint, sha3Hash, strCert, certBody);
  140 + break;
159 141 }
  142 + } else {
  143 + log.trace("[{}][{}] Certificate mismatch. Expected: {}, Actual: {}", endpoint, sha3Hash, strCert, certBody);
160 144 }
161 145 }
162   - } catch (InterruptedException |
163   - CertificateEncodingException |
  146 + } catch (CertificateEncodingException |
164 147 CertificateExpiredException |
165 148 CertificateNotYetValidException e) {
166 149 log.error(e.getMessage(), e);
... ...
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MSecurityInfo.java renamed from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/EndpointSecurityInfo.java
... ... @@ -24,7 +24,7 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
24 24 import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapConfig;
25 25
26 26 @Data
27   -public class EndpointSecurityInfo {
  27 +public class TbLwM2MSecurityInfo {
28 28 private ValidateDeviceCredentialsResponse msg;
29 29 private SecurityInfo securityInfo;
30 30 private SecurityMode securityMode;
... ...
... ... @@ -5,7 +5,7 @@
5 5 * you may not use this file except in compliance with the License.
6 6 * You may obtain a copy of the License at
7 7 *
8   - * http://www.apache.org/licenses/LICENSE-2.0
  8 + * http://www.apache.org/licenses/LICENSE-2.0
9 9 *
10 10 * Unless required by applicable law or agreed to in writing, software
11 11 * distributed under the License is distributed on an "AS IS" BASIS,
... ... @@ -31,7 +31,6 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance;
31 31 import org.eclipse.leshan.core.node.LwM2mPath;
32 32 import org.eclipse.leshan.core.node.LwM2mResource;
33 33 import org.eclipse.leshan.core.observation.Observation;
34   -import org.eclipse.leshan.core.request.ContentFormat;
35 34 import org.eclipse.leshan.core.request.WriteRequest;
36 35 import org.eclipse.leshan.core.response.ReadResponse;
37 36 import org.eclipse.leshan.server.registration.Registration;
... ... @@ -58,6 +57,8 @@ import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
58 57 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
59 58 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper;
60 59 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
  60 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientState;
  61 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientStateException;
61 62 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
62 63 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
63 64 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
... ... @@ -91,7 +92,6 @@ import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.DOWN
91 92 import static org.thingsboard.server.common.data.ota.OtaPackageUpdateStatus.UPDATING;
92 93 import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH;
93 94 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServerHelper.getValueFromKvProto;
94   -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.CLIENT_NOT_AUTHORIZED;
95 95 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.DEVICE_ATTRIBUTES_REQUEST;
96 96 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_ID;
97 97 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.FW_RESULT_ID;
... ... @@ -99,6 +99,7 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.L
99 99 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_INFO;
100 100 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_TELEMETRY;
101 101 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_VALUE;
  102 +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LOG_LW2M_WARN;
102 103 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LWM2M_STRATEGY_2;
103 104 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.DISCOVER;
104 105 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.LwM2mTypeOper.EXECUTE;
... ... @@ -182,32 +183,38 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
182 183 */
183 184 public void onRegistered(Registration registration, Collection<Observation> previousObservations) {
184 185 registrationExecutor.submit(() -> {
  186 + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
185 187 try {
186 188 log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
187   - LwM2mClient lwM2MClient = this.clientContext.registerOrUpdate(registration);
188 189 if (lwM2MClient != null) {
189   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
190   - if (sessionInfo != null) {
191   - transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
192   - TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()
193   - .setSessionInfo(sessionInfo)
194   - .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))
195   - .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build())
196   - .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().build())
197   - .build();
198   - transportService.process(msg, null);
199   - this.getInfoFirmwareUpdate(lwM2MClient, null);
200   - this.getInfoSoftwareUpdate(lwM2MClient, null);
201   - this.initLwM2mFromClientValue(registration, lwM2MClient);
202   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId());
203   - } else {
204   - log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
205   - }
  190 + this.clientContext.register(lwM2MClient, registration);
  191 + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_INFO + ": Client registered with registration id: " + registration.getId());
  192 + SessionInfoProto sessionInfo = lwM2MClient.getSession();
  193 + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo));
  194 + TransportProtos.TransportToDeviceActorMsg msg = TransportProtos.TransportToDeviceActorMsg.newBuilder()
  195 + .setSessionInfo(sessionInfo)
  196 + .setSessionEvent(DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN))
  197 + .setSubscribeToAttributes(TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build())
  198 + .setSubscribeToRPC(TransportProtos.SubscribeToRPCMsg.newBuilder().build())
  199 + .build();
  200 + transportService.process(msg, null);
  201 + this.getInfoFirmwareUpdate(lwM2MClient, null);
  202 + this.getInfoSoftwareUpdate(lwM2MClient, null);
  203 + this.initClientTelemetry(lwM2MClient);
206 204 } else {
207   - log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null);
  205 + log.error("Client: [{}] onRegistered [{}] name [{}] lwM2MClient ", registration.getId(), registration.getEndpoint(), null);
  206 + }
  207 + } catch (LwM2MClientStateException stateException) {
  208 + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) {
  209 + log.info("[{}] retry registration due to race condition: [{}].", registration.getEndpoint(), stateException.getState());
  210 + // Race condition detected and the client was in progress of unregistration while new registration arrived. Let's try again.
  211 + onRegistered(registration, previousObservations);
  212 + } else {
  213 + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to invalid state: " + stateException.getState());
208 214 }
209 215 } catch (Throwable t) {
210 216 log.error("[{}] endpoint [{}] error Unable registration.", registration.getEndpoint(), t);
  217 + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_WARN + ": Client registration failed due to: " + t.getMessage());
211 218 }
212 219 });
213 220 }
... ... @@ -219,25 +226,26 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
219 226 */
220 227 public void updatedReg(Registration registration) {
221 228 updateRegistrationExecutor.submit(() -> {
  229 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
222 230 try {
223   - LwM2mClient client = clientContext.getOrRegister(registration);
224   - if (client != null && client.getSession() != null) {
225   - SessionInfoProto sessionInfo = client.getSession();
226   - this.reportActivityAndRegister(sessionInfo);
227   - if (registration.getBindingMode().useQueueMode()) {
228   - LwM2mQueuedRequest request;
229   - while ((request = client.getQueuedRequests().poll()) != null) {
230   - request.send();
231   - }
  231 + clientContext.updateRegistration(lwM2MClient, registration);
  232 + TransportProtos.SessionInfoProto sessionInfo = lwM2MClient.getSession();
  233 + this.reportActivityAndRegister(sessionInfo);
  234 + if (registration.usesQueueMode()) {
  235 + LwM2mQueuedRequest request;
  236 + while ((request = lwM2MClient.getQueuedRequests().poll()) != null) {
  237 + request.send();
232 238 }
233   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client update Registration", registration.getId());
  239 + }
  240 + } catch (LwM2MClientStateException stateException) {
  241 + if (LwM2MClientState.UNREGISTERED.equals(stateException.getState())) {
  242 + log.info("[{}] update registration failed because client was already unregistered: [{}].", registration.getEndpoint(), stateException.getState());
234 243 } else {
235   - log.error("Client: [{}] updatedReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
236   - this.sendLogsToThingsboard(LOG_LW2M_ERROR + ": Client update Registration", registration.getId());
  244 + log.info("[{}] update registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());
237 245 }
238 246 } catch (Throwable t) {
239 247 log.error("[{}] endpoint [{}] error Unable update registration.", registration.getEndpoint(), t);
240   - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()), registration.getId());
  248 + this.sendLogsToThingsboard(lwM2MClient, LOG_LW2M_ERROR + String.format(": Client update Registration, %s", t.getMessage()));
241 249 }
242 250 });
243 251 }
... ... @@ -248,34 +256,32 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
248 256 */
249 257 public void unReg(Registration registration, Collection<Observation> observations) {
250 258 unRegistrationExecutor.submit(() -> {
  259 + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());
251 260 try {
252   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId());
253   - this.closeClientSession(registration);
  261 + this.sendLogsToThingsboard(client, LOG_LW2M_INFO + ": Client unRegistration");
  262 + clientContext.unregister(client, registration);
  263 + SessionInfoProto sessionInfo = client.getSession();
  264 + if (sessionInfo != null) {
  265 + transportService.deregisterSession(sessionInfo);
  266 + sessionStore.remove(registration.getEndpoint());
  267 + this.doCloseSession(sessionInfo);
  268 + log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
  269 + } else {
  270 + log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
  271 + }
  272 + } catch (LwM2MClientStateException stateException) {
  273 + log.info("[{}] delete registration: [{}] {}.", registration.getEndpoint(), stateException.getState(), stateException.getMessage());
254 274 } catch (Throwable t) {
255 275 log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t);
256   - this.sendLogsToThingsboard(LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()), registration.getId());
  276 + this.sendLogsToThingsboard(client, LOG_LW2M_ERROR + String.format(": Client Unable un Registration, %s", t.getMessage()));
257 277 }
258 278 });
259 279 }
260 280
261   - private void closeClientSession(Registration registration) {
262   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registration);
263   - if (sessionInfo != null) {
264   - transportService.deregisterSession(sessionInfo);
265   - sessionStore.remove(registration.getEndpoint());
266   - this.doCloseSession(sessionInfo);
267   - clientContext.removeClientByRegistrationId(registration.getId());
268   - log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType());
269   - } else {
270   - log.error("Client close session: [{}] unReg [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null);
271   - }
272   - }
273   -
274 281 @Override
275 282 public void onSleepingDev(Registration registration) {
276 283 log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint());
277   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId());
278   -
  284 + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is sleeping!");
279 285 //TODO: associate endpointId with device information.
280 286 }
281 287
... ... @@ -285,8 +291,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
285 291 @Override
286 292 public void setCancelObservationsAll(Registration registration) {
287 293 if (registration != null) {
288   - this.lwM2mTransportRequest.sendAllRequest(registration, null, OBSERVE_CANCEL_ALL,
289   - null, null, this.config.getTimeout(), null);
  294 + LwM2mClient client = clientContext.getClientByEndpoint(registration.getEndpoint());
  295 + if (client != null && client.getRegistration() != null && client.getRegistration().getId().equals(registration.getId())) {
  296 + this.lwM2mTransportRequest.sendAllRequest(client, null, OBSERVE_CANCEL_ALL,
  297 + null, null, this.config.getTimeout(), null);
  298 + }
290 299 }
291 300 }
292 301
... ... @@ -300,7 +309,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
300 309 @Override
301 310 public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) {
302 311 if (response.getContent() != null) {
303   - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
  312 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
304 313 ObjectModel objectModelVersion = lwM2MClient.getObjectModel(path, this.config.getModelProvider());
305 314 if (objectModelVersion != null) {
306 315 if (response.getContent() instanceof LwM2mObject) {
... ... @@ -332,7 +341,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
332 341 }
333 342 String msg = String.format("%s: type operation %s path - %s value - %s", LOG_LW2M_INFO,
334 343 READ, pathIdVer, value);
335   - this.sendLogsToThingsboard(msg, registration.getId());
  344 + this.sendLogsToThingsboard(lwM2MClient, msg);
336 345 rpcRequest.setValueMsg(String.format("%s", value));
337 346 this.sentRpcResponse(rpcRequest, response.getCode().getName(), (String) value, LOG_LW2M_VALUE);
338 347 }
... ... @@ -350,9 +359,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
350 359 */
351 360 @Override
352 361 public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) {
353   - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
  362 + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);
354 363 if (msg.getSharedUpdatedCount() > 0 && lwM2MClient != null) {
355   - log.warn ("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());
  364 + log.warn("2) OnAttributeUpdate, SharedUpdatedList() [{}]", msg.getSharedUpdatedList());
356 365 msg.getSharedUpdatedList().forEach(tsKvProto -> {
357 366 String pathName = tsKvProto.getKv().getKey();
358 367 String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName);
... ... @@ -377,13 +386,13 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
377 386 log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew);
378 387 String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated",
379 388 LOG_LW2M_ERROR, pathIdVer, valueNew);
380   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
  389 + this.sendLogsToThingsboard(lwM2MClient, logMsg);
381 390 }
382 391 } else if (!isFwSwWords(pathName)) {
383 392 log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew);
384 393 String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated",
385 394 LOG_LW2M_ERROR, pathName, valueNew);
386   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
  395 + this.sendLogsToThingsboard(lwM2MClient, logMsg);
387 396 }
388 397
389 398 });
... ... @@ -396,9 +405,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
396 405 }
397 406 });
398 407 log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo);
399   - }
400   - else if (lwM2MClient == null) {
401   - log.error ("OnAttributeUpdate, lwM2MClient is null");
  408 + } else if (lwM2MClient == null) {
  409 + log.error("OnAttributeUpdate, lwM2MClient is null");
402 410 }
403 411 }
404 412
... ... @@ -408,12 +416,11 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
408 416 */
409 417 @Override
410 418 public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) {
411   - Set<LwM2mClient> clients = clientContext.getLwM2mClients()
412   - .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toSet());
  419 + List<LwM2mClient> clients = clientContext.getLwM2mClients()
  420 + .stream().filter(e -> e.getProfileId().equals(deviceProfile.getUuidId())).collect(Collectors.toList());
413 421 clients.forEach(client -> client.onDeviceProfileUpdate(deviceProfile));
414   - Set<String> registrationIds = clients.stream().map(LwM2mClient::getRegistration).map(Registration::getId).collect(Collectors.toSet());
415   - if (registrationIds.size() > 0) {
416   - this.onDeviceProfileUpdate(registrationIds, deviceProfile);
  422 + if (clients.size() > 0) {
  423 + this.onDeviceProfileUpdate(clients, deviceProfile);
417 424 }
418 425 }
419 426
... ... @@ -446,7 +453,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
446 453 public void onToDeviceRpcRequest(TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg, SessionInfoProto sessionInfo) {
447 454 // #1
448 455 this.checkRpcRequestTimeout();
449   - log.warn ("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
  456 + log.warn("4) toDeviceRpcRequestMsg: [{}], sessionUUID: [{}]", toDeviceRpcRequestMsg, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
450 457 String bodyParams = StringUtils.trimToNull(toDeviceRpcRequestMsg.getParams()) != null ? toDeviceRpcRequestMsg.getParams() : "null";
451 458 LwM2mTypeOper lwM2mTypeOper = setValidTypeOper(toDeviceRpcRequestMsg.getMethodName());
452 459 UUID requestUUID = new UUID(toDeviceRpcRequestMsg.getRequestIdMSB(), toDeviceRpcRequestMsg.getRequestIdLSB());
... ... @@ -454,13 +461,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
454 461 this.rpcSubscriptions.put(requestUUID, toDeviceRpcRequestMsg.getExpirationTime());
455 462 Lwm2mClientRpcRequest lwm2mClientRpcRequest = null;
456 463 try {
457   - Registration registration = clientContext.getClient(sessionInfo).getRegistration();
  464 + LwM2mClient client = clientContext.getClientBySessionInfo(sessionInfo);
  465 + Registration registration = client.getRegistration();
458 466 lwm2mClientRpcRequest = new Lwm2mClientRpcRequest(lwM2mTypeOper, bodyParams, toDeviceRpcRequestMsg.getRequestId(), sessionInfo, registration, this);
459 467 if (lwm2mClientRpcRequest.getErrorMsg() != null) {
460 468 lwm2mClientRpcRequest.setResponseCode(BAD_REQUEST.name());
461 469 this.onToDeviceRpcResponse(lwm2mClientRpcRequest.getDeviceRpcResponseResultMsg(), sessionInfo);
462 470 } else {
463   - lwM2mTransportRequest.sendAllRequest(registration, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(),
  471 + lwM2mTransportRequest.sendAllRequest(client, lwm2mClientRpcRequest.getTargetIdVer(), lwm2mClientRpcRequest.getTypeOper(),
464 472 null,
465 473 lwm2mClientRpcRequest.getValue() == null ? lwm2mClientRpcRequest.getParams() : lwm2mClientRpcRequest.getValue(),
466 474 this.config.getTimeout(), lwm2mClientRpcRequest);
... ... @@ -506,7 +514,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
506 514
507 515 @Override
508 516 public void onToDeviceRpcResponse(TransportProtos.ToDeviceRpcResponseMsg toDeviceResponse, SessionInfoProto sessionInfo) {
509   - log.warn ("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
  517 + log.warn("5) onToDeviceRpcResponse: [{}], sessionUUID: [{}]", toDeviceResponse, new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()));
510 518 transportService.process(sessionInfo, toDeviceResponse, null);
511 519 }
512 520
... ... @@ -515,17 +523,6 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
515 523 }
516 524
517 525 /**
518   - * Trigger Server path = "/1/0/8"
519   - * <p>
520   - * Trigger bootStrap path = "/1/0/9" - have to implemented on client
521   - */
522   - @Override
523   - public void doTrigger(Registration registration, String path) {
524   - lwM2mTransportRequest.sendAllRequest(registration, path, EXECUTE,
525   - ContentFormat.TLV.getName(), null, this.config.getTimeout(), null);
526   - }
527   -
528   - /**
529 526 * Deregister session in transport
530 527 *
531 528 * @param sessionInfo - lwm2m client
... ... @@ -558,7 +555,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
558 555 @Override
559 556 public void onAwakeDev(Registration registration) {
560 557 log.trace("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint());
561   - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId());
  558 + this.sendLogsToThingsboard(clientContext.getClientByEndpoint(registration.getEndpoint()), LOG_LW2M_INFO + ": Client is awake!");
562 559 //TODO: associate endpointId with device information.
563 560 }
564 561
... ... @@ -567,13 +564,17 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
567 564 * @param registrationId - Id of Registration LwM2M Client
568 565 */
569 566 @Override
570   - public void sendLogsToThingsboard(String logMsg, String registrationId) {
571   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(registrationId);
572   - if (logMsg != null && sessionInfo != null) {
  567 + public void sendLogsToThingsboard(String registrationId, String logMsg) {
  568 + sendLogsToThingsboard(clientContext.getClientByRegistrationId(registrationId), logMsg);
  569 + }
  570 +
  571 + @Override
  572 + public void sendLogsToThingsboard(LwM2mClient client, String logMsg) {
  573 + if (logMsg != null && client != null && client.getSession() != null) {
573 574 if (logMsg.length() > 1024) {
574 575 logMsg = logMsg.substring(0, 1024);
575 576 }
576   - this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), sessionInfo);
  577 + this.helper.sendParametersOnThingsboardTelemetry(this.helper.getKvStringtoThingsboard(LOG_LW2M_TELEMETRY, logMsg), client.getSession());
577 578 }
578 579 }
579 580
... ... @@ -586,24 +587,23 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
586 587 * - Read Request to the client after registration to read all resource values for all objects
587 588 * - then Observe Request to the client marked as observe from the profile configuration.
588 589 *
589   - * @param registration - Registration LwM2M Client
590   - * @param lwM2MClient - object with All parameters off client
  590 + * @param lwM2MClient - object with All parameters off client
591 591 */
592   - private void initLwM2mFromClientValue(Registration registration, LwM2mClient lwM2MClient) {
593   - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);
594   - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
  592 + private void initClientTelemetry(LwM2mClient lwM2MClient) {
  593 + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId());
  594 + Set<String> clientObjects = clientContext.getSupportedIdVerInClient(lwM2MClient);
595 595 if (clientObjects != null && clientObjects.size() > 0) {
596 596 if (LWM2M_STRATEGY_2 == LwM2mTransportUtil.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) {
597 597 // #2
598 598 lwM2MClient.getPendingReadRequests().addAll(clientObjects);
599   - clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(),
  599 + clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, READ,
600 600 null, this.config.getTimeout(), null));
601 601 }
602 602 // #1
603   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, READ, clientObjects);
604   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, OBSERVE, clientObjects);
605   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, WRITE_ATTRIBUTES, clientObjects);
606   - this.initReadAttrTelemetryObserveToClient(registration, lwM2MClient, DISCOVER, clientObjects);
  603 + this.initReadAttrTelemetryObserveToClient(lwM2MClient, READ, clientObjects);
  604 + this.initReadAttrTelemetryObserveToClient(lwM2MClient, OBSERVE, clientObjects);
  605 + this.initReadAttrTelemetryObserveToClient(lwM2MClient, WRITE_ATTRIBUTES, clientObjects);
  606 + this.initReadAttrTelemetryObserveToClient(lwM2MClient, DISCOVER, clientObjects);
607 607 }
608 608 }
609 609
... ... @@ -645,7 +645,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
645 645 * @param path - resource
646 646 */
647 647 private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) {
648   - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
  648 + LwM2mClient lwM2MClient = clientContext.getClientByEndpoint(registration.getEndpoint());
649 649 if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.config.getModelProvider())) {
650 650 /** version != null
651 651 * set setClient_fw_info... = value
... ... @@ -740,15 +740,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
740 740 }
741 741 }
742 742
743   - /**
744   - * Start observe/read: Attr/Telemetry
745   - * #1 - Analyze: path in resource profile == client resource
746   - *
747   - * @param registration -
748   - */
749   - private void initReadAttrTelemetryObserveToClient(Registration registration, LwM2mClient lwM2MClient,
750   - LwM2mTypeOper typeOper, Set<String> clientObjects) {
751   - LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(registration);
  743 + private void initReadAttrTelemetryObserveToClient(LwM2mClient lwM2MClient, LwM2mTypeOper typeOper, Set<String> clientObjects) {
  744 + LwM2mClientProfile lwM2MClientProfile = clientContext.getProfile(lwM2MClient.getProfileId());
752 745 Set<String> result = null;
753 746 ConcurrentHashMap<String, Object> params = null;
754 747 if (READ.equals(typeOper)) {
... ... @@ -768,28 +761,42 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
768 761 params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile());
769 762 result = params.keySet();
770 763 }
771   - if (result != null && !result.isEmpty()) {
772   - // #1
773   - Set<String> pathSend = result.stream().filter(target -> {
774   - return target.split(LWM2M_SEPARATOR_PATH).length < 3 ?
775   - clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) :
776   - clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]);
777   - }
  764 + sendRequestsToClient(lwM2MClient, typeOper, clientObjects, result, params);
  765 + }
  766 +
  767 + private void sendRequestsToClient(LwM2mClient lwM2MClient, LwM2mTypeOper operationType, Set<String> supportedObjectIds, Set<String> desiredObjectIds, ConcurrentHashMap<String, Object> params) {
  768 + if (desiredObjectIds != null && !desiredObjectIds.isEmpty()) {
  769 + Set<String> targetObjectIds = desiredObjectIds.stream().filter(target -> isSupportedTargetId(supportedObjectIds, target)
778 770 ).collect(Collectors.toUnmodifiableSet());
779   - if (!pathSend.isEmpty()) {
780   - lwM2MClient.getPendingReadRequests().addAll(pathSend);
781   - ConcurrentHashMap<String, Object> finalParams = params;
782   - pathSend.forEach(target -> {
783   - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(),
784   - finalParams != null ? finalParams.get(target) : null, this.config.getTimeout(), null);
  771 + if (!targetObjectIds.isEmpty()) {
  772 + //TODO: remove this side effect?
  773 + lwM2MClient.getPendingReadRequests().addAll(targetObjectIds);
  774 + targetObjectIds.forEach(target -> {
  775 + Object additionalParams = params != null ? params.get(target) : null;
  776 + lwM2mTransportRequest.sendAllRequest(lwM2MClient, target, operationType, additionalParams, this.config.getTimeout(), null);
785 777 });
786   - if (OBSERVE.equals(typeOper)) {
  778 + if (OBSERVE.equals(operationType)) {
787 779 lwM2MClient.initReadValue(this, null);
788 780 }
789 781 }
790 782 }
791 783 }
792 784
  785 + private boolean isSupportedTargetId(Set<String> supportedIds, String targetId) {
  786 + String[] targetIdParts = targetId.split(LWM2M_SEPARATOR_PATH);
  787 + if (targetIdParts.length <= 1) {
  788 + return false;
  789 + }
  790 + String targetIdSearch = targetIdParts[0];
  791 + for (int i = 1; i < targetIdParts.length; i++) {
  792 + targetIdSearch += "/" + targetIdParts[i];
  793 + if (supportedIds.contains(targetIdSearch)) {
  794 + return true;
  795 + }
  796 + }
  797 + return false;
  798 + }
  799 +
793 800 private ConcurrentHashMap<String, Object> getPathForWriteAttributes(JsonObject objectJson) {
794 801 ConcurrentHashMap<String, Object> pathAttributes = new Gson().fromJson(objectJson.toString(),
795 802 new TypeToken<ConcurrentHashMap<String, Object>>() {
... ... @@ -798,7 +805,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
798 805 }
799 806
800 807 private void onDeviceUpdate(LwM2mClient lwM2MClient, Device device, Optional<DeviceProfile> deviceProfileOpt) {
801   - deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singleton(lwM2MClient.getRegistration().getId()), deviceProfile));
  808 + deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceProfileUpdate(Collections.singletonList(lwM2MClient), deviceProfile));
802 809 lwM2MClient.onDeviceUpdate(device, deviceProfileOpt);
803 810 }
804 811
... ... @@ -843,7 +850,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
843 850 }
844 851
845 852 private TransportProtos.KeyValueProto getKvToThingsboard(String pathIdVer, Registration registration) {
846   - LwM2mClient lwM2MClient = this.clientContext.getClientByRegistrationId(registration.getId());
  853 + LwM2mClient lwM2MClient = this.clientContext.getClientByEndpoint(registration.getEndpoint());
847 854 JsonObject names = clientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile();
848 855 if (names != null && names.has(pathIdVer)) {
849 856 String resourceName = names.get(pathIdVer).getAsString();
... ... @@ -858,7 +865,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
858 865 valueKvProto = new JsonObject();
859 866 Object finalvalueKvProto = valueKvProto;
860 867 Gson gson = new GsonBuilder().create();
861   - resourceValue.getValues().forEach((k, v) -> {
  868 + resourceValue.getInstances().forEach((k, v) -> {
862 869 Object val = this.converter.convertValue(v, currentType, expectedType,
863 870 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
864 871 JsonElement element = gson.toJsonTree(val, val.getClass());
... ... @@ -892,9 +899,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
892 899 ResourceModel.Type expectedType = this.helper.getResourceModelTypeEqualsKvProtoValueType(currentType, pathIdVer);
893 900 return this.converter.convertValue(resourceValue.getValue(), currentType, expectedType,
894 901 new LwM2mPath(convertPathFromIdVerToObjectId(pathIdVer)));
895   - }
896   -
897   - else {
  902 + } else {
898 903 return null;
899 904 }
900 905 }
... ... @@ -955,10 +960,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
955 960 * #6.1 - update WriteAttribute
956 961 * #6.2 - del WriteAttribute
957 962 *
958   - * @param registrationIds -
959   - * @param deviceProfile -
  963 + * @param clients -
  964 + * @param deviceProfile -
960 965 */
961   - private void onDeviceProfileUpdate(Set<String> registrationIds, DeviceProfile deviceProfile) {
  966 + private void onDeviceProfileUpdate(List<LwM2mClient> clients, DeviceProfile deviceProfile) {
962 967 LwM2mClientProfile lwM2MClientProfileOld = clientContext.getProfiles().get(deviceProfile.getUuidId()).clone();
963 968 if (clientContext.profileUpdate(deviceProfile) != null) {
964 969 // #1
... ... @@ -1009,15 +1014,14 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1009 1014
1010 1015 // #3.4, #6
1011 1016 if (!attributeLwm2mOld.equals(attributeLwm2mNew)) {
1012   - this.getAnalyzerAttributeLwm2m(registrationIds, attributeLwm2mOld, attributeLwm2mNew);
  1017 + this.getAnalyzerAttributeLwm2m(clients, attributeLwm2mOld, attributeLwm2mNew);
1013 1018 }
1014 1019
1015 1020 // #4.1 add
1016 1021 if (sendAttrToThingsboard.getPathPostParametersAdd().size() > 0) {
1017 1022 // update value in Resources
1018   - registrationIds.forEach(registrationId -> {
1019   - Registration registration = clientContext.getRegistration(registrationId);
1020   - this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
  1023 + clients.forEach(client -> {
  1024 + this.readObserveFromProfile(client, sendAttrToThingsboard.getPathPostParametersAdd(), READ);
1021 1025 });
1022 1026 }
1023 1027 // #4.2 del
... ... @@ -1041,15 +1045,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1041 1045 // does not include oldObserve
1042 1046 ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sendObserveToClientOld.getPathPostParametersAdd(), sendObserveToClientNew.getPathPostParametersAdd());
1043 1047 // send Request observe to Client
1044   - registrationIds.forEach(registrationId -> {
1045   - Registration registration = clientContext.getRegistration(registrationId);
  1048 + clients.forEach(client -> {
  1049 + Registration registration = client.getRegistration();
1046 1050 if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) {
1047   - this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
  1051 + this.readObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE);
1048 1052 }
1049 1053 // 5.3 del
1050 1054 // send Request cancel observe to Client
1051 1055 if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) {
1052   - this.cancelObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersDel());
  1056 + this.cancelObserveFromProfile(client, postObserveAnalyzer.getPathPostParametersDel());
1053 1057 }
1054 1058 });
1055 1059 }
... ... @@ -1086,19 +1090,18 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1086 1090 * Update Resource value after change RezAttrTelemetry in config Profile
1087 1091 * send response Read to Client and add path to pathResAttrTelemetry in LwM2MClient.getAttrTelemetryObserveValue()
1088 1092 *
1089   - * @param registration - Registration LwM2M Client
1090   - * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]
  1093 + * @param targets - path Resources == [ "/2/0/0", "/2/0/1"]
1091 1094 */
1092   - private void readObserveFromProfile(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) {
  1095 + private void readObserveFromProfile(LwM2mClient client, Set<String> targets, LwM2mTypeOper typeOper) {
1093 1096 targets.forEach(target -> {
1094 1097 LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target));
1095 1098 if (pathIds.isResource()) {
1096 1099 if (READ.equals(typeOper)) {
1097   - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
1098   - ContentFormat.TLV.getName(), null, this.config.getTimeout(), null);
  1100 + lwM2mTransportRequest.sendAllRequest(client, target, typeOper,
  1101 + null, this.config.getTimeout(), null);
1099 1102 } else if (OBSERVE.equals(typeOper)) {
1100   - lwM2mTransportRequest.sendAllRequest(registration, target, typeOper,
1101   - null, null, this.config.getTimeout(), null);
  1103 + lwM2mTransportRequest.sendAllRequest(client, target, typeOper,
  1104 + null, this.config.getTimeout(), null);
1102 1105 }
1103 1106 }
1104 1107 });
... ... @@ -1124,7 +1127,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1124 1127 * @param attributeLwm2mNew -
1125 1128 * @return
1126 1129 */
1127   - private void getAnalyzerAttributeLwm2m(Set<String> registrationIds, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) {
  1130 + private void getAnalyzerAttributeLwm2m(List<LwM2mClient> clients, JsonObject attributeLwm2mOld, JsonObject attributeLwm2mNew) {
1128 1131 ResultsAnalyzerParameters analyzerParameters = new ResultsAnalyzerParameters();
1129 1132 ConcurrentHashMap<String, Object> lwm2mAttributesOld = new Gson().fromJson(attributeLwm2mOld.toString(),
1130 1133 new TypeToken<ConcurrentHashMap<String, Object>>() {
... ... @@ -1146,23 +1149,22 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1146 1149 // #6
1147 1150 // #6.2
1148 1151 if (analyzerParameters.getPathPostParametersAdd().size() > 0) {
1149   - registrationIds.forEach(registrationId -> {
1150   - Registration registration = this.clientContext.getRegistration(registrationId);
1151   - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
  1152 + clients.forEach(client -> {
  1153 + Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);
1152 1154 Set<String> pathSend = analyzerParameters.getPathPostParametersAdd().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
1153 1155 .collect(Collectors.toUnmodifiableSet());
1154 1156 if (!pathSend.isEmpty()) {
1155 1157 ConcurrentHashMap<String, Object> finalParams = lwm2mAttributesNew;
1156   - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
  1158 + pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES,
1157 1159 finalParams.get(target), this.config.getTimeout(), null));
1158 1160 }
1159 1161 });
1160 1162 }
1161 1163 // #6.2
1162 1164 if (analyzerParameters.getPathPostParametersDel().size() > 0) {
1163   - registrationIds.forEach(registrationId -> {
1164   - Registration registration = this.clientContext.getRegistration(registrationId);
1165   - Set<String> clientObjects = clientContext.getSupportedIdVerInClient(registration);
  1165 + clients.forEach(client -> {
  1166 + Registration registration = client.getRegistration();
  1167 + Set<String> clientObjects = clientContext.getSupportedIdVerInClient(client);
1166 1168 Set<String> pathSend = analyzerParameters.getPathPostParametersDel().stream().filter(target -> clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]))
1167 1169 .collect(Collectors.toUnmodifiableSet());
1168 1170 if (!pathSend.isEmpty()) {
... ... @@ -1170,8 +1172,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1170 1172 Map<String, Object> params = (Map<String, Object>) lwm2mAttributesOld.get(target);
1171 1173 params.clear();
1172 1174 params.put(OBJECT_VERSION, "");
1173   - lwM2mTransportRequest.sendAllRequest(registration, target, WRITE_ATTRIBUTES, ContentFormat.TLV.getName(),
1174   - params, this.config.getTimeout(), null);
  1175 + lwM2mTransportRequest.sendAllRequest(client, target, WRITE_ATTRIBUTES, params, this.config.getTimeout(), null);
1175 1176 });
1176 1177 }
1177 1178 });
... ... @@ -1179,12 +1180,10 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1179 1180
1180 1181 }
1181 1182
1182   - private void cancelObserveFromProfile(Registration registration, Set<String> paramAnallyzer) {
1183   - LwM2mClient lwM2MClient = clientContext.getOrRegister(registration);
  1183 + private void cancelObserveFromProfile(LwM2mClient lwM2mClient, Set<String> paramAnallyzer) {
1184 1184 paramAnallyzer.forEach(pathIdVer -> {
1185   - if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) {
1186   - lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, OBSERVE_CANCEL, null,
1187   - null, this.config.getTimeout(), null);
  1185 + if (this.getResourceValueFromLwM2MClient(lwM2mClient, pathIdVer) != null) {
  1186 + lwM2mTransportRequest.sendAllRequest(lwM2mClient, pathIdVer, OBSERVE_CANCEL, null, this.config.getTimeout(), null);
1188 1187 }
1189 1188 }
1190 1189 );
... ... @@ -1192,14 +1191,12 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1192 1191
1193 1192 private void updateResourcesValueToClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) {
1194 1193 if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) {
1195   - lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), path, WRITE_REPLACE,
1196   - ContentFormat.TLV.getName(), valueNew,
1197   - this.config.getTimeout(), null);
  1194 + lwM2mTransportRequest.sendAllRequest(lwM2MClient, path, WRITE_REPLACE, valueNew, this.config.getTimeout(), null);
1198 1195 } else {
1199 1196 log.error("Failed update resource [{}] [{}]", path, valueNew);
1200 1197 String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad",
1201 1198 LOG_LW2M_ERROR, path, valueNew);
1202   - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId());
  1199 + this.sendLogsToThingsboard(lwM2MClient, logMsg);
1203 1200 log.info("Failed update resource [{}] [{}]", path, valueNew);
1204 1201 }
1205 1202 }
... ... @@ -1221,7 +1218,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1221 1218 */
1222 1219 public String getPresentPathIntoProfile(TransportProtos.SessionInfoProto sessionInfo, String name) {
1223 1220 LwM2mClientProfile profile = clientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB()));
1224   - LwM2mClient lwM2mClient = clientContext.getClient(sessionInfo);
  1221 + LwM2mClient lwM2mClient = clientContext.getClientBySessionInfo(sessionInfo);
1225 1222 return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream()
1226 1223 .filter(e -> e.getValue().getAsString().equals(name) && validateResourceInModel(lwM2mClient, e.getKey(), false)).findFirst().map(Map.Entry::getKey)
1227 1224 .orElse(null);
... ... @@ -1256,7 +1253,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1256 1253 * @param sessionInfo
1257 1254 */
1258 1255 public void updateAttributeFromThingsboard(List<TransportProtos.TsKvProto> tsKvProtos, TransportProtos.SessionInfoProto sessionInfo) {
1259   - LwM2mClient lwM2MClient = clientContext.getClient(sessionInfo);
  1256 + LwM2mClient lwM2MClient = clientContext.getClientBySessionInfo(sessionInfo);
1260 1257 if (lwM2MClient != null) {
1261 1258 log.warn("1) UpdateAttributeFromThingsboard, tsKvProtos [{}]", tsKvProtos);
1262 1259 tsKvProtos.forEach(tsKvProto -> {
... ... @@ -1275,8 +1272,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1275 1272 this.updateResourcesValueToClient(lwM2MClient, this.getResourceValueFormatKv(lwM2MClient, pathIdVer),
1276 1273 getValueFromKvProto(tsKvProto.getKv()), pathIdVer);
1277 1274 });
1278   - }
1279   - else {
  1275 + } else {
1280 1276 log.error("UpdateAttributeFromThingsboard, lwM2MClient is null");
1281 1277 }
1282 1278 }
... ... @@ -1285,14 +1281,9 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1285 1281 * @param lwM2MClient -
1286 1282 * @return SessionInfoProto -
1287 1283 */
1288   - private SessionInfoProto getSessionInfoOrCloseSession(LwM2mClient lwM2MClient) {
1289   - if (lwM2MClient != null) {
1290   - SessionInfoProto sessionInfoProto = lwM2MClient.getSession();
1291   - if (sessionInfoProto == null) {
1292   - log.info("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED);
1293   - this.closeClientSession(lwM2MClient.getRegistration());
1294   - }
1295   - return sessionInfoProto;
  1284 + private SessionInfoProto getSessionInfo(LwM2mClient lwM2MClient) {
  1285 + if (lwM2MClient != null && lwM2MClient.getSession() != null) {
  1286 + return lwM2MClient.getSession();
1296 1287 }
1297 1288 return null;
1298 1289 }
... ... @@ -1302,15 +1293,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1302 1293 * @return - sessionInfo after access connect client
1303 1294 */
1304 1295 public SessionInfoProto getSessionInfoOrCloseSession(Registration registration) {
1305   - return getSessionInfoOrCloseSession(clientContext.getOrRegister(registration));
1306   - }
1307   -
1308   - /**
1309   - * @param registrationId -
1310   - * @return -
1311   - */
1312   - private SessionInfoProto getSessionInfoOrCloseSession(String registrationId) {
1313   - return getSessionInfoOrCloseSession(clientContext.getClientByRegistrationId(registrationId));
  1296 + return getSessionInfo(clientContext.getClientByEndpoint(registration.getEndpoint()));
1314 1297 }
1315 1298
1316 1299 /**
... ... @@ -1340,7 +1323,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1340 1323 * @param lwM2MClient - LwM2M Client
1341 1324 */
1342 1325 public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) {
1343   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
  1326 + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);
1344 1327 if (sessionInfo != null) {
1345 1328 //#1.1
1346 1329 ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient);
... ... @@ -1359,7 +1342,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1359 1342
1360 1343 public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) {
1361 1344 if (lwM2MClient.getRegistration().getSupportedVersion(FW_ID) != null) {
1362   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
  1345 + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);
1363 1346 if (sessionInfo != null) {
1364 1347 DefaultLwM2MTransportMsgHandler handler = this;
1365 1348 this.transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.FIRMWARE.name()),
... ... @@ -1368,16 +1351,15 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1368 1351 public void onSuccess(TransportProtos.GetOtaPackageResponseMsg response) {
1369 1352 if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())
1370 1353 && response.getType().equals(OtaPackageType.FIRMWARE.name())) {
1371   - log.warn ("7) firmware start with ver: [{}]", response.getVersion());
  1354 + log.warn("7) firmware start with ver: [{}]", response.getVersion());
1372 1355 lwM2MClient.getFwUpdate().setRpcRequest(rpcRequest);
1373 1356 lwM2MClient.getFwUpdate().setCurrentVersion(response.getVersion());
1374 1357 lwM2MClient.getFwUpdate().setCurrentTitle(response.getTitle());
1375 1358 lwM2MClient.getFwUpdate().setCurrentId(new OtaPackageId(new UUID(response.getOtaPackageIdMSB(), response.getOtaPackageIdLSB())).getId());
1376 1359 if (rpcRequest == null) {
1377 1360 lwM2MClient.getFwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
1378   - }
1379   - else {
1380   - lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
  1361 + } else {
  1362 + lwM2MClient.getFwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
1381 1363 }
1382 1364 } else {
1383 1365 log.trace("OtaPackage [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
... ... @@ -1395,7 +1377,7 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1395 1377
1396 1378 public void getInfoSoftwareUpdate(LwM2mClient lwM2MClient, Lwm2mClientRpcRequest rpcRequest) {
1397 1379 if (lwM2MClient.getRegistration().getSupportedVersion(SW_ID) != null) {
1398   - SessionInfoProto sessionInfo = this.getSessionInfoOrCloseSession(lwM2MClient);
  1380 + SessionInfoProto sessionInfo = this.getSessionInfo(lwM2MClient);
1399 1381 if (sessionInfo != null) {
1400 1382 DefaultLwM2MTransportMsgHandler handler = this;
1401 1383 transportService.process(sessionInfo, createOtaPackageRequestMsg(sessionInfo, OtaPackageType.SOFTWARE.name()),
... ... @@ -1411,9 +1393,8 @@ public class DefaultLwM2MTransportMsgHandler implements LwM2mTransportMsgHandler
1411 1393 lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
1412 1394 if (rpcRequest == null) {
1413 1395 lwM2MClient.getSwUpdate().sendReadObserveInfo(lwM2mTransportRequest);
1414   - }
1415   - else {
1416   - lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
  1396 + } else {
  1397 + lwM2MClient.getSwUpdate().writeFwSwWare(handler, lwM2mTransportRequest);
1417 1398 }
1418 1399 } else {
1419 1400 log.trace("Software [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString());
... ...
... ... @@ -36,6 +36,8 @@ import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC;
36 36 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MAuthorizer;
37 37 import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MDtlsCertificateVerifier;
38 38 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  39 +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore;
  40 +import org.thingsboard.server.transport.lwm2m.server.store.TbSecurityStore;
39 41 import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
40 42
41 43 import javax.annotation.PostConstruct;
... ... @@ -83,7 +85,7 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService {
83 85 private final LwM2mTransportServerHelper helper;
84 86 private final LwM2mTransportMsgHandler handler;
85 87 private final CaliforniumRegistrationStore registrationStore;
86   - private final EditableSecurityStore securityStore;
  88 + private final TbSecurityStore securityStore;
87 89 private final LwM2mClientContext lwM2mClientContext;
88 90 private final TbLwM2MDtlsCertificateVerifier certificateVerifier;
89 91 private final TbLwM2MAuthorizer authorizer;
... ...
... ... @@ -87,7 +87,7 @@ public class LwM2mServerListener {
87 87 @Override
88 88 public void cancelled(Observation observation) {
89 89 String msg = String.format("%s: Canceled Observation %s.", LOG_LW2M_INFO, observation.getPath());
90   - service.sendLogsToThingsboard(msg, observation.getRegistrationId());
  90 + service.sendLogsToThingsboard(observation.getRegistrationId(), msg);
91 91 log.warn(msg);
92 92 }
93 93
... ... @@ -109,7 +109,7 @@ public class LwM2mServerListener {
109 109 String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO,
110 110 observation.getPath());
111 111 log.warn(msg);
112   - service.sendLogsToThingsboard(msg, registration.getId());
  112 + service.sendLogsToThingsboard(registration.getId(), msg);
113 113 }
114 114 };
115 115 }
... ...
... ... @@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.Device;
22 22 import org.thingsboard.server.common.data.DeviceProfile;
23 23 import org.thingsboard.server.gen.transport.TransportProtos;
24 24 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
  25 +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
25 26 import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest;
26 27
27 28 import java.util.Collection;
... ... @@ -57,13 +58,13 @@ public interface LwM2mTransportMsgHandler {
57 58
58 59 void onToServerRpcResponse(TransportProtos.ToServerRpcResponseMsg toServerResponse);
59 60
60   - void doTrigger(Registration registration, String path);
61   -
62 61 void doDisconnect(TransportProtos.SessionInfoProto sessionInfo);
63 62
64 63 void onAwakeDev(Registration registration);
65 64
66   - void sendLogsToThingsboard(String msg, String registrationId);
  65 + void sendLogsToThingsboard(LwM2mClient client, String msg);
  66 +
  67 + void sendLogsToThingsboard(String registrationId, String msg);
67 68
68 69 LwM2MTransportServerConfig getConfig();
69 70 }
... ...
... ... @@ -32,10 +32,10 @@ import org.eclipse.leshan.core.observation.Observation;
32 32 import org.eclipse.leshan.core.request.ContentFormat;
33 33 import org.eclipse.leshan.core.request.DeleteRequest;
34 34 import org.eclipse.leshan.core.request.DiscoverRequest;
35   -import org.eclipse.leshan.core.request.DownlinkRequest;
36 35 import org.eclipse.leshan.core.request.ExecuteRequest;
37 36 import org.eclipse.leshan.core.request.ObserveRequest;
38 37 import org.eclipse.leshan.core.request.ReadRequest;
  38 +import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
39 39 import org.eclipse.leshan.core.request.WriteAttributesRequest;
40 40 import org.eclipse.leshan.core.request.WriteRequest;
41 41 import org.eclipse.leshan.core.request.exception.ClientSleepingException;
... ... @@ -116,32 +116,30 @@ public class LwM2mTransportRequest {
116 116 new NamedThreadFactory(String.format("LwM2M %s channel response after request", RESPONSE_REQUEST_CHANNEL)));
117 117 }
118 118
119   - /**
120   - * Device management and service enablement, including Read, Write, Execute, Discover, Create, Delete and Write-Attributes
121   - *
122   - * @param registration -
123   - * @param targetIdVer -
124   - * @param typeOper -
125   - * @param contentFormatName -
126   - */
  119 + public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) {
  120 + sendAllRequest(lwM2MClient, targetIdVer, typeOper, lwM2MClient.getDefaultContentFormat(), params, timeoutInMs, lwm2mClientRpcRequest);
  121 + }
  122 +
127 123
128   - public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper,
129   - String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) {
  124 + public void sendAllRequest(LwM2mClient lwM2MClient, String targetIdVer, LwM2mTypeOper typeOper,
  125 + ContentFormat contentFormat, Object params, long timeoutInMs, Lwm2mClientRpcRequest lwm2mClientRpcRequest) {
  126 + Registration registration = lwM2MClient.getRegistration();
130 127 try {
131 128 String target = convertPathFromIdVerToObjectId(targetIdVer);
132   - ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT;
133   - LwM2mClient lwM2MClient = this.lwM2mClientContext.getOrRegister(registration);
  129 + if(contentFormat == null){
  130 + contentFormat = ContentFormat.DEFAULT;
  131 + }
134 132 LwM2mPath resultIds = target != null ? new LwM2mPath(target) : null;
135 133 if (!OBSERVE_CANCEL.name().equals(typeOper.name()) && resultIds != null && registration != null && resultIds.getObjectId() >= 0 && lwM2MClient != null) {
136 134 if (lwM2MClient.isValidObjectVersion(targetIdVer)) {
137 135 timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT;
138   - DownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,
  136 + SimpleDownlinkRequest request = createRequest(registration, lwM2MClient, typeOper, contentFormat, target,
139 137 targetIdVer, resultIds, params, lwm2mClientRpcRequest);
140 138 if (request != null) {
141 139 try {
142 140 this.sendRequest(registration, lwM2MClient, request, timeoutInMs, lwm2mClientRpcRequest);
143 141 } catch (ClientSleepingException e) {
144   - DownlinkRequest finalRequest = request;
  142 + SimpleDownlinkRequest finalRequest = request;
145 143 long finalTimeoutInMs = timeoutInMs;
146 144 Lwm2mClientRpcRequest finalRpcRequest = lwm2mClientRpcRequest;
147 145 lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, finalRpcRequest));
... ... @@ -185,7 +183,7 @@ public class LwM2mTransportRequest {
185 183 }
186 184 String msg = String.format("%s: type operation %s paths - %s", LOG_LW2M_INFO,
187 185 typeOper.name(), paths);
188   - this.handler.sendLogsToThingsboard(msg, registration.getId());
  186 + this.handler.sendLogsToThingsboard(lwM2MClient, msg);
189 187 if (lwm2mClientRpcRequest != null) {
190 188 String valueMsg = String.format("Paths - %s", paths);
191 189 this.handler.sentRpcResponse(lwm2mClientRpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE);
... ... @@ -204,7 +202,7 @@ public class LwM2mTransportRequest {
204 202 observeCancelMsg = String.format("%s: type operation %s paths: All count: %d", LOG_LW2M_INFO,
205 203 OBSERVE_CANCEL.name(), observeCancelCnt);
206 204 }
207   - this.afterObserveCancel(registration, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest);
  205 + this.afterObserveCancel(lwM2MClient, observeCancelCnt, observeCancelMsg, lwm2mClientRpcRequest);
208 206 break;
209 207 // lwm2mClientRpcRequest != null
210 208 case FW_UPDATE:
... ... @@ -215,7 +213,7 @@ public class LwM2mTransportRequest {
215 213 } catch (Exception e) {
216 214 String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR,
217 215 typeOper.name(), e.getMessage());
218   - handler.sendLogsToThingsboard(msg, registration.getId());
  216 + handler.sendLogsToThingsboard(lwM2MClient, msg);
219 217 if (lwm2mClientRpcRequest != null) {
220 218 String errorMsg = String.format("Path %s type operation %s %s", targetIdVer, typeOper.name(), e.getMessage());
221 219 handler.sentRpcResponse(lwm2mClientRpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR);
... ... @@ -223,10 +221,10 @@ public class LwM2mTransportRequest {
223 221 }
224 222 }
225 223
226   - private DownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,
  224 + private SimpleDownlinkRequest createRequest(Registration registration, LwM2mClient lwM2MClient, LwM2mTypeOper typeOper,
227 225 ContentFormat contentFormat, String target, String targetIdVer,
228 226 LwM2mPath resultIds, Object params, Lwm2mClientRpcRequest rpcRequest) {
229   - DownlinkRequest request = null;
  227 + SimpleDownlinkRequest request = null;
230 228 switch (typeOper) {
231 229 case READ:
232 230 request = new ReadRequest(contentFormat, target);
... ... @@ -273,7 +271,7 @@ public class LwM2mTransportRequest {
273 271 contentFormat = getContentFormatByResourceModelType(resourceModelWrite, contentFormat);
274 272 request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(),
275 273 resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModelWrite.type,
276   - registration, rpcRequest);
  274 + lwM2MClient, rpcRequest);
277 275 }
278 276 break;
279 277 case WRITE_UPDATE:
... ... @@ -329,7 +327,7 @@ public class LwM2mTransportRequest {
329 327 */
330 328
331 329 @SuppressWarnings({"error sendRequest"})
332   - private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request,
  330 + private void sendRequest(Registration registration, LwM2mClient lwM2MClient, SimpleDownlinkRequest request,
333 331 long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) {
334 332 context.getServer().send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
335 333
... ... @@ -337,11 +335,11 @@ public class LwM2mTransportRequest {
337 335 lwM2MClient.initReadValue(this.handler, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration));
338 336 }
339 337 if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) {
340   - this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest);
  338 + this.handleResponse(lwM2MClient, request.getPath().toString(), response, request, rpcRequest);
341 339 } else {
342 340 String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(),
343 341 ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString());
344   - handler.sendLogsToThingsboard(msg, registration.getId());
  342 + handler.sendLogsToThingsboard(lwM2MClient, msg);
345 343 log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(),
346 344 ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString());
347 345 if (!lwM2MClient.isInit()) {
... ... @@ -388,7 +386,7 @@ public class LwM2mTransportRequest {
388 386 }
389 387 String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s",
390 388 LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage());
391   - handler.sendLogsToThingsboard(msg, registration.getId());
  389 + handler.sendLogsToThingsboard(lwM2MClient, msg);
392 390 log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString());
393 391 if (rpcRequest != null) {
394 392 handler.sentRpcResponse(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR);
... ... @@ -398,7 +396,7 @@ public class LwM2mTransportRequest {
398 396
399 397 private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId,
400 398 Integer resourceId, Object value, ResourceModel.Type type,
401   - Registration registration, Lwm2mClientRpcRequest rpcRequest) {
  399 + LwM2mClient client, Lwm2mClientRpcRequest rpcRequest) {
402 400 try {
403 401 if (type != null) {
404 402 switch (type) {
... ... @@ -433,7 +431,7 @@ public class LwM2mTransportRequest {
433 431 String patn = "/" + objectId + "/" + instanceId + "/" + resourceId;
434 432 String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client",
435 433 patn, type, value, e.toString());
436   - handler.sendLogsToThingsboard(msg, registration.getId());
  434 + handler.sendLogsToThingsboard(client, msg);
437 435 log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString());
438 436 if (rpcRequest != null) {
439 437 String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value);
... ... @@ -443,13 +441,13 @@ public class LwM2mTransportRequest {
443 441 }
444 442 }
445 443
446   - private void handleResponse(Registration registration, final String path, LwM2mResponse response,
447   - DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
  444 + private void handleResponse(LwM2mClient lwM2mClient, final String path, LwM2mResponse response,
  445 + SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
448 446 responseRequestExecutor.submit(() -> {
449 447 try {
450   - this.sendResponse(registration, path, response, request, rpcRequest);
  448 + this.sendResponse(lwM2mClient, path, response, request, rpcRequest);
451 449 } catch (Exception e) {
452   - log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", registration.getEndpoint(), path, e);
  450 + log.error("[{}] endpoint [{}] path [{}] Exception Unable to after send response.", lwM2mClient.getRegistration().getEndpoint(), path, e);
453 451 }
454 452 });
455 453 }
... ... @@ -461,8 +459,9 @@ public class LwM2mTransportRequest {
461 459 * @param path -
462 460 * @param response -
463 461 */
464   - private void sendResponse(Registration registration, String path, LwM2mResponse response,
465   - DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
  462 + private void sendResponse(LwM2mClient lwM2mClient, String path, LwM2mResponse response,
  463 + SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
  464 + Registration registration = lwM2mClient.getRegistration();
466 465 String pathIdVer = convertPathFromObjectIdToIdVer(path, registration);
467 466 String msgLog = "";
468 467 if (response instanceof ReadResponse) {
... ... @@ -477,7 +476,7 @@ public class LwM2mTransportRequest {
477 476 String discoverValue = Link.serialize(((DiscoverResponse) response).getObjectLinks());
478 477 msgLog = String.format("%s: type operation: %s path: %s value: %s",
479 478 LOG_LW2M_INFO, DISCOVER.name(), request.getPath().toString(), discoverValue);
480   - handler.sendLogsToThingsboard(msgLog, registration.getId());
  479 + handler.sendLogsToThingsboard(lwM2mClient, msgLog);
481 480 log.warn("DiscoverResponse: [{}]", (DiscoverResponse) response);
482 481 if (rpcRequest != null) {
483 482 handler.sentRpcResponse(rpcRequest, response.getCode().getName(), discoverValue, LOG_LW2M_VALUE);
... ... @@ -486,7 +485,7 @@ public class LwM2mTransportRequest {
486 485 msgLog = String.format("%s: type operation: %s path: %s",
487 486 LOG_LW2M_INFO, EXECUTE.name(), request.getPath().toString());
488 487 log.warn("9) [{}] ", msgLog);
489   - handler.sendLogsToThingsboard(msgLog, registration.getId());
  488 + handler.sendLogsToThingsboard(lwM2mClient, msgLog);
490 489 if (rpcRequest != null) {
491 490 msgLog = String.format("Start %s path: %S. Preparation finished: %s", EXECUTE.name(), path, rpcRequest.getInfoMsg());
492 491 rpcRequest.setInfoMsg(msgLog);
... ... @@ -496,7 +495,7 @@ public class LwM2mTransportRequest {
496 495 } else if (response instanceof WriteAttributesResponse) {
497 496 msgLog = String.format("%s: type operation: %s path: %s value: %s",
498 497 LOG_LW2M_INFO, WRITE_ATTRIBUTES.name(), request.getPath().toString(), ((WriteAttributesRequest) request).getAttributes().toString());
499   - handler.sendLogsToThingsboard(msgLog, registration.getId());
  498 + handler.sendLogsToThingsboard(lwM2mClient, msgLog);
500 499 log.warn("12) [{}] Path [{}] WriteAttributesResponse", pathIdVer, response);
501 500 if (rpcRequest != null) {
502 501 handler.sentRpcResponse(rpcRequest, response.getCode().getName(), response.toString(), LOG_LW2M_VALUE);
... ... @@ -504,13 +503,14 @@ public class LwM2mTransportRequest {
504 503 } else if (response instanceof WriteResponse) {
505 504 msgLog = String.format("Type operation: Write path: %s", pathIdVer);
506 505 log.warn("10) [{}] response: [{}]", msgLog, response);
507   - this.infoWriteResponse(registration, response, request, rpcRequest);
  506 + this.infoWriteResponse(lwM2mClient, response, request, rpcRequest);
508 507 handler.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request);
509 508 }
510 509 }
511 510
512   - private void infoWriteResponse(Registration registration, LwM2mResponse response, DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
  511 + private void infoWriteResponse(LwM2mClient lwM2mClient, LwM2mResponse response, SimpleDownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) {
513 512 try {
  513 + Registration registration = lwM2mClient.getRegistration();
514 514 LwM2mNode node = ((WriteRequest) request).getNode();
515 515 String msg = null;
516 516 Object value;
... ... @@ -545,7 +545,7 @@ public class LwM2mTransportRequest {
545 545 }
546 546 }
547 547 if (msg != null) {
548   - handler.sendLogsToThingsboard(msg, registration.getId());
  548 + handler.sendLogsToThingsboard(lwM2mClient, msg);
549 549 if (request.getPath().toString().equals(FW_PACKAGE_ID) || request.getPath().toString().equals(SW_PACKAGE_ID)) {
550 550 this.afterWriteSuccessFwSwUpdate(registration, request);
551 551 if (rpcRequest != null) {
... ... @@ -566,7 +566,7 @@ public class LwM2mTransportRequest {
566 566 * fw_state/sw_state = DOWNLOADED
567 567 * send operation Execute
568 568 */
569   - private void afterWriteSuccessFwSwUpdate(Registration registration, DownlinkRequest request) {
  569 + private void afterWriteSuccessFwSwUpdate(Registration registration, SimpleDownlinkRequest request) {
570 570 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
571 571 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
572 572 lwM2MClient.getFwUpdate().setStateUpdate(DOWNLOADED.name());
... ... @@ -581,7 +581,7 @@ public class LwM2mTransportRequest {
581 581 /**
582 582 * After finish operation FwSwUpdate Write (error): fw_state = FAILED
583 583 */
584   - private void afterWriteFwSWUpdateError(Registration registration, DownlinkRequest request, String msgError) {
  584 + private void afterWriteFwSWUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) {
585 585 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
586 586 if (request.getPath().toString().equals(FW_PACKAGE_ID) && lwM2MClient.getFwUpdate() != null) {
587 587 lwM2MClient.getFwUpdate().setStateUpdate(FAILED.name());
... ... @@ -593,7 +593,7 @@ public class LwM2mTransportRequest {
593 593 }
594 594 }
595 595
596   - private void afterExecuteFwSwUpdateError(Registration registration, DownlinkRequest request, String msgError) {
  596 + private void afterExecuteFwSwUpdateError(Registration registration, SimpleDownlinkRequest request, String msgError) {
597 597 LwM2mClient lwM2MClient = this.lwM2mClientContext.getClientByRegistrationId(registration.getId());
598 598 if (request.getPath().toString().equals(FW_UPDATE_ID) && lwM2MClient.getFwUpdate() != null) {
599 599 lwM2MClient.getFwUpdate().sendLogs(this.handler, EXECUTE.name(), LOG_LW2M_ERROR, msgError);
... ... @@ -603,8 +603,8 @@ public class LwM2mTransportRequest {
603 603 }
604 604 }
605 605
606   - private void afterObserveCancel(Registration registration, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) {
607   - handler.sendLogsToThingsboard(observeCancelMsg, registration.getId());
  606 + private void afterObserveCancel(LwM2mClient lwM2mClient, int observeCancelCnt, String observeCancelMsg, Lwm2mClientRpcRequest rpcRequest) {
  607 + handler.sendLogsToThingsboard(lwM2mClient, observeCancelMsg);
608 608 log.warn("[{}]", observeCancelMsg);
609 609 if (rpcRequest != null) {
610 610 rpcRequest.setInfoMsg(String.format("Count: %d", observeCancelCnt));
... ...
... ... @@ -137,7 +137,7 @@ public class LwM2mTransportServerHelper {
137 137 public ObjectModel parseFromXmlToObjectModel(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) {
138 138 try {
139 139 DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator);
140   - return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0);
  140 + return ddfFileParser.parse(new ByteArrayInputStream(xmlByte), streamName).get(0);
141 141 } catch (IOException | InvalidDDFFileException e) {
142 142 log.error("Could not parse the XML file [{}]", streamName, e);
143 143 return null;
... ...
... ... @@ -36,7 +36,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance;
36 36 import org.eclipse.leshan.core.node.LwM2mPath;
37 37 import org.eclipse.leshan.core.node.LwM2mSingleResource;
38 38 import org.eclipse.leshan.core.node.codec.CodecException;
39   -import org.eclipse.leshan.core.request.DownlinkRequest;
  39 +import org.eclipse.leshan.core.request.SimpleDownlinkRequest;
40 40 import org.eclipse.leshan.core.request.WriteAttributesRequest;
41 41 import org.eclipse.leshan.core.util.Hex;
42 42 import org.eclipse.leshan.server.registration.Registration;
... ... @@ -839,7 +839,7 @@ public class LwM2mTransportUtil {
839 839 * Attribute pmax = new Attribute(MAXIMUM_PERIOD, "60");
840 840 * Attribute [] attrs = {gt, st};
841 841 */
842   - public static DownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) {
  842 + public static SimpleDownlinkRequest createWriteAttributeRequest(String target, Object params, DefaultLwM2MTransportMsgHandler serviceImpl) {
843 843 AttributeSet attrSet = new AttributeSet(createWriteAttributes(params, serviceImpl, target));
844 844 return attrSet.getAttributes().size() > 0 ? new WriteAttributesRequest(target, attrSet) : null;
845 845 }
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.client;
  17 +
  18 +public enum LwM2MClientState {
  19 +
  20 + CREATED, REGISTERED, UNREGISTERED
  21 +
  22 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.client;
  17 +
  18 +import lombok.Getter;
  19 +
  20 +public class LwM2MClientStateException extends Exception {
  21 +
  22 + private static final long serialVersionUID = 3307690997951364046L;
  23 +
  24 + @Getter
  25 + private final LwM2MClientState state;
  26 +
  27 + public LwM2MClientStateException(LwM2MClientState state, String message) {
  28 + super(message);
  29 + this.state = state;
  30 + }
  31 +}
... ...
... ... @@ -26,6 +26,7 @@ import org.eclipse.leshan.core.node.LwM2mObjectInstance;
26 26 import org.eclipse.leshan.core.node.LwM2mPath;
27 27 import org.eclipse.leshan.core.node.LwM2mResource;
28 28 import org.eclipse.leshan.core.node.LwM2mSingleResource;
  29 +import org.eclipse.leshan.core.request.ContentFormat;
29 30 import org.eclipse.leshan.server.model.LwM2mModelProvider;
30 31 import org.eclipse.leshan.server.registration.Registration;
31 32 import org.eclipse.leshan.server.security.SecurityInfo;
... ... @@ -49,6 +50,8 @@ import java.util.UUID;
49 50 import java.util.concurrent.ConcurrentHashMap;
50 51 import java.util.concurrent.ConcurrentLinkedQueue;
51 52 import java.util.concurrent.CopyOnWriteArrayList;
  53 +import java.util.concurrent.locks.Lock;
  54 +import java.util.concurrent.locks.ReentrantLock;
52 55 import java.util.stream.Collectors;
53 56
54 57 import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
... ... @@ -62,12 +65,28 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.g
62 65
63 66 @Slf4j
64 67 public class LwM2mClient implements Cloneable {
  68 +
  69 + private final String nodeId;
  70 + @Getter
  71 + private final String endpoint;
  72 + private final Lock lock;
  73 + @Getter
  74 + @Setter
  75 + private LwM2MClientState state;
  76 + @Getter
  77 + private final Map<String, ResourceValue> resources;
  78 + @Getter
  79 + private final Map<String, TsKvProto> delayedRequests;
  80 + @Getter
  81 + private final List<String> pendingReadRequests;
  82 + @Getter
  83 + private final Queue<LwM2mQueuedRequest> queuedRequests;
  84 +
65 85 @Getter
66 86 private String deviceName;
67 87 @Getter
68 88 private String deviceProfileName;
69   - @Getter
70   - private String endpoint;
  89 +
71 90 @Getter
72 91 private String identity;
73 92 @Getter
... ... @@ -93,33 +112,29 @@ public class LwM2mClient implements Cloneable {
93 112 private ValidateDeviceCredentialsResponse credentials;
94 113
95 114 @Getter
96   - private final Map<String, ResourceValue> resources;
97   - @Getter
98   - private final Map<String, TsKvProto> delayedRequests;
99   - @Getter
100   - @Setter
101   - private final List<String> pendingReadRequests;
102   - @Getter
103   - private final Queue<LwM2mQueuedRequest> queuedRequests;
104   - @Getter
105 115 private boolean init;
106 116
107 117 public Object clone() throws CloneNotSupportedException {
108 118 return super.clone();
109 119 }
110 120
111   - public LwM2mClient(String nodeId, String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) {
  121 + public LwM2mClient(String nodeId, String endpoint) {
  122 + this.nodeId = nodeId;
112 123 this.endpoint = endpoint;
113   - this.identity = identity;
114   - this.securityInfo = securityInfo;
115   - this.credentials = credentials;
  124 + this.lock = new ReentrantLock();
116 125 this.delayedRequests = new ConcurrentHashMap<>();
117 126 this.pendingReadRequests = new CopyOnWriteArrayList<>();
118 127 this.resources = new ConcurrentHashMap<>();
119   - this.profileId = profileId;
120   - this.init = false;
121 128 this.queuedRequests = new ConcurrentLinkedQueue<>();
  129 + this.state = LwM2MClientState.CREATED;
  130 + }
122 131
  132 + public void init(String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponse credentials, UUID profileId, UUID sessionId) {
  133 + this.identity = identity;
  134 + this.securityInfo = securityInfo;
  135 + this.credentials = credentials;
  136 + this.profileId = profileId;
  137 + this.init = false;
123 138 this.fwUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.FIRMWARE);
124 139 this.swUpdate = new LwM2mFwSwUpdate(this, OtaPackageType.SOFTWARE);
125 140 if (this.credentials != null && this.credentials.hasDeviceInfo()) {
... ... @@ -131,6 +146,14 @@ public class LwM2mClient implements Cloneable {
131 146 }
132 147 }
133 148
  149 + public void lock() {
  150 + lock.lock();
  151 + }
  152 +
  153 + public void unlock() {
  154 + lock.unlock();
  155 + }
  156 +
134 157 public void onDeviceUpdate(Device device, Optional<DeviceProfile> deviceProfileOpt) {
135 158 SessionInfoProto.Builder builder = SessionInfoProto.newBuilder().mergeFrom(session);
136 159 this.deviceId = device.getUuidId();
... ... @@ -193,9 +216,7 @@ public class LwM2mClient implements Cloneable {
193 216 public Object getResourceValue(String pathRezIdVer, String pathRezId) {
194 217 String pathRez = pathRezIdVer == null ? convertPathFromObjectIdToIdVer(pathRezId, this.registration) : pathRezIdVer;
195 218 if (this.resources.get(pathRez) != null) {
196   - return this.resources.get(pathRez).getLwM2mResource().isMultiInstances() ?
197   - this.resources.get(pathRez).getLwM2mResource().getValues() :
198   - this.resources.get(pathRez).getLwM2mResource().getValue();
  219 + return this.resources.get(pathRez).getLwM2mResource().getValue();
199 220 }
200 221 return null;
201 222 }
... ... @@ -366,5 +387,14 @@ public class LwM2mClient implements Cloneable {
366 387 }
367 388 }
368 389
  390 + public ContentFormat getDefaultContentFormat() {
  391 + if (registration == null) {
  392 + return ContentFormat.DEFAULT;
  393 + } else if (registration.getLwM2mVersion().equals("1.0")) {
  394 + return ContentFormat.TLV;
  395 + } else {
  396 + return ContentFormat.TEXT;
  397 + }
  398 + }
369 399 }
370 400
... ...
... ... @@ -16,6 +16,7 @@
16 16 package org.thingsboard.server.transport.lwm2m.server.client;
17 17
18 18 import org.eclipse.leshan.server.registration.Registration;
  19 +import org.eclipse.leshan.server.security.SecurityInfo;
19 20 import org.thingsboard.server.common.data.DeviceProfile;
20 21 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
21 22 import org.thingsboard.server.gen.transport.TransportProtos;
... ... @@ -27,21 +28,17 @@ import java.util.UUID;
27 28
28 29 public interface LwM2mClientContext {
29 30
30   - void removeClientByRegistrationId(String registrationId);
31   -
32   - LwM2mClient getClientByEndpoint(String endpoint);
33   -
34 31 LwM2mClient getClientByRegistrationId(String registrationId);
35 32
36   - LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo);
  33 + LwM2mClient getClientByEndpoint(String endpoint);
37 34
38   - LwM2mClient getOrRegister(Registration registration);
  35 + LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo);
39 36
40   - LwM2mClient registerOrUpdate(Registration registration);
  37 + void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException;
41 38
42   - LwM2mClient fetchClientByEndpoint(String endpoint);
  39 + void updateRegistration(LwM2mClient client, Registration registration) throws LwM2MClientStateException;
43 40
44   - Registration getRegistration(String registrationId);
  41 + void unregister(LwM2mClient client, Registration registration) throws LwM2MClientStateException;
45 42
46 43 Collection<LwM2mClient> getLwM2mClients();
47 44
... ... @@ -55,9 +52,11 @@ public interface LwM2mClientContext {
55 52
56 53 LwM2mClientProfile profileUpdate(DeviceProfile deviceProfile);
57 54
58   - Set<String> getSupportedIdVerInClient(Registration registration);
  55 + Set<String> getSupportedIdVerInClient(LwM2mClient registration);
59 56
60 57 LwM2mClient getClientByDeviceId(UUID deviceId);
61 58
62 59 void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials);
  60 +
  61 +
63 62 }
... ...
... ... @@ -19,16 +19,15 @@ import lombok.RequiredArgsConstructor;
19 19 import lombok.extern.slf4j.Slf4j;
20 20 import org.eclipse.leshan.core.node.LwM2mPath;
21 21 import org.eclipse.leshan.server.registration.Registration;
22   -import org.eclipse.leshan.server.security.EditableSecurityStore;
23 22 import org.springframework.stereotype.Service;
24 23 import org.thingsboard.server.common.data.DeviceProfile;
25 24 import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse;
26 25 import org.thingsboard.server.gen.transport.TransportProtos;
27 26 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
28   -import org.thingsboard.server.transport.lwm2m.secure.EndpointSecurityInfo;
29   -import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
  27 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
30 28 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContext;
31 29 import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
  30 +import org.thingsboard.server.transport.lwm2m.server.store.TbEditableSecurityStore;
32 31
33 32 import java.util.Arrays;
34 33 import java.util.Collection;
... ... @@ -48,46 +47,107 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil.c
48 47 public class LwM2mClientContextImpl implements LwM2mClientContext {
49 48
50 49 private final LwM2mTransportContext context;
  50 + private final TbEditableSecurityStore securityStore;
51 51 private final Map<String, LwM2mClient> lwM2mClientsByEndpoint = new ConcurrentHashMap<>();
52 52 private final Map<String, LwM2mClient> lwM2mClientsByRegistrationId = new ConcurrentHashMap<>();
53 53 private Map<UUID, LwM2mClientProfile> profiles = new ConcurrentHashMap<>();
54 54
55   - private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator;
56   -
57   - private final EditableSecurityStore securityStore;
58   -
59 55 @Override
60 56 public LwM2mClient getClientByEndpoint(String endpoint) {
61   - return lwM2mClientsByEndpoint.get(endpoint);
  57 + return lwM2mClientsByEndpoint.computeIfAbsent(endpoint, ep -> new LwM2mClient(context.getNodeId(), ep));
62 58 }
63 59
64 60 @Override
65   - public LwM2mClient getClientByRegistrationId(String registrationId) {
66   - return lwM2mClientsByRegistrationId.get(registrationId);
  61 + public void register(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException {
  62 + lwM2MClient.lock();
  63 + try {
  64 + if (LwM2MClientState.UNREGISTERED.equals(lwM2MClient.getState())) {
  65 + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
  66 + }
  67 + TbLwM2MSecurityInfo securityInfo = securityStore.getTbLwM2MSecurityInfoByEndpoint(lwM2MClient.getEndpoint());
  68 + if (securityInfo.getSecurityMode() != null) {
  69 + if (securityInfo.getDeviceProfile() != null) {
  70 + UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile()) != null ? securityInfo.getDeviceProfile().getUuidId() : null;
  71 + if (securityInfo.getSecurityInfo() != null) {
  72 + lwM2MClient.init(securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(), securityInfo.getMsg(), profileUuid, UUID.randomUUID());
  73 + } else if (NO_SEC.equals(securityInfo.getSecurityMode())) {
  74 + lwM2MClient.init(null, null, securityInfo.getMsg(), profileUuid, UUID.randomUUID());
  75 + } else {
  76 + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint()));
  77 + }
  78 + } else {
  79 + throw new RuntimeException(String.format("Registration failed: device %s not found.", lwM2MClient.getEndpoint()));
  80 + }
  81 + } else {
  82 + throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", lwM2MClient.getEndpoint()));
  83 + }
  84 + lwM2MClient.setRegistration(registration);
  85 + this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient);
  86 + lwM2MClient.setState(LwM2MClientState.REGISTERED);
  87 + } finally {
  88 + lwM2MClient.unlock();
  89 + }
67 90 }
68 91
69 92 @Override
70   - public LwM2mClient getOrRegister(Registration registration) {
71   - if (registration == null) {
72   - return null;
  93 + public void updateRegistration(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException {
  94 + lwM2MClient.lock();
  95 + try {
  96 + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) {
  97 + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
  98 + }
  99 + Registration currentRegistration = lwM2MClient.getRegistration();
  100 + if (currentRegistration.getId().equals(registration.getId())) {
  101 + lwM2MClient.setRegistration(registration);
  102 + } else {
  103 + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration.");
  104 + }
  105 + } finally {
  106 + lwM2MClient.unlock();
73 107 }
74   - LwM2mClient client = lwM2mClientsByRegistrationId.get(registration.getId());
75   - if (client == null) {
76   - client = lwM2mClientsByEndpoint.get(registration.getEndpoint());
77   - if (client == null) {
78   - client = registerOrUpdate(registration);
  108 + }
  109 +
  110 + @Override
  111 + public void unregister(LwM2mClient lwM2MClient, Registration registration) throws LwM2MClientStateException {
  112 + lwM2MClient.lock();
  113 + try {
  114 + if (!LwM2MClientState.REGISTERED.equals(lwM2MClient.getState())) {
  115 + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client is in invalid state.");
79 116 }
  117 + lwM2mClientsByRegistrationId.remove(registration.getId());
  118 + Registration currentRegistration = lwM2MClient.getRegistration();
  119 + if (currentRegistration.getId().equals(registration.getId())) {
  120 + lwM2MClient.setState(LwM2MClientState.UNREGISTERED);
  121 + lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint());
  122 + this.securityStore.remove(lwM2MClient.getEndpoint());
  123 + this.lwM2mClientsByRegistrationId.remove(registration.getId());
  124 + UUID profileId = lwM2MClient.getProfileId();
  125 + if (profileId != null) {
  126 + Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst();
  127 + if (otherClients.isEmpty()) {
  128 + profiles.remove(profileId);
  129 + }
  130 + }
  131 + } else {
  132 + throw new LwM2MClientStateException(lwM2MClient.getState(), "Client has different registration.");
  133 + }
  134 + } finally {
  135 + lwM2MClient.unlock();
80 136 }
81   - return client;
82 137 }
83 138
84 139 @Override
85   - public LwM2mClient getClient(TransportProtos.SessionInfoProto sessionInfo) {
86   - LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c ->
  140 + public LwM2mClient getClientByRegistrationId(String registrationId) {
  141 + return lwM2mClientsByRegistrationId.get(registrationId);
  142 + }
  143 +
  144 + @Override
  145 + public LwM2mClient getClientBySessionInfo(TransportProtos.SessionInfoProto sessionInfo) {
  146 + LwM2mClient lwM2mClient = lwM2mClientsByEndpoint.values().stream().filter(c ->
87 147 (new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()))
88 148 .equals((new UUID(c.getSession().getSessionIdMSB(), c.getSession().getSessionIdLSB())))
89 149
90   - ).findAny().get();
  150 + ).findAny().orElse(null);
91 151 if (lwM2mClient == null) {
92 152 log.warn("Device TimeOut? lwM2mClient is null.");
93 153 log.warn("SessionInfo input [{}], lwM2mClientsByEndpoint size: [{}]", sessionInfo, lwM2mClientsByEndpoint.values().size());
... ... @@ -96,60 +156,14 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
96 156 return lwM2mClient;
97 157 }
98 158
99   - @Override
100   - public LwM2mClient registerOrUpdate(Registration registration) {
101   - LwM2mClient lwM2MClient = lwM2mClientsByEndpoint.get(registration.getEndpoint());
102   - if (lwM2MClient == null) {
103   - lwM2MClient = this.fetchClientByEndpoint(registration.getEndpoint());
104   - }
105   - lwM2MClient.setRegistration(registration);
106   -// TODO: this remove is probably redundant. We should remove it.
107   -// this.lwM2mClientsByEndpoint.remove(registration.getEndpoint());
108   - this.lwM2mClientsByRegistrationId.put(registration.getId(), lwM2MClient);
109   - return lwM2MClient;
110   - }
111   -
112 159 public Registration getRegistration(String registrationId) {
113 160 return this.lwM2mClientsByRegistrationId.get(registrationId).getRegistration();
114 161 }
115 162
116 163 @Override
117   - public LwM2mClient fetchClientByEndpoint(String endpoint) {
118   - EndpointSecurityInfo securityInfo = lwM2MCredentialsSecurityInfoValidator.getEndpointSecurityInfo(endpoint, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
119   - if (securityInfo.getSecurityMode() != null) {
120   - if (securityInfo.getDeviceProfile() != null) {
121   - UUID profileUuid = profileUpdate(securityInfo.getDeviceProfile())!= null ?
122   - securityInfo.getDeviceProfile().getUuidId() : null;
123   - // TODO: for tests bug.
124   - if (profileUuid== null) {
125   - log.trace("input parameters toClientProfile if the result is null: [{}]", securityInfo.getDeviceProfile());
126   - }
127   - LwM2mClient client;
128   - if (securityInfo.getSecurityInfo() != null) {
129   - client = new LwM2mClient(context.getNodeId(), securityInfo.getSecurityInfo().getEndpoint(),
130   - securityInfo.getSecurityInfo().getIdentity(), securityInfo.getSecurityInfo(),
131   - securityInfo.getMsg(), profileUuid, UUID.randomUUID());
132   - } else if (NO_SEC.equals(securityInfo.getSecurityMode())) {
133   - client = new LwM2mClient(context.getNodeId(), endpoint,
134   - null, null,
135   - securityInfo.getMsg(), profileUuid, UUID.randomUUID());
136   - } else {
137   - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint));
138   - }
139   - lwM2mClientsByEndpoint.put(client.getEndpoint(), client);
140   - return client;
141   - } else {
142   - throw new RuntimeException(String.format("Registration failed: device %s not found.", endpoint));
143   - }
144   - } else {
145   - throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", endpoint));
146   - }
147   - }
148   -
149   - @Override
150 164 public void registerClient(Registration registration, ValidateDeviceCredentialsResponse credentials) {
151   - LwM2mClient client = new LwM2mClient(context.getNodeId(), registration.getEndpoint(), null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID());
152   - lwM2mClientsByEndpoint.put(registration.getEndpoint(), client);
  165 + LwM2mClient client = getClientByEndpoint(registration.getEndpoint());
  166 + client.init(null, null, credentials, credentials.getDeviceProfile().getUuidId(), UUID.randomUUID());
153 167 lwM2mClientsByRegistrationId.put(registration.getId(), client);
154 168 profileUpdate(credentials.getDeviceProfile());
155 169 }
... ... @@ -171,7 +185,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
171 185
172 186 @Override
173 187 public LwM2mClientProfile getProfile(Registration registration) {
174   - return this.getProfiles().get(getOrRegister(registration).getProfileId());
  188 + return this.getProfiles().get(getClientByEndpoint(registration.getEndpoint()).getProfileId());
175 189 }
176 190
177 191 @Override
... ... @@ -186,25 +200,18 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
186 200 if (lwM2MClientProfile != null) {
187 201 profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile);
188 202 return lwM2MClientProfile;
189   - }
190   - else {
  203 + } else {
191 204 return null;
192 205 }
193 206 }
194 207
195   - /**
196   - * if isVer - ok or default ver=DEFAULT_LWM2M_VERSION
197   - *
198   - * @param registration -
199   - * @return - all objectIdVer in client
200   - */
201 208 @Override
202   - public Set<String> getSupportedIdVerInClient(Registration registration) {
  209 + public Set<String> getSupportedIdVerInClient(LwM2mClient client) {
203 210 Set<String> clientObjects = ConcurrentHashMap.newKeySet();
204   - Arrays.stream(registration.getObjectLinks()).forEach(url -> {
205   - LwM2mPath pathIds = new LwM2mPath(url.getUrl());
  211 + Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> {
  212 + LwM2mPath pathIds = new LwM2mPath(link.getUrl());
206 213 if (!pathIds.isRoot()) {
207   - clientObjects.add(convertPathFromObjectIdToIdVer(url.getUrl(), registration));
  214 + clientObjects.add(convertPathFromObjectIdToIdVer(link.getUrl(), client.getRegistration()));
208 215 }
209 216 });
210 217 return (clientObjects.size() > 0) ? clientObjects : null;
... ... @@ -215,20 +222,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
215 222 return lwM2mClientsByRegistrationId.values().stream().filter(e -> deviceId.equals(e.getDeviceId())).findFirst().orElse(null);
216 223 }
217 224
218   - @Override
219   - public void removeClientByRegistrationId(String registrationId) {
220   - LwM2mClient lwM2MClient = this.lwM2mClientsByRegistrationId.get(registrationId);
221   - if (lwM2MClient != null) {
222   - this.securityStore.remove(lwM2MClient.getEndpoint(), false);
223   - this.lwM2mClientsByEndpoint.remove(lwM2MClient.getEndpoint());
224   - this.lwM2mClientsByRegistrationId.remove(registrationId);
225   - UUID profileId = lwM2MClient.getProfileId();
226   - if (profileId != null) {
227   - Optional<LwM2mClient> otherClients = lwM2mClientsByRegistrationId.values().stream().filter(e -> e.getProfileId().equals(profileId)).findFirst();
228   - if (otherClients.isEmpty()) {
229   - profiles.remove(profileId);
230   - }
231   - }
232   - }
233   - }
234 225 }
... ...
... ... @@ -167,9 +167,9 @@ public class LwM2mFwSwUpdate {
167 167 String targetIdVer = convertPathFromObjectIdToIdVer(this.pathPackageId, this.lwM2MClient.getRegistration());
168 168 String fwMsg = String.format("%s: Start type operation %s paths: %s", LOG_LW2M_INFO,
169 169 LwM2mTransportUtil.LwM2mTypeOper.FW_UPDATE.name(), FW_PACKAGE_ID);
170   - handler.sendLogsToThingsboard(fwMsg, lwM2MClient.getRegistration().getId());
  170 + handler.sendLogsToThingsboard(lwM2MClient, fwMsg);
171 171 log.warn("8) Start firmware Update. Send save to: [{}] ver: [{}] path: [{}]", this.lwM2MClient.getDeviceName(), this.currentVersion, targetIdVer);
172   - request.sendAllRequest(this.lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE.getName(),
  172 + request.sendAllRequest(this.lwM2MClient, targetIdVer, WRITE_REPLACE, ContentFormat.OPAQUE,
173 173 firmwareChunk, handler.config.getTimeout(), this.rpcRequest);
174 174 }
175 175 else {
... ... @@ -190,7 +190,7 @@ public class LwM2mFwSwUpdate {
190 190 if (LOG_LW2M_ERROR.equals(typeInfo)) {
191 191 msg = String.format("%s Error: %s", msg, msgError);
192 192 }
193   - handler.sendLogsToThingsboard(msg, lwM2MClient.getRegistration().getId());
  193 + handler.sendLogsToThingsboard(lwM2MClient, msg);
194 194 }
195 195
196 196
... ... @@ -202,8 +202,7 @@ public class LwM2mFwSwUpdate {
202 202 public void executeFwSwWare(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
203 203 this.setStateUpdate(UPDATING.name());
204 204 this.sendLogs(handler, EXECUTE.name(), LOG_LW2M_INFO, null);
205   - request.sendAllRequest(this.lwM2MClient.getRegistration(), this.pathInstallId, EXECUTE, ContentFormat.TLV.getName(),
206   - null, 0, this.rpcRequest);
  205 + request.sendAllRequest(this.lwM2MClient, this.pathInstallId, EXECUTE, null, 0, this.rpcRequest);
207 206 }
208 207
209 208 /**
... ... @@ -334,10 +333,10 @@ public class LwM2mFwSwUpdate {
334 333 }
335 334
336 335 private void observeStateUpdate(DefaultLwM2MTransportMsgHandler handler, LwM2mTransportRequest request) {
337   - request.sendAllRequest(lwM2MClient.getRegistration(),
  336 + request.sendAllRequest(lwM2MClient,
338 337 convertPathFromObjectIdToIdVer(this.pathStateId, this.lwM2MClient.getRegistration()), OBSERVE,
339 338 null, null, 0, null);
340   - request.sendAllRequest(lwM2MClient.getRegistration(),
  339 + request.sendAllRequest(lwM2MClient,
341 340 convertPathFromObjectIdToIdVer(this.pathResultId, this.lwM2MClient.getRegistration()), OBSERVE,
342 341 null, null, 0, null);
343 342 }
... ... @@ -364,8 +363,7 @@ public class LwM2mFwSwUpdate {
364 363 this.pendingInfoRequestsStart.add(convertPathFromObjectIdToIdVer(
365 364 this.pathResultId, this.lwM2MClient.getRegistration()));
366 365 this.pendingInfoRequestsStart.forEach(pathIdVer -> {
367   - request.sendAllRequest(this.lwM2MClient.getRegistration(), pathIdVer, OBSERVE, ContentFormat.TLV.getName(),
368   - null, 0, this.rpcRequest);
  366 + request.sendAllRequest(this.lwM2MClient, pathIdVer, OBSERVE, null, 0, this.rpcRequest);
369 367 });
370 368
371 369 }
... ...
... ... @@ -273,7 +273,7 @@ public class Lwm2mClientRpcRequest {
273 273 }
274 274
275 275 private String getRezIdByResourceNameAndObjectInstanceId(String resourceName, DefaultLwM2MTransportMsgHandler handler) {
276   - LwM2mClient lwM2mClient = handler.clientContext.getClient(this.sessionInfo);
  276 + LwM2mClient lwM2mClient = handler.clientContext.getClientBySessionInfo(this.sessionInfo);
277 277 return lwM2mClient != null ?
278 278 lwM2mClient.getRezIdByResourceNameAndObjectInstanceId(resourceName, this.targetIdVer, handler.config.getModelProvider()) :
279 279 null;
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.store;
  17 +
  18 +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
  19 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
  20 +
  21 +public interface TbEditableSecurityStore extends TbSecurityStore {
  22 +
  23 + void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException;
  24 +
  25 + void remove(String endpoint);
  26 +
  27 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.store;
  17 +
  18 +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
  19 +import org.eclipse.leshan.server.security.SecurityInfo;
  20 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
  21 +
  22 +import java.util.HashMap;
  23 +import java.util.Map;
  24 +import java.util.concurrent.locks.Lock;
  25 +import java.util.concurrent.locks.ReadWriteLock;
  26 +import java.util.concurrent.locks.ReentrantReadWriteLock;
  27 +
  28 +public class TbInMemorySecurityStore implements TbEditableSecurityStore {
  29 + // lock for the two maps
  30 + protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
  31 + protected final Lock readLock = readWriteLock.readLock();
  32 + protected final Lock writeLock = readWriteLock.writeLock();
  33 +
  34 + // by client end-point
  35 + protected Map<String, TbLwM2MSecurityInfo> securityByEp = new HashMap<>();
  36 +
  37 + // by PSK identity
  38 + protected Map<String, TbLwM2MSecurityInfo> securityByIdentity = new HashMap<>();
  39 +
  40 + public TbInMemorySecurityStore() {
  41 + }
  42 +
  43 + /**
  44 + * {@inheritDoc}
  45 + */
  46 + @Override
  47 + public SecurityInfo getByEndpoint(String endpoint) {
  48 + readLock.lock();
  49 + try {
  50 + TbLwM2MSecurityInfo securityInfo = securityByEp.get(endpoint);
  51 + if (securityInfo != null) {
  52 + return securityInfo.getSecurityInfo();
  53 + } else {
  54 + return null;
  55 + }
  56 + } finally {
  57 + readLock.unlock();
  58 + }
  59 + }
  60 +
  61 + /**
  62 + * {@inheritDoc}
  63 + */
  64 + @Override
  65 + public SecurityInfo getByIdentity(String identity) {
  66 + readLock.lock();
  67 + try {
  68 + TbLwM2MSecurityInfo securityInfo = securityByIdentity.get(identity);
  69 + if (securityInfo != null) {
  70 + return securityInfo.getSecurityInfo();
  71 + } else {
  72 + return null;
  73 + }
  74 + } finally {
  75 + readLock.unlock();
  76 + }
  77 + }
  78 +
  79 + @Override
  80 + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException {
  81 + writeLock.lock();
  82 + try {
  83 + String identity = null;
  84 + if (tbSecurityInfo.getSecurityInfo() != null) {
  85 + identity = tbSecurityInfo.getSecurityInfo().getIdentity();
  86 + if (identity != null) {
  87 + TbLwM2MSecurityInfo infoByIdentity = securityByIdentity.get(identity);
  88 + if (infoByIdentity != null && !tbSecurityInfo.getSecurityInfo().getEndpoint().equals(infoByIdentity.getEndpoint())) {
  89 + throw new NonUniqueSecurityInfoException("PSK Identity " + identity + " is already used");
  90 + }
  91 + securityByIdentity.put(tbSecurityInfo.getSecurityInfo().getIdentity(), tbSecurityInfo);
  92 + }
  93 + }
  94 +
  95 + TbLwM2MSecurityInfo previous = securityByEp.put(tbSecurityInfo.getEndpoint(), tbSecurityInfo);
  96 + if (previous != null && previous.getSecurityInfo() != null) {
  97 + String previousIdentity = previous.getSecurityInfo().getIdentity();
  98 + if (previousIdentity != null && !previousIdentity.equals(identity)) {
  99 + securityByIdentity.remove(previousIdentity);
  100 + }
  101 + }
  102 + } finally {
  103 + writeLock.unlock();
  104 + }
  105 + }
  106 +
  107 + @Override
  108 + public void remove(String endpoint) {
  109 + writeLock.lock();
  110 + try {
  111 + TbLwM2MSecurityInfo securityInfo = securityByEp.remove(endpoint);
  112 + if (securityInfo != null && securityInfo.getSecurityInfo() != null && securityInfo.getSecurityInfo().getIdentity() != null) {
  113 + securityByIdentity.remove(securityInfo.getSecurityInfo().getIdentity());
  114 + }
  115 + } finally {
  116 + writeLock.unlock();
  117 + }
  118 + }
  119 +
  120 + @Override
  121 + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) {
  122 + readLock.lock();
  123 + try {
  124 + return securityByEp.get(endpoint);
  125 + } finally {
  126 + readLock.unlock();
  127 + }
  128 + }
  129 +
  130 +}
... ...
... ... @@ -22,11 +22,13 @@ import org.eclipse.leshan.core.Destroyable;
22 22 import org.eclipse.leshan.core.Startable;
23 23 import org.eclipse.leshan.core.Stoppable;
24 24 import org.eclipse.leshan.core.observation.Observation;
  25 +import org.eclipse.leshan.core.request.Identity;
25 26 import org.eclipse.leshan.core.util.NamedThreadFactory;
26 27 import org.eclipse.leshan.core.util.Validate;
27 28 import org.eclipse.leshan.server.californium.observation.ObserveUtil;
28 29 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
29 30 import org.eclipse.leshan.server.redis.RedisRegistrationStore;
  31 +import org.eclipse.leshan.server.redis.serialization.IdentitySerDes;
30 32 import org.eclipse.leshan.server.redis.serialization.ObservationSerDes;
31 33 import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes;
32 34 import org.eclipse.leshan.server.registration.Deregistration;
... ... @@ -73,6 +75,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
73 75 private static final String REG_EP = "REG:EP:"; // (Endpoint => Registration)
74 76 private static final String REG_EP_REGID_IDX = "EP:REGID:"; // secondary index key (Registration ID => Endpoint)
75 77 private static final String REG_EP_ADDR_IDX = "EP:ADDR:"; // secondary index key (Socket Address => Endpoint)
  78 + private static final String REG_EP_IDENTITY = "EP:IDENTITY:"; // secondary index key (Identity => Endpoint)
76 79 private static final String LOCK_EP = "LOCK:EP:";
77 80 private static final byte[] OBS_TKN = "OBS:TKN:".getBytes(UTF_8);
78 81 private static final String OBS_TKNS_REGID_IDX = "TKNS:REGID:"; // secondary index (token list by registration)
... ... @@ -155,6 +158,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
155 158 connection.set(regid_idx, registration.getEndpoint().getBytes(UTF_8));
156 159 byte[] addr_idx = toRegAddrKey(registration.getSocketAddress());
157 160 connection.set(addr_idx, registration.getEndpoint().getBytes(UTF_8));
  161 + byte[] identity_idx = toRegIdentityKey(registration.getIdentity());
  162 + connection.set(identity_idx, registration.getEndpoint().getBytes(UTF_8));
158 163
159 164 // Add or update expiration
160 165 addOrUpdateExpiration(connection, registration);
... ... @@ -167,6 +172,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
167 172 if (!oldRegistration.getSocketAddress().equals(registration.getSocketAddress())) {
168 173 removeAddrIndex(connection, oldRegistration);
169 174 }
  175 + if (!oldRegistration.getIdentity().equals(registration.getIdentity())) {
  176 + removeIdentityIndex(connection, oldRegistration);
  177 + }
170 178 // remove old observation
171 179 Collection<Observation> obsRemoved = unsafeRemoveAllObservations(connection, oldRegistration.getId());
172 180
... ... @@ -222,6 +230,9 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
222 230 if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) {
223 231 removeAddrIndex(connection, r);
224 232 }
  233 + if (!r.getIdentity().equals(updatedRegistration.getIdentity())) {
  234 + removeIdentityIndex(connection, r);
  235 + }
225 236
226 237 return new UpdatedRegistration(r, updatedRegistration);
227 238
... ... @@ -269,6 +280,22 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
269 280 }
270 281
271 282 @Override
  283 + public Registration getRegistrationByIdentity(Identity identity) {
  284 + Validate.notNull(identity);
  285 + try (var connection = connectionFactory.getConnection()) {
  286 + byte[] ep = connection.get(toRegIdentityKey(identity));
  287 + if (ep == null) {
  288 + return null;
  289 + }
  290 + byte[] data = connection.get(toEndpointKey(ep));
  291 + if (data == null) {
  292 + return null;
  293 + }
  294 + return deserializeReg(data);
  295 + }
  296 + }
  297 +
  298 + @Override
272 299 public Iterator<Registration> getAllRegistrations() {
273 300 try (var connection = connectionFactory.getConnection()) {
274 301 Collection<Registration> list = new LinkedList<>();
... ... @@ -325,6 +352,7 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
325 352 connection.del(toEndpointKey(r.getEndpoint()));
326 353 Collection<Observation> obsRemoved = unsafeRemoveAllObservations(connection, r.getId());
327 354 removeAddrIndex(connection, r);
  355 + removeIdentityIndex(connection, r);
328 356 removeExpiration(connection, r);
329 357 return new Deregistration(r, obsRemoved);
330 358 }
... ... @@ -337,20 +365,27 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
337 365 }
338 366 }
339 367
  368 + private void removeAddrIndex(RedisConnection connection, Registration r) {
  369 + removeSecondaryIndex(connection, toRegAddrKey(r.getSocketAddress()), r.getEndpoint());
  370 + }
  371 +
  372 + private void removeIdentityIndex(RedisConnection connection, Registration r) {
  373 + removeSecondaryIndex(connection, toRegIdentityKey(r.getIdentity()), r.getEndpoint());
  374 + }
  375 +
340 376 //TODO: JedisCluster didn't implement Transaction, maybe should use some advanced key creation strategies
341   - private void removeAddrIndex(RedisConnection connection, Registration registration) {
  377 + private void removeSecondaryIndex(RedisConnection connection, byte[] indexKey, String endpointName) {
342 378 // Watch the key to remove.
343   - byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress());
344   -// connection.watch(regAddrKey);
  379 +// connection.watch(indexKey);
345 380
346   - byte[] epFromAddr = connection.get(regAddrKey);
  381 + byte[] epFromAddr = connection.get(indexKey);
347 382 // Delete the key if needed.
348   - if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) {
  383 + if (Arrays.equals(epFromAddr, endpointName.getBytes(UTF_8))) {
349 384 // Try to delete the key
350 385 // connection.multi();
351   - connection.del(regAddrKey);
  386 + connection.del(indexKey);
352 387 // connection.exec();
353   - // if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to
  388 + // if transaction failed this is not an issue as the index is probably reused and we don't need to
354 389 // delete it anymore.
355 390 } else {
356 391 // the key must not be deleted.
... ... @@ -374,6 +409,10 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
374 409 return toKey(REG_EP_ADDR_IDX, addr.getAddress().toString() + ":" + addr.getPort());
375 410 }
376 411
  412 + private byte[] toRegIdentityKey(Identity identity) {
  413 + return toKey(REG_EP_IDENTITY, IdentitySerDes.serialize(identity).toString());
  414 + }
  415 +
377 416 private byte[] toEndpointKey(String endpoint) {
378 417 return toKey(REG_EP, endpoint);
379 418 }
... ... @@ -723,7 +762,6 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto
723 762
724 763 @Override
725 764 public void run() {
726   -
727 765 try (var connection = connectionFactory.getConnection()) {
728 766 Set<byte[]> endpointsExpired = connection.zRangeByScore(EXP_EP, Double.NEGATIVE_INFINITY,
729 767 System.currentTimeMillis(), 0, cleanLimit);
... ...
... ... @@ -24,13 +24,14 @@ import org.springframework.data.redis.connection.RedisClusterConnection;
24 24 import org.springframework.data.redis.connection.RedisConnectionFactory;
25 25 import org.springframework.data.redis.core.Cursor;
26 26 import org.springframework.data.redis.core.ScanOptions;
  27 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
27 28
28 29 import java.util.ArrayList;
29 30 import java.util.Collection;
30 31 import java.util.LinkedList;
31 32 import java.util.List;
32 33
33   -public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
  34 +public class TbLwM2mRedisSecurityStore implements TbEditableSecurityStore {
34 35 private static final String SEC_EP = "SEC#EP#";
35 36
36 37 private static final String PSKID_SEC = "PSKID#SEC";
... ... @@ -72,73 +73,89 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
72 73 }
73 74
74 75 @Override
75   - public Collection<SecurityInfo> getAll() {
76   - try (var connection = connectionFactory.getConnection()) {
77   - Collection<SecurityInfo> list = new LinkedList<>();
78   - ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build();
79   - List<Cursor<byte[]>> scans = new ArrayList<>();
80   - if (connection instanceof RedisClusterConnection) {
81   - ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
82   - scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
83   - });
84   - } else {
85   - scans.add(connection.scan(scanOptions));
86   - }
87   -
88   - scans.forEach(scan -> {
89   - scan.forEachRemaining(key -> {
90   - byte[] element = connection.get(key);
91   - list.add(deserialize(element));
92   - });
93   - });
94   - return list;
95   - }
  76 + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException {
  77 + //TODO: implement
96 78 }
97 79
98 80 @Override
99   - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
100   - byte[] data = serialize(info);
101   - try (var connection = connectionFactory.getConnection()) {
102   - if (info.getIdentity() != null) {
103   - // populate the secondary index (security info by PSK id)
104   - String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes()));
105   - if (!oldEndpoint.equals(info.getEndpoint())) {
106   - throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used");
107   - }
108   - connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes());
109   - }
110   -
111   - byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data);
112   - SecurityInfo previous = previousData == null ? null : deserialize(previousData);
113   - String previousIdentity = previous == null ? null : previous.getIdentity();
114   - if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) {
115   - connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes());
116   - }
117   -
118   - return previous;
119   - }
  81 + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) {
  82 + //TODO: implement
  83 + return null;
120 84 }
121 85
122 86 @Override
123   - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
124   - try (var connection = connectionFactory.getConnection()) {
125   - byte[] data = connection.get((SEC_EP + endpoint).getBytes());
126   -
127   - if (data != null) {
128   - SecurityInfo info = deserialize(data);
129   - if (info.getIdentity() != null) {
130   - connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes());
131   - }
132   - connection.del((SEC_EP + endpoint).getBytes());
133   - if (listener != null) {
134   - listener.securityInfoRemoved(infosAreCompromised, info);
135   - }
136   - return info;
137   - }
138   - }
139   - return null;
  87 + public void remove(String endpoint) {
  88 + //TODO: implement
140 89 }
141 90
  91 + // @Override
  92 +// public Collection<SecurityInfo> getAll() {
  93 +// try (var connection = connectionFactory.getConnection()) {
  94 +// Collection<SecurityInfo> list = new LinkedList<>();
  95 +// ScanOptions scanOptions = ScanOptions.scanOptions().count(100).match(SEC_EP + "*").build();
  96 +// List<Cursor<byte[]>> scans = new ArrayList<>();
  97 +// if (connection instanceof RedisClusterConnection) {
  98 +// ((RedisClusterConnection) connection).clusterGetNodes().forEach(node -> {
  99 +// scans.add(((RedisClusterConnection) connection).scan(node, scanOptions));
  100 +// });
  101 +// } else {
  102 +// scans.add(connection.scan(scanOptions));
  103 +// }
  104 +//
  105 +// scans.forEach(scan -> {
  106 +// scan.forEachRemaining(key -> {
  107 +// byte[] element = connection.get(key);
  108 +// list.add(deserialize(element));
  109 +// });
  110 +// });
  111 +// return list;
  112 +// }
  113 +// }
  114 +//
  115 +// @Override
  116 +// public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
  117 +// byte[] data = serialize(info);
  118 +// try (var connection = connectionFactory.getConnection()) {
  119 +// if (info.getIdentity() != null) {
  120 +// // populate the secondary index (security info by PSK id)
  121 +// String oldEndpoint = new String(connection.hGet(PSKID_SEC.getBytes(), info.getIdentity().getBytes()));
  122 +// if (!oldEndpoint.equals(info.getEndpoint())) {
  123 +// throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used");
  124 +// }
  125 +// connection.hSet(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes());
  126 +// }
  127 +//
  128 +// byte[] previousData = connection.getSet((SEC_EP + info.getEndpoint()).getBytes(), data);
  129 +// SecurityInfo previous = previousData == null ? null : deserialize(previousData);
  130 +// String previousIdentity = previous == null ? null : previous.getIdentity();
  131 +// if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) {
  132 +// connection.hDel(PSKID_SEC.getBytes(), previousIdentity.getBytes());
  133 +// }
  134 +//
  135 +// return previous;
  136 +// }
  137 +// }
  138 +//
  139 +// @Override
  140 +// public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
  141 +// try (var connection = connectionFactory.getConnection()) {
  142 +// byte[] data = connection.get((SEC_EP + endpoint).getBytes());
  143 +//
  144 +// if (data != null) {
  145 +// SecurityInfo info = deserialize(data);
  146 +// if (info.getIdentity() != null) {
  147 +// connection.hDel(PSKID_SEC.getBytes(), info.getIdentity().getBytes());
  148 +// }
  149 +// connection.del((SEC_EP + endpoint).getBytes());
  150 +// if (listener != null) {
  151 +// listener.securityInfoRemoved(infosAreCompromised, info);
  152 +// }
  153 +// return info;
  154 +// }
  155 +// }
  156 +// return null;
  157 +// }
  158 +
142 159 private byte[] serialize(SecurityInfo secInfo) {
143 160 return SecurityInfoSerDes.serialize(secInfo);
144 161 }
... ... @@ -147,8 +164,4 @@ public class TbLwM2mRedisSecurityStore implements EditableSecurityStore {
147 164 return SecurityInfoSerDes.deserialize(data);
148 165 }
149 166
150   - @Override
151   - public void setListener(SecurityStoreListener listener) {
152   - this.listener = listener;
153   - }
154 167 }
... ...
... ... @@ -19,63 +19,39 @@ import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.leshan.server.security.EditableSecurityStore;
20 20 import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException;
21 21 import org.eclipse.leshan.server.security.SecurityInfo;
  22 +import org.eclipse.leshan.server.security.SecurityStore;
22 23 import org.eclipse.leshan.server.security.SecurityStoreListener;
  24 +import org.jetbrains.annotations.Nullable;
23 25 import org.springframework.stereotype.Component;
24 26 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
25   -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
  27 +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
  28 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
  29 +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportUtil;
26 30 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
27 31
28 32 import java.util.Collection;
29 33
30 34 @Slf4j
31   -@Component
32   -@TbLwM2mTransportComponent
33   -public class TbLwM2mSecurityStore implements EditableSecurityStore {
  35 +public class TbLwM2mSecurityStore implements TbEditableSecurityStore {
34 36
35   - private final LwM2mClientContext clientContext;
36   - private final EditableSecurityStore securityStore;
  37 + private final TbEditableSecurityStore securityStore;
  38 + private final LwM2mCredentialsSecurityInfoValidator validator;
37 39
38   - public TbLwM2mSecurityStore(LwM2mClientContext clientContext, EditableSecurityStore securityStore) {
39   - this.clientContext = clientContext;
  40 + public TbLwM2mSecurityStore(TbEditableSecurityStore securityStore, LwM2mCredentialsSecurityInfoValidator validator) {
40 41 this.securityStore = securityStore;
  42 + this.validator = validator;
41 43 }
42 44
43 45 @Override
44   - public Collection<SecurityInfo> getAll() {
45   - return securityStore.getAll();
46   - }
47   -
48   - @Override
49   - public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException {
50   - return securityStore.add(info);
51   - }
52   -
53   - @Override
54   - public SecurityInfo remove(String endpoint, boolean infosAreCompromised) {
55   - return securityStore.remove(endpoint, infosAreCompromised);
56   - }
57   -
58   - @Override
59   - public void setListener(SecurityStoreListener listener) {
60   - securityStore.setListener(listener);
  46 + public TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint) {
  47 + return securityStore.getTbLwM2MSecurityInfoByEndpoint(endpoint);
61 48 }
62 49
63 50 @Override
64 51 public SecurityInfo getByEndpoint(String endpoint) {
65 52 SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint);
66 53 if (securityInfo == null) {
67   - LwM2mClient lwM2mClient = clientContext.getClientByEndpoint(endpoint);
68   - if (lwM2mClient != null && lwM2mClient.getRegistration() != null && !lwM2mClient.getRegistration().getIdentity().isSecure()) {
69   - return null;
70   - }
71   - securityInfo = clientContext.fetchClientByEndpoint(endpoint).getSecurityInfo();
72   - try {
73   - if (securityInfo != null) {
74   - add(securityInfo);
75   - }
76   - } catch (NonUniqueSecurityInfoException e) {
77   - log.trace("Failed to add security info: {}", securityInfo, e);
78   - }
  54 + securityInfo = fetchAndPutSecurityInfo(endpoint);
79 55 }
80 56 return securityInfo;
81 57 }
... ... @@ -84,15 +60,31 @@ public class TbLwM2mSecurityStore implements EditableSecurityStore {
84 60 public SecurityInfo getByIdentity(String pskIdentity) {
85 61 SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity);
86 62 if (securityInfo == null) {
87   - securityInfo = clientContext.fetchClientByEndpoint(pskIdentity).getSecurityInfo();
88   - try {
89   - if (securityInfo != null) {
90   - add(securityInfo);
91   - }
92   - } catch (NonUniqueSecurityInfoException e) {
93   - log.trace("Failed to add security info: {}", securityInfo, e);
94   - }
  63 + securityInfo = fetchAndPutSecurityInfo(pskIdentity);
95 64 }
96 65 return securityInfo;
97 66 }
  67 +
  68 + @Nullable
  69 + public SecurityInfo fetchAndPutSecurityInfo(String credentialsId) {
  70 + TbLwM2MSecurityInfo securityInfo = validator.getEndpointSecurityInfoByCredentialsId(credentialsId, LwM2mTransportUtil.LwM2mTypeServer.CLIENT);
  71 + try {
  72 + if (securityInfo != null) {
  73 + securityStore.put(securityInfo);
  74 + }
  75 + } catch (NonUniqueSecurityInfoException e) {
  76 + log.trace("Failed to add security info: {}", securityInfo, e);
  77 + }
  78 + return securityInfo != null ? securityInfo.getSecurityInfo() : null;
  79 + }
  80 +
  81 + @Override
  82 + public void put(TbLwM2MSecurityInfo tbSecurityInfo) throws NonUniqueSecurityInfoException {
  83 + securityStore.put(tbSecurityInfo);
  84 + }
  85 +
  86 + @Override
  87 + public void remove(String endpoint) {
  88 + securityStore.remove(endpoint);
  89 + }
98 90 }
... ...
... ... @@ -17,17 +17,14 @@ package org.thingsboard.server.transport.lwm2m.server.store;
17 17
18 18 import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
19 19 import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore;
20   -import org.eclipse.leshan.server.security.EditableSecurityStore;
21   -import org.eclipse.leshan.server.security.InMemorySecurityStore;
22 20 import org.springframework.beans.factory.annotation.Autowired;
23 21 import org.springframework.beans.factory.annotation.Value;
24 22 import org.springframework.context.annotation.Bean;
25   -import org.springframework.context.annotation.Lazy;
26 23 import org.springframework.stereotype.Component;
27 24 import org.thingsboard.server.cache.TBRedisCacheConfiguration;
28 25 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
29 26 import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig;
30   -import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
  27 +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator;
31 28
32 29 import java.util.Optional;
33 30
... ... @@ -42,8 +39,7 @@ public class TbLwM2mStoreFactory {
42 39 private LwM2MTransportServerConfig config;
43 40
44 41 @Autowired
45   - @Lazy
46   - private LwM2mClientContext clientContext;
  42 + private LwM2mCredentialsSecurityInfoValidator validator;
47 43
48 44 @Value("${transport.lwm2m.redis.enabled:false}")
49 45 private boolean useRedis;
... ... @@ -55,9 +51,9 @@ public class TbLwM2mStoreFactory {
55 51 }
56 52
57 53 @Bean
58   - private EditableSecurityStore securityStore() {
59   - return new TbLwM2mSecurityStore(clientContext, redisConfiguration.isPresent() && useRedis ?
60   - new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore());
  54 + private TbEditableSecurityStore securityStore() {
  55 + return new TbLwM2mSecurityStore(redisConfiguration.isPresent() && useRedis ?
  56 + new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new TbInMemorySecurityStore(), validator);
61 57 }
62 58
63 59 @Bean
... ...
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.transport.lwm2m.server.store;
  17 +
  18 +import org.eclipse.leshan.server.security.SecurityStore;
  19 +import org.thingsboard.server.transport.lwm2m.secure.TbLwM2MSecurityInfo;
  20 +
  21 +public interface TbSecurityStore extends SecurityStore {
  22 +
  23 + TbLwM2MSecurityInfo getTbLwM2MSecurityInfoByEndpoint(String endpoint);
  24 +
  25 +}
... ...
... ... @@ -69,9 +69,7 @@
69 69 <jackson-core.version>2.12.1</jackson-core.version>
70 70 <json-schema-validator.version>2.2.6</json-schema-validator.version>
71 71 <californium.version>2.6.1</californium.version>
72   - <leshan-server.version>1.3.1</leshan-server.version>
73   - <leshan-core.version>1.3.1</leshan-core.version>
74   - <leshan-client.version>1.3.1</leshan-client.version>
  72 + <leshan.version>2.0.0-M3</leshan.version>
75 73 <gson.version>2.6.2</gson.version>
76 74 <freemarker.version>2.3.30</freemarker.version>
77 75 <mail.version>1.6.2</mail.version>
... ... @@ -1222,22 +1220,22 @@
1222 1220 <dependency>
1223 1221 <groupId>org.eclipse.leshan</groupId>
1224 1222 <artifactId>leshan-server-cf</artifactId>
1225   - <version>${leshan-server.version}</version>
  1223 + <version>${leshan.version}</version>
1226 1224 </dependency>
1227 1225 <dependency>
1228 1226 <groupId>org.eclipse.leshan</groupId>
1229 1227 <artifactId>leshan-client-cf</artifactId>
1230   - <version>${leshan-client.version}</version>
  1228 + <version>${leshan.version}</version>
1231 1229 </dependency>
1232 1230 <dependency>
1233 1231 <groupId>org.eclipse.leshan</groupId>
1234 1232 <artifactId>leshan-server-redis</artifactId>
1235   - <version>${leshan-server.version}</version>
  1233 + <version>${leshan.version}</version>
1236 1234 </dependency>
1237 1235 <dependency>
1238 1236 <groupId>org.eclipse.leshan</groupId>
1239 1237 <artifactId>leshan-core</artifactId>
1240   - <version>${leshan-core.version}</version>
  1238 + <version>${leshan.version}</version>
1241 1239 </dependency>
1242 1240 <dependency>
1243 1241 <groupId>org.eclipse.californium</groupId>
... ...