Browse Source

Merge pull request #4238 from thingsboard/add-models

Add models
pull/4270/head
Andrew Shvayka 6 years ago
committed by GitHub
parent
commit
0a2477da79
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      application/src/main/java/org/thingsboard/server/controller/ResourceController.java
  2. 75
      application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java
  3. 1
      application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java
  4. 5
      application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java
  5. 2
      application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java
  6. 2
      application/src/main/java/org/thingsboard/server/service/queue/TbClusterService.java
  7. 4
      application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java
  8. 8
      common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java
  9. 37
      common/data/src/main/java/org/thingsboard/server/common/data/transport/resource/Resource.java
  10. 20
      common/data/src/main/java/org/thingsboard/server/common/data/transport/resource/ResourceType.java
  11. 3
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapServerConfiguration.java
  12. 48
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java
  13. 6
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java
  14. 8
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java
  15. 26
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java
  16. 15
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java
  17. 136
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java
  18. 2
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java
  19. 13
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java
  20. 14
      common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java
  21. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportResourceCache.java
  22. 39
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/lwm2m/LwM2MTransportConfigServer.java
  23. 2
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java
  24. 3
      common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java
  25. 2
      dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceEntity.java
  26. 14
      dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java
  27. 9
      dao/src/main/java/org/thingsboard/server/dao/resource/ResourceDao.java
  28. 11
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceDaoImpl.java
  29. 4
      dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceRepository.java
  30. 6
      pom.xml

4
application/src/main/java/org/thingsboard/server/controller/ResourceController.java

@ -23,12 +23,12 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.dao.resource.ResourceService; import org.thingsboard.server.dao.resource.ResourceService;
import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.queue.util.TbCoreComponent;

75
application/src/main/java/org/thingsboard/server/service/install/InstallScripts.java

@ -17,19 +17,23 @@ package org.thingsboard.server.service.install;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.slf4j.Slf4j; 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.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.Dashboard;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate; import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
import org.thingsboard.server.common.data.rule.RuleChain; import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainMetaData;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetType;
import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
@ -39,6 +43,8 @@ import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetTypeService;
import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.dao.widget.WidgetsBundleService;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.DirectoryStream; import java.nio.file.DirectoryStream;
import java.nio.file.Files; import java.nio.file.Files;
@ -196,18 +202,23 @@ public class InstallScripts {
} }
public void loadSystemLwm2mResources() throws Exception { 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); Path modelsDir = Paths.get(getDataDir(), MODELS_DIR);
if (Files.isDirectory(modelsDir)) { if (Files.isDirectory(modelsDir)) {
try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) { try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
dirStream.forEach( dirStream.forEach(
path -> { path -> {
try { try {
Resource resource = new Resource(); byte[] fileBytes = Files.readAllBytes(path);
resource.setTenantId(TenantId.SYS_TENANT_ID); String key = getObjectModelLwm2mValid(fileBytes, path.getFileName().toString(), new DefaultDDFFileValidator());
resource.setResourceType(ResourceType.LWM2M_MODEL); if (key != null) {
resource.setResourceId(path.getFileName().toString()); Resource resource = new Resource();
resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(path))); resource.setTenantId(TenantId.SYS_TENANT_ID);
resourceService.saveResource(resource); resource.setResourceType(ResourceType.LWM2M_MODEL);
resource.setResourceId(key);
resource.setValue(Base64.getEncoder().encodeToString(fileBytes));
resourceService.saveResource(resource);
}
} catch (Exception e) { } catch (Exception e) {
log.error("Unable to load lwm2m model [{}]", path.toString()); log.error("Unable to load lwm2m model [{}]", path.toString());
throw new RuntimeException("Unable to load lwm2m model", e); throw new RuntimeException("Unable to load lwm2m model", e);
@ -218,17 +229,43 @@ public class InstallScripts {
} }
Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks"); Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
try { try {
Resource resource = new Resource(); Resource resource = new Resource();
resource.setTenantId(TenantId.SYS_TENANT_ID); resource.setTenantId(TenantId.SYS_TENANT_ID);
resource.setResourceType(ResourceType.JKS); resource.setResourceType(ResourceType.JKS);
resource.setResourceId(jksPath.getFileName().toString()); resource.setResourceId(jksPath.getFileName().toString());
resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath))); resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
resourceService.saveResource(resource); resourceService.saveResource(resource);
} catch (Exception e) { } catch (Exception e) {
log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString()); log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
throw new RuntimeException("Unable to load l2m2m serverKeyStore", e); 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 { public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {

1
application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java

@ -447,6 +447,7 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
" );"); " );");
conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;"); conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;");
installScripts.loadSystemLwm2mResources();
} catch (Exception e) { } catch (Exception e) {
log.error("Failed updating schema!!!", e); log.error("Failed updating schema!!!", e);
} }

