Commit 648e8ec262ee4aea594aa438d4d2b651f09bed80

Authored by nickAS21
1 parent d27c721b

lwm2m: add Lwm2m provider for models

... ... @@ -17,6 +17,10 @@ package org.thingsboard.server.service.install;
17 17
18 18 import com.fasterxml.jackson.databind.JsonNode;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.eclipse.leshan.core.model.DDFFileParser;
  21 +import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
  22 +import org.eclipse.leshan.core.model.InvalidDDFFileException;
  23 +import org.eclipse.leshan.core.model.ObjectModel;
20 24 import org.springframework.beans.factory.annotation.Autowired;
21 25 import org.springframework.beans.factory.annotation.Value;
22 26 import org.springframework.stereotype.Component;
... ... @@ -39,6 +43,8 @@ import org.thingsboard.server.dao.rule.RuleChainService;
39 43 import org.thingsboard.server.dao.widget.WidgetTypeService;
40 44 import org.thingsboard.server.dao.widget.WidgetsBundleService;
41 45
  46 +import java.io.ByteArrayInputStream;
  47 +import java.io.File;
42 48 import java.io.IOException;
43 49 import java.nio.file.DirectoryStream;
44 50 import java.nio.file.Files;
... ... @@ -196,37 +202,70 @@ public class InstallScripts {
196 202 }
197 203
198 204 public void loadSystemLwm2mResources() throws Exception {
  205 +// Path modelsDir = Paths.get("/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/");
199 206 Path modelsDir = Paths.get(getDataDir(), MODELS_DIR);
200   - try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
201   - dirStream.forEach(
202   - path -> {
203   - try {
204   - Resource resource = new Resource();
205   - resource.setTenantId(TenantId.SYS_TENANT_ID);
206   - resource.setResourceType(ResourceType.LWM2M_MODEL);
207   - resource.setResourceId(path.getFileName().toString());
208   - resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(path)));
209   - resourceService.saveResource(resource);
210   - } catch (Exception e) {
211   - log.error("Unable to load lwm2m model [{}]", path.toString());
212   - throw new RuntimeException("Unable to load lwm2m model", e);
  207 + if (Files.isDirectory(modelsDir)) {
  208 + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
  209 + dirStream.forEach(
  210 + path -> {
  211 + try {
  212 + byte[] fileBytes = Files.readAllBytes(path);
  213 + String key = getObjectModelLwm2mValid(fileBytes, path.getFileName().toString(), new DefaultDDFFileValidator());
  214 + if (key != null) {
  215 + Resource resource = new Resource();
  216 + resource.setTenantId(TenantId.SYS_TENANT_ID);
  217 + resource.setResourceType(ResourceType.LWM2M_MODEL);
  218 + resource.setResourceId(key);
  219 + resource.setValue(Base64.getEncoder().encodeToString(fileBytes));
  220 + resourceService.saveResource(resource);
  221 + }
  222 + } catch (Exception e) {
  223 + log.error("Unable to load lwm2m model [{}]", path.toString());
  224 + throw new RuntimeException("Unable to load lwm2m model", e);
  225 + }
213 226 }
214   - }
215   - );
  227 + );
  228 + }
