Commit 648e8ec262ee4aea594aa438d4d2b651f09bed80
1 parent
d27c721b
lwm2m: add Lwm2m provider for models
Showing
13 changed files
with
189 additions
and
218 deletions
... | ... | @@ -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 | } | ... | ... |
... | ... | @@ -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> | ... | ... |