5
application/src/main/java/org/thingsboard/server/service/lwm2m/LwM2MModelsRepository.java

@ -33,7 +33,6 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.service.Validator;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
import java.math.BigInteger; import java.math.BigInteger;
@ -102,8 +101,8 @@ public class LwM2MModelsRepository {
*/ */
private List<LwM2mObject> getLwm2mObjects(Predicate<? super ObjectModel> predicate, String sortProperty, String sortOrder) { private List<LwM2mObject> getLwm2mObjects(Predicate<? super ObjectModel> predicate, String sortProperty, String sortOrder) {
List<LwM2mObject> lwM2mObjects = new ArrayList<>(); List<LwM2mObject> lwM2mObjects = new ArrayList<>();
List<ObjectModel> listObjects = (predicate == null) ? this.contextServer.getModelsValue() : List<ObjectModel> listObjects = (predicate == null) ? this.contextServer.getModelsValueCommon() :
contextServer.getModelsValue().stream() contextServer.getModelsValueCommon().stream()
.filter(predicate) .filter(predicate)
.collect(Collectors.toList()); .collect(Collectors.toList());

2
application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java

@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.HasName; import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
@ -34,7 +35,6 @@ import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.ServiceType;

2
application/src/main/java/org/thingsboard/server/service/queue/TbClusterService.java

@ -19,12 +19,12 @@ import org.thingsboard.rule.engine.api.msg.ToDeviceActorNotificationMsg;
import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.ApiUsageState;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos;

4
application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java

@ -31,6 +31,8 @@ import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.TenantProfile;
import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData; import org.thingsboard.server.common.data.device.credentials.ProvisionDeviceCredentialsData;
@ -42,8 +44,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelation;
import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentials;
import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.msg.EncryptionUtil;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgDataType;

8
common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java

@ -15,11 +15,13 @@
*/ */
package org.thingsboard.server.dao.resource; package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType; import java.util.List;
public interface ResourceService { public interface ResourceService {
@ -29,6 +31,8 @@ public interface ResourceService {
PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink); PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
List<Resource> findResourcesByTenantIdResourceType(TenantId tenantId, ResourceType resourceType);
void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId); void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
void deleteResourcesByTenantId(TenantId tenantId); void deleteResourcesByTenantId(TenantId tenantId);

37
common/data/src/main/java/org/thingsboard/server/common/data/transport/resource/Resource.java

@ -0,0 +1,37 @@
/**
* Copyright © 2016-2021 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.resource;
import lombok.Data;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.id.TenantId;
@Data
public class Resource implements HasTenantId {
private TenantId tenantId;
private ResourceType resourceType;
private String resourceId;
private String value;
@Override
public String toString() {
return "Resource{" +
"tenantId=" + tenantId +
", resourceType=" + resourceType +
", resourceId='" + resourceId + '\'' +
'}';
}
}

20
common/data/src/main/java/org/thingsboard/server/common/data/transport/resource/ResourceType.java

@ -0,0 +1,20 @@
/**
* Copyright © 2016-2021 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.thingsboard.server.common.data.transport.resource;
public enum ResourceType {
LWM2M_MODEL, JKS, PKCS_12
}

3
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 lombok.extern.slf4j.Slf4j;
import org.eclipse.californium.scandium.config.DtlsConnectorConfig; 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.core.util.Hex;
import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager;
import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer;
@ -94,7 +93,7 @@ public class LwM2MTransportBootstrapServerConfiguration {
builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort));
/** Define model provider (Create Models )*/ /** Define model provider (Create Models )*/
builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValue())); // builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon()));
/** Create credentials */ /** Create credentials */
this.setServerWithCredentials(builder); this.setServerWithCredentials(builder);

48
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; package org.thingsboard.server.transport.lwm2m.server;
/** /**
* Copyright © 2016-2020 The Thingsboard Authors * Copyright © 2016-2020 The Thingsboard Authors
* * <p>
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* * <p>
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* * <p>
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -34,16 +34,27 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; 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.springframework.stereotype.Component;
import org.thingsboard.server.common.transport.TransportContext; 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.TransportService;
import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.TransportServiceCallback;
import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.AdaptorException;
import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
import org.thingsboard.server.gen.transport.TransportProtos.PostTelemetryMsg;
import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto;
import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY;
@Slf4j @Slf4j
@ -56,12 +67,16 @@ public class LwM2mTransportContextServer extends TransportContext {
private final TransportService transportService; private final TransportService transportService;
private final TransportResourceCache transportResourceCache;
@Getter @Getter
private final LwM2MJsonAdaptor adaptor; 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.lwM2MTransportConfigServer = lwM2MTransportConfigServer;
this.transportService = transportService; this.transportService = transportService;
this.transportResourceCache = transportResourceCache;
this.adaptor = adaptor; this.adaptor = adaptor;
} }
@ -69,6 +84,10 @@ public class LwM2mTransportContextServer extends TransportContext {
return this.lwM2MTransportConfigServer; return this.lwM2MTransportConfigServer;
} }
public TransportResourceCache getTransportResourceCache() {
return this.transportResourceCache;
}
/** /**
* Sent to Thingsboard Attribute || Telemetry * Sent to Thingsboard Attribute || Telemetry
* *
@ -89,14 +108,14 @@ public class LwM2mTransportContextServer extends TransportContext {
}; };
} }
public void sentParametersOnThingsboard(JsonElement msg, String topicName, TransportProtos.SessionInfoProto sessionInfo) { public void sentParametersOnThingsboard(JsonElement msg, String topicName, SessionInfoProto sessionInfo) {
try { try {
if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) {
TransportProtos.PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg);
TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postAttributeMsg); TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postAttributeMsg);
transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSentAttrTelemetry(call)); transportService.process(sessionInfo, postAttributeMsg, this.getPubAckCallbackSentAttrTelemetry(call));
} else if (topicName.equals(LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC)) { } else if (topicName.equals(LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC)) {
TransportProtos.PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg); PostTelemetryMsg postTelemetryMsg = adaptor.convertToPostTelemetry(msg);
TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postTelemetryMsg); TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postTelemetryMsg);
transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(call)); transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(call));
} }
@ -115,8 +134,8 @@ public class LwM2mTransportContextServer extends TransportContext {
/** /**
* @return - sessionInfo after access connect client * @return - sessionInfo after access connect client
*/ */
public TransportProtos.SessionInfoProto getValidateSessionInfo(TransportProtos.ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) { public SessionInfoProto getValidateSessionInfo(ValidateDeviceCredentialsResponseMsg msg, long mostSignificantBits, long leastSignificantBits) {
return TransportProtos.SessionInfoProto.newBuilder() return SessionInfoProto.newBuilder()
.setNodeId(this.getNodeId()) .setNodeId(this.getNodeId())
.setSessionIdMSB(mostSignificantBits) .setSessionIdMSB(mostSignificantBits)
.setSessionIdLSB(leastSignificantBits) .setSessionIdLSB(leastSignificantBits)
@ -131,4 +150,13 @@ public class LwM2mTransportContextServer extends TransportContext {
.build(); .build();
} }
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;
}
}
} }

