From 648e8ec262ee4aea594aa438d4d2b651f09bed80 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Fri, 12 Mar 2021 17:53:03 +0200 Subject: [PATCH] lwm2m: add Lwm2m provider for models --- .../service/install/InstallScripts.java | 91 ++++++++++---- ...TransportBootstrapServerConfiguration.java | 3 +- .../server/LwM2mTransportContextServer.java | 87 ++++--------- .../lwm2m/server/LwM2mTransportHandler.java | 6 +- .../lwm2m/server/LwM2mTransportRequest.java | 4 +- .../LwM2mTransportServerConfiguration.java | 30 ++--- .../server/LwM2mTransportServiceImpl.java | 20 --- .../server/LwM2mVersionedModelProvider.java | 116 +++++++++++------- .../server/client/LwM2mClientContextImpl.java | 1 - .../server/client/LwM2mClientProfile.java | 5 +- .../lwm2m/utils/LwM2mValueConverterImpl.java | 5 + .../lwm2m/LwM2MTransportConfigServer.java | 37 +----- pom.xml | 6 +- 13 files changed, 191 insertions(+), 220 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java index 4cb4fbd059..f9ef8e03e1 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java +++ b/application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java @@ -17,6 +17,10 @@ package org.thingsboard.server.service.install; import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.DDFFileParser; +import org.eclipse.leshan.core.model.DefaultDDFFileValidator; +import org.eclipse.leshan.core.model.InvalidDDFFileException; +import org.eclipse.leshan.core.model.ObjectModel; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -39,6 +43,8 @@ import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetsBundleService; +import java.io.ByteArrayInputStream; +import java.io.File; import java.io.IOException; import java.nio.file.DirectoryStream; import java.nio.file.Files; @@ -196,37 +202,70 @@ public class InstallScripts { } public void loadSystemLwm2mResources() throws Exception { +// Path modelsDir = Paths.get("/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/"); Path modelsDir = Paths.get(getDataDir(), MODELS_DIR); - try (DirectoryStream dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { - dirStream.forEach( - path -> { - try { - Resource resource = new Resource(); - resource.setTenantId(TenantId.SYS_TENANT_ID); - resource.setResourceType(ResourceType.LWM2M_MODEL); - resource.setResourceId(path.getFileName().toString()); - resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(path))); - resourceService.saveResource(resource); - } catch (Exception e) { - log.error("Unable to load lwm2m model [{}]", path.toString()); - throw new RuntimeException("Unable to load lwm2m model", e); + if (Files.isDirectory(modelsDir)) { + try (DirectoryStream dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { + dirStream.forEach( + path -> { + try { + byte[] fileBytes = Files.readAllBytes(path); + String key = getObjectModelLwm2mValid(fileBytes, path.getFileName().toString(), new DefaultDDFFileValidator()); + if (key != null) { + Resource resource = new Resource(); + resource.setTenantId(TenantId.SYS_TENANT_ID); + resource.setResourceType(ResourceType.LWM2M_MODEL); + resource.setResourceId(key); + resource.setValue(Base64.getEncoder().encodeToString(fileBytes)); + resourceService.saveResource(resource); + } + } catch (Exception e) { + log.error("Unable to load lwm2m model [{}]", path.toString()); + throw new RuntimeException("Unable to load lwm2m model", e); + } } - } - ); + ); + } } Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks"); - try { - Resource resource = new Resource(); - resource.setTenantId(TenantId.SYS_TENANT_ID); - resource.setResourceType(ResourceType.JKS); - resource.setResourceId(jksPath.getFileName().toString()); - resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath))); - resourceService.saveResource(resource); - } catch (Exception e) { - log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString()); - throw new RuntimeException("Unable to load l2m2m serverKeyStore", e); - } + try { + Resource resource = new Resource(); + resource.setTenantId(TenantId.SYS_TENANT_ID); + resource.setResourceType(ResourceType.JKS); + resource.setResourceId(jksPath.getFileName().toString()); + resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath))); + resourceService.saveResource(resource); + } catch (Exception e) { + log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString()); + throw new RuntimeException("Unable to load l2m2m serverKeyStore", e); + } + } + + private String getObjectModelLwm2mValid(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) { + try { + DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator); + ObjectModel objectModel = ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0); + return objectModel.id + "##" + objectModel.getVersion(); + } catch (IOException | InvalidDDFFileException e) { + log.error("Could not parse the XML file [{}]", streamName, e); + return null; + } + + } + + private void removeFile(Path modelsDir, String nameFile, byte[] fileBytes) { + String path = "/home/nick/Igor_project/thingsboard_ce_3_2_docker/thingsboard/common/transport/lwm2m/src/main/resources/models/"; + File file = new File(path + nameFile); + if (!file.isDirectory()) { + try { + Files.write(Paths.get(path + "server/" + nameFile), fileBytes); + file.delete(); + } catch (IOException e) { + e.printStackTrace(); + } + + } } public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java index 59e1087f21..e531de3628 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java @@ -17,7 +17,6 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; -import org.eclipse.leshan.core.model.StaticModel; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; @@ -94,7 +93,7 @@ public class LwM2MTransportBootstrapServerConfiguration { builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); /** Define model provider (Create Models )*/ - builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon())); +// builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon())); /** Create credentials */ this.setServerWithCredentials(builder); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java index 92db005094..2fffd17a4c 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java @@ -16,13 +16,13 @@ package org.thingsboard.server.transport.lwm2m.server; /** * Copyright © 2016-2020 The Thingsboard Authors - * + *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + *

* http://www.apache.org/licenses/LICENSE-2.0 - * + *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -34,9 +34,13 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.DDFFileParser; +import org.eclipse.leshan.core.model.DefaultDDFFileValidator; +import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.ObjectModel; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportContext; +import org.thingsboard.server.common.transport.TransportResourceCache; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.adaptor.AdaptorException; @@ -48,7 +52,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCreden import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; -import java.util.List; +import java.io.ByteArrayInputStream; +import java.io.IOException; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY; @@ -62,14 +67,16 @@ public class LwM2mTransportContextServer extends TransportContext { private final TransportService transportService; - private List modelsValueServer; + private final TransportResourceCache transportResourceCache; + @Getter private final LwM2MJsonAdaptor adaptor; - public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, LwM2MJsonAdaptor adaptor) { + public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, TransportResourceCache transportResourceCache, LwM2MJsonAdaptor adaptor) { this.lwM2MTransportConfigServer = lwM2MTransportConfigServer; this.transportService = transportService; + this.transportResourceCache = transportResourceCache; this.adaptor = adaptor; } @@ -77,6 +84,10 @@ public class LwM2mTransportContextServer extends TransportContext { return this.lwM2MTransportConfigServer; } + public TransportResourceCache getTransportResourceCache() { + return this.transportResourceCache; + } + /** * Sent to Thingsboard Attribute || Telemetry * @@ -139,59 +150,13 @@ public class LwM2mTransportContextServer extends TransportContext { .build(); } - - - -// /** -// * ResourcesRequestMsg -// * -// * @param resourceType -// * @return -// */ -// public GetResourcesResponseMsg getResourceTenant (UUID tenantId, String resourceType) { -// CountDownLatch latch = new CountDownLatch(1); -// GetResourcesResponseMsg responseMsg = -// this.getTransportService() -// .getResources(GetResourcesRequestMsg.newBuilder() -// .setResourceType(resourceType) -// .setTenantIdLSB(tenantId.getLeastSignificantBits()) -// .setTenantIdMSB(tenantId.getMostSignificantBits()) -// .build()); -// latch.countDown(); -// try { -// latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS); -// } catch (InterruptedException e) { -// log.error("Failed to await credentials!", e); -// } -// -// return responseMsg; -// } - -// public GetResourcesResponseMsg getResourceTenantProcess (UUID tenantId, String resourceType) { -// CountDownLatch latch = new CountDownLatch(2); -// final GetResourcesResponseMsg[] responseMsg = {null}; -// this.getTransportService().process(GetResourcesRequestMsg.newBuilder() -// .setResourceType(resourceType) -// .setTenantIdLSB(tenantId.getLeastSignificantBits()) -// .setTenantIdMSB(tenantId.getMostSignificantBits()) -// .build(), -// new TransportServiceCallback<>() { -// @Override -// public void onSuccess(GetResourcesResponseMsg msg) { responseMsg[0] = msg; -// latch.countDown(); -// } -// -// @Override -// public void onError(Throwable e) { -// log.trace("[{}] [{}] Failed to process credentials ", tenantId, e); -// latch.countDown(); -// } -// }); -// try { -// latch.await(this.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS); -// } catch (InterruptedException e) { -// log.error("Failed to await credentials!", e); -// } -// return responseMsg[0]; -// } + public ObjectModel parseFromXmlToObjectModel(byte[] xmlByte, String streamName, DefaultDDFFileValidator ddfValidator) { + try { + DDFFileParser ddfFileParser = new DDFFileParser(ddfValidator); + return ddfFileParser.parseEx(new ByteArrayInputStream(xmlByte), streamName).get(0); + } catch (IOException | InvalidDDFFileException e) { + log.error("Could not parse the XML file [{}]", streamName, e); + return null; + } + } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java index 150fe9b5d0..5b6ec23a6e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java @@ -35,6 +35,7 @@ import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.nustaq.serialization.FSTConfiguration; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; @@ -45,7 +46,6 @@ import java.util.Arrays; import java.util.Date; import java.util.LinkedList; import java.util.Optional; -import java.util.UUID; @Slf4j //@Component("LwM2MTransportHandler") @@ -189,7 +189,7 @@ public class LwM2mTransportHandler { return null; } - public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, UUID tenantId) { + public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) { LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile(); lwM2MClientProfile.setTenantId(tenantId); lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject()); @@ -223,7 +223,7 @@ public class LwM2mTransportHandler { ObjectMapper mapper = new ObjectMapper(); String profileStr = mapper.writeValueAsString(profile); JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null; - return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId().getId()) : null; + return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null; } catch (IOException e) { log.error("", e); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index fc14b9c080..fa7f0d68b8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java @@ -87,9 +87,6 @@ public class LwM2mTransportRequest { private final LeshanServer leshanServer; -// @Autowired -// private LwM2mTransportServiceImpl serviceImpl; - private final LwM2mTransportServiceImpl serviceImpl; public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) { @@ -232,6 +229,7 @@ public class LwM2mTransportRequest { private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) { LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); leshanServer.send(registration, request, timeoutInMs, (ResponseCallback) response -> { + if (!lwM2MClient.isInit()) { lwM2MClient.initValue(this.serviceImpl, request.getPath().toString()); } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java index 7fa417b145..0af20b3e51 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java @@ -27,7 +27,6 @@ import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.security.DefaultAuthorizer; import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; @@ -61,24 +60,23 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_W import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; @Slf4j -@Component("LwM2MTransportServerConfiguration") +@Component @TbLwM2mTransportComponent public class LwM2mTransportServerConfiguration { private PublicKey publicKey; private PrivateKey privateKey; private boolean pskMode = false; + private final LwM2mTransportContextServer context; + private final CaliforniumRegistrationStore registrationStore; + private final EditableSecurityStore securityStore; + private final LwM2mClientContext lwM2mClientContext; - @Autowired - private LwM2mTransportContextServer context; - - @Autowired - private CaliforniumRegistrationStore registrationStore; - - @Autowired - private EditableSecurityStore securityStore; - - @Autowired - private LwM2mClientContext lwM2mClientContext;; + public LwM2mTransportServerConfiguration(LwM2mTransportContextServer context, CaliforniumRegistrationStore registrationStore, EditableSecurityStore securityStore, LwM2mClientContext lwM2mClientContext) { + this.context = context; + this.registrationStore = registrationStore; + this.securityStore = securityStore; + this.lwM2mClientContext = lwM2mClientContext; + } @Bean public LeshanServer getLeshanServer() { @@ -98,10 +96,8 @@ public class LwM2mTransportServerConfiguration { builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); /** Define model provider (Create Models )*/ -// TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name()); -// TransportProtos.GetResourcesResponseMsg responseMsg= this.context.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name()); -// LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueCommon()); - LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValueServer(), this.lwM2mClientContext); + LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.context); + this.context.getLwM2MTransportConfigServer().setModelProvider(modelProvider); builder.setObjectModelProvider(modelProvider); /** Create credentials */ diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java index df469d5a96..1af4e8bfd8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java @@ -153,11 +153,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { executorRegistered.submit(() -> { try { log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - ((LwM2mVersionedModelProvider)leshanServer.getModelProvider()).setRepository(this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getModelsValueCommon()); -// TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenantProcess(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name()); -// TransportProtos.GetResourcesResponseMsg responseMsg= this.lwM2mTransportContextServer.getResourceTenant(TenantId.SYS_TENANT_ID.getId(), ResourceType.LWM2M_MODEL.name()); - - // (((VersionedModelProvider) (leshanServer)).modelProvider).repository; LwM2mClient lwM2MClient = this.lwM2mClientContext.updateInSessionsLwM2MClient(registration); if (lwM2MClient != null) { SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); @@ -657,21 +652,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { return (clientInstances.size() > 0) ? clientInstances : null; } -// /** -// * get AttrName/TelemetryName with value from Client -// * -// * @param registration - -// * @return - JsonObject, format: {name: value}} -// */ -// private JsonObject getAttributeClient(Registration registration) { -// if (registration.getAdditionalRegistrationAttributes().size() > 0) { -// JsonObject resNameValues = new JsonObject(); -// registration.getAdditionalRegistrationAttributes().forEach(resNameValues::addProperty); -// return resNameValues; -// } -// return null; -// } - /** * @param attributes - new JsonObject * @param telemetry - new JsonObject diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java index 64e9f67199..503af176af 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java @@ -15,100 +15,122 @@ */ package org.thingsboard.server.transport.lwm2m.server; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.model.DefaultDDFFileValidator; import org.eclipse.leshan.core.model.LwM2mModel; -import org.eclipse.leshan.core.model.LwM2mModelRepository; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; +import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; +import java.util.Iterator; import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -public class LwM2mVersionedModelProvider implements LwM2mModelProvider { +import static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL; - private LwM2mModelRepository repository; - private Map repositoriesTenant; - private LwM2mClientContext lwM2mClientContext; +@Slf4j +public class LwM2mVersionedModelProvider implements LwM2mModelProvider { - public LwM2mVersionedModelProvider(Collection objectModels, LwM2mClientContext lwM2mClientContext) { - this.repository = new LwM2mModelRepository(objectModels); + /** + * int objectId + * String version ("1.01") + * Key = objectId + "##" + version + * Value = TenantId + */ + private final LwM2mClientContext lwM2mClientContext; + private final LwM2mTransportContextServer lwM2mTransportContextServer; + + public LwM2mVersionedModelProvider(LwM2mClientContext lwM2mClientContext, LwM2mTransportContextServer lwM2mTransportContextServer) { this.lwM2mClientContext = lwM2mClientContext; - this.repositoriesTenant = new ConcurrentHashMap<>(); + this.lwM2mTransportContextServer = lwM2mTransportContextServer; + } + private String getIdVer(ObjectModel objectModel) { + return objectModel.id + "##" + ((objectModel.getVersion() == null || objectModel.getVersion().isEmpty()) ? ObjectModel.DEFAULT_VERSION : objectModel.getVersion()); } - public LwM2mVersionedModelProvider(LwM2mModelRepository repository, LwM2mClientContext lwM2mClientContext) { - this.repository = repository; - this.lwM2mClientContext = lwM2mClientContext; - this.repositoriesTenant = new ConcurrentHashMap<>(); - } - - public void setRepositoriesTenant (String tenantID, LwM2mModelRepository repositoryTenant) { - this.repositoriesTenant.put(tenantID, repositoryTenant); - } - - public LwM2mModelRepository getRepositoriesTenant (String tenantID) { - return this.repositoriesTenant.get(tenantID); - } - - public void setRepository (Collection objectModels) { - this.repository = new LwM2mModelRepository(objectModels); - } - - public LwM2mModelRepository getRepositoriesCommonTenant (String tenantID) { - LwM2mModelRepository repository = new LwM2mModelRepository(); - - return repository; + private String getIdVer(Integer objectId, String version) { + return objectId != null ? objectId + "##" + ((version == null || version.isEmpty()) ? ObjectModel.DEFAULT_VERSION : version) : null; } + /** + * Update repository if need + * + * @param registration + * @return + */ @Override public LwM2mModel getObjectModel(Registration registration) { - return new DynamicModel(registration, this.lwM2mClientContext.getProfile(registration).getTenantId()); + return new DynamicModel(registration + ); } private class DynamicModel implements LwM2mModel { private final Registration registration; - private final UUID tenantId; + private final TenantId tenantId; - public DynamicModel(Registration registration, UUID tenantId) { + public DynamicModel(Registration registration) { this.registration = registration; - this.tenantId = tenantId; + this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId(); } @Override public ResourceModel getResourceModel(int objectId, int resourceId) { - ObjectModel objectModel = getObjectModel(objectId); - if (objectModel != null) - return objectModel.resources.get(resourceId); - else + try { + ObjectModel objectModel = getObjectModel(objectId); + if (objectModel != null) + return objectModel.resources.get(resourceId); + else + return null; + } catch (Exception e) { + log.error("", e); return null; + } } @Override public ObjectModel getObjectModel(int objectId) { String version = registration.getSupportedVersion(objectId); if (version != null) { - return repository.getObjectModel(objectId, version); + return this.getObjectModelDynamic(objectId, version); } return null; } @Override public Collection getObjectModels() { - Map supportedObjects = registration.getSupportedObject(); - Collection result = new ArrayList<>(supportedObjects.size()); - for (Map.Entry supportedObject : supportedObjects.entrySet()) { - ObjectModel objectModel = repository.getObjectModel(supportedObject.getKey(), - supportedObject.getValue()); - if (objectModel != null) + Map supportedObjects = this.registration.getSupportedObject(); + Collection result = new ArrayList(supportedObjects.size()); + Iterator i$ = supportedObjects.entrySet().iterator(); + + while (i$.hasNext()) { + Map.Entry supportedObject = (Map.Entry) i$.next(); + ObjectModel objectModel = this.getObjectModelDynamic((Integer) supportedObject.getKey(), (String) supportedObject.getValue()); + if (objectModel != null) { result.add(objectModel); + } } return result; } + + private ObjectModel getObjectModelDynamic(Integer objectId, String version) { + String key = getIdVer(objectId, version); + String xmlB64 = lwM2mTransportContextServer.getTransportResourceCache().get( + this.tenantId, + LWM2M_MODEL, + key). + getValue(); + return xmlB64 != null && !xmlB64.isEmpty() ? + lwM2mTransportContextServer.parseFromXmlToObjectModel( + Base64.getDecoder().decode(xmlB64), + key + ".xml", + new DefaultDDFFileValidator()) : + null; + } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index b41e7cfdaa..d30628a43f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -168,5 +168,4 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { } return false; } - } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java index dcda2cc62b..8285c9bc8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java @@ -19,13 +19,12 @@ import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import lombok.Data; - -import java.util.UUID; +import org.thingsboard.server.common.data.id.TenantId; @Data public class LwM2mClientProfile { - private UUID tenantId; + private TenantId tenantId; /** * {"clientLwM2mSettings": { * clientUpdateValueAfterConnect: false; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java index 136de3eb95..85283749dc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java @@ -31,6 +31,8 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; +import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE; + @Slf4j public class LwM2mValueConverterImpl implements LwM2mValueConverter { @@ -52,6 +54,9 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter { /** expected type */ return value; } + if (currentType == null) { + currentType = OPAQUE; + } switch (expectedType) { case INTEGER: diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java index 4e57e61190..1208ace313 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java @@ -18,10 +18,10 @@ package org.thingsboard.server.common.transport.lwm2m; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.model.ObjectLoader; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mPath; +import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; @@ -38,9 +38,7 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; -import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; @Slf4j @Component @@ -87,7 +85,7 @@ public class LwM2MTransportConfigServer { @Getter @Setter - private List modelsValueServer; + private LwM2mModelProvider modelProvider; @Getter @Value("${transport.lwm2m.timeout:}") @@ -189,35 +187,11 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.server.secure.alias:}") private String serverAlias; - - @PostConstruct public void init() { - modelsValueServer = ObjectLoader.loadDefault(); - modelsValueServer.remove(3); - modelsValueCommon = ObjectLoader.loadDefault(); - File path = getPathModels(); - if (path.isDirectory()) { - try { - modelsValueCommon.addAll(ObjectLoader.loadObjectsFromDir(path)); - log.info(" [{}] Models directory is a directory", path.getAbsoluteFile()); - } catch (Exception e) { - log.error(" [{}] Could not parse the resource definition file", e.toString()); - } - } else { - log.error(" [{}] Read Models", path.getAbsoluteFile()); - } this.getInKeyStore(); } - private File getPathModels() { - Path pathModels = (modelPathFile != null && !modelPathFile.isEmpty()) ? Paths.get(modelPathFile) : - (new File(Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT).toUri()).isDirectory()) ? - Paths.get(getBaseDirPath(), PATH_DATA, MODEL_PATH_DEFAULT) : - Paths.get(getBaseDirPath(), APP_DIR, TRANSPORT_DIR, LWM2M_DIR, SRC_DIR, MAIN_DIR, RESOURCES_DIR, MODEL_PATH_DEFAULT); - return (pathModels != null) ? new File(pathModels.toUri()) : null; - } - private KeyStore getInKeyStore() { try { if (keyStoreValue != null && keyStoreValue.size() > 0) @@ -260,12 +234,7 @@ public class LwM2MTransportConfigServer { } public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) { - String pathLink = "/" + pathIds.getObjectId() + "/" + pathIds.getObjectInstanceId(); - return (Arrays.stream(registration.getObjectLinks()).filter(p-> p.getUrl().equals(pathLink)).findFirst().isPresent() && - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).size() > 0) && - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.containsKey(pathIds.getResourceId()) ? - this.modelsValueCommon.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.get(pathIds.getResourceId()) : - null; + return this.modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()); } public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) { diff --git a/pom.xml b/pom.xml index 7e12adff98..4f8c7d3790 100755 --- a/pom.xml +++ b/pom.xml @@ -66,9 +66,9 @@ 2.12.1 2.2.6 2.6.1 - 1.3.0 - 1.3.0 - 1.3.0 + 1.3.1 + 1.3.1 + 1.3.1 2.6.2 2.3.30 1.6.2