216 229 }
217 230
218 231 Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
219   - try {
220   - Resource resource = new Resource();
221   - resource.setTenantId(TenantId.SYS_TENANT_ID);
222   - resource.setResourceType(ResourceType.JKS);
223   - resource.setResourceId(jksPath.getFileName().toString());
224   - resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
225   - resourceService.saveResource(resource);
226   - } catch (Exception e) {
227   - log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
228   - throw new RuntimeException("Unable to load l2m2m serverKeyStore", e);
229   - }
  232 + try {
  233 + Resource resource = new Resource();
  234 + resource.setTenantId(TenantId.SYS_TENANT_ID);
  235 + resource.setResourceType(ResourceType.JKS);
  236 + resource.setResourceId(jksPath.getFileName().toString());
  237 + resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
  238 + resourceService.saveResource(resource);
  239 + } catch (Exception e) {
  240 + log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
  241 + throw new RuntimeException("Unable to load l2m2m serverKeyStore", e);
  242 + }
  243 + }
  244 +
  245 + private String getObjectModelLwm2mValid(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) {
  246 + try {
  247 + DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator);
  248 + ObjectModel objectModel = ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0);
  249 + return objectModel.id + "##" + objectModel.getVersion();
  250 + } catch (IOException | InvalidDDFFileException e) {
  251 + log.error("Could not parse the XML file [{}]", streamName, e);
  252 + return null;
  253 + }
  254 +
  255 + }
  256 +
  257 + private void removeFile(Path modelsDir, String nameFile, byte[] fileBytes) {
  258 + String path = "/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/";
  259 + File file = new File(path + nameFile);
  260 + if (!file.isDirectory()) {
  261 + try {
  262 + Files.write(Paths.get(path + "server/" + nameFile), fileBytes);
  263 + file.delete();
  264 + } catch (IOException e) {
  265 + e.printStackTrace();
  266 + }
  267 +
  268 + }
230 269 }
231 270
232 271 public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {
... ...
... ... @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap;
17 17
18 18 import lombok.extern.slf4j.Slf4j;
19 19 import org.eclipse.californium.scandium.config.DtlsConnectorConfig;
20   -import org.eclipse.leshan.core.model.StaticModel;
21 20 import org.eclipse.leshan.core.util.Hex;
22 21 import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
23 22 import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
... ... @@ -94,7 +93,7 @@ public class LwM2MTransportBootstrapServerConfiguration {
94 93 builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort));
95 94
96 95 /** Define model provider (Create Models )*/
97   - builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
  96 +// builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
98 97
99 98 /** Create credentials */
100 99 this.setServerWithCredentials(builder);
... ...
... ... @@ -16,13 +16,13 @@
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17 /**
18 18 * Copyright © 2016-2020 The Thingsboard Authors
19   - *
  19 + * <p>
20 20 * Licensed under the Apache License, Version 2.0 (the "License");
21 21 * you may not use this file except in compliance with the License.
22 22 * You may obtain a copy of the License at
23   - *
  23 + * <p>
24 24 * http://www.apache.org/licenses/LICENSE-2.0
25   - *
  25 + * <p>
26 26 * Unless required by applicable law or agreed to in writing, software
27 27 * distributed under the License is distributed on an "AS IS" BASIS,
28 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
... ... @@ -34,9 +34,13 @@ import com.google.gson.JsonElement;
34 34 import com.google.gson.JsonObject;
35 35 import lombok.Getter;
36 36 import lombok.extern.slf4j.Slf4j;
  37 +import org.eclipse.leshan.core.model.DDFFileParser;
  38 +import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
  39 +import org.eclipse.leshan.core.model.InvalidDDFFileException;
37 40 import org.eclipse.leshan.core.model.ObjectModel;
38 41 import org.springframework.stereotype.Component;
39 42 import org.thingsboard.server.common.transport.TransportContext;
  43 +import org.thingsboard.server.common.transport.TransportResourceCache;
40 44 import org.thingsboard.server.common.transport.TransportService;
41 45 import org.thingsboard.server.common.transport.TransportServiceCallback;
42 46 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
... ... @@ -48,7 +52,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCreden
48 52 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
49 53 import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
50 54
51   -import java.util.List;
  55 +import java.io.ByteArrayInputStream;
  56 +import java.io.IOException;
52 57
53 58 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
54 59
... ... @@ -62,14 +67,16 @@ public class LwM2mTransportContextServer extends TransportContext {
62 67
63 68 private final TransportService transportService;
64 69
65   - private List<ObjectModel> modelsValueServer;
  70 + private final TransportResourceCache transportResourceCache;
  71 +
66 72
67 73 @Getter
68 74 private final LwM2MJsonAdaptor adaptor;
69 75
70   - public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, LwM2MJsonAdaptor adaptor) {
  76 + public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, TransportResourceCache transportResourceCache, LwM2MJsonAdaptor adaptor) {
71 77 this.lwM2MTransportConfigServer = lwM2MTransportConfigServer;
72 78 this.transportService = transportService;
  79 + this.transportResourceCache = transportResourceCache;
73 80 this.adaptor = adaptor;
74 81 }
75 82
... ... @@ -77,6 +84,10 @@ public class LwM2mTransportContextServer extends TransportContext {
77 84 return this.lwM2MTransportConfigServer;
78 85 }
79 86
  87 + public TransportResourceCache getTransportResourceCache() {
  88 + return this.transportResourceCache;
  89 + }
  90 +
80 91 /**
81 92 * Sent to Thingsboard Attribute || Telemetry
82 93 *
... ... @@ -139,59 +150,13 @@ public class LwM2mTransportContextServer extends TransportContext {
139 150 .build();
140 151 }
141 152
142   -
143   -
144   -
145   -// /**
146   -// * ResourcesRequestMsg
147   -// *
148   -// * @param resourceType
149   -// * @return
150   -// */
151   -// public GetResourcesResponseMsg getResourceTenant (UUID tenantId, String resourceType) {
152   -// CountDownLatch latch = new CountDownLatch(1);
153   -// GetResourcesResponseMsg responseMsg =
154   -// this.getTransportService()
155   -// .getResources(GetResourcesRequestMsg.newBuilder()
156   -// .setResourceType(resourceType)
157   -// .setTenantIdLSB(tenantId.getLeastSignificantBits())
158   -// .setTenantIdMSB(tenantId.getMostSignificantBits())
159   -// .build());
160   -// latch.countDown();
161   -// try {
162   -// latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS);
163   -// } catch (InterruptedException e) {
164   -// log.error("Failed to await credentials!", e);
165   -// }
166   -//
167   -// return responseMsg;
168   -// }
169   -
170   -// public GetResourcesResponseMsg getResourceTenantProcess (UUID tenantId, String resourceType) {
171   -// CountDownLatch latch = new CountDownLatch(2);
172   -// final GetResourcesResponseMsg[] responseMsg = {null};
173   -// this.getTransportService().process(GetResourcesRequestMsg.newBuilder()
174   -// .setResourceType(resourceType)
175   -// .setTenantIdLSB(tenantId.getLeastSignificantBits())
176   -// .setTenantIdMSB(tenantId.getMostSignificantBits())
177   -// .build(),
178   -// new TransportServiceCallback<>() {
179   -// @Override
180   -// public void onSuccess(GetResourcesResponseMsg msg) { responseMsg[0] = msg;
181   -// latch.countDown();
182   -// }
183   -//
184   -// @Override
185   -// public void onError(Throwable e) {
186   -// log.trace("[{}] [{}] Failed to process credentials ", tenantId, e);
187   -// latch.countDown();
188   -// }
189   -// });
190   -// try {
191   -// latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS);
192   -// } catch (InterruptedException e) {
193   -// log.error("Failed to await credentials!", e);
194   -// }
195   -// return responseMsg[0];
196   -// }
  153 + public ObjectModel parseFromXmlToObjectModel(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) {
  154 + try {
  155 + DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator);
  156 + return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0);
  157 + } catch (IOException | InvalidDDFFileException e) {
  158 + log.error("Could not parse the XML file [{}]", streamName, e);
  159 + return null;
  160 + }
  161 + }
197 162 }
... ...
... ... @@ -35,6 +35,7 @@ import org.eclipse.leshan.server.californium.LeshanServerBuilder;
35 35 import org.nustaq.serialization.FSTConfiguration;
36 36 import org.thingsboard.server.common.data.DeviceProfile;
37 37 import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration;
  38 +import org.thingsboard.server.common.data.id.TenantId;
38 39 import org.thingsboard.server.common.transport.TransportServiceCallback;
39 40 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
40 41 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
... ... @@ -45,7 +46,6 @@ import java.util.Arrays;
45 46 import java.util.Date;
46 47 import java.util.LinkedList;
47 48 import java.util.Optional;
48   -import java.util.UUID;
49 49
50 50 @Slf4j
51 51 //@Component("LwM2MTransportHandler")
... ... @@ -189,7 +189,7 @@ public class LwM2mTransportHandler {
189 189 return null;
190 190 }
191 191
192   - public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, UUID tenantId) {
  192 + public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
193 193 LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
194 194 lwM2MClientProfile.setTenantId(tenantId);
195 195 lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());
... ... @@ -223,7 +223,7 @@ public class LwM2mTransportHandler {
223 223 ObjectMapper mapper = new ObjectMapper();
224 224 String profileStr = mapper.writeValueAsString(profile);
225 225 JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
226   - return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId().getId()) : null;
  226 + return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
227 227 } catch (IOException e) {
228 228 log.error("", e);
229 229 }
... ...
... ... @@ -87,9 +87,6 @@ public class LwM2mTransportRequest {
87 87
88 88 private final LeshanServer leshanServer;
89 89
90   -// @Autowired
91   -// private LwM2mTransportServiceImpl serviceImpl;
92   -
93 90 private final LwM2mTransportServiceImpl serviceImpl;
94 91
95 92 public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) {
... ... @@ -232,6 +229,7 @@ public class LwM2mTransportRequest {
232 229 private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) {
233 230 LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
234 231 leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
  232 +
235 233 if (!lwM2MClient.isInit()) {
236 234 lwM2MClient.initValue(this.serviceImpl, request.getPath().toString());
237 235 }
... ...
... ... @@ -27,7 +27,6 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider;
27 27 import org.eclipse.leshan.server.security.DefaultAuthorizer;
28 28 import org.eclipse.leshan.server.security.EditableSecurityStore;
29 29 import org.eclipse.leshan.server.security.SecurityChecker;
30   -import org.springframework.beans.factory.annotation.Autowired;
31 30 import org.springframework.context.annotation.Bean;
32 31 import org.springframework.stereotype.Component;
33 32 import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
... ... @@ -61,24 +60,23 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_W
61 60 import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig;
62 61
63 62 @Slf4j
64   -@Component("LwM2MTransportServerConfiguration")
  63 +@Component
65 64 @TbLwM2mTransportComponent
66 65 public class LwM2mTransportServerConfiguration {
67 66 private PublicKey publicKey;
68 67 private PrivateKey privateKey;
69 68 private boolean pskMode = false;
  69 + private final LwM2mTransportContextServer context;
  70 + private final CaliforniumRegistrationStore registrationStore;
  71 + private final EditableSecurityStore securityStore;
  72 + private final LwM2mClientContext lwM2mClientContext;
70 73
71   - @Autowired
72   - private LwM2mTransportContextServer context;
73   -
74   - @Autowired
75   - private CaliforniumRegistrationStore registrationStore;
76   -
77   - @Autowired
78   - private EditableSecurityStore securityStore;
79   -
80   - @Autowired
81   - private LwM2mClientContext lwM2mClientContext;;
  74 + public LwM2mTransportServerConfiguration(LwM2mTransportContextServer context, CaliforniumRegistrationStore registrationStore, EditableSecurityStore securityStore, LwM2mClientContext lwM2mClientContext) {
  75 + this.context = context;
  76 + this.registrationStore = registrationStore;
  77 + this.securityStore = securityStore;
  78 + this.lwM2mClientContext = lwM2mClientContext;
  79 + }
82 80
83 81 @Bean
84 82 public LeshanServer getLeshanServer() {
... ... @@ -98,10 +96,8 @@ public class LwM2mTransportServerConfiguration {
98 96 builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort));
99 97
100 98 /** Define model provider (Create Models )*/
101   -// TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
102   -// TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
103   -// LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueCommon());
104   - LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueServer(), this.lwM2mClientContext);
  99 + LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.context);
  100 + this.context.getLwM2MTransportConfigServer().setModelProvider(modelProvider);
105 101 builder.setObjectModelProvider(modelProvider);
106 102
107 103 /** Create credentials */
... ...
... ... @@ -153,11 +153,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
153 153 executorRegistered.submit(() -> {
154 154 try {
155 155 log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId());
156   - ((LwM2mVersionedModelProvider)leshanServer.getModelProvider()).setRepository(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelsValueCommon());
157   -// TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
158   -// TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name());
159   -
160   - // (((VersionedModelProvider) (leshanServer)).modelProvider).repository;
161 156 LwM2mClient lwM2MClient = this.lwM2mClientContext.updateInSessionsLwM2MClient(registration);
162 157 if (lwM2MClient != null) {
163 158 SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration);
... ... @@ -657,21 +652,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
657 652 return (clientInstances.size() > 0) ? clientInstances : null;
658 653 }
659 654
660   -// /**
661   -// * get AttrName/TelemetryName with value from Client
662   -// *
663   -// * @param registration -
664   -// * @return - JsonObject, format: {name: value}}
665   -// */
666   -// private JsonObject getAttributeClient(Registration registration) {
667   -// if (registration.getAdditionalRegistrationAttributes().size() > 0) {
668   -// JsonObject resNameValues = new JsonObject();
669   -// registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty);
670   -// return resNameValues;
671   -// }
672   -// return null;
673   -// }
674   -
675 655 /**
676 656 * @param attributes - new JsonObject
677 657 * @param telemetry - new JsonObject
... ...
... ... @@ -15,100 +15,122 @@
15 15 */
16 16 package org.thingsboard.server.transport.lwm2m.server;
17 17
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.eclipse.leshan.core.model.DefaultDDFFileValidator;
18 20 import org.eclipse.leshan.core.model.LwM2mModel;
19   -import org.eclipse.leshan.core.model.LwM2mModelRepository;
20 21 import org.eclipse.leshan.core.model.ObjectModel;
21 22 import org.eclipse.leshan.core.model.ResourceModel;
22 23 import org.eclipse.leshan.server.model.LwM2mModelProvider;
23 24 import org.eclipse.leshan.server.registration.Registration;
  25 +import org.thingsboard.server.common.data.id.TenantId;
24 26 import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
25 27
26 28 import java.util.ArrayList;
  29 +import java.util.Base64;
27 30 import java.util.Collection;
  31 +import java.util.Iterator;
28 32 import java.util.Map;
29   -import java.util.UUID;
30   -import java.util.concurrent.ConcurrentHashMap;
31 33
32   -public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
  34 +import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL;
33 35
34   - private LwM2mModelRepository repository;
35   - private Map<String, LwM2mModelRepository> repositoriesTenant;
36   - private LwM2mClientContext lwM2mClientContext;
  36 +@Slf4j
  37 +public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
37 38
38   - public LwM2mVersionedModelProvider(Collection<ObjectModel> objectModels, LwM2mClientContext lwM2mClientContext) {
39   - this.repository = new LwM2mModelRepository(objectModels);
40   - this.lwM2mClientContext = lwM2mClientContext;
41   - this.repositoriesTenant = new ConcurrentHashMap<>();
42   - }
  39 + /**
  40 + * int objectId
  41 + * String version ("1.01")
  42 + * Key = objectId + "##" + version
  43 + * Value = TenantId
  44 + */
  45 + private final LwM2mClientContext lwM2mClientContext;
  46 + private final LwM2mTransportContextServer lwM2mTransportContextServer;
43 47
44   - public LwM2mVersionedModelProvider(LwM2mModelRepository repository, LwM2mClientContext lwM2mClientContext) {
45   - this.repository = repository;
  48 + public LwM2mVersionedModelProvider(LwM2mClientContext lwM2mClientContext, LwM2mTransportContextServer lwM2mTransportContextServer) {
46 49 this.lwM2mClientContext = lwM2mClientContext;
47   - this.repositoriesTenant = new ConcurrentHashMap<>();
  50 + this.lwM2mTransportContextServer = lwM2mTransportContextServer;
48 51 }
49   -
50   - public void setRepositoriesTenant (String tenantID, LwM2mModelRepository repositoryTenant) {
51   - this.repositoriesTenant.put(tenantID, repositoryTenant);
  52 + private String getIdVer(ObjectModel objectModel) {
  53 + return objectModel.id + "##" + ((objectModel.getVersion() == null || objectModel.getVersion().isEmpty()) ? ObjectModel.DEFAULT_VERSION : objectModel.getVersion());
52 54 }
53 55
54   - public LwM2mModelRepository getRepositoriesTenant (String tenantID) {
55   - return this.repositoriesTenant.get(tenantID);
56   - }
57   -
58   - public void setRepository (Collection<ObjectModel> objectModels) {
59   - this.repository = new LwM2mModelRepository(objectModels);
60   - }
61   -
62   - public LwM2mModelRepository getRepositoriesCommonTenant (String tenantID) {
63   - LwM2mModelRepository repository = new LwM2mModelRepository();
64   -
65   - return repository;
  56 + private String getIdVer(Integer objectId, String version) {
  57 + return objectId != null ? objectId + "##" + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null;
66 58 }
67 59
  60 + /**
  61 + * Update repository if need
  62 + *
  63 + * @param registration
  64 + * @return
  65 + */
68 66 @Override
69 67 public LwM2mModel getObjectModel(Registration registration) {
70   - return new DynamicModel(registration, this.lwM2mClientContext.getProfile(registration).getTenantId());
  68 + return new DynamicModel(registration
  69 + );
71 70 }
72 71
73 72 private class DynamicModel implements LwM2mModel {
74 73
75 74 private final Registration registration;
76   - private final UUID tenantId;
  75 + private final TenantId tenantId;
77 76
78   - public DynamicModel(Registration registration, UUID tenantId) {
  77 + public DynamicModel(Registration registration) {
79 78 this.registration = registration;
80   - this.tenantId = tenantId;
  79 + this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId();
81 80 }
82 81
83 82 @Override
84 83 public ResourceModel getResourceModel(int objectId, int resourceId) {
85   - ObjectModel objectModel = getObjectModel(objectId);
86   - if (objectModel != null)
87   - return objectModel.resources.get(resourceId);
88   - else
  84 + try {
  85 + ObjectModel objectModel = getObjectModel(objectId);
  86 + if (objectModel != null)
  87 + return objectModel.resources.get(resourceId);
  88 + else
  89 + return null;
  90 + } catch (Exception e) {
  91 + log.error("", e);
89 92 return null;
  93 + }
90 94 }
91 95
92 96 @Override
93 97 public ObjectModel getObjectModel(int objectId) {
94 98 String version = registration.getSupportedVersion(objectId);
95 99 if (version != null) {
96   - return repository.getObjectModel(objectId, version);
  100 + return this.getObjectModelDynamic(objectId, version);
97 101 }
98 102 return null;
99 103 }
100 104
101 105 @Override
102 106 public Collection<ObjectModel> getObjectModels() {
103   - Map<Integer, String> supportedObjects = registration.getSupportedObject();
104   - Collection<ObjectModel> result = new ArrayList<>(supportedObjects.size());
105   - for (Map.Entry<Integer, String> supportedObject : supportedObjects.entrySet()) {
106   - ObjectModel objectModel = repository.getObjectModel(supportedObject.getKey(),
107   - supportedObject.getValue());
108   - if (objectModel != null)
  107 + Map<Integer, String> supportedObjects = this.registration.getSupportedObject();
  108 + Collection<ObjectModel> result = new ArrayList(supportedObjects.size());
  109 + Iterator i$ = supportedObjects.entrySet().iterator();
  110 +
  111 + while (i$.hasNext()) {
  112 + Map.Entry<Integer, String> supportedObject = (Map.Entry) i$.next();
  113 + ObjectModel objectModel = this.getObjectModelDynamic((Integer) supportedObject.getKey(), (String) supportedObject.getValue());
  114 + if (objectModel != null) {
109 115 result.add(objectModel);
  116 + }
110 117 }
111 118 return result;
112 119 }
  120 +
  121 + private ObjectModel getObjectModelDynamic(Integer objectId, String version) {
  122 + String key = getIdVer(objectId, version);
  123 + String xmlB64 = lwM2mTransportContextServer.getTransportResourceCache().get(
  124 + this.tenantId,
  125 + LWM2M_MODEL,
  126 + key).
  127 + getValue();
  128 + return xmlB64 != null && !xmlB64.isEmpty() ?
  129 + lwM2mTransportContextServer.parseFromXmlToObjectModel(
  130 + Base64.getDecoder().decode(xmlB64),
  131 + key + ".xml",
  132 + new DefaultDDFFileValidator()) :
  133 + null;
  134 + }
113 135 }
114 136 }
... ...
... ... @@ -168,5 +168,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
168 168 }
169 169 return false;
170 170 }
171   -
172 171 }
... ...
... ... @@ -19,13 +19,12 @@ import com.google.gson.Gson;
19 19 import com.google.gson.JsonArray;
20 20 import com.google.gson.JsonObject;
21 21 import lombok.Data;
22   -
23   -import java.util.UUID;
  22 +import org.thingsboard.server.common.data.id.TenantId;
24 23
25 24 @Data
26 25 public class LwM2mClientProfile {
27 26
28   - private UUID tenantId;
  27 + private TenantId tenantId;
29 28 /**
30 29 * {"clientLwM2mSettings": {
31 30 * clientUpdateValueAfterConnect: false;
... ...
... ... @@ -31,6 +31,8 @@ import java.text.DateFormat;
31 31 import java.text.SimpleDateFormat;
32 32 import java.util.Date;
33 33
  34 +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
  35 +
34 36 @Slf4j
35 37 public class LwM2mValueConverterImpl implements LwM2mValueConverter {
36 38
... ... @@ -52,6 +54,9 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
52 54 /** expected type */
53 55 return value;
54 56 }
  57 + if (currentType == null) {
  58 + currentType = OPAQUE;
  59 + }
55 60
56 61 switch (expectedType) {
57 62 case INTEGER:
... ...
... ... @@ -18,10 +18,10 @@ package org.thingsboard.server.common.transport.lwm2m;
18 18 import lombok.Getter;
19 19 import lombok.Setter;
20 20 import lombok.extern.slf4j.Slf4j;
21   -import org.eclipse.leshan.core.model.ObjectLoader;
22 21 import org.eclipse.leshan.core.model.ObjectModel;
23 22 import org.eclipse.leshan.core.model.ResourceModel;
24 23 import org.eclipse.leshan.core.node.LwM2mPath;
  24 +import org.eclipse.leshan.server.model.LwM2mModelProvider;
25 25 import org.eclipse.leshan.server.registration.Registration;
26 26 import org.springframework.beans.factory.annotation.Value;
27 27 import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
... ... @@ -38,9 +38,7 @@ import java.security.KeyStore;
38 38 import java.security.KeyStoreException;
39 39 import java.security.NoSuchAlgorithmException;
40 40 import java.security.cert.CertificateException;
41   -import java.util.Arrays;
42 41 import java.util.List;
43   -import java.util.stream.Collectors;
44 42
45 43 @Slf4j
46 44 @Component
... ... @@ -87,7 +85,7 @@ public class LwM2MTransportConfigServer {
87 85
88 86 @Getter
89 87 @Setter
90   - private List<ObjectModel> modelsValueServer;
  88 + private LwM2mModelProvider modelProvider;
91 89
92 90 @Getter
93 91 @Value("${transport.lwm2m.timeout:}")
... ... @@ -189,35 +187,11 @@ public class LwM2MTransportConfigServer {
189 187 @Value("${transport.lwm2m.server.secure.alias:}")
190 188 private String serverAlias;
191 189
192   -
193   -
194 190 @PostConstruct
195 191 public void init() {
196   - modelsValueServer = ObjectLoader.loadDefault();
197   - modelsValueServer.remove(3);
198   - modelsValueCommon = ObjectLoader.loadDefault();
199   - File path = getPathModels();
200   - if (path.isDirectory()) {
201   - try {
202   - modelsValueCommon.addAll(ObjectLoader.loadObjectsFromDir(path));
203   - log.info(" [{}] Models directory is a directory", path.getAbsoluteFile());
204   - } catch (Exception e) {
205   - log.error(" [{}] Could not parse the resource definition file", e.toString());
206   - }
207   - } else {
208   - log.error(" [{}] Read Models", path.getAbsoluteFile());
209   - }
210 192 this.getInKeyStore();
211 193 }
212 194
213   - private File getPathModels() {
214   - Path pathModels = (modelPathFile != null && !modelPathFile.isEmpty()) ? Paths.get(modelPathFile) :
215   - (new File(Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT).toUri()).isDirectory()) ?
216   - Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT) :
217   - Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, MODEL_PATH_DEFAULT);
218   - return (pathModels != null) ? new File(pathModels.toUri()) : null;
219   - }
220   -
221 195 private KeyStore getInKeyStore() {
222 196 try {
223 197 if (keyStoreValue != null && keyStoreValue.size() > 0)
... ... @@ -260,12 +234,7 @@ public class LwM2MTransportConfigServer {
260 234 }
261 235
262 236 public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) {
263   - String pathLink = "/" + pathIds.getObjectId() + "/" + pathIds.getObjectInstanceId();
264   - return (Arrays.stream(registration.getObjectLinks()).filter(p-> p.getUrl().equals(pathLink)).findFirst().isPresent() &&
265   - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).size() > 0) &&
266   - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.containsKey(pathIds.getResourceId()) ?
267   - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.get(pathIds.getResourceId()) :
268   - null;
  237 + return this.modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
269 238 }
270 239
271 240 public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) {
... ...
... ... @@ -66,9 +66,9 @@
66 66 <jackson-core.version>2.12.1</jackson-core.version>
67 67 <json-schema-validator.version>2.2.6</json-schema-validator.version>
68 68 <californium.version>2.6.1</californium.version>
69   - <leshan-server.version>1.3.0</leshan-server.version>
70   - <leshan-core.version>1.3.0</leshan-core.version>
71   - <leshan-client.version>1.3.0</leshan-client.version>
  69 + <leshan-server.version>1.3.1</leshan-server.version>
  70 + <leshan-core.version>1.3.1</leshan-core.version>
  71 + <leshan-client.version>1.3.1</leshan-client.version>
72 72 <gson.version>2.6.2</gson.version>
73 73 <freemarker.version>2.3.30</freemarker.version>
74 74 <mail.version>1.6.2</mail.version>
... ...