6
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.nustaq.serialization.FSTConfiguration;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; 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.common.transport.TransportServiceCallback;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile;
@ -188,8 +189,9 @@ public class LwM2mTransportHandler {
return null; return null;
} }
public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData) { public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData, TenantId tenantId) {
LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile(); LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile();
lwM2MClientProfile.setTenantId(tenantId);
lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject()); lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject());
lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject()); lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject());
lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray()); lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray());
@ -221,7 +223,7 @@ public class LwM2mTransportHandler {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
String profileStr = mapper.writeValueAsString(profile); String profileStr = mapper.writeValueAsString(profile);
JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null; JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null;
return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson) : null; return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson, deviceProfile.getTenantId()) : null;
} catch (IOException e) { } catch (IOException e) {
log.error("", e); log.error("", e);
} }

8
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java

@ -47,7 +47,6 @@ import org.eclipse.leshan.core.util.Hex;
import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.core.util.NamedThreadFactory;
import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServer;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient;
@ -88,13 +87,13 @@ public class LwM2mTransportRequest {
private final LeshanServer leshanServer; private final LeshanServer leshanServer;
@Autowired private final LwM2mTransportServiceImpl serviceImpl;
private LwM2mTransportServiceImpl serviceImpl;
public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer) { public LwM2mTransportRequest(LwM2mTransportContextServer context, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, LwM2mTransportServiceImpl serviceImpl) {
this.context = context; this.context = context;
this.lwM2mClientContext = lwM2mClientContext; this.lwM2mClientContext = lwM2mClientContext;
this.leshanServer = leshanServer; this.leshanServer = leshanServer;
this.serviceImpl = serviceImpl;
} }
@PostConstruct @PostConstruct
@ -230,6 +229,7 @@ public class LwM2mTransportRequest {
private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) { private void sendRequest(Registration registration, DownlinkRequest request, long timeoutInMs) {
LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null);
leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> {
if (!lwM2MClient.isInit()) { if (!lwM2MClient.isInit()) {
lwM2MClient.initValue(this.serviceImpl, request.getPath().toString()); lwM2MClient.initValue(this.serviceImpl, request.getPath().toString());
} }

26
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java

@ -24,14 +24,13 @@ import org.eclipse.leshan.server.californium.LeshanServer;
import org.eclipse.leshan.server.californium.LeshanServerBuilder; import org.eclipse.leshan.server.californium.LeshanServerBuilder;
import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore;
import org.eclipse.leshan.server.model.LwM2mModelProvider; import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.model.VersionedModelProvider;
import org.eclipse.leshan.server.security.DefaultAuthorizer; import org.eclipse.leshan.server.security.DefaultAuthorizer;
import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.eclipse.leshan.server.security.SecurityChecker; import org.eclipse.leshan.server.security.SecurityChecker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext;
import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl;
import java.math.BigInteger; import java.math.BigInteger;
@ -61,21 +60,23 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_W
import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig;
@Slf4j @Slf4j
@Component("LwM2MTransportServerConfiguration") @Component
@TbLwM2mTransportComponent @TbLwM2mTransportComponent
public class LwM2mTransportServerConfiguration { public class LwM2mTransportServerConfiguration {
private PublicKey publicKey; private PublicKey publicKey;
private PrivateKey privateKey; private PrivateKey privateKey;
private boolean pskMode = false; private boolean pskMode = false;
private final LwM2mTransportContextServer context;
private final CaliforniumRegistrationStore registrationStore;
private final EditableSecurityStore securityStore;
private final LwM2mClientContext lwM2mClientContext;
@Autowired public LwM2mTransportServerConfiguration(LwM2mTransportContextServer context, CaliforniumRegistrationStore registrationStore, EditableSecurityStore securityStore, LwM2mClientContext lwM2mClientContext) {
private LwM2mTransportContextServer context; this.context = context;
this.registrationStore = registrationStore;
@Autowired this.securityStore = securityStore;
private CaliforniumRegistrationStore registrationStore; this.lwM2mClientContext = lwM2mClientContext;
}
@Autowired
private EditableSecurityStore securityStore;
@Bean @Bean
public LeshanServer getLeshanServer() { public LeshanServer getLeshanServer() {
@ -95,7 +96,8 @@ public class LwM2mTransportServerConfiguration {
builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort));
/** Define model provider (Create Models )*/ /** Define model provider (Create Models )*/
LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValue()); LwM2mModelProvider modelProvider = new LwM2mVersionedModelProvider(this.lwM2mClientContext, this.context);
this.context.getLwM2MTransportConfigServer().setModelProvider(modelProvider);
builder.setObjectModelProvider(modelProvider); builder.setObjectModelProvider(modelProvider);
/** Create credentials */ /** Create credentials */

15
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java

@ -652,21 +652,6 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
return (clientInstances.size() > 0) ? clientInstances : null; 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 attributes - new JsonObject
* @param telemetry - new JsonObject * @param telemetry - new JsonObject

136
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mVersionedModelProvider.java

@ -0,0 +1,136 @@
/**
* Copyright © 2016-2021 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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.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 static org.thingsboard.server.common.data.ResourceType.LWM2M_MODEL;
@Slf4j
public class LwM2mVersionedModelProvider implements LwM2mModelProvider {
/**
* 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.lwM2mTransportContextServer = lwM2mTransportContextServer;
}
private String getIdVer(ObjectModel objectModel) {
return objectModel.id + "##" + ((objectModel.getVersion() == null || objectModel.getVersion().isEmpty()) ? ObjectModel.DEFAULT_VERSION : objectModel.getVersion());
}
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
);
}
private class DynamicModel implements LwM2mModel {
private final Registration registration;
private final TenantId tenantId;
public DynamicModel(Registration registration) {
this.registration = registration;
this.tenantId = lwM2mClientContext.getProfile(registration).getTenantId();
}
@Override
public ResourceModel getResourceModel(int objectId, int resourceId) {
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 this.getObjectModelDynamic(objectId, version);
}
return null;
}
@Override
public Collection<ObjectModel> getObjectModels() {
Map<Integer, String> supportedObjects = this.registration.getSupportedObject();
Collection<ObjectModel> result = new ArrayList(supportedObjects.size());
Iterator i$ = supportedObjects.entrySet().iterator();
while (i$.hasNext()) {
Map.Entry<Integer, String> 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;
}
}
}

2
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java

@ -15,7 +15,6 @@
*/ */
package org.thingsboard.server.transport.lwm2m.server.client; package org.thingsboard.server.transport.lwm2m.server.client;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.eclipse.leshan.server.security.EditableSecurityStore; import org.eclipse.leshan.server.security.EditableSecurityStore;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -105,6 +104,7 @@ public class LwM2mClientContextImpl implements LwM2mClientContext {
/** /**
* Add new LwM2MClient to session * Add new LwM2MClient to session
*
* @param identity- * @param identity-
* @return SecurityInfo. If error - SecurityInfoError * @return SecurityInfo. If error - SecurityInfoError
* and log: * and log:

13
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java

@ -19,15 +19,18 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray; import com.google.gson.JsonArray;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
@Data @Data
public class LwM2mClientProfile { public class LwM2mClientProfile {
private TenantId tenantId;
/** /**
* {"clientLwM2mSettings": { * {"clientLwM2mSettings": {
* clientUpdateValueAfterConnect: false; * clientUpdateValueAfterConnect: false;
* } * }
**/ **/
JsonObject postClientLwM2mSettings; private JsonObject postClientLwM2mSettings;
/** /**
* {"keyName": { * {"keyName": {
@ -36,22 +39,22 @@ public class LwM2mClientProfile {
* "/3/0/2": "serialNumber" * "/3/0/2": "serialNumber"
* } * }
**/ **/
JsonObject postKeyNameProfile; private JsonObject postKeyNameProfile;
/** /**
* [ "/2/0/0", "/2/0/1"] * [ "/2/0/0", "/2/0/1"]
*/ */
JsonArray postAttributeProfile; private JsonArray postAttributeProfile;
/** /**
* [ "/2/0/0", "/2/0/1"] * [ "/2/0/0", "/2/0/1"]
*/ */
JsonArray postTelemetryProfile; private JsonArray postTelemetryProfile;
/** /**
* [ "/2/0/0", "/2/0/1"] * [ "/2/0/0", "/2/0/1"]
*/ */
JsonArray postObserveProfile; private JsonArray postObserveProfile;
public LwM2mClientProfile clone() { public LwM2mClientProfile clone() {
LwM2mClientProfile lwM2mClientProfile = new LwM2mClientProfile(); LwM2mClientProfile lwM2mClientProfile = new LwM2mClientProfile();

14
common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2mValueConverterImpl.java

@ -26,10 +26,13 @@ import org.eclipse.leshan.core.util.StringUtils;
import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.datatype.XMLGregorianCalendar;
import java.math.BigInteger;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import static org.eclipse.leshan.core.model.ResourceModel.Type.OPAQUE;
@Slf4j @Slf4j
public class LwM2mValueConverterImpl implements LwM2mValueConverter { public class LwM2mValueConverterImpl implements LwM2mValueConverter {
@ -51,6 +54,9 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
/** expected type */ /** expected type */
return value; return value;
} }
if (currentType == null) {
currentType = OPAQUE;
}
switch (expectedType) { switch (expectedType) {
case INTEGER: case INTEGER:
@ -130,7 +136,13 @@ public class LwM2mValueConverterImpl implements LwM2mValueConverter {
return String.valueOf(value); return String.valueOf(value);
case TIME: case TIME:
String DATE_FORMAT = "MMM d, yyyy HH:mm a"; String DATE_FORMAT = "MMM d, yyyy HH:mm a";
Long timeValue = ((Date) value).getTime(); Long timeValue;
try {
timeValue = ((Date) value).getTime();
}
catch (Exception e){
timeValue = new BigInteger((byte [])value).longValue();
}
DateFormat formatter = new SimpleDateFormat(DATE_FORMAT); DateFormat formatter = new SimpleDateFormat(DATE_FORMAT);
return formatter.format(new Date(timeValue)); return formatter.format(new Date(timeValue));
default: default:

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportResourceCache.java

@ -15,9 +15,9 @@
*/ */
package org.thingsboard.server.common.transport; package org.thingsboard.server.common.transport;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.Resource; import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
public interface TransportResourceCache { public interface TransportResourceCache {

39
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.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; 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.ObjectModel;
import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.model.ResourceModel;
import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mPath;
import org.eclipse.leshan.server.model.LwM2mModelProvider;
import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.registration.Registration;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
@ -38,16 +38,13 @@ import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
@Slf4j @Slf4j
@Component @Component
@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'") @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith' || '${service.type:null}'=='tb-core'")
public class LwM2MTransportConfigServer { public class LwM2MTransportConfigServer {
@Getter @Getter
private String MODEL_PATH_DEFAULT = "models"; private String MODEL_PATH_DEFAULT = "models";
@ -84,7 +81,11 @@ public class LwM2MTransportConfigServer {
@Getter @Getter
@Setter @Setter
private List<ObjectModel> modelsValue; private List<ObjectModel> modelsValueCommon;
@Getter
@Setter
private LwM2mModelProvider modelProvider;
@Getter @Getter
@Value("${transport.lwm2m.timeout:}") @Value("${transport.lwm2m.timeout:}")
@ -188,29 +189,9 @@ public class LwM2MTransportConfigServer {
@PostConstruct @PostConstruct
public void init() { public void init() {
modelsValue = ObjectLoader.loadDefault();
File path = getPathModels();
if (path.isDirectory()) {
try {
modelsValue.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(); 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() { private KeyStore getInKeyStore() {
try { try {
if (keyStoreValue != null && keyStoreValue.size() > 0) if (keyStoreValue != null && keyStoreValue.size() > 0)
@ -253,12 +234,7 @@ public class LwM2MTransportConfigServer {
} }
public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) { public ResourceModel getResourceModel(Registration registration, LwM2mPath pathIds) {
String pathLink = "/" + pathIds.getObjectId() + "/" + pathIds.getObjectInstanceId(); return this.modelProvider.getObjectModel(registration).getResourceModel(pathIds.getObjectId(), pathIds.getResourceId());
return (Arrays.stream(registration.getObjectLinks()).filter(p-> p.getUrl().equals(pathLink)).findFirst().isPresent() &&
this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).size() > 0) &&
this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.containsKey(pathIds.getResourceId()) ?
this.modelsValue.stream().filter(v -> v.id == pathIds.getObjectId()).collect(Collectors.toList()).get(0).resources.get(pathIds.getResourceId()) :
null;
} }
public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) { public ResourceModel.Type getResourceModelType(Registration registration, LwM2mPath pathIds) {
@ -270,4 +246,5 @@ public class LwM2MTransportConfigServer {
ResourceModel resource = this.getResourceModel(registration, pathIds); ResourceModel resource = this.getResourceModel(registration, pathIds);
return (resource == null) ? ResourceModel.Operations.NONE : resource.operations; return (resource == null) ? ResourceModel.Operations.NONE : resource.operations;
} }
} }

2
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportResourceCache.java

@ -19,9 +19,9 @@ import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.Resource; import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.transport.TransportResourceCache; import org.thingsboard.server.common.transport.TransportResourceCache;
import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportService;
import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService;

3
common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/service/DefaultTransportService.java

@ -31,13 +31,13 @@ import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.DeviceTransportType;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.DeviceProfileId;
import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.id.TenantProfileId;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsg;
import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.common.msg.queue.ServiceQueue; import org.thingsboard.server.common.msg.queue.ServiceQueue;
@ -295,6 +295,7 @@ public class DefaultTransportService implements TransportService {
response -> callback.onSuccess(response.getValue().getValidateCredResponseMsg()), callback::onError, transportCallbackExecutor); response -> callback.onSuccess(response.getValue().getValidateCredResponseMsg()), callback::onError, transportCallbackExecutor);
} }
@Override
public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) { public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceX509CertRequestMsg msg, TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
log.trace("Processing msg: {}", msg); log.trace("Processing msg: {}", msg);
TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build()); TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(UUID.randomUUID(), TransportApiRequestMsg.newBuilder().setValidateX509CertRequestMsg(msg).build());

2
dao/src/main/java/org/thingsboard/server/dao/model/sql/ResourceEntity.java

@ -16,9 +16,9 @@
package org.thingsboard.server.dao.model.sql; package org.thingsboard.server.dao.model.sql;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.Resource; import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.ToData; import org.thingsboard.server.dao.model.ToData;
import javax.persistence.Column; import javax.persistence.Column;

14
dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java

@ -17,13 +17,15 @@ package org.thingsboard.server.dao.resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.DataValidationException;
import java.util.List;
import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID;
import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validateId;
@ -65,6 +67,14 @@ public class BaseResourceService implements ResourceService {
return resourceDao.findAllByTenantId(tenantId, pageLink); return resourceDao.findAllByTenantId(tenantId, pageLink);
} }
@Override
public List<Resource> findResourcesByTenantIdResourceType(TenantId tenantId, ResourceType resourceType) {
log.trace("Executing findByTenantId [{}]", tenantId);
validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
return resourceDao.findAllByTenantIdResourceType(tenantId, resourceType);
}
@Override @Override
public void deleteResourcesByTenantId(TenantId tenantId) { public void deleteResourcesByTenantId(TenantId tenantId) {
log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId); log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);

9
dao/src/main/java/org/thingsboard/server/dao/resource/ResourceDao.java

@ -15,11 +15,13 @@
*/ */
package org.thingsboard.server.dao.resource; package org.thingsboard.server.dao.resource;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType; import java.util.List;
public interface ResourceDao { public interface ResourceDao {
@ -31,5 +33,8 @@ public interface ResourceDao {
PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink); PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
List<Resource> findAllByTenantIdResourceType(TenantId tenantId, ResourceType resourceType);
void removeAllByTenantId(TenantId tenantId); void removeAllByTenantId(TenantId tenantId);
} }

11
dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceDaoImpl.java

@ -18,16 +18,18 @@ package org.thingsboard.server.dao.sql.resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.Resource;
import org.thingsboard.server.common.data.ResourceType;
import org.thingsboard.server.dao.DaoUtil; import org.thingsboard.server.dao.DaoUtil;
import org.thingsboard.server.dao.model.sql.ResourceCompositeKey; import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
import org.thingsboard.server.dao.model.sql.ResourceEntity; import org.thingsboard.server.dao.model.sql.ResourceEntity;
import org.thingsboard.server.dao.resource.ResourceDao; import org.thingsboard.server.dao.resource.ResourceDao;
import java.util.List;
@Slf4j @Slf4j
@Component @Component
public class ResourceDaoImpl implements ResourceDao { public class ResourceDaoImpl implements ResourceDao {
@ -70,6 +72,11 @@ public class ResourceDaoImpl implements ResourceDao {
return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink))); return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
} }
@Override
public List<Resource> findAllByTenantIdResourceType(TenantId tenantId, ResourceType resourceType) {
return DaoUtil.convertDataList(resourceRepository.findAllByTenantIdAndResourceType(tenantId.getId(), resourceType.name()));
}
@Override @Override
public void removeAllByTenantId(TenantId tenantId) { public void removeAllByTenantId(TenantId tenantId) {
resourceRepository.removeAllByTenantId(tenantId.getId()); resourceRepository.removeAllByTenantId(tenantId.getId());

4
dao/src/main/java/org/thingsboard/server/dao/sql/resource/ResourceRepository.java

@ -21,11 +21,15 @@ import org.springframework.data.repository.CrudRepository;
import org.thingsboard.server.dao.model.sql.ResourceCompositeKey; import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
import org.thingsboard.server.dao.model.sql.ResourceEntity; import org.thingsboard.server.dao.model.sql.ResourceEntity;
import java.util.List;
import java.util.UUID; import java.util.UUID;
public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> { public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> {
Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable); Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
List<ResourceEntity> findAllByTenantIdAndResourceType(UUID tenantId, String resourceType);
void removeAllByTenantId(UUID tenantId); void removeAllByTenantId(UUID tenantId);
} }

6
pom.xml

@ -66,9 +66,9 @@
<jackson-core.version>2.12.1</jackson-core.version> <jackson-core.version>2.12.1</jackson-core.version>
<json-schema-validator.version>2.2.6</json-schema-validator.version> <json-schema-validator.version>2.2.6</json-schema-validator.version>
<californium.version>2.6.1</californium.version> <californium.version>2.6.1</californium.version>
<leshan-server.version>1.3.0</leshan-server.version> <leshan-server.version>1.3.1</leshan-server.version>
<leshan-core.version>1.3.0</leshan-core.version> <leshan-core.version>1.3.1</leshan-core.version>
<leshan-client.version>1.3.0</leshan-client.version> <leshan-client.version>1.3.1</leshan-client.version>
<gson.version>2.6.2</gson.version> <gson.version>2.6.2</gson.version>
<freemarker.version>2.3.30</freemarker.version> <freemarker.version>2.3.30</freemarker.version>
<mail.version>1.6.2</mail.version> <mail.version>1.6.2</mail.version>

Loading…
Cancel
Save