From 3716e2833aec84f49d64826f6e5ff72e962dcfd6 Mon Sep 17 00:00:00 2001 From: Yevhen Bondarenko <56396344+YevhenBondarenko@users.noreply.github.com> Date: Fri, 26 Feb 2021 14:16:34 +0200 Subject: [PATCH] [WIP]added redis stores support to lwm2m transport (#4164) * added redis stores support to lwm2m transport * added cache dependency to dao * added cache dependency to dao-api * moved JacksonUtil to the common.util package * added cache to the component scan for install * lwm2m stores improvements --- .../server/ThingsboardInstallApplication.java | 3 +- .../controller/DashboardController.java | 3 +- .../device/DeviceProvisionServiceImpl.java | 2 +- .../update/DefaultDataUpdateService.java | 10 +- .../query/DefaultEntityQueryService.java | 2 +- .../queue/DefaultTbCoreConsumerService.java | 2 +- .../system/DefaultSystemSecurityService.java | 2 +- .../server/service/sms/DefaultSmsService.java | 2 +- .../state/DefaultDeviceStateService.java | 2 +- .../DefaultSubscriptionManagerService.java | 2 +- .../subscription/TbSubscriptionUtils.java | 2 +- .../transport/DefaultTransportApiService.java | 2 +- .../src/main/resources/thingsboard.yml | 4 +- ...tMqttAttributesRequestIntegrationTest.java | 2 +- ...tMqttAttributesUpdatesIntegrationTest.java | 2 +- .../AbstractMqttProvisionJsonDeviceTest.java | 2 +- .../AbstractMqttProvisionProtoDeviceTest.java | 3 +- ...tractMqttServerSideRpcIntegrationTest.java | 2 +- common/cache/pom.xml | 115 +++ .../thingsboard/server}/cache/CacheSpecs.java | 2 +- .../cache/CaffeineCacheConfiguration.java | 10 +- .../cache/TBRedisCacheConfiguration.java | 8 +- .../cache/TBRedisClusterConfiguration.java | 2 +- .../cache/TBRedisStandaloneConfiguration.java | 2 +- common/pom.xml | 1 + .../queue/util/TbLwM2mTransportComponent.java | 26 + common/transport/lwm2m/pom.xml | 1 - ...TransportBootstrapServerConfiguration.java | 22 +- .../LwM2MTransportContextBootstrap.java | 14 +- .../secure/LwM2MBootstrapSecurityStore.java | 35 +- ...LwM2mCredentialsSecurityInfoValidator.java | 43 +- .../lwm2m/server/LwM2mServerListener.java | 4 +- ...ener.java => LwM2mSessionMsgListener.java} | 6 +- ....java => LwM2mTransportContextServer.java} | 42 +- ...andler.java => LwM2mTransportHandler.java} | 22 +- ...equest.java => LwM2mTransportRequest.java} | 52 +- ...=> LwM2mTransportServerConfiguration.java} | 71 +- ...a => LwM2mTransportServerInitializer.java} | 12 +- ...ervice.java => LwM2mTransportService.java} | 2 +- ...pl.java => LwM2mTransportServiceImpl.java} | 272 +++--- .../{LwM2MClient.java => LwM2mClient.java} | 34 +- .../server/client/LwM2mClientContext.java | 54 ++ .../server/client/LwM2mClientContextImpl.java | 171 ++++ ...ntProfile.java => LwM2mClientProfile.java} | 2 +- .../LwM2mInMemorySecurityStore.java | 90 +- .../store/TbLwM2mRedisRegistrationStore.java | 785 ++++++++++++++++++ .../store/TbLwM2mRedisSecurityStore.java | 148 ++++ .../store/TbLwM2mStoreConfiguration.java | 123 +++ common/transport/transport-api/pom.xml | 4 + .../common/transport/TransportContext.java | 4 +- .../lwm2m/LwM2MTransportConfigServer.java | 4 - common/util/pom.xml | 4 + .../thingsboard/common/util}/JacksonUtil.java | 2 +- dao/pom.xml | 4 + .../server/dao/audit/AuditLogServiceImpl.java | 2 +- ...eviousDeviceCredentialsIdKeyGenerator.java | 2 + .../device/DeviceCredentialsServiceImpl.java | 2 +- .../server/dao/device/DeviceServiceImpl.java | 2 +- .../dao/model/sql/AbstractDeviceEntity.java | 2 +- .../dao/model/sql/DeviceProfileEntity.java | 2 +- .../dao/model/sql/TenantProfileEntity.java | 2 +- .../server/dao/user/UserServiceImpl.java | 2 +- .../dao/util/mapping/JsonTypeDescriptor.java | 1 + .../dao/service/BaseAlarmServiceTest.java | 2 +- pom.xml | 5 + .../rule/engine/api/util/TbNodeUtilsTest.java | 2 +- .../engine/action/TbAbstractAlarmNode.java | 2 +- .../engine/metadata/CalculateDeltaNode.java | 2 +- .../rule/engine/profile/AlarmState.java | 5 +- .../rule/engine/profile/DeviceState.java | 2 +- .../engine/profile/TbDeviceProfileNode.java | 2 +- .../TbDeviceProfileNodeConfiguration.java | 23 - transport/lwm2m/pom.xml | 14 +- .../ThingsboardLwm2mTransportApplication.java | 2 +- .../src/main/resources/tb-lwm2m-transport.yml | 81 +- 75 files changed, 1932 insertions(+), 469 deletions(-) create mode 100644 common/cache/pom.xml rename {dao/src/main/java/org/thingsboard/server/dao => common/cache/src/main/java/org/thingsboard/server}/cache/CacheSpecs.java (94%) rename {dao/src/main/java/org/thingsboard/server/dao => common/cache/src/main/java/org/thingsboard/server}/cache/CaffeineCacheConfiguration.java (91%) rename {dao/src/main/java/org/thingsboard/server/dao => common/cache/src/main/java/org/thingsboard/server}/cache/TBRedisCacheConfiguration.java (95%) rename {dao/src/main/java/org/thingsboard/server/dao => common/cache/src/main/java/org/thingsboard/server}/cache/TBRedisClusterConfiguration.java (98%) rename {dao/src/main/java/org/thingsboard/server/dao => common/cache/src/main/java/org/thingsboard/server}/cache/TBRedisStandaloneConfiguration.java (98%) create mode 100644 common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MSessionMsgListener.java => LwM2mSessionMsgListener.java} (95%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportContextServer.java => LwM2mTransportContextServer.java} (80%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportHandler.java => LwM2mTransportHandler.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportRequest.java => LwM2mTransportRequest.java} (93%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportServerConfiguration.java => LwM2mTransportServerConfiguration.java} (78%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportServerInitializer.java => LwM2mTransportServerInitializer.java} (80%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportService.java => LwM2mTransportService.java} (98%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{LwM2MTransportServiceImpl.java => LwM2mTransportServiceImpl.java} (83%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2MClient.java => LwM2mClient.java} (72%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/{LwM2MClientProfile.java => LwM2mClientProfile.java} (97%) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/{secure => store}/LwM2mInMemorySecurityStore.java (73%) create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java create mode 100644 common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java rename common/{dao-api/src/main/java/org/thingsboard/server/dao/util/mapping => util/src/main/java/org/thingsboard/common/util}/JacksonUtil.java (98%) diff --git a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java index 6eaac0157b..32c995ac82 100644 --- a/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java +++ b/application/src/main/java/org/thingsboard/server/ThingsboardInstallApplication.java @@ -30,7 +30,8 @@ import java.util.Arrays; "org.thingsboard.server.service.component", "org.thingsboard.server.service.install", "org.thingsboard.server.dao", - "org.thingsboard.server.common.stats"}) + "org.thingsboard.server.common.stats", + "org.thingsboard.server.cache"}) public class ThingsboardInstallApplication { private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java index f5b350d861..2e6efc4246 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java @@ -44,8 +44,7 @@ import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; -import org.thingsboard.server.common.data.page.TimePageLink; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.permission.Operation; diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java index 3bd540048f..3fea206c3b 100644 --- a/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java +++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceProvisionServiceImpl.java @@ -50,7 +50,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.device.provision.ProvisionResponse; import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.queue.TbQueueCallback; diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 4bbe7c46f2..f232c0a41e 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -15,9 +15,7 @@ */ package org.thingsboard.server.service.install.update; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -25,16 +23,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; import org.thingsboard.rule.engine.profile.TbDeviceProfileNode; import org.thingsboard.rule.engine.profile.TbDeviceProfileNodeConfiguration; import org.thingsboard.server.common.data.EntityView; -import org.thingsboard.server.common.data.SearchTextBased; import org.thingsboard.server.common.data.Tenant; -import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; import org.thingsboard.server.common.data.kv.ReadTsKvQuery; import org.thingsboard.server.common.data.kv.TsKvEntry; @@ -47,10 +41,9 @@ import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.rule.RuleChainService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.service.install.InstallScripts; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -58,7 +51,6 @@ import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; @Service @Profile("install") diff --git a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java index 7e1101dfc8..22658563e4 100644 --- a/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java +++ b/application/src/main/java/org/thingsboard/server/service/query/DefaultEntityQueryService.java @@ -47,7 +47,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.security.AccessValidator; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index af9239d298..02f69ce10d 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos.DeviceStateServiceMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.FromDeviceRPCResponseProto; import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto; diff --git a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java index c86b1cdcfe..5db9509a77 100644 --- a/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java +++ b/application/src/main/java/org/thingsboard/server/service/security/system/DefaultSystemSecurityService.java @@ -49,7 +49,7 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.settings.AdminSettingsService; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.user.UserServiceImpl; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.service.security.exception.UserPasswordExpiredException; import org.thingsboard.server.utils.MiscUtils; diff --git a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java index af72b909ca..f7a012b23e 100644 --- a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java +++ b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsService.java @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.settings.AdminSettingsService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.queue.usagestats.TbApiUsageClient; import org.thingsboard.server.service.apiusage.TbApiUsageStateService; diff --git a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java index be31a0df45..c8a4e80e0e 100644 --- a/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/state/DefaultDeviceStateService.java @@ -52,7 +52,7 @@ import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.discovery.PartitionChangeEvent; import org.thingsboard.server.queue.discovery.PartitionService; diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java index 844db92de8..ce8838aaa8 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/DefaultSubscriptionManagerService.java @@ -39,7 +39,7 @@ import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos.*; import org.thingsboard.server.gen.transport.TransportProtos.LocalSubscriptionServiceMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateProto; diff --git a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java index c6da1aad29..da84e8e4ea 100644 --- a/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java +++ b/application/src/main/java/org/thingsboard/server/service/subscription/TbSubscriptionUtils.java @@ -30,7 +30,7 @@ import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; import org.thingsboard.server.common.data.kv.StringDataEntry; import org.thingsboard.server.common.data.kv.TsKvEntry; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueProto; import org.thingsboard.server.gen.transport.TransportProtos.KeyValueType; diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index a56e98fe5f..b157e0d0a7 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -54,7 +54,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.device.provision.ProvisionResponse; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 93fff15df2..dbd8d09412 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -635,8 +635,8 @@ transport: public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" # Only Certificate_x509: alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" - # Redis - redis_url: "${LWM2M_REDIS_URL:''}" + # Use redis for Security and Registration stores + redis.enabled: "${LWM2M_REDIS_ENABLED:false}" swagger: api_path_regex: "${SWAGGER_API_PATH_REGEX:/api.*}" diff --git a/application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java index 002474c59d..6ad5db9aff 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/attributes/request/AbstractMqttAttributesRequestIntegrationTest.java @@ -26,7 +26,7 @@ import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; import java.nio.charset.StandardCharsets; diff --git a/application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java index 7045e28f62..9810c4fe3a 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/attributes/updates/AbstractMqttAttributesUpdatesIntegrationTest.java @@ -25,7 +25,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.mqtt.attributes.AbstractMqttAttributesIntegrationTest; import java.nio.charset.StandardCharsets; diff --git a/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java index 0fce47fc84..1011c86b7f 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionJsonDeviceTest.java @@ -37,7 +37,7 @@ import org.thingsboard.server.common.transport.util.JsonUtils; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; import java.util.concurrent.CountDownLatch; diff --git a/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java index 0478a402d9..476b4add4c 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/provision/AbstractMqttProvisionProtoDeviceTest.java @@ -36,7 +36,7 @@ import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.dao.device.DeviceCredentialsService; import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.gen.transport.TransportProtos.CredentialsDataProto; import org.thingsboard.server.gen.transport.TransportProtos.CredentialsType; import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceCredentialsMsg; @@ -47,7 +47,6 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenR import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; -import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; diff --git a/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java index 4ae0072029..19e74b6fdc 100644 --- a/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java @@ -30,7 +30,7 @@ import org.junit.Assert; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.mqtt.AbstractMqttIntegrationTest; import java.util.Arrays; diff --git a/common/cache/pom.xml b/common/cache/pom.xml new file mode 100644 index 0000000000..80000b80a0 --- /dev/null +++ b/common/cache/pom.xml @@ -0,0 +1,115 @@ + + + 4.0.0 + + org.thingsboard + 3.3.0-SNAPSHOT + common + + org.thingsboard.common + cache + jar + + Thingsboard Server Common Cache + https://thingsboard.io + + + UTF-8 + ${basedir}/../.. + + + + + org.thingsboard.common + data + + + org.springframework.boot + spring-boot-autoconfigure + + + org.springframework.data + spring-data-redis + + + redis.clients + jedis + + + com.github.ben-manes.caffeine + caffeine + + + org.apache.commons + commons-lang3 + + + org.slf4j + slf4j-api + + + org.slf4j + log4j-over-slf4j + + + ch.qos.logback + logback-core + + + ch.qos.logback + logback-classic + + + junit + junit + test + + + org.mockito + mockito-core + test + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/CacheSpecs.java b/common/cache/src/main/java/org/thingsboard/server/cache/CacheSpecs.java similarity index 94% rename from dao/src/main/java/org/thingsboard/server/dao/cache/CacheSpecs.java rename to common/cache/src/main/java/org/thingsboard/server/cache/CacheSpecs.java index 6130942118..15a733c9ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/CacheSpecs.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/CacheSpecs.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.cache; +package org.thingsboard.server.cache; import lombok.Data; diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/CaffeineCacheConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineCacheConfiguration.java similarity index 91% rename from dao/src/main/java/org/thingsboard/server/dao/cache/CaffeineCacheConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/CaffeineCacheConfiguration.java index f3bffb7cb9..7a0ce251fe 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/CaffeineCacheConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/CaffeineCacheConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.cache; +package org.thingsboard.server.cache; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.RemovalCause; @@ -26,7 +26,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.cache.caffeine.CaffeineCache; -import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -78,14 +77,9 @@ public class CaffeineCacheConfiguration { return Ticker.systemTicker(); } - @Bean - public KeyGenerator previousDeviceCredentialsId() { - return new PreviousDeviceCredentialsIdKeyGenerator(); - } - private Weigher collectionSafeWeigher() { return (Weigher) (key, value) -> { - if(value instanceof Collection) { + if (value instanceof Collection) { return ((Collection) value).size(); } return 1; diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisCacheConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java similarity index 95% rename from dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisCacheConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java index 5cadda82ba..b57e1579c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisCacheConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisCacheConfiguration.java @@ -13,14 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.cache; +package org.thingsboard.server.cache; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.interceptor.KeyGenerator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.convert.converter.ConverterRegistry; @@ -89,11 +88,6 @@ public abstract class TBRedisCacheConfiguration { return RedisCacheManager.builder(cf).cacheDefaults(configuration).build(); } - @Bean - public KeyGenerator previousDeviceCredentialsId() { - return new PreviousDeviceCredentialsIdKeyGenerator(); - } - @Bean public RedisTemplate redisTemplate() { RedisTemplate template = new RedisTemplate<>(); diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisClusterConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java similarity index 98% rename from dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisClusterConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java index b2248989c8..912fabfbf4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisClusterConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisClusterConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.cache; +package org.thingsboard.server.cache; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisStandaloneConfiguration.java b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java similarity index 98% rename from dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisStandaloneConfiguration.java rename to common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java index 26651f928d..4373c8b7ca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/TBRedisStandaloneConfiguration.java +++ b/common/cache/src/main/java/org/thingsboard/server/cache/TBRedisStandaloneConfiguration.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.cache; +package org.thingsboard.server.cache; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; diff --git a/common/pom.xml b/common/pom.xml index 11b1e02477..7568d18ca6 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -42,6 +42,7 @@ transport dao-api stats + cache diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java new file mode 100644 index 0000000000..3bc4d494f2 --- /dev/null +++ b/common/queue/src/main/java/org/thingsboard/server/queue/util/TbLwM2mTransportComponent.java @@ -0,0 +1,26 @@ +/** + * 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.queue.util; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +public @interface TbLwM2mTransportComponent { +} diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 83986a953e..ee3d5fc759 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -90,7 +90,6 @@ org.eclipse.leshan leshan-client-cf - org.eclipse.leshan leshan-server-redis 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 68fdc94dac..757b91956b 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 @@ -29,7 +29,7 @@ import org.springframework.stereotype.Component; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MBootstrapSecurityStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.bootstrap.secure.LwM2mDefaultBootstrapSessionManager; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer; import java.math.BigInteger; import java.security.AlgorithmParameters; @@ -56,7 +56,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; @Slf4j @Component @@ -70,7 +70,7 @@ public class LwM2MTransportBootstrapServerConfiguration { private LwM2MTransportContextBootstrap contextBs; @Autowired - private LwM2MTransportContextServer contextS; + private LwM2mTransportContextServer contextS; @Autowired private LwM2MBootstrapSecurityStore lwM2MBootstrapSecurityStore; @@ -94,7 +94,7 @@ public class LwM2MTransportBootstrapServerConfiguration { builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); /** Define model provider (Create Models )*/ - builder.setModel(new StaticModel(contextS.getCtxServer().getModelsValue())); + builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValue())); /** Create credentials */ this.setServerWithCredentials(builder); @@ -108,8 +108,8 @@ public class LwM2MTransportBootstrapServerConfiguration { /** Create and Set DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedSupportedGroupsOnly(this.contextS.getCtxServer().isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getCtxServer().isRecommendedCiphers()); + dtlsConfig.setRecommendedSupportedGroupsOnly(this.contextS.getLwM2MTransportConfigServer().isRecommendedSupportedGroups()); + dtlsConfig.setRecommendedCipherSuitesOnly(this.contextS.getLwM2MTransportConfigServer().isRecommendedCiphers()); if (this.pskMode) { dtlsConfig.setSupportedCipherSuites( TLS_PSK_WITH_AES_128_CCM_8, @@ -135,10 +135,10 @@ public class LwM2MTransportBootstrapServerConfiguration { private void setServerWithCredentials(LeshanBootstrapServerBuilder builder) { try { - if (this.contextS.getCtxServer().getKeyStoreValue() != null) { - KeyStore keyStoreServer = this.contextS.getCtxServer().getKeyStoreValue(); + if (this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue() != null) { + KeyStore keyStoreServer = this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue(); if (this.setBuilderX509(builder)) { - X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getCtxServer().getRootAlias()); + X509Certificate rootCAX509Cert = (X509Certificate) keyStoreServer.getCertificate(this.contextS.getLwM2MTransportConfigServer().getRootAlias()); if (rootCAX509Cert != null) { X509Certificate[] trustedCertificates = new X509Certificate[1]; trustedCertificates[0] = rootCAX509Cert; @@ -169,8 +169,8 @@ public class LwM2MTransportBootstrapServerConfiguration { * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks */ try { - X509Certificate serverCertificate = (X509Certificate) this.contextS.getCtxServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); - PrivateKey privateKey = (PrivateKey) this.contextS.getCtxServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getCtxServer().getKeyStorePasswordServer() == null ? null : this.contextS.getCtxServer().getKeyStorePasswordServer().toCharArray()); + X509Certificate serverCertificate = (X509Certificate) this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.contextBs.getCtxBootStrap().getBootstrapAlias()); + PrivateKey privateKey = (PrivateKey) this.contextS.getLwM2MTransportConfigServer().getKeyStoreValue().getKey(this.contextBs.getCtxBootStrap().getBootstrapAlias(), this.contextS.getLwM2MTransportConfigServer().getKeyStorePasswordServer() == null ? null : this.contextS.getLwM2MTransportConfigServer().getKeyStorePasswordServer().toCharArray()); PublicKey publicKey = serverCertificate.getPublicKey(); if (serverCertificate != null && privateKey != null && privateKey.getEncoded().length > 0 && diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java index 5028b90634..43e3781716 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportContextBootstrap.java @@ -31,30 +31,24 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; */ import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportContext; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; -import javax.annotation.PostConstruct; - @Slf4j @Component @ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || '${service.type:null}'=='monolith'") public class LwM2MTransportContextBootstrap extends TransportContext { - private LwM2MTransportConfigBootstrap ctxBootStrap; - @Autowired - LwM2MTransportConfigBootstrap lwM2MTransportConfigBootstarp; + private final LwM2MTransportConfigBootstrap lwM2MTransportConfigBootstrap; - @PostConstruct - public void init() { - this.ctxBootStrap = lwM2MTransportConfigBootstarp; + public LwM2MTransportContextBootstrap(LwM2MTransportConfigBootstrap ctxBootStrap) { + this.lwM2MTransportConfigBootstrap = ctxBootStrap; } public LwM2MTransportConfigBootstrap getCtxBootStrap() { - return this.ctxBootStrap; + return this.lwM2MTransportConfigBootstrap; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java index 35a1406b83..8e266a2638 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/secure/LwM2MBootstrapSecurityStore.java @@ -27,16 +27,15 @@ import org.eclipse.leshan.server.bootstrap.EditableBootstrapConfigStore; import org.eclipse.leshan.server.bootstrap.InvalidConfigurationException; import org.eclipse.leshan.server.security.BootstrapSecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; -import org.thingsboard.server.transport.lwm2m.server.LwM2MSessionMsgListener; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; +import org.thingsboard.server.transport.lwm2m.server.LwM2mSessionMsgListener; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler; import org.thingsboard.server.transport.lwm2m.utils.TypeServer; import java.io.IOException; @@ -45,12 +44,12 @@ import java.util.Arrays; import java.util.List; import java.util.UUID; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.BOOTSTRAP_SERVER; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LWM2M_SERVER; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.SERVERS; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getBootstrapParametersFromThingsboard; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.BOOTSTRAP_SERVER; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LWM2M_SERVER; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVERS; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getBootstrapParametersFromThingsboard; @Slf4j @Service("LwM2MBootstrapSecurityStore") @@ -59,14 +58,14 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { private final EditableBootstrapConfigStore bootstrapConfigStore; - @Autowired - LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; + private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; - @Autowired - public LwM2MTransportContextServer context; + private final LwM2mTransportContextServer context; - public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore) { + public LwM2MBootstrapSecurityStore(EditableBootstrapConfigStore bootstrapConfigStore, LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, LwM2mTransportContextServer context) { this.bootstrapConfigStore = bootstrapConfigStore; + this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator; + this.context = context; } @Override @@ -162,18 +161,18 @@ public class LwM2MBootstrapSecurityStore implements BootstrapSecurityStore { LwM2MServerBootstrap profileLwm2mServer = mapper.readValue(bootstrapObject.get(LWM2M_SERVER).toString(), LwM2MServerBootstrap.class); UUID sessionUUiD = UUID.randomUUID(); TransportProtos.SessionInfoProto sessionInfo = context.getValidateSessionInfo(store.getMsg(), sessionUUiD.getMostSignificantBits(), sessionUUiD.getLeastSignificantBits()); - context.getTransportService().registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(null, sessionInfo)); + context.getTransportService().registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(null, sessionInfo)); if (this.getValidatedSecurityMode(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap, lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer)) { lwM2MBootstrapConfig.bootstrapServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.bootstrapServer, profileServerBootstrap); lwM2MBootstrapConfig.lwm2mServer = new LwM2MServerBootstrap(lwM2MBootstrapConfig.lwm2mServer, profileLwm2mServer); String logMsg = String.format("%s: getParametersBootstrap: %s Access connect client with bootstrap server.", LOG_LW2M_INFO, store.getEndPoint()); - context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); return lwM2MBootstrapConfig; } else { log.error(" [{}] Different values SecurityMode between of client and profile.", store.getEndPoint()); log.error("{} getParametersBootstrap: [{}] Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint()); String logMsg = String.format("%s: getParametersBootstrap: %s Different values SecurityMode between of client and profile.", LOG_LW2M_ERROR, store.getEndPoint()); - context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); + context.sentParametersOnThingsboard(context.getTelemetryMsgObject(logMsg), LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC, sessionInfo); return null; } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java index 64739e85f5..86a333e361 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/LwM2mCredentialsSecurityInfoValidator.java @@ -20,16 +20,14 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.SecurityInfo; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.transport.TransportServiceCallback; -import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; -import org.thingsboard.server.transport.lwm2m.bootstrap.LwM2MTransportContextBootstrap; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportContextServer; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; +import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceLwM2MCredentialsRequestMsg; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportContextServer; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler; import org.thingsboard.server.transport.lwm2m.utils.TypeServer; import java.io.IOException; @@ -45,47 +43,46 @@ import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.RP import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.X509; @Slf4j -@Component("LwM2MGetSecurityInfo") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +@Component +@TbLwM2mTransportComponent public class LwM2mCredentialsSecurityInfoValidator { - @Autowired - public LwM2MTransportContextServer contextS; - - @Autowired - public LwM2MTransportContextBootstrap contextBS; + private final LwM2mTransportContextServer contextS; + public LwM2mCredentialsSecurityInfoValidator(LwM2mTransportContextServer contextS) { + this.contextS = contextS; + } /** * Request to thingsboard Response from thingsboard ValidateDeviceLwM2MCredentials - * @param endPoint - + * @param endpoint - * @param keyValue - * @return ValidateDeviceCredentialsResponseMsg and SecurityInfo */ - public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endPoint, TypeServer keyValue) { + public ReadResultSecurityStore createAndValidateCredentialsSecurityInfo(String endpoint, TypeServer keyValue) { CountDownLatch latch = new CountDownLatch(1); final ReadResultSecurityStore[] resultSecurityStore = new ReadResultSecurityStore[1]; - contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endPoint).build(), - new TransportServiceCallback() { + contextS.getTransportService().process(ValidateDeviceLwM2MCredentialsRequestMsg.newBuilder().setCredentialsId(endpoint).build(), + new TransportServiceCallback<>() { @Override public void onSuccess(ValidateDeviceCredentialsResponseMsg msg) { String credentialsBody = msg.getCredentialsBody(); - resultSecurityStore[0] = createSecurityInfo(endPoint, credentialsBody, keyValue); + resultSecurityStore[0] = createSecurityInfo(endpoint, credentialsBody, keyValue); resultSecurityStore[0].setMsg(msg); - Optional deviceProfileOpt = LwM2MTransportHandler.decode(msg.getProfileBody().toByteArray()); + Optional deviceProfileOpt = LwM2mTransportHandler.decode(msg.getProfileBody().toByteArray()); deviceProfileOpt.ifPresent(profile -> resultSecurityStore[0].setDeviceProfile(profile)); latch.countDown(); } @Override public void onError(Throwable e) { - log.trace("[{}] [{}] Failed to process credentials ", endPoint, e); - resultSecurityStore[0] = createSecurityInfo(endPoint, null, null); + log.trace("[{}] [{}] Failed to process credentials ", endpoint, e); + resultSecurityStore[0] = createSecurityInfo(endpoint, null, null); latch.countDown(); } }); try { - latch.await(contextS.getCtxServer().getTimeout(), TimeUnit.MILLISECONDS); + latch.await(contextS.getLwM2MTransportConfigServer().getTimeout(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.error("Failed to await credentials!", e); } @@ -101,7 +98,7 @@ public class LwM2mCredentialsSecurityInfoValidator { */ private ReadResultSecurityStore createSecurityInfo(String endPoint, String jsonStr, TypeServer keyValue) { ReadResultSecurityStore result = new ReadResultSecurityStore(); - JsonObject objectMsg = LwM2MTransportHandler.validateJson(jsonStr); + JsonObject objectMsg = LwM2mTransportHandler.validateJson(jsonStr); if (objectMsg != null && !objectMsg.isJsonNull()) { JsonObject object = (objectMsg.has(keyValue.type) && !objectMsg.get(keyValue.type).isJsonNull()) ? objectMsg.get(keyValue.type).getAsJsonObject() : null; /** diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 5ff826b25b..933b3865a8 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -31,9 +31,9 @@ import java.util.Collection; public class LwM2mServerListener { private final LeshanServer lhServer; - private final LwM2MTransportServiceImpl service; + private final LwM2mTransportServiceImpl service; - public LwM2mServerListener(LeshanServer lhServer, LwM2MTransportServiceImpl service) { + public LwM2mServerListener(LeshanServer lhServer, LwM2mTransportServiceImpl service) { this.lhServer = lhServer; this.service = service; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java similarity index 95% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java index 21f1c5e2cc..15fb015f32 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MSessionMsgListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mSessionMsgListener.java @@ -32,11 +32,11 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToTransportUpdateCre import java.util.Optional; @Slf4j -public class LwM2MSessionMsgListener implements GenericFutureListener>, SessionMsgListener { - private LwM2MTransportServiceImpl service; +public class LwM2mSessionMsgListener implements GenericFutureListener>, SessionMsgListener { + private LwM2mTransportServiceImpl service; private TransportProtos.SessionInfoProto sessionInfo; - public LwM2MSessionMsgListener(LwM2MTransportServiceImpl service, TransportProtos.SessionInfoProto sessionInfo) { + public LwM2mSessionMsgListener(LwM2mTransportServiceImpl service, TransportProtos.SessionInfoProto sessionInfo) { this.service = service; this.sessionInfo = sessionInfo; } 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 similarity index 80% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportContextServer.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportContextServer.java index fa171a9399..062c0f1148 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 @@ -34,8 +34,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.common.transport.TransportContext; import org.thingsboard.server.common.transport.TransportService; @@ -43,40 +41,32 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.server.adaptors.LwM2MJsonAdaptor; -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; -import javax.annotation.PostConstruct; - -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 @Component -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportContextServer extends TransportContext { +@TbLwM2mTransportComponent +public class LwM2mTransportContextServer extends TransportContext { - private LwM2MTransportConfigServer ctxServer; - @Autowired - protected LwM2MTransportConfigServer lwM2MTransportConfigServer; + private final LwM2MTransportConfigServer lwM2MTransportConfigServer; - @Autowired - private TransportService transportService; + private final TransportService transportService; @Getter - @Autowired - private LwM2MJsonAdaptor adaptor; - - @Autowired - LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + private final LwM2MJsonAdaptor adaptor; - @PostConstruct - public void init() { - this.ctxServer = lwM2MTransportConfigServer; + public LwM2mTransportContextServer(LwM2MTransportConfigServer lwM2MTransportConfigServer, TransportService transportService, LwM2MJsonAdaptor adaptor) { + this.lwM2MTransportConfigServer = lwM2MTransportConfigServer; + this.transportService = transportService; + this.adaptor = adaptor; } - public LwM2MTransportConfigServer getCtxServer() { - return this.ctxServer; + public LwM2MTransportConfigServer getLwM2MTransportConfigServer() { + return this.lwM2MTransportConfigServer; } /** @@ -86,7 +76,7 @@ public class LwM2MTransportContextServer extends TransportContext { * @return - dummy */ private TransportServiceCallback getPubAckCallbackSentAttrTelemetry(final T msg) { - return new TransportServiceCallback() { + return new TransportServiceCallback<>() { @Override public void onSuccess(Void dummy) { log.trace("Success to publish msg: {}, dummy: {}", msg, dummy); @@ -101,11 +91,11 @@ public class LwM2MTransportContextServer extends TransportContext { public void sentParametersOnThingsboard(JsonElement msg, String topicName, TransportProtos.SessionInfoProto sessionInfo) { try { - if (topicName.equals(LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { + if (topicName.equals(LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC)) { TransportProtos.PostAttributeMsg postAttributeMsg = adaptor.convertToPostAttributes(msg); TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postAttributeMsg); 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); TransportServiceCallback call = this.getPubAckCallbackSentAttrTelemetry(postTelemetryMsg); transportService.process(sessionInfo, postTelemetryMsg, this.getPubAckCallbackSentAttrTelemetry(call)); 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 similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportHandler.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportHandler.java index 878f7c8542..8d660b3c22 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 @@ -36,8 +36,8 @@ 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.transport.TransportServiceCallback; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientProfile; -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.LwM2mClient; import java.io.File; import java.io.IOException; @@ -49,7 +49,7 @@ import java.util.Optional; @Slf4j //@Component("LwM2MTransportHandler") //@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportHandler { +public class LwM2mTransportHandler { // We choose a default timeout a bit higher to the MAX_TRANSMIT_WAIT(62-93s) which is the time from starting to // send a Confirmable message to the time when an acknowledgement is no longer expected. @@ -188,8 +188,8 @@ public class LwM2MTransportHandler { return null; } - public static LwM2MClientProfile getNewProfileParameters(JsonObject profilesConfigData) { - LwM2MClientProfile lwM2MClientProfile = new LwM2MClientProfile(); + public static LwM2mClientProfile getNewProfileParameters(JsonObject profilesConfigData) { + LwM2mClientProfile lwM2MClientProfile = new LwM2mClientProfile(); lwM2MClientProfile.setPostClientLwM2mSettings(profilesConfigData.get(CLIENT_LWM2M_SETTINGS).getAsJsonObject()); lwM2MClientProfile.setPostKeyNameProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(KEY_NAME).getAsJsonObject()); lwM2MClientProfile.setPostAttributeProfile(profilesConfigData.get(OBSERVE_ATTRIBUTE_TELEMETRY).getAsJsonObject().get(ATTRIBUTE).getAsJsonArray()); @@ -214,14 +214,14 @@ public class LwM2MTransportHandler { * "telemetry":["/1/0/1","/2/0/1","/6/0/1"], * "observe":["/2/0","/2/0/0","/4/0/2"]} */ - public static LwM2MClientProfile getLwM2MClientProfileFromThingsboard(DeviceProfile deviceProfile) { + public static LwM2mClientProfile getLwM2MClientProfileFromThingsboard(DeviceProfile deviceProfile) { if (deviceProfile != null && ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties().size() > 0) { Object profile = ((Lwm2mDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration()).getProperties(); try { ObjectMapper mapper = new ObjectMapper(); String profileStr = mapper.writeValueAsString(profile); JsonObject profileJson = (profileStr != null) ? validateJson(profileStr) : null; - return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2MTransportHandler.getNewProfileParameters(profileJson) : null; + return (getValidateCredentialsBodyFromThingsboard(profileJson)) ? LwM2mTransportHandler.getNewProfileParameters(profileJson) : null; } catch (IOException e) { log.error("", e); } @@ -244,12 +244,12 @@ public class LwM2MTransportHandler { return null; } - public static boolean getClientUpdateValueAfterConnect (LwM2MClientProfile profile) { + public static boolean getClientUpdateValueAfterConnect (LwM2mClientProfile profile) { return profile.getPostClientLwM2mSettings().getAsJsonObject().has("clientUpdateValueAfterConnect") && profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientUpdateValueAfterConnect").getAsBoolean(); } - public static boolean getClientOnlyObserveAfterConnect (LwM2MClientProfile profile) { + public static boolean getClientOnlyObserveAfterConnect (LwM2mClientProfile profile) { return profile.getPostClientLwM2mSettings().getAsJsonObject().has("clientOnlyObserveAfterConnect") && profile.getPostClientLwM2mSettings().getAsJsonObject().get("clientOnlyObserveAfterConnect").getAsBoolean(); } @@ -336,11 +336,11 @@ public class LwM2MTransportHandler { return StringUtils.join(linkedListOut, ""); } - public static TransportServiceCallback getAckCallback(LwM2MClient lwM2MClient, int requestId, String typeTopic) { + public static TransportServiceCallback getAckCallback(LwM2mClient lwM2MClient, int requestId, String typeTopic) { return new TransportServiceCallback() { @Override public void onSuccess(Void dummy) { - log.trace("[{}] [{}] - requestId [{}] - EndPoint , Access AckCallback", typeTopic, requestId, lwM2MClient.getEndPoint()); + log.trace("[{}] [{}] - requestId [{}] - EndPoint , Access AckCallback", typeTopic, requestId, lwM2MClient.getEndpoint()); } @Override 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 similarity index 93% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportRequest.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportRequest.java index 5b499bc892..c58d2c35e0 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 @@ -48,9 +48,10 @@ import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -63,40 +64,41 @@ import java.util.concurrent.Executors; import static org.eclipse.californium.core.coap.CoAP.ResponseCode.isSuccess; import static org.eclipse.leshan.core.attributes.Attribute.MINIMUM_PERIOD; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEFAULT_TIMEOUT; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_DISCOVER; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_OBSERVE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_EXECUTE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_OBSERVE_CANCEL; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.RESPONSE_CHANNEL; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_DISCOVER; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_OBSERVE_CANCEL; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_ATTRIBUTES; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.PUT_TYPE_OPER_WRITE_UPDATE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.RESPONSE_CHANNEL; @Slf4j -@Service("LwM2MTransportRequest") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportRequest { +@Service("LwM2mTransportRequest") +@TbLwM2mTransportComponent +public class LwM2mTransportRequest { private ExecutorService executorResponse; - private ExecutorService executorResponseError; + private LwM2mValueConverterImpl converter; @Autowired - LwM2MTransportServiceImpl service; + private LwM2mTransportServiceImpl service; + + @Autowired + private LwM2mTransportContextServer context; @Autowired - public LwM2MTransportContextServer context; + private LwM2mClientContext lwM2mClientContext; @PostConstruct public void init() { this.converter = LwM2mValueConverterImpl.getInstance(); - executorResponse = Executors.newFixedThreadPool(this.context.getCtxServer().getRequestPoolSize(), + executorResponse = Executors.newFixedThreadPool(this.context.getLwM2MTransportConfigServer().getRequestPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel response", RESPONSE_CHANNEL))); - executorResponseError = Executors.newFixedThreadPool(this.context.getCtxServer().getRequestErrorPoolSize(), - new NamedThreadFactory(String.format("LwM2M %s channel response Error", RESPONSE_CHANNEL))); } public Collection doGetRegistrations(LeshanServer lwServer) { @@ -124,7 +126,7 @@ public class LwM2MTransportRequest { if (registration != null && resultIds.getObjectId() >= 0) { DownlinkRequest request = null; ContentFormat contentFormat = contentFormatParam != null ? ContentFormat.fromName(contentFormatParam.toUpperCase()) : null; - ResourceModel resource = service.context.getCtxServer().getResourceModel(registration, resultIds); + ResourceModel resource = service.context.getLwM2MTransportConfigServer().getResourceModel(registration, resultIds); timeoutInMs = timeoutInMs > 0 ? timeoutInMs : DEFAULT_TIMEOUT; switch (typeOper) { case GET_TYPE_OPER_READ: @@ -234,7 +236,7 @@ public class LwM2MTransportRequest { @SuppressWarnings("unchecked") private void sendRequest(LeshanServer lwServer, Registration registration, DownlinkRequest request, long timeoutInMs) { - LwM2MClient lwM2MClient = this.service.lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); lwServer.send(registration, request, timeoutInMs, (ResponseCallback) response -> { if (!lwM2MClient.isInit()) { lwM2MClient.initValue(this.service, 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 similarity index 78% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerConfiguration.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerConfiguration.java index 5981a05e06..ace2fb4896 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 @@ -22,15 +22,16 @@ import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; import org.eclipse.leshan.core.util.Hex; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.californium.LeshanServerBuilder; +import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; 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.EditableSecurityStore; import org.eclipse.leshan.server.security.SecurityChecker; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.math.BigInteger; @@ -57,32 +58,35 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getCoapConfig; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; @Slf4j @Component("LwM2MTransportServerConfiguration") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportServerConfiguration { +@TbLwM2mTransportComponent +public class LwM2mTransportServerConfiguration { private PublicKey publicKey; private PrivateKey privateKey; private boolean pskMode = false; @Autowired - private LwM2MTransportContextServer context; + private LwM2mTransportContextServer context; @Autowired - private LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + private CaliforniumRegistrationStore registrationStore; + + @Autowired + private EditableSecurityStore securityStore; @Bean public LeshanServer getLeshanServer() { log.info("Starting LwM2M transport Server... PostConstruct"); - return this.getLhServer(this.context.getCtxServer().getServerPortNoSec(), this.context.getCtxServer().getServerPortSecurity()); + return this.getLhServer(this.context.getLwM2MTransportConfigServer().getServerPortNoSec(), this.context.getLwM2MTransportConfigServer().getServerPortSecurity()); } private LeshanServer getLhServer(Integer serverPortNoSec, Integer serverSecurePort) { LeshanServerBuilder builder = new LeshanServerBuilder(); - builder.setLocalAddress(this.context.getCtxServer().getServerHost(), serverPortNoSec); - builder.setLocalSecureAddress(this.context.getCtxServer().getServerHostSecurity(), serverSecurePort); + builder.setLocalAddress(this.context.getLwM2MTransportConfigServer().getServerHost(), serverPortNoSec); + builder.setLocalSecureAddress(this.context.getLwM2MTransportConfigServer().getServerHostSecurity(), serverSecurePort); builder.setDecoder(new DefaultLwM2mNodeDecoder()); /** Use a magic converter to support bad type send by the UI. */ builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); @@ -91,26 +95,26 @@ public class LwM2MTransportServerConfiguration { builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); /** Define model provider (Create Models )*/ - LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getCtxServer().getModelsValue()); + LwM2mModelProvider modelProvider = new VersionedModelProvider(this.context.getLwM2MTransportConfigServer().getModelsValue()); builder.setObjectModelProvider(modelProvider); /** Create credentials */ this.setServerWithCredentials(builder); /** Set securityStore with new registrationStore */ - builder.setSecurityStore(lwM2mInMemorySecurityStore); + builder.setSecurityStore(securityStore); + builder.setRegistrationStore(registrationStore); /** Create DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getCtxServer().isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getCtxServer().isRecommendedCiphers()); + dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getLwM2MTransportConfigServer().isRecommendedSupportedGroups()); + dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getLwM2MTransportConfigServer().isRecommendedCiphers()); if (this.pskMode) { dtlsConfig.setSupportedCipherSuites( TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256); - } - else { + } else { dtlsConfig.setSupportedCipherSuites( TLS_PSK_WITH_AES_128_CCM_8, TLS_PSK_WITH_AES_128_CBC_SHA256, @@ -118,7 +122,6 @@ public class LwM2MTransportServerConfiguration { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); } - /** Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); @@ -128,9 +131,9 @@ public class LwM2MTransportServerConfiguration { private void setServerWithCredentials(LeshanServerBuilder builder) { try { - if (this.context.getCtxServer().getKeyStoreValue() != null) { + if (this.context.getLwM2MTransportConfigServer().getKeyStoreValue() != null) { if (this.setBuilderX509(builder)) { - X509Certificate rootCAX509Cert = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getRootAlias()); + X509Certificate rootCAX509Cert = (X509Certificate) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.context.getLwM2MTransportConfigServer().getRootAlias()); if (rootCAX509Cert != null) { X509Certificate[] trustedCertificates = new X509Certificate[1]; trustedCertificates[0] = rootCAX509Cert; @@ -140,7 +143,7 @@ public class LwM2MTransportServerConfiguration { builder.setTrustedCertificates(new X509Certificate[0]); } /** Set securityStore with registrationStore*/ - builder.setAuthorizer(new DefaultAuthorizer(lwM2mInMemorySecurityStore, new SecurityChecker() { + builder.setAuthorizer(new DefaultAuthorizer(securityStore, new SecurityChecker() { @Override protected boolean matchX509Identity(String endpoint, String receivedX509CommonName, String expectedX509CommonName) { @@ -169,8 +172,8 @@ public class LwM2MTransportServerConfiguration { * For idea => KeyStorePathResource == common/transport/lwm2m/src/main/resources/credentials: in LwM2MTransportContextServer: credentials/serverKeyStore.jks */ try { - X509Certificate serverCertificate = (X509Certificate) this.context.getCtxServer().getKeyStoreValue().getCertificate(this.context.getCtxServer().getServerAlias()); - PrivateKey privateKey = (PrivateKey) this.context.getCtxServer().getKeyStoreValue().getKey(this.context.getCtxServer().getServerAlias(), this.context.getCtxServer().getKeyStorePasswordServer() == null ? null : this.context.getCtxServer().getKeyStorePasswordServer().toCharArray()); + X509Certificate serverCertificate = (X509Certificate) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getCertificate(this.context.getLwM2MTransportConfigServer().getServerAlias()); + PrivateKey privateKey = (PrivateKey) this.context.getLwM2MTransportConfigServer().getKeyStoreValue().getKey(this.context.getLwM2MTransportConfigServer().getServerAlias(), this.context.getLwM2MTransportConfigServer().getKeyStorePasswordServer() == null ? null : this.context.getLwM2MTransportConfigServer().getKeyStorePasswordServer().toCharArray()); PublicKey publicKey = serverCertificate.getPublicKey(); if (serverCertificate != null && privateKey != null && privateKey.getEncoded().length > 0 && @@ -203,8 +206,8 @@ public class LwM2MTransportServerConfiguration { private void infoPramsUri(String mode) { log.info("Server uses [{}]: serverNoSecureURI : [{}], serverSecureURI : [{}]", mode, - this.context.getCtxServer().getServerHost() + ":" + this.context.getCtxServer().getServerPortNoSec(), - this.context.getCtxServer().getServerHostSecurity() + ":" + this.context.getCtxServer().getServerPortSecurity()); + this.context.getLwM2MTransportConfigServer().getServerHost() + ":" + this.context.getLwM2MTransportConfigServer().getServerPortNoSec(), + this.context.getLwM2MTransportConfigServer().getServerHostSecurity() + ":" + this.context.getLwM2MTransportConfigServer().getServerPortSecurity()); } private boolean setServerRPK(LeshanServerBuilder builder) { @@ -234,27 +237,27 @@ public class LwM2MTransportServerConfiguration { AlgorithmParameters algoParameters = AlgorithmParameters.getInstance("EC"); algoParameters.init(new ECGenParameterSpec("secp256r1")); ECParameterSpec parameterSpec = algoParameters.getParameterSpec(ECParameterSpec.class); - if (this.context.getCtxServer().getServerPublicX() != null && - !this.context.getCtxServer().getServerPublicX().isEmpty() && - this.context.getCtxServer().getServerPublicY() != null && - !this.context.getCtxServer().getServerPublicY().isEmpty()) { + if (this.context.getLwM2MTransportConfigServer().getServerPublicX() != null && + !this.context.getLwM2MTransportConfigServer().getServerPublicX().isEmpty() && + this.context.getLwM2MTransportConfigServer().getServerPublicY() != null && + !this.context.getLwM2MTransportConfigServer().getServerPublicY().isEmpty()) { /** Get point values */ - byte[] publicX = Hex.decodeHex(this.context.getCtxServer().getServerPublicX().toCharArray()); - byte[] publicY = Hex.decodeHex(this.context.getCtxServer().getServerPublicY().toCharArray()); + byte[] publicX = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPublicX().toCharArray()); + byte[] publicY = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPublicY().toCharArray()); /** Create key specs */ KeySpec publicKeySpec = new ECPublicKeySpec(new ECPoint(new BigInteger(publicX), new BigInteger(publicY)), parameterSpec); /** Get keys */ this.publicKey = KeyFactory.getInstance("EC").generatePublic(publicKeySpec); } - if (this.context.getCtxServer().getServerPrivateEncoded() != null && - !this.context.getCtxServer().getServerPrivateEncoded().isEmpty()) { + if (this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded() != null && + !this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded().isEmpty()) { /** Get private key */ - byte[] privateS = Hex.decodeHex(this.context.getCtxServer().getServerPrivateEncoded().toCharArray()); + byte[] privateS = Hex.decodeHex(this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded().toCharArray()); try { this.privateKey = KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateS)); } catch (InvalidKeySpecException ignore2) { - log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", this.context.getCtxServer().getServerPrivateEncoded()); + log.error("Invalid Server rpk.PrivateKey.getEncoded () [{}}]. PrivateKey has no EC algorithm", this.context.getLwM2MTransportConfigServer().getServerPrivateEncoded()); } } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerInitializer.java similarity index 80% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerInitializer.java index 2805fd7f91..9c8d62f1e0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServerInitializer.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServerInitializer.java @@ -18,8 +18,8 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.server.californium.LeshanServer; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; import org.thingsboard.server.transport.lwm2m.secure.LWM2MGenerationPSkRPkECC; import javax.annotation.PostConstruct; @@ -27,21 +27,21 @@ import javax.annotation.PreDestroy; @Slf4j @Component("LwM2MTransportServerInitializer") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportServerInitializer { +@TbLwM2mTransportComponent +public class LwM2mTransportServerInitializer { @Autowired - private LwM2MTransportServiceImpl service; + private LwM2mTransportServiceImpl service; @Autowired(required = false) private LeshanServer leshanServer; @Autowired - private LwM2MTransportContextServer context; + private LwM2mTransportContextServer context; @PostConstruct public void init() { - if (this.context.getCtxServer().getEnableGenNewKeyPskRpk()) { + if (this.context.getLwM2MTransportConfigServer().getEnableGenNewKeyPskRpk()) { new LWM2MGenerationPSkRPkECC(); } this.startLhServer(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportService.java similarity index 98% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportService.java index 8abfcc6a1d..46c9cf5e64 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportService.java @@ -26,7 +26,7 @@ import org.thingsboard.server.gen.transport.TransportProtos; import java.util.Collection; import java.util.Optional; -public interface LwM2MTransportService { +public interface LwM2mTransportService { void onRegistered(LeshanServer lwServer, Registration registration, Collection previousObsersations); 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 similarity index 83% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MTransportServiceImpl.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportServiceImpl.java index 31e2fc7671..87a7fcbc07 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 @@ -36,7 +36,6 @@ import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; @@ -48,11 +47,12 @@ import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.SessionEvent; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClient; -import org.thingsboard.server.transport.lwm2m.server.client.LwM2MClientProfile; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; import org.thingsboard.server.transport.lwm2m.server.client.ResultsAnalyzerParameters; -import org.thingsboard.server.transport.lwm2m.server.secure.LwM2mInMemorySecurityStore; import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PostConstruct; @@ -79,24 +79,24 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.stream.Collectors; import static org.thingsboard.server.common.transport.util.JsonUtils.getJsonObject; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.CLIENT_NOT_AUTHORIZED; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEVICE_ATTRIBUTES_REQUEST; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEVICE_ATTRIBUTES_TOPIC; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.DEVICE_TELEMETRY_TOPIC; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_OBSERVE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.GET_TYPE_OPER_READ; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_ERROR; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_INFO; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.LOG_LW2M_TELEMETRY; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_EXECUTE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.SERVICE_CHANNEL; -import static org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler.getAckCallback; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_TOPIC; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_TELEMETRY_TOPIC; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_OBSERVE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.GET_TYPE_OPER_READ; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_TELEMETRY; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_EXECUTE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.POST_TYPE_OPER_WRITE_REPLACE; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.SERVICE_CHANNEL; +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getAckCallback; @Slf4j -@Service("LwM2MTransportService") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") -public class LwM2MTransportServiceImpl implements LwM2MTransportService { +@Service +@TbLwM2mTransportComponent +public class LwM2mTransportServiceImpl implements LwM2mTransportService { private ExecutorService executorRegistered; private ExecutorService executorUpdateRegistered; @@ -105,27 +105,29 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { protected final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); protected final Lock writeLock = readWriteLock.writeLock(); - @Autowired private TransportService transportService; @Autowired - public LwM2MTransportContextServer context; + public LwM2mTransportContextServer context; @Autowired - private LwM2MTransportRequest lwM2MTransportRequest; + private LwM2mTransportRequest lwM2mTransportRequest; @Autowired - LwM2mInMemorySecurityStore lwM2mInMemorySecurityStore; + private LwM2mClientContext lwM2mClientContext; + + @Autowired(required = false) + private LeshanServer leshanServer; @PostConstruct public void init() { - this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getCtxServer().getSessionReportTimeout()), context.getCtxServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); - this.executorRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getRegisteredPoolSize(), + this.context.getScheduler().scheduleAtFixedRate(this::checkInactivityAndReportActivity, new Random().nextInt((int) context.getLwM2MTransportConfigServer().getSessionReportTimeout()), context.getLwM2MTransportConfigServer().getSessionReportTimeout(), TimeUnit.MILLISECONDS); + this.executorRegistered = Executors.newFixedThreadPool(this.context.getLwM2MTransportConfigServer().getRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel registered", SERVICE_CHANNEL))); - this.executorUpdateRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getUpdateRegisteredPoolSize(), + this.executorUpdateRegistered = Executors.newFixedThreadPool(this.context.getLwM2MTransportConfigServer().getUpdateRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel update registered", SERVICE_CHANNEL))); - this.executorUnRegistered = Executors.newFixedThreadPool(this.context.getCtxServer().getUnRegisteredPoolSize(), + this.executorUnRegistered = Executors.newFixedThreadPool(this.context.getLwM2MTransportConfigServer().getUnRegisteredPoolSize(), new NamedThreadFactory(String.format("LwM2M %s channel un registered", SERVICE_CHANNEL))); this.converter = LwM2mValueConverterImpl.getInstance(); } @@ -149,17 +151,16 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { executorRegistered.submit(() -> { try { log.warn("[{}] [{{}] Client: create after Registration", registration.getEndpoint(), registration.getId()); - LwM2MClient lwM2MClient = this.lwM2mInMemorySecurityStore.updateInSessionsLwM2MClient(lwServer, registration); + LwM2mClient lwM2MClient = this.lwM2mClientContext.updateInSessionsLwM2MClient(registration); if (lwM2MClient != null) { - lwM2MClient.setLwM2MTransportServiceImpl(this); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client Registered", registration); SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); if (sessionInfo != null) { - lwM2MClient.setDeviceUuid(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); - lwM2MClient.setProfileUuid(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + lwM2MClient.setDeviceId(new UUID(sessionInfo.getDeviceIdMSB(), sessionInfo.getDeviceIdLSB())); + lwM2MClient.setProfileId(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); lwM2MClient.setDeviceName(sessionInfo.getDeviceName()); lwM2MClient.setDeviceProfileName(sessionInfo.getDeviceType()); - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); this.sentLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); @@ -221,8 +222,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { if (sessionInfo != null) { transportService.deregisterSession(sessionInfo); this.doCloseSession(sessionInfo); - lwM2mInMemorySecurityStore.delRemoveSessionAndListener(registration.getId()); - if (lwM2mInMemorySecurityStore.getProfiles().size() > 0) { + lwM2mClientContext.delRemoveSessionAndListener(registration.getId()); + if (lwM2mClientContext.getProfiles().size() > 0) { this.syncSessionsAndProfiles(); } log.info("Client close session: [{}] unReg [{}] name [{}] profile ", registration.getId(), registration.getEndpoint(), sessionInfo.getDeviceType()); @@ -292,13 +293,13 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { el.getAsJsonObject().entrySet().forEach(de -> { String path = this.getPathAttributeUpdate(sessionInfo, de.getKey()); String value = de.getValue().getAsString(); - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); - ResourceModel resourceModel = context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + ResourceModel resourceModel = context.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(path)); if (!path.isEmpty() && (this.validatePathInAttrProfile(profile, path) || this.validatePathInTelemetryProfile(profile, path))) { if (resourceModel != null && resourceModel.operations.isWritable()) { - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, - ContentFormat.TLV.getName(), null, value, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(leshanServer, lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), null, value, this.context.getLwM2MTransportConfigServer().getTimeout()); } else { log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", path, value); String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", @@ -323,9 +324,9 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ @Override public void onDeviceProfileUpdate(SessionInfoProto sessionInfo, DeviceProfile deviceProfile) { - Set registrationIds = lwM2mInMemorySecurityStore.getSessions().entrySet() + Set registrationIds = lwM2mClientContext.getLwM2mClients().entrySet() .stream() - .filter(e -> e.getValue().getProfileUuid().equals(deviceProfile.getUuidId())) + .filter(e -> e.getValue().getProfileId().equals(deviceProfile.getUuidId())) .map(Map.Entry::getKey).sorted().collect(Collectors.toCollection(LinkedHashSet::new)); if (registrationIds.size() > 0) { this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile); @@ -339,8 +340,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ @Override public void onDeviceUpdate(SessionInfoProto sessionInfo, Device device, Optional deviceProfileOpt) { - Optional registrationIdOpt = lwM2mInMemorySecurityStore.getSessions().entrySet().stream() - .filter(e -> device.getUuidId().equals(e.getValue().getDeviceUuid())) + Optional registrationIdOpt = lwM2mClientContext.getLwM2mClients().entrySet().stream() + .filter(e -> device.getUuidId().equals(e.getValue().getDeviceId())) .map(Map.Entry::getKey) .findFirst(); registrationIdOpt.ifPresent(registrationId -> this.onDeviceUpdateLwM2MClient(registrationId, device, deviceProfileOpt)); @@ -353,8 +354,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ @Override public void doTrigger(LeshanServer lwServer, Registration registration, String path) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, - ContentFormat.TLV.getName(), null, null, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(lwServer, registration, path, POST_TYPE_OPER_EXECUTE, + ContentFormat.TLV.getName(), null, null, this.context.getLwM2MTransportConfigServer().getTimeout()); } /** @@ -397,18 +398,18 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * Removes a profile if not used in sessions */ private void syncSessionsAndProfiles() { - Map profilesClone = lwM2mInMemorySecurityStore.getProfiles().entrySet() + Map profilesClone = lwM2mClientContext.getProfiles().entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); profilesClone.forEach((k, v) -> { - String registrationId = lwM2mInMemorySecurityStore.getSessions().entrySet() + String registrationId = lwM2mClientContext.getLwM2mClients().entrySet() .stream() - .filter(e -> e.getValue().getProfileUuid().equals(k)) + .filter(e -> e.getValue().getProfileId().equals(k)) .findFirst() .map(Map.Entry::getKey) // return the key of the matching entry if found .orElse(""); if (registrationId.isEmpty()) { - lwM2mInMemorySecurityStore.getProfiles().remove(k); + lwM2mClientContext.getProfiles().remove(k); } }); } @@ -458,12 +459,12 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param registration - Registration LwM2M Client * @param lwM2MClient - object with All parameters off client */ - private void initLwM2mFromClientValue(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient) { - LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId()); + private void initLwM2mFromClientValue(LeshanServer lwServer, Registration registration, LwM2mClient lwM2MClient) { + LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); Set clientObjects = this.getAllOjectsInClient(registration); - if (clientObjects != null && !LwM2MTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { + if (clientObjects != null && !LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { // #2 - if (!LwM2MTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) { + if (!LwM2mTransportHandler.getClientUpdateValueAfterConnect(lwM2MClientProfile)) { this.initReadAttrTelemetryObserveToClient(lwServer, registration, lwM2MClient, GET_TYPE_OPER_READ); } @@ -471,8 +472,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { else { lwM2MClient.getPendingRequests().addAll(clientObjects); clientObjects.forEach(path -> { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), - null, null, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(lwServer, registration, path, GET_TYPE_OPER_READ, ContentFormat.TLV.getName(), + null, null, this.context.getLwM2MTransportConfigServer().getTimeout()); }); } } @@ -517,7 +518,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param path - resource */ private void updateResourcesValue(Registration registration, LwM2mResource lwM2mResource, String path) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); lwM2MClient.updateResourceValue(path, lwM2mResource); Set paths = new HashSet<>(); paths.add(path); @@ -565,8 +566,9 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param path - * @return true if path isPresent in postAttributeProfile */ - private boolean validatePathInAttrProfile(LwM2MClientProfile profile, String path) { - Set attributesSet = new Gson().fromJson(profile.getPostAttributeProfile(), new TypeToken<>(){}.getType()); + private boolean validatePathInAttrProfile(LwM2mClientProfile profile, String path) { + Set attributesSet = new Gson().fromJson(profile.getPostAttributeProfile(), new TypeToken<>() { + }.getType()); return attributesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); } @@ -575,8 +577,9 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param path - * @return true if path isPresent in postAttributeProfile */ - private boolean validatePathInTelemetryProfile(LwM2MClientProfile profile, String path) { - Set telemetriesSet = new Gson().fromJson(profile.getPostTelemetryProfile(), new TypeToken<>(){}.getType()); + private boolean validatePathInTelemetryProfile(LwM2mClientProfile profile, String path) { + Set telemetriesSet = new Gson().fromJson(profile.getPostTelemetryProfile(), new TypeToken<>() { + }.getType()); return telemetriesSet.stream().filter(p -> p.equals(path)).findFirst().isPresent(); } @@ -588,16 +591,19 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param lwServer - * @param registration - */ - private void initReadAttrTelemetryObserveToClient(LeshanServer lwServer, Registration registration, LwM2MClient lwM2MClient, String typeOper) { + private void initReadAttrTelemetryObserveToClient(LeshanServer lwServer, Registration registration, LwM2mClient lwM2MClient, String typeOper) { try { - LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId()); + LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); Set clientInstances = this.getAllInstancesInClient(registration); Set result; if (GET_TYPE_OPER_READ.equals(typeOper)) { - result = new ObjectMapper().readValue(lwM2MClientProfile.getPostAttributeProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() {}); - result.addAll(new ObjectMapper().readValue(lwM2MClientProfile.getPostTelemetryProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() {})); + result = new ObjectMapper().readValue(lwM2MClientProfile.getPostAttributeProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() { + }); + result.addAll(new ObjectMapper().readValue(lwM2MClientProfile.getPostTelemetryProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() { + })); } else { - result = new ObjectMapper().readValue(lwM2MClientProfile.getPostObserveProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() {}); + result = new ObjectMapper().readValue(lwM2MClientProfile.getPostObserveProfile().getAsJsonArray().toString().getBytes(), new TypeReference<>() { + }); } Set pathSent = ConcurrentHashMap.newKeySet(); result.forEach(p -> { @@ -611,8 +617,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { }); lwM2MClient.getPendingRequests().addAll(pathSent); pathSent.forEach(target -> { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, ContentFormat.TLV.getName(), - null, null, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, ContentFormat.TLV.getName(), + null, null, this.context.getLwM2MTransportConfigServer().getTimeout()); }); if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { lwM2MClient.initValue(this, null); @@ -630,15 +636,15 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param device - */ private void onDeviceUpdateLwM2MClient(String registrationId, Device device, Optional deviceProfileOpt) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registrationId); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClients().get(registrationId); lwM2MClient.setDeviceName(device.getName()); - if (!lwM2MClient.getProfileUuid().equals(device.getDeviceProfileId().getId())) { + if (!lwM2MClient.getProfileId().equals(device.getDeviceProfileId().getId())) { Set registrationIds = new HashSet<>(); registrationIds.add(registrationId); deviceProfileOpt.ifPresent(deviceProfile -> this.onDeviceUpdateChangeProfile(registrationIds, deviceProfile)); } - lwM2MClient.setProfileUuid(device.getDeviceProfileId().getId()); + lwM2MClient.setProfileId(device.getDeviceProfileId().getId()); } /** @@ -693,20 +699,20 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param path */ private void getParametersFromProfile(JsonObject attributes, JsonObject telemetry, Registration registration, Set path) { - LwM2MClientProfile lwM2MClientProfile = lwM2mInMemorySecurityStore.getProfile(registration.getId()); + LwM2mClientProfile lwM2MClientProfile = lwM2mClientContext.getProfile(registration); lwM2MClientProfile.getPostAttributeProfile().forEach(p -> { - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + LwM2mPath pathIds = new LwM2mPath(p.getAsString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), attributes, registration); + this.addParameters(p.getAsString(), attributes, registration); } } }); lwM2MClientProfile.getPostTelemetryProfile().forEach(p -> { - LwM2mPath pathIds = new LwM2mPath(p.getAsString().toString()); + LwM2mPath pathIds = new LwM2mPath(p.getAsString()); if (pathIds.isResource()) { if (path == null || path.contains(p.getAsString())) { - this.addParameters(p.getAsString().toString(), telemetry, registration); + this.addParameters(p.getAsString(), telemetry, registration); } } }); @@ -717,8 +723,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param registration - Registration LwM2M Client */ private void addParameters(String path, JsonObject parameters, Registration registration) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getSessions().get(registration.getId()); - JsonObject names = lwM2mInMemorySecurityStore.getProfiles().get(lwM2MClient.getProfileUuid()).getPostKeyNameProfile(); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); + JsonObject names = lwM2mClientContext.getProfiles().get(lwM2MClient.getProfileId()).getPostKeyNameProfile(); String resName = String.valueOf(names.get(path)); if (resName != null && !resName.isEmpty()) { try { @@ -727,7 +733,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { parameters.addProperty(resName, resValue); } } catch (Exception e) { - log.error(e.getStackTrace().toString()); + log.error("Failed to add parameters.", e); } } } @@ -736,11 +742,11 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param path - path resource * @return - value of Resource or null */ - private String getResourceValueToString(LwM2MClient lwM2MClient, String path) { + private String getResourceValueToString(LwM2mClient lwM2MClient, String path) { LwM2mPath pathIds = new LwM2mPath(path); ResourceValue resourceValue = this.returnResourceValueFromLwM2MClient(lwM2MClient, pathIds); - return (resourceValue == null) ? null : - (String) this.converter.convertValue(resourceValue.getResourceValue(), this.context.getCtxServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds); + return resourceValue == null ? null : + this.converter.convertValue(resourceValue.getResourceValue(), this.context.getLwM2MTransportConfigServer().getResourceModelType(lwM2MClient.getRegistration(), pathIds), ResourceModel.Type.STRING, pathIds).toString(); } /** @@ -749,7 +755,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param pathIds - * @return - return value of Resource by idPath */ - private ResourceValue returnResourceValueFromLwM2MClient(LwM2MClient lwM2MClient, LwM2mPath pathIds) { + private ResourceValue returnResourceValueFromLwM2MClient(LwM2mClient lwM2MClient, LwM2mPath pathIds) { ResourceValue resourceValue = null; if (pathIds.isResource()) { resourceValue = lwM2MClient.getResources().get(pathIds.toString()); @@ -790,23 +796,25 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param deviceProfile - */ private void onDeviceUpdateChangeProfile(Set registrationIds, DeviceProfile deviceProfile) { - - LwM2MClientProfile lwM2MClientProfileOld = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); - if (lwM2mInMemorySecurityStore.addUpdateProfileParameters(deviceProfile)) { - + LwM2mClientProfile lwM2MClientProfileOld = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId()); + if (lwM2mClientContext.addUpdateProfileParameters(deviceProfile)) { // #1 JsonArray attributeOld = lwM2MClientProfileOld.getPostAttributeProfile(); - Set attributeSetOld = new Gson().fromJson(attributeOld, new TypeToken<>(){}.getType()); + Set attributeSetOld = new Gson().fromJson(attributeOld, new TypeToken<>() { + }.getType()); JsonArray telemetryOld = lwM2MClientProfileOld.getPostTelemetryProfile(); - Set telemetrySetOld = new Gson().fromJson(telemetryOld, new TypeToken<>(){}.getType()); + Set telemetrySetOld = new Gson().fromJson(telemetryOld, new TypeToken<>() { + }.getType()); JsonArray observeOld = lwM2MClientProfileOld.getPostObserveProfile(); JsonObject keyNameOld = lwM2MClientProfileOld.getPostKeyNameProfile(); - LwM2MClientProfile lwM2MClientProfileNew = lwM2mInMemorySecurityStore.getProfiles().get(deviceProfile.getUuidId()); + LwM2mClientProfile lwM2MClientProfileNew = lwM2mClientContext.getProfiles().get(deviceProfile.getUuidId()); JsonArray attributeNew = lwM2MClientProfileNew.getPostAttributeProfile(); - Set attributeSetNew = new Gson().fromJson(attributeNew, new TypeToken<>(){}.getType()); + Set attributeSetNew = new Gson().fromJson(attributeNew, new TypeToken<>() { + }.getType()); JsonArray telemetryNew = lwM2MClientProfileNew.getPostTelemetryProfile(); - Set telemetrySetNew = new Gson().fromJson(telemetryNew, new TypeToken<>(){}.getType()); + Set telemetrySetNew = new Gson().fromJson(telemetryNew, new TypeToken<>() { + }.getType()); JsonArray observeNew = lwM2MClientProfileNew.getPostObserveProfile(); JsonObject keyNameNew = lwM2MClientProfileNew.getPostKeyNameProfile(); @@ -814,20 +822,24 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { ResultsAnalyzerParameters sentAttrToThingsboard = new ResultsAnalyzerParameters(); // #3.1 if (!attributeOld.equals(attributeNew)) { - ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, new TypeToken>(){}.getType()), attributeSetNew); + ResultsAnalyzerParameters postAttributeAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(attributeOld, new TypeToken>() { + }.getType()), attributeSetNew); sentAttrToThingsboard.getPathPostParametersAdd().addAll(postAttributeAnalyzer.getPathPostParametersAdd()); sentAttrToThingsboard.getPathPostParametersDel().addAll(postAttributeAnalyzer.getPathPostParametersDel()); } // #3.2 - if (!attributeOld.equals(attributeNew)) { - ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, new TypeToken>(){}.getType()), telemetrySetNew); + if (!telemetryOld.equals(telemetryNew)) { + ResultsAnalyzerParameters postTelemetryAnalyzer = this.getAnalyzerParameters(new Gson().fromJson(telemetryOld, new TypeToken>() { + }.getType()), telemetrySetNew); sentAttrToThingsboard.getPathPostParametersAdd().addAll(postTelemetryAnalyzer.getPathPostParametersAdd()); sentAttrToThingsboard.getPathPostParametersDel().addAll(postTelemetryAnalyzer.getPathPostParametersDel()); } // #3.3 if (!keyNameOld.equals(keyNameNew)) { - ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), new TypeToken>(){}.getType()), - new Gson().fromJson(keyNameNew.toString(), new TypeToken>(){}.getType())); + ResultsAnalyzerParameters keyNameChange = this.getAnalyzerKeyName(new Gson().fromJson(keyNameOld.toString(), new TypeToken>() { + }.getType()), + new Gson().fromJson(keyNameNew.toString(), new TypeToken>() { + }.getType())); sentAttrToThingsboard.getPathPostParametersAdd().addAll(keyNameChange.getPathPostParametersAdd()); } @@ -835,9 +847,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { if (sentAttrToThingsboard.getPathPostParametersAdd().size() > 0) { // update value in Resources registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); - LeshanServer lwServer = lwM2MClient.getLwServer(); - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + LeshanServer lwServer = leshanServer; + Registration registration = lwM2mClientContext.getRegistration(registrationId); this.readResourceValueObserve(lwServer, registration, sentAttrToThingsboard.getPathPostParametersAdd(), GET_TYPE_OPER_READ); // sent attr/telemetry to tingsboard for new path this.updateAttrTelemetry(registration, false, sentAttrToThingsboard.getPathPostParametersAdd()); @@ -851,8 +862,10 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { // #5.1 if (!observeOld.equals(observeNew)) { - Set observeSetOld = new Gson().fromJson(observeOld, new TypeToken<>(){}.getType()); - Set observeSetNew = new Gson().fromJson(observeNew, new TypeToken<>(){}.getType()); + Set observeSetOld = new Gson().fromJson(observeOld, new TypeToken<>() { + }.getType()); + Set observeSetNew = new Gson().fromJson(observeNew, new TypeToken<>() { + }.getType()); //#5.2 add // path Attr/Telemetry includes newObserve attributeSetOld.addAll(telemetrySetOld); @@ -863,9 +876,8 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { ResultsAnalyzerParameters postObserveAnalyzer = this.getAnalyzerParameters(sentObserveToClientOld.getPathPostParametersAdd(), sentObserveToClientNew.getPathPostParametersAdd()); // sent Request observe to Client registrationIds.forEach(registrationId -> { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(null, registrationId); - LeshanServer lwServer = lwM2MClient.getLwServer(); - Registration registration = lwM2mInMemorySecurityStore.getByRegistration(registrationId); + LeshanServer lwServer = leshanServer; + Registration registration = lwM2mClientContext.getRegistration(registrationId); this.readResourceValueObserve(lwServer, registration, postObserveAnalyzer.getPathPostParametersAdd(), GET_TYPE_OPER_OBSERVE); // 5.3 del // sent Request cancel observe to Client @@ -914,11 +926,11 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { LwM2mPath pathIds = new LwM2mPath(target); if (pathIds.isResource()) { if (GET_TYPE_OPER_READ.equals(typeOper)) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - ContentFormat.TLV.getName(), null, null, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + ContentFormat.TLV.getName(), null, null, this.context.getLwM2MTransportConfigServer().getTimeout()); } else if (GET_TYPE_OPER_OBSERVE.equals(typeOper)) { - lwM2MTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, - null, null, null, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(lwServer, registration, target, typeOper, + null, null, null, this.context.getLwM2MTransportConfigServer().getTimeout()); } } }); @@ -935,7 +947,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { } private void cancelObserveIsValue(LeshanServer lwServer, Registration registration, Set paramAnallyzer) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); paramAnallyzer.forEach(p -> { if (this.returnResourceValueFromLwM2MClient(lwM2MClient, new LwM2mPath(p)) != null) { this.setCancelObservationRecourse(lwServer, registration, p); @@ -944,10 +956,10 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { ); } - private void putDelayedUpdateResourcesClient(LwM2MClient lwM2MClient, Object valueOld, Object valueNew, String path) { + private void putDelayedUpdateResourcesClient(LwM2mClient lwM2MClient, Object valueOld, Object valueNew, String path) { if (valueNew != null && (valueOld == null || !valueNew.toString().equals(valueOld.toString()))) { - lwM2MTransportRequest.sendAllRequest(lwM2MClient.getLwServer(), lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, - ContentFormat.TLV.getName(), null, valueNew, this.context.getCtxServer().getTimeout()); + lwM2mTransportRequest.sendAllRequest(leshanServer, lwM2MClient.getRegistration(), path, POST_TYPE_OPER_WRITE_REPLACE, + ContentFormat.TLV.getName(), null, valueNew, this.context.getLwM2MTransportConfigServer().getTimeout()); } else { log.error("05 delayError"); } @@ -982,7 +994,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @return - */ private String getPathAttributeUpdateProfile(TransportProtos.SessionInfoProto sessionInfo, String name) { - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); + LwM2mClientProfile profile = lwM2mClientContext.getProfile(new UUID(sessionInfo.getDeviceProfileIdMSB(), sessionInfo.getDeviceProfileIdLSB())); return profile.getPostKeyNameProfile().getAsJsonObject().entrySet().stream() .filter(e -> e.getValue().getAsString().equals(name)).findFirst().map(Map.Entry::getKey) .orElse(""); @@ -1002,7 +1014,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { try { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClient(sessionInfo); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2MClient(sessionInfo); attributesResponse.getSharedAttributeListList().forEach(attr -> { String path = this.getPathAttributeUpdate(sessionInfo, attr.getKv().getKey()); // #1.1 @@ -1027,18 +1039,18 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param lwM2MClient - * @return */ - private SessionInfoProto getNewSessionInfoProto(LwM2MClient lwM2MClient) { + private SessionInfoProto getNewSessionInfoProto(LwM2mClient lwM2MClient) { if (lwM2MClient != null) { TransportProtos.ValidateDeviceCredentialsResponseMsg msg = lwM2MClient.getCredentialsResponse(); if (msg == null || msg.getDeviceInfo() == null) { - log.error("[{}] [{}]", lwM2MClient.getEndPoint(), CLIENT_NOT_AUTHORIZED); + log.error("[{}] [{}]", lwM2MClient.getEndpoint(), CLIENT_NOT_AUTHORIZED); this.closeClientSession(lwM2MClient.getRegistration()); return null; } else { return SessionInfoProto.newBuilder() .setNodeId(this.context.getNodeId()) - .setSessionIdMSB(lwM2MClient.getSessionUuid().getMostSignificantBits()) - .setSessionIdLSB(lwM2MClient.getSessionUuid().getLeastSignificantBits()) + .setSessionIdMSB(lwM2MClient.getSessionId().getMostSignificantBits()) + .setSessionIdLSB(lwM2MClient.getSessionId().getLeastSignificantBits()) .setDeviceIdMSB(msg.getDeviceInfo().getDeviceIdMSB()) .setDeviceIdLSB(msg.getDeviceInfo().getDeviceIdLSB()) .setTenantIdMSB(msg.getDeviceInfo().getTenantIdMSB()) @@ -1053,13 +1065,12 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { return null; } - /** * @param registration - Registration LwM2M Client * @return - sessionInfo after access connect client */ private SessionInfoProto getValidateSessionInfo(Registration registration) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(registration, null); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); return getNewSessionInfoProto(lwM2MClient); } @@ -1068,7 +1079,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @return - */ private SessionInfoProto getValidateSessionInfo(String registrationId) { - LwM2MClient lwM2MClient = lwM2mInMemorySecurityStore.getLwM2MClientWithReg(null, registrationId); + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId); return getNewSessionInfoProto(lwM2MClient); } @@ -1079,12 +1090,12 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { */ private void checkInactivity(SessionInfoProto sessionInfo) { if (transportService.reportActivity(sessionInfo) == null) { - transportService.registerAsyncSession(sessionInfo, new LwM2MSessionMsgListener(this, sessionInfo)); + transportService.registerAsyncSession(sessionInfo, new LwM2mSessionMsgListener(this, sessionInfo)); } } private void checkInactivityAndReportActivity() { - lwM2mInMemorySecurityStore.getSessions().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); + lwM2mClientContext.getLwM2mClients().forEach((key, value) -> this.checkInactivity(this.getValidateSessionInfo(key))); } /** @@ -1095,7 +1106,7 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * * @param lwM2MClient - LwM2M Client */ - public void putDelayedUpdateResourcesThingsboard(LwM2MClient lwM2MClient) { + public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); if (sessionInfo != null) { //#1.1 + #1.2 @@ -1119,15 +1130,16 @@ public class LwM2MTransportServiceImpl implements LwM2MTransportService { * @param lwM2MClient - * @return ArrayList keyNames from profile attr resources shared!!!! && IsWritable */ - private List getNamesAttrFromProfileIsWritable(LwM2MClient lwM2MClient) { - LwM2MClientProfile profile = lwM2mInMemorySecurityStore.getProfile(lwM2MClient.getProfileUuid()); + private List getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) { + LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); Set attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), Set.class); - ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), new TypeToken>(){}.getType()); + ConcurrentMap keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), new TypeToken>() { + }.getType()); ConcurrentMap keyNamesIsWritable = keyNamesMap.entrySet() .stream() - .filter(e -> (attrSet.contains(e.getKey()) && context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && - context.getCtxServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable())) + .filter(e -> (attrSet.contains(e.getKey()) && context.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())) != null && + context.getLwM2MTransportConfigServer().getResourceModel(lwM2MClient.getRegistration(), new LwM2mPath(e.getKey())).operations.isWritable())) .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); Set namesIsWritable = ConcurrentHashMap.newKeySet(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java similarity index 72% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index f330968e97..1c9afaab6d 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -20,13 +20,11 @@ import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; -import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.SecurityInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceCredentialsResponseMsg; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportServiceImpl; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportServiceImpl; import java.util.List; import java.util.Map; @@ -36,42 +34,36 @@ import java.util.concurrent.CopyOnWriteArrayList; @Slf4j @Data -public class LwM2MClient implements Cloneable { +public class LwM2mClient implements Cloneable { private String deviceName; private String deviceProfileName; - private String endPoint; + private String endpoint; private String identity; private SecurityInfo securityInfo; - private UUID deviceUuid; - private UUID sessionUuid; - private UUID profileUuid; - private LeshanServer lwServer; - private LwM2MTransportServiceImpl lwM2MTransportServiceImpl; + private UUID deviceId; + private UUID sessionId; + private UUID profileId; private Registration registration; private ValidateDeviceCredentialsResponseMsg credentialsResponse; - private final Map attributes; private final Map resources; private final Map delayedRequests; private final List pendingRequests; private boolean init; - private final LwM2mValueConverterImpl converter; public Object clone() throws CloneNotSupportedException { return super.clone(); } - public LwM2MClient(String endPoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileUuid, UUID sessionUuid) { - this.endPoint = endPoint; + public LwM2mClient(String endpoint, String identity, SecurityInfo securityInfo, ValidateDeviceCredentialsResponseMsg credentialsResponse, UUID profileId, UUID sessionId) { + this.endpoint = endpoint; this.identity = identity; this.securityInfo = securityInfo; this.credentialsResponse = credentialsResponse; - this.attributes = new ConcurrentHashMap<>(); this.delayedRequests = new ConcurrentHashMap<>(); this.pendingRequests = new CopyOnWriteArrayList<>(); this.resources = new ConcurrentHashMap<>(); - this.profileUuid = profileUuid; - this.sessionUuid = sessionUuid; - this.converter = LwM2mValueConverterImpl.getInstance(); + this.profileId = profileId; + this.sessionId = sessionId; this.init = false; } @@ -83,7 +75,7 @@ public class LwM2MClient implements Cloneable { } } - public void initValue(LwM2MTransportServiceImpl lwM2MTransportService, String path) { + public void initValue(LwM2mTransportServiceImpl lwM2MTransportService, String path) { if (path != null) { this.pendingRequests.remove(path); } @@ -93,8 +85,8 @@ public class LwM2MClient implements Cloneable { } } - public LwM2MClient copy() { - return new LwM2MClient(this.endPoint, this.identity, this.securityInfo, this.credentialsResponse, this.profileUuid, this.sessionUuid); + public LwM2mClient copy() { + return new LwM2mClient(this.endpoint, this.identity, this.securityInfo, this.credentialsResponse, this.profileId, this.sessionId); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java new file mode 100644 index 0000000000..2aea3fdc3e --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContext.java @@ -0,0 +1,54 @@ +/** + * 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.client; + +import org.eclipse.leshan.server.registration.Registration; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.Map; +import java.util.UUID; + +public interface LwM2mClientContext { + + void delRemoveSessionAndListener(String registrationId); + + LwM2mClient getLwM2MClient(String endPoint, String identity); + + LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo); + + LwM2mClient getLwM2mClient(UUID sessionId); + + LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId); + + LwM2mClient updateInSessionsLwM2MClient(Registration registration); + + LwM2mClient addLwM2mClientToSession(String identity); + + Registration getRegistration(String registrationId); + + Map getLwM2mClients(); + + Map getProfiles(); + + LwM2mClientProfile getProfile(UUID profileUuId); + + LwM2mClientProfile getProfile(Registration registration); + + Map setProfiles(Map profiles); + + boolean addUpdateProfileParameters(DeviceProfile deviceProfile); +} 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 new file mode 100644 index 0000000000..b965c99611 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -0,0 +1,171 @@ +/** + * 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.client; + +import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.DeviceProfile; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; +import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; +import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; +import org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler; +import org.thingsboard.server.transport.lwm2m.utils.TypeServer; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; + +@Service +@TbLwM2mTransportComponent +public class LwM2mClientContextImpl implements LwM2mClientContext { + private static final boolean INFOS_ARE_COMPROMISED = false; + + private final Map lwM2mClients = new ConcurrentHashMap<>(); + private Map profiles = new ConcurrentHashMap<>(); + + private final LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator; + + private final EditableSecurityStore securityStore; + + public LwM2mClientContextImpl(LwM2mCredentialsSecurityInfoValidator lwM2MCredentialsSecurityInfoValidator, EditableSecurityStore securityStore) { + this.lwM2MCredentialsSecurityInfoValidator = lwM2MCredentialsSecurityInfoValidator; + this.securityStore = securityStore; + } + + public void delRemoveSessionAndListener(String registrationId) { + LwM2mClient lwM2MClient = lwM2mClients.get(registrationId); + if (lwM2MClient != null) { + securityStore.remove(lwM2MClient.getEndpoint(), INFOS_ARE_COMPROMISED); + lwM2mClients.remove(registrationId); + } + } + + @Override + public LwM2mClient getLwM2MClient(String endPoint, String identity) { + Map.Entry modelClients = endPoint != null ? + this.lwM2mClients.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).findAny().orElse(null) : + this.lwM2mClients.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null); + return modelClients != null ? modelClients.getValue() : null; + } + + @Override + public LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) { + return getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); + } + + @Override + public LwM2mClient getLwM2mClient(UUID sessionId) { + return lwM2mClients.values().stream().filter(c -> c.getSessionId().equals(sessionId)).findAny().get(); + } + + @Override + public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) { + LwM2mClient client = registrationId != null ? + this.lwM2mClients.get(registrationId) : + this.lwM2mClients.containsKey(registration.getId()) ? + this.lwM2mClients.get(registration.getId()) : + this.lwM2mClients.get(registration.getEndpoint()); + return client != null ? client : updateInSessionsLwM2MClient(registration); + } + + @Override + public LwM2mClient updateInSessionsLwM2MClient(Registration registration) { + if (this.lwM2mClients.get(registration.getEndpoint()) == null) { + addLwM2mClientToSession(registration.getEndpoint()); + } + LwM2mClient lwM2MClient = lwM2mClients.get(registration.getEndpoint()); + lwM2MClient.setRegistration(registration); + this.lwM2mClients.remove(registration.getEndpoint()); + this.lwM2mClients.put(registration.getId(), lwM2MClient); + return lwM2MClient; + } + + public Registration getRegistration(String registrationId) { + return this.lwM2mClients.get(registrationId).getRegistration(); + } + + /** + * Add new LwM2MClient to session + * @param identity- + * @return SecurityInfo. If error - SecurityInfoError + * and log: + * - FORBIDDEN - if there is no authorization + * - profileUuid - if the device does not have a profile + * - device - if the thingsboard does not have a device with a name equal to the identity + */ + @Override + public LwM2mClient addLwM2mClientToSession(String identity) { + ReadResultSecurityStore store = lwM2MCredentialsSecurityInfoValidator.createAndValidateCredentialsSecurityInfo(identity, TypeServer.CLIENT); + if (store.getSecurityMode() < LwM2MSecurityMode.DEFAULT_MODE.code) { + UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; + LwM2mClient client; + if (store.getSecurityInfo() != null && profileUuid != null) { + String endpoint = store.getSecurityInfo().getEndpoint(); + client = new LwM2mClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid, UUID.randomUUID()); + lwM2mClients.put(endpoint, client); + } else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) { + client = new LwM2mClient(identity, null, null, store.getMsg(), profileUuid, UUID.randomUUID()); + lwM2mClients.put(identity, client); + } else { + throw new RuntimeException(String.format("Registration failed: FORBIDDEN/profileUuid/device %s , endpointId: %s [PSK]", profileUuid, identity)); + } + return client; + } else { + throw new RuntimeException(String.format("Registration failed: FORBIDDEN, endpointId: %s", identity)); + } + } + + @Override + public Map getLwM2mClients() { + return lwM2mClients; + } + + @Override + public Map getProfiles() { + return profiles; + } + + @Override + public LwM2mClientProfile getProfile(UUID profileId) { + return profiles.get(profileId); + } + + @Override + public LwM2mClientProfile getProfile(Registration registration) { + return this.getProfiles().get(getLwM2mClientWithReg(registration, null).getProfileId()); + } + + @Override + public Map setProfiles(Map profiles) { + return this.profiles = profiles; + } + + @Override + public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) { + LwM2mClientProfile lwM2MClientProfile = LwM2mTransportHandler.getLwM2MClientProfileFromThingsboard(deviceProfile); + if (lwM2MClientProfile != null) { + profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); + return true; + } + 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 similarity index 97% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2MClientProfile.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientProfile.java index 77f7a67646..6f28d54d67 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 @@ -20,7 +20,7 @@ import com.google.gson.JsonObject; import lombok.Data; @Data -public class LwM2MClientProfile { +public class LwM2mClientProfile { /** * {"clientLwM2mSettings": { * clientUpdateValueAfterConnect: false; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/LwM2mInMemorySecurityStore.java similarity index 73% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/LwM2mInMemorySecurityStore.java index 06a37a3290..fc66a5fed0 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/secure/LwM2mInMemorySecurityStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/LwM2mInMemorySecurityStore.java @@ -13,30 +13,26 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.lwm2m.server.secure; +package org.thingsboard.server.transport.lwm2m.server.store; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.core.util.Hex; -import org.eclipse.leshan.server.californium.LeshanServer; import org.eclipse.leshan.server.registration.Registration; import org.eclipse.leshan.server.security.InMemorySecurityStore; import org.eclipse.leshan.server.security.SecurityInfo; import org.eclipse.leshan.server.security.SecurityStoreListener; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; -import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; import org.thingsboard.server.transport.lwm2m.secure.LwM2mCredentialsSecurityInfoValidator; import org.thingsboard.server.transport.lwm2m.secure.ReadResultSecurityStore; -import org.thingsboard.server.transport.lwm2m.server.LwM2MTransportHandler; -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.LwM2mTransportHandler; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; import org.thingsboard.server.transport.lwm2m.utils.TypeServer; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; @@ -49,8 +45,9 @@ import java.util.stream.Collectors; import static org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode.NO_SEC; @Slf4j -@Service("LwM2mInMemorySecurityStore") -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' )|| ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") +//@Service("LwM2mInMemorySecurityStore") +//@TbLwM2mTransportComponent +@Deprecated public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { private static final boolean INFOS_ARE_COMPROMISED = false; @@ -58,8 +55,8 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private final Lock readLock = readWriteLock.readLock(); private final Lock writeLock = readWriteLock.writeLock(); - private final Map sessions = new ConcurrentHashMap<>(); - private Map profiles = new ConcurrentHashMap<>(); + private final Map sessions = new ConcurrentHashMap<>(); + private Map profiles = new ConcurrentHashMap<>(); private SecurityStoreListener listener; @Autowired @@ -102,7 +99,7 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { public Collection getAll() { readLock.lock(); try { - return Collections.unmodifiableCollection(this.sessions.values().stream().map(LwM2MClient::getSecurityInfo).collect(Collectors.toList())); + return this.sessions.values().stream().map(LwM2mClient::getSecurityInfo).collect(Collectors.toUnmodifiableList()); } finally { readLock.unlock(); } @@ -115,7 +112,7 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { public void delRemoveSessionAndListener(String registrationId) { writeLock.lock(); try { - LwM2MClient lwM2MClient = (sessions.get(registrationId) != null) ? sessions.get(registrationId) : null; + LwM2mClient lwM2MClient = (sessions.get(registrationId) != null) ? sessions.get(registrationId) : null; if (lwM2MClient != null) { if (listener != null) { listener.securityInfoRemoved(INFOS_ARE_COMPROMISED, lwM2MClient.getSecurityInfo()); @@ -132,14 +129,14 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { this.listener = listener; } - public LwM2MClient getLwM2MClient(String endPoint, String identity) { - Map.Entry modelClients = (endPoint != null) ? - this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndPoint())).findAny().orElse(null) : + public LwM2mClient getLwM2MClient(String endPoint, String identity) { + Map.Entry modelClients = endPoint != null ? + this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).findAny().orElse(null) : this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).findAny().orElse(null); - return (modelClients != null) ? modelClients.getValue() : null; + return modelClients != null ? modelClients.getValue() : null; } - public LwM2MClient getLwM2MClientWithReg(Registration registration, String registrationId) { + public LwM2mClient getLwM2MClientWithReg(Registration registration, String registrationId) { return registrationId != null ? this.sessions.get(registrationId) : this.sessions.containsKey(registration.getId()) ? @@ -147,28 +144,25 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { this.sessions.get(registration.getEndpoint()); } - public LwM2MClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) { + public LwM2mClient getLwM2MClient(TransportProtos.SessionInfoProto sessionInfo) { return this.getSession(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())).entrySet().iterator().next().getValue(); - } /** * Update in sessions (LwM2MClient for key registration_Id) after starting registration LwM2MClient in LwM2MTransportServiceImpl * Remove from sessions LwM2MClient with key registration_Endpoint - * @param lwServer - * @param registration - * @return LwM2MClient after adding it to session */ - public LwM2MClient updateInSessionsLwM2MClient(LeshanServer lwServer, Registration registration) { + public LwM2mClient updateInSessionsLwM2MClient(Registration registration) { writeLock.lock(); try { if (this.sessions.get(registration.getEndpoint()) == null) { this.addLwM2MClientToSession(registration.getEndpoint()); } - LwM2MClient lwM2MClient = this.sessions.get(registration.getEndpoint()); - lwM2MClient.setLwServer(lwServer); + LwM2mClient lwM2MClient = this.sessions.get(registration.getEndpoint()); lwM2MClient.setRegistration(registration); - lwM2MClient.getAttributes().putAll(registration.getAdditionalRegistrationAttributes()); +// lwM2MClient.getAttributes().putAll(registration.getAdditionalRegistrationAttributes()); this.sessions.remove(registration.getEndpoint()); this.sessions.put(registration.getId(), lwM2MClient); return lwM2MClient; @@ -179,7 +173,7 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { private String getRegistrationId(String endPoint, String identity) { List registrationIds = (endPoint != null) ? - this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndPoint())).map(Map.Entry::getKey).collect(Collectors.toList()) : + this.sessions.entrySet().stream().filter(model -> endPoint.equals(model.getValue().getEndpoint())).map(Map.Entry::getKey).collect(Collectors.toList()) : this.sessions.entrySet().stream().filter(model -> identity.equals(model.getValue().getIdentity())).map(Map.Entry::getKey).collect(Collectors.toList()); return (registrationIds != null && registrationIds.size() > 0) ? registrationIds.get(0) : null; } @@ -203,49 +197,51 @@ public class LwM2mInMemorySecurityStore extends InMemorySecurityStore { UUID profileUuid = (store.getDeviceProfile() != null && addUpdateProfileParameters(store.getDeviceProfile())) ? store.getDeviceProfile().getUuidId() : null; if (store.getSecurityInfo() != null && profileUuid != null) { String endpoint = store.getSecurityInfo().getEndpoint(); - sessions.put(endpoint, new LwM2MClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid, UUID.randomUUID())); + sessions.put(endpoint, new LwM2mClient(endpoint, store.getSecurityInfo().getIdentity(), store.getSecurityInfo(), store.getMsg(), profileUuid, UUID.randomUUID())); } else if (store.getSecurityMode() == NO_SEC.code && profileUuid != null) { - sessions.put(identity, new LwM2MClient(identity, null, null, store.getMsg(), profileUuid, UUID.randomUUID())); + sessions.put(identity, new LwM2mClient(identity, null, null, store.getMsg(), profileUuid, UUID.randomUUID())); } else { - log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); - /** - * Return Error securityInfo - */ - byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray()); - SecurityInfo infoError = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey); - return infoError; - } + log.error("Registration failed: FORBIDDEN/profileUuid/device [{}] , endpointId: [{}]", profileUuid, identity); + /** + * Return Error securityInfo + */ + byte[] preSharedKey = Hex.decodeHex("0A0B".toCharArray()); + SecurityInfo infoError = SecurityInfo.newPreSharedKeyInfo("error", "error_identity", preSharedKey); + return infoError; } - return store.getSecurityInfo(); + } + return store.getSecurityInfo(); } - public Map getSession(UUID sessionUuId) { - return this.sessions.entrySet().stream().filter(e -> e.getValue().getSessionUuid().equals(sessionUuId)).collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + public Map getSession(UUID sessionUuId) { + return this.sessions.entrySet().stream() + .filter(e -> e.getValue().getSessionId().equals(sessionUuId)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } - public Map getSessions() { + public Map getSessions() { return this.sessions; } - public Map getProfiles() { + public Map getProfiles() { return this.profiles; } - public LwM2MClientProfile getProfile(UUID profileUuId) { + public LwM2mClientProfile getProfile(UUID profileUuId) { return this.profiles.get(profileUuId); } - public LwM2MClientProfile getProfile(String registrationId) { - UUID profileUUid = this.getSessions().get(registrationId).getProfileUuid(); + public LwM2mClientProfile getProfile(String registrationId) { + UUID profileUUid = this.getSessions().get(registrationId).getProfileId(); return this.getProfiles().get(profileUUid); } - public Map setProfiles(Map profiles) { + public Map setProfiles(Map profiles) { return this.profiles = profiles; } public boolean addUpdateProfileParameters(DeviceProfile deviceProfile) { - LwM2MClientProfile lwM2MClientProfile = LwM2MTransportHandler.getLwM2MClientProfileFromThingsboard(deviceProfile); + LwM2mClientProfile lwM2MClientProfile = LwM2mTransportHandler.getLwM2MClientProfileFromThingsboard(deviceProfile); if (lwM2MClientProfile != null) { profiles.put(deviceProfile.getUuidId(), lwM2MClientProfile); return true; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java new file mode 100644 index 0000000000..6d24ac5ca0 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -0,0 +1,785 @@ +/** + * 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.store; + +import org.eclipse.californium.core.coap.Token; +import org.eclipse.californium.core.observe.ObservationStoreException; +import org.eclipse.californium.elements.EndpointContext; +import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.util.NamedThreadFactory; +import org.eclipse.leshan.core.util.Validate; +import org.eclipse.leshan.server.Destroyable; +import org.eclipse.leshan.server.Startable; +import org.eclipse.leshan.server.Stoppable; +import org.eclipse.leshan.server.californium.observation.ObserveUtil; +import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; +import org.eclipse.leshan.server.redis.JedisLock; +import org.eclipse.leshan.server.redis.RedisRegistrationStore; +import org.eclipse.leshan.server.redis.SingleInstanceJedisLock; +import org.eclipse.leshan.server.redis.serialization.ObservationSerDes; +import org.eclipse.leshan.server.redis.serialization.RegistrationSerDes; +import org.eclipse.leshan.server.registration.Deregistration; +import org.eclipse.leshan.server.registration.ExpirationListener; +import org.eclipse.leshan.server.registration.Registration; +import org.eclipse.leshan.server.registration.RegistrationUpdate; +import org.eclipse.leshan.server.registration.UpdatedRegistration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.ScanResult; +import redis.clients.jedis.Transaction; + +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import static java.nio.charset.StandardCharsets.UTF_8; + +public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationStore, Startable, Stoppable, Destroyable { + /** Default time in seconds between 2 cleaning tasks (used to remove expired registration). */ + public static final long DEFAULT_CLEAN_PERIOD = 60; + public static final int DEFAULT_CLEAN_LIMIT = 500; + /** Defaut Extra time for registration lifetime in seconds */ + public static final long DEFAULT_GRACE_PERIOD = 0; + + private static final Logger LOG = LoggerFactory.getLogger(RedisRegistrationStore.class); + + // Redis key prefixes + private static final String REG_EP = "REG:EP:"; // (Endpoint => Registration) + private static final String REG_EP_REGID_IDX = "EP:REGID:"; // secondary index key (Registration ID => Endpoint) + private static final String REG_EP_ADDR_IDX = "EP:ADDR:"; // secondary index key (Socket Address => Endpoint) + private static final String LOCK_EP = "LOCK:EP:"; + private static final byte[] OBS_TKN = "OBS:TKN:".getBytes(UTF_8); + private static final String OBS_TKNS_REGID_IDX = "TKNS:REGID:"; // secondary index (token list by registration) + private static final byte[] EXP_EP = "EXP:EP".getBytes(UTF_8); // a sorted set used for registration expiration + // (expiration date, Endpoint) + + private final RedisConnectionFactory connectionFactory; + + // Listener use to notify when a registration expires + private ExpirationListener expirationListener; + + private final ScheduledExecutorService schedExecutor; + private ScheduledFuture cleanerTask; + private boolean started = false; + + private final long cleanPeriod; // in seconds + private final int cleanLimit; // maximum number to clean in a clean period + private final long gracePeriod; // in seconds + + private final JedisLock lock; + + public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory) { + this(connectionFactory, DEFAULT_CLEAN_PERIOD, DEFAULT_GRACE_PERIOD, DEFAULT_CLEAN_LIMIT); // default clean period 60s + } + + public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, long cleanPeriodInSec, long lifetimeGracePeriodInSec, int cleanLimit) { + this(connectionFactory, Executors.newScheduledThreadPool(1, + new NamedThreadFactory(String.format("RedisRegistrationStore Cleaner (%ds)", cleanPeriodInSec))), + cleanPeriodInSec, lifetimeGracePeriodInSec, cleanLimit); + } + + public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, ScheduledExecutorService schedExecutor, long cleanPeriodInSec, + long lifetimeGracePeriodInSec, int cleanLimit) { + this(connectionFactory, schedExecutor, cleanPeriodInSec, lifetimeGracePeriodInSec, cleanLimit, new SingleInstanceJedisLock()); + } + + /** + * @since 1.1 + */ + public TbLwM2mRedisRegistrationStore(RedisConnectionFactory connectionFactory, ScheduledExecutorService schedExecutor, long cleanPeriodInSec, + long lifetimeGracePeriodInSec, int cleanLimit, JedisLock redisLock) { + this.connectionFactory = connectionFactory; + this.schedExecutor = schedExecutor; + this.cleanPeriod = cleanPeriodInSec; + this.cleanLimit = cleanLimit; + this.gracePeriod = lifetimeGracePeriodInSec; + this.lock = redisLock; + } + + /* *************** Redis Key utility function **************** */ + + private byte[] toKey(byte[] prefix, byte[] key) { + byte[] result = new byte[prefix.length + key.length]; + System.arraycopy(prefix, 0, result, 0, prefix.length); + System.arraycopy(key, 0, result, prefix.length, key.length); + return result; + } + + private byte[] toKey(String prefix, String registrationID) { + return (prefix + registrationID).getBytes(); + } + + private byte[] toLockKey(String endpoint) { + return toKey(LOCK_EP, endpoint); + } + + private byte[] toLockKey(byte[] endpoint) { + return toKey(LOCK_EP.getBytes(UTF_8), endpoint); + } + + /* *************** Leshan Registration API **************** */ + + @Override + public Deregistration addRegistration(Registration registration) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] lockValue = null; + byte[] lockKey = toLockKey(registration.getEndpoint()); + + try { + lockValue = lock.acquire(j, lockKey); + + // add registration + byte[] k = toEndpointKey(registration.getEndpoint()); + byte[] old = j.getSet(k, serializeReg(registration)); + + // add registration: secondary indexes + byte[] regid_idx = toRegIdKey(registration.getId()); + j.set(regid_idx, registration.getEndpoint().getBytes(UTF_8)); + byte[] addr_idx = toRegAddrKey(registration.getSocketAddress()); + j.set(addr_idx, registration.getEndpoint().getBytes(UTF_8)); + + // Add or update expiration + addOrUpdateExpiration(j, registration); + + if (old != null) { + Registration oldRegistration = deserializeReg(old); + // remove old secondary index + if (!registration.getId().equals(oldRegistration.getId())) + j.del(toRegIdKey(oldRegistration.getId())); + if (!oldRegistration.getSocketAddress().equals(registration.getSocketAddress())) { + removeAddrIndex(j, oldRegistration); + } + // remove old observation + Collection obsRemoved = unsafeRemoveAllObservations(j, oldRegistration.getId()); + + return new Deregistration(oldRegistration, obsRemoved); + } + + return null; + } finally { + lock.release(j, lockKey, lockValue); + } + } + } + + @Override + public UpdatedRegistration updateRegistration(RegistrationUpdate update) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + + // Fetch the registration ep by registration ID index + byte[] ep = j.get(toRegIdKey(update.getRegistrationId())); + if (ep == null) { + return null; + } + + byte[] lockValue = null; + byte[] lockKey = toLockKey(ep); + try { + lockValue = lock.acquire(j, lockKey); + + // Fetch the registration + byte[] data = j.get(toEndpointKey(ep)); + if (data == null) { + return null; + } + + Registration r = deserializeReg(data); + + Registration updatedRegistration = update.update(r); + + // Store the new registration + j.set(toEndpointKey(updatedRegistration.getEndpoint()), serializeReg(updatedRegistration)); + + // Add or update expiration + addOrUpdateExpiration(j, updatedRegistration); + + // Update secondary index : + // If registration is already associated to this address we don't care as we only want to keep the most + // recent binding. + byte[] addr_idx = toRegAddrKey(updatedRegistration.getSocketAddress()); + j.set(addr_idx, updatedRegistration.getEndpoint().getBytes(UTF_8)); + if (!r.getSocketAddress().equals(updatedRegistration.getSocketAddress())) { + removeAddrIndex(j, r); + } + + return new UpdatedRegistration(r, updatedRegistration); + + } finally { + lock.release(j, lockKey, lockValue); + } + } + } + + @Override + public Registration getRegistration(String registrationId) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + return getRegistration(j, registrationId); + } + } + + @Override + public Registration getRegistrationByEndpoint(String endpoint) { + Validate.notNull(endpoint); + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] data = j.get(toEndpointKey(endpoint)); + if (data == null) { + return null; + } + return deserializeReg(data); + } + } + + @Override + public Registration getRegistrationByAdress(InetSocketAddress address) { + Validate.notNull(address); + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] ep = j.get(toRegAddrKey(address)); + if (ep == null) { + return null; + } + byte[] data = j.get(toEndpointKey(ep)); + if (data == null) { + return null; + } + return deserializeReg(data); + } + } + + @Override + public Iterator getAllRegistrations() { + return new TbLwM2mRedisRegistrationStore.RedisIterator(connectionFactory, new ScanParams().match(REG_EP + "*").count(100)); + } + + protected class RedisIterator implements Iterator { + + private RedisConnectionFactory connectionFactory; + private ScanParams scanParams; + + private String cursor; + private List scanResult; + + public RedisIterator(RedisConnectionFactory connectionFactory, ScanParams scanParams) { + this.connectionFactory = connectionFactory; + this.scanParams = scanParams; + // init scan result + scanNext("0"); + } + + private void scanNext(String cursor) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + do { + ScanResult sr = j.scan(cursor.getBytes(), scanParams); + + this.scanResult = new ArrayList<>(); + if (sr.getResult() != null && !sr.getResult().isEmpty()) { + for (byte[] value : j.mget(sr.getResult().toArray(new byte[][]{}))) { + this.scanResult.add(deserializeReg(value)); + } + } + + cursor = sr.getCursor(); + } while (!"0".equals(cursor) && scanResult.isEmpty()); + + this.cursor = cursor; + } + } + + @Override + public boolean hasNext() { + if (!scanResult.isEmpty()) { + return true; + } + if ("0".equals(cursor)) { + // no more elements to scan + return false; + } + + // read more elements + scanNext(cursor); + return !scanResult.isEmpty(); + } + + @Override + public Registration next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return scanResult.remove(0); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + @Override + public Deregistration removeRegistration(String registrationId) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + return removeRegistration(j, registrationId, false); + } + } + + private Deregistration removeRegistration(Jedis j, String registrationId, boolean removeOnlyIfNotAlive) { + // fetch the client ep by registration ID index + byte[] ep = j.get(toRegIdKey(registrationId)); + if (ep == null) { + return null; + } + + byte[] lockValue = null; + byte[] lockKey = toLockKey(ep); + try { + lockValue = lock.acquire(j, lockKey); + + // fetch the client + byte[] data = j.get(toEndpointKey(ep)); + if (data == null) { + return null; + } + Registration r = deserializeReg(data); + + if (!removeOnlyIfNotAlive || !r.isAlive(gracePeriod)) { + long nbRemoved = j.del(toRegIdKey(r.getId())); + if (nbRemoved > 0) { + j.del(toEndpointKey(r.getEndpoint())); + Collection obsRemoved = unsafeRemoveAllObservations(j, r.getId()); + removeAddrIndex(j, r); + removeExpiration(j, r); + return new Deregistration(r, obsRemoved); + } + } + return null; + } finally { + lock.release(j, lockKey, lockValue); + } + } + + private void removeAddrIndex(Jedis j, Registration registration) { + // Watch the key to remove. + byte[] regAddrKey = toRegAddrKey(registration.getSocketAddress()); + j.watch(regAddrKey); + + byte[] epFromAddr = j.get(regAddrKey); + // Delete the key if needed. + if (Arrays.equals(epFromAddr, registration.getEndpoint().getBytes(UTF_8))) { + // Try to delete the key + Transaction transaction = j.multi(); + transaction.del(regAddrKey); + transaction.exec(); + // if transaction failed this is not an issue as the socket address is probably reused and we don't neeed to + // delete it anymore. + } else { + // the key must not be deleted. + j.unwatch(); + } + } + + private void addOrUpdateExpiration(Jedis j, Registration registration) { + j.zadd(EXP_EP, registration.getExpirationTimeStamp(gracePeriod), registration.getEndpoint().getBytes(UTF_8)); + } + + private void removeExpiration(Jedis j, Registration registration) { + j.zrem(EXP_EP, registration.getEndpoint().getBytes(UTF_8)); + } + + private byte[] toRegIdKey(String registrationId) { + return toKey(REG_EP_REGID_IDX, registrationId); + } + + private byte[] toRegAddrKey(InetSocketAddress addr) { + return toKey(REG_EP_ADDR_IDX, addr.getAddress().toString() + ":" + addr.getPort()); + } + + private byte[] toEndpointKey(String endpoint) { + return toKey(REG_EP, endpoint); + } + + private byte[] toEndpointKey(byte[] endpoint) { + return toKey(REG_EP.getBytes(UTF_8), endpoint); + } + + private byte[] serializeReg(Registration registration) { + return RegistrationSerDes.bSerialize(registration); + } + + private Registration deserializeReg(byte[] data) { + return RegistrationSerDes.deserialize(data); + } + + /* *************** Leshan Observation API **************** */ + + /* + * The observation is not persisted here, it is done by the Californium layer (in the implementation of the + * org.eclipse.californium.core.observe.ObservationStore#add method) + */ + @Override + public Collection addObservation(String registrationId, Observation observation) { + + List removed = new ArrayList<>(); + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + + // fetch the client ep by registration ID index + byte[] ep = j.get(toRegIdKey(registrationId)); + if (ep == null) { + return null; + } + + byte[] lockValue = null; + byte[] lockKey = toLockKey(ep); + + try { + lockValue = lock.acquire(j, lockKey); + + // cancel existing observations for the same path and registration id. + for (Observation obs : getObservations(j, registrationId)) { + if (observation.getPath().equals(obs.getPath()) + && !Arrays.equals(observation.getId(), obs.getId())) { + removed.add(obs); + unsafeRemoveObservation(j, registrationId, obs.getId()); + } + } + + } finally { + lock.release(j, lockKey, lockValue); + } + } + return removed; + } + + @Override + public Observation removeObservation(String registrationId, byte[] observationId) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + + // fetch the client ep by registration ID index + byte[] ep = j.get(toRegIdKey(registrationId)); + if (ep == null) { + return null; + } + + // remove observation + byte[] lockValue = null; + byte[] lockKey = toLockKey(ep); + try { + lockValue = lock.acquire(j, lockKey); + + Observation observation = build(get(new Token(observationId))); + if (observation != null && registrationId.equals(observation.getRegistrationId())) { + unsafeRemoveObservation(j, registrationId, observationId); + return observation; + } + return null; + + } finally { + lock.release(j, lockKey, lockValue); + } + } + } + + @Override + public Observation getObservation(String registrationId, byte[] observationId) { + return build(get(new Token(observationId))); + } + + @Override + public Collection getObservations(String registrationId) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + return getObservations(j, registrationId); + } + } + + private Collection getObservations(Jedis j, String registrationId) { + Collection result = new ArrayList<>(); + for (byte[] token : j.lrange(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, -1)) { + byte[] obs = j.get(toKey(OBS_TKN, token)); + if (obs != null) { + result.add(build(deserializeObs(obs))); + } + } + return result; + } + + @Override + public Collection removeObservations(String registrationId) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + // check registration exists + Registration registration = getRegistration(j, registrationId); + if (registration == null) + return Collections.emptyList(); + + // get endpoint and create lock + String endpoint = registration.getEndpoint(); + byte[] lockValue = null; + byte[] lockKey = toKey(LOCK_EP, endpoint); + try { + lockValue = lock.acquire(j, lockKey); + + return unsafeRemoveAllObservations(j, registrationId); + } finally { + lock.release(j, lockKey, lockValue); + } + } + } + + /* *************** Californium ObservationStore API **************** */ + + @Override + public org.eclipse.californium.core.observe.Observation putIfAbsent(Token token, + org.eclipse.californium.core.observe.Observation obs) throws ObservationStoreException { + return add(token, obs, true); + } + + @Override + public org.eclipse.californium.core.observe.Observation put(Token token, + org.eclipse.californium.core.observe.Observation obs) throws ObservationStoreException { + return add(token, obs, false); + } + + private org.eclipse.californium.core.observe.Observation add(Token token, + org.eclipse.californium.core.observe.Observation obs, boolean ifAbsent) throws ObservationStoreException { + String endpoint = ObserveUtil.validateCoapObservation(obs); + org.eclipse.californium.core.observe.Observation previousObservation = null; + + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] lockValue = null; + byte[] lockKey = toKey(LOCK_EP, endpoint); + try { + lockValue = lock.acquire(j, lockKey); + + String registrationId = ObserveUtil.extractRegistrationId(obs); + if (!j.exists(toRegIdKey(registrationId))) + throw new ObservationStoreException("no registration for this Id"); + byte[] key = toKey(OBS_TKN, obs.getRequest().getToken().getBytes()); + byte[] serializeObs = serializeObs(obs); + byte[] previousValue = null; + if (ifAbsent) { + previousValue = j.get(key); + if (previousValue == null || previousValue.length == 0) { + j.set(key, serializeObs); + } else { + return deserializeObs(previousValue); + } + } else { + previousValue = j.getSet(key, serializeObs); + } + + // secondary index to get the list by registrationId + j.lpush(toKey(OBS_TKNS_REGID_IDX, registrationId), obs.getRequest().getToken().getBytes()); + + // log any collisions + if (previousValue != null && previousValue.length != 0) { + previousObservation = deserializeObs(previousValue); + LOG.warn( + "Token collision ? observation from request [{}] will be replaced by observation from request [{}] ", + previousObservation.getRequest(), obs.getRequest()); + } + } finally { + lock.release(j, lockKey, lockValue); + } + } + return previousObservation; + } + + @Override + public void remove(Token token) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] tokenKey = toKey(OBS_TKN, token.getBytes()); + + // fetch the observation by token + byte[] serializedObs = j.get(tokenKey); + if (serializedObs == null) + return; + + org.eclipse.californium.core.observe.Observation obs = deserializeObs(serializedObs); + String registrationId = ObserveUtil.extractRegistrationId(obs); + Registration registration = getRegistration(j, registrationId); + if (registration == null) { + LOG.warn("Unable to remove observation {}, registration {} does not exist anymore", obs.getRequest(), + registrationId); + return; + } + + String endpoint = registration.getEndpoint(); + byte[] lockValue = null; + byte[] lockKey = toKey(LOCK_EP, endpoint); + try { + lockValue = lock.acquire(j, lockKey); + + unsafeRemoveObservation(j, registrationId, token.getBytes()); + } finally { + lock.release(j, lockKey, lockValue); + } + } + + } + + @Override + public org.eclipse.californium.core.observe.Observation get(Token token) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] obs = j.get(toKey(OBS_TKN, token.getBytes())); + if (obs == null) { + return null; + } else { + return deserializeObs(obs); + } + } + } + + /* *************** Observation utility functions **************** */ + + private Registration getRegistration(Jedis j, String registrationId) { + byte[] ep = j.get(toRegIdKey(registrationId)); + if (ep == null) { + return null; + } + byte[] data = j.get(toEndpointKey(ep)); + if (data == null) { + return null; + } + + return deserializeReg(data); + } + + private void unsafeRemoveObservation(Jedis j, String registrationId, byte[] observationId) { + if (j.del(toKey(OBS_TKN, observationId)) > 0L) { + j.lrem(toKey(OBS_TKNS_REGID_IDX, registrationId), 0, observationId); + } + } + + private Collection unsafeRemoveAllObservations(Jedis j, String registrationId) { + Collection removed = new ArrayList<>(); + byte[] regIdKey = toKey(OBS_TKNS_REGID_IDX, registrationId); + + // fetch all observations by token + for (byte[] token : j.lrange(regIdKey, 0, -1)) { + byte[] obs = j.get(toKey(OBS_TKN, token)); + if (obs != null) { + removed.add(build(deserializeObs(obs))); + } + j.del(toKey(OBS_TKN, token)); + } + j.del(regIdKey); + + return removed; + } + + @Override + public void setContext(Token token, EndpointContext correlationContext) { + // In Leshan we always set context when we send the request, so this should not be needed to implement this. + } + + private byte[] serializeObs(org.eclipse.californium.core.observe.Observation obs) { + return ObservationSerDes.serialize(obs); + } + + private org.eclipse.californium.core.observe.Observation deserializeObs(byte[] data) { + return ObservationSerDes.deserialize(data); + } + + private Observation build(org.eclipse.californium.core.observe.Observation cfObs) { + if (cfObs == null) + return null; + + return ObserveUtil.createLwM2mObservation(cfObs.getRequest()); + } + + /* *************** Expiration handling **************** */ + + /** + * Start regular cleanup of dead registrations. + */ + @Override + public synchronized void start() { + if (!started) { + started = true; + cleanerTask = schedExecutor.scheduleAtFixedRate(new TbLwM2mRedisRegistrationStore.Cleaner(), cleanPeriod, cleanPeriod, TimeUnit.SECONDS); + } + } + + /** + * Stop the underlying cleanup of the registrations. + */ + @Override + public synchronized void stop() { + if (started) { + started = false; + if (cleanerTask != null) { + cleanerTask.cancel(false); + cleanerTask = null; + } + } + } + + /** + * Destroy "cleanup" scheduler. + */ + @Override + public synchronized void destroy() { + started = false; + schedExecutor.shutdownNow(); + try { + schedExecutor.awaitTermination(5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + LOG.warn("Destroying RedisRegistrationStore was interrupted.", e); + } + } + + private class Cleaner implements Runnable { + + @Override + public void run() { + + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + Set endpointsExpired = j.zrangeByScore(EXP_EP, Double.NEGATIVE_INFINITY, + System.currentTimeMillis(), 0, cleanLimit); + + for (byte[] endpoint : endpointsExpired) { + Registration r = deserializeReg(j.get(toEndpointKey(endpoint))); + if (!r.isAlive(gracePeriod)) { + Deregistration dereg = removeRegistration(j, r.getId(), true); + if (dereg != null) + expirationListener.registrationExpired(dereg.getRegistration(), dereg.getObservations()); + } + } + } catch (Exception e) { + LOG.warn("Unexpected Exception while registration cleaning", e); + } + } + } + + @Override + public void setExpirationListener(ExpirationListener listener) { + expirationListener = listener; + } + + @Override + public void setExecutor(ScheduledExecutorService executor) { + // TODO should we reuse californium executor ? + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java new file mode 100644 index 0000000000..7d05630ba4 --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisSecurityStore.java @@ -0,0 +1,148 @@ +/** + * 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.store; + +import org.eclipse.leshan.server.redis.serialization.SecurityInfoSerDes; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.eclipse.leshan.server.security.SecurityStoreListener; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.stereotype.Service; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.ScanParams; +import redis.clients.jedis.ScanResult; + +import java.util.Collection; +import java.util.LinkedList; + +@Service +public class TbLwM2mRedisSecurityStore implements EditableSecurityStore { + private static final String SEC_EP = "SEC#EP#"; + + private static final String PSKID_SEC = "PSKID#SEC"; + + private final RedisConnectionFactory connectionFactory; + private SecurityStoreListener listener; + + public TbLwM2mRedisSecurityStore(RedisConnectionFactory connectionFactory) { + this.connectionFactory = connectionFactory; + } + + @Override + public SecurityInfo getByEndpoint(String endpoint) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] data = j.get((SEC_EP + endpoint).getBytes()); + if (data == null) { + return null; + } else { + return deserialize(data); + } + } + } + + @Override + public SecurityInfo getByIdentity(String identity) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + String ep = j.hget(PSKID_SEC, identity); + if (ep == null) { + return null; + } else { + byte[] data = j.get((SEC_EP + ep).getBytes()); + if (data == null) { + return null; + } else { + return deserialize(data); + } + } + } + } + + @Override + public Collection getAll() { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + ScanParams params = new ScanParams().match(SEC_EP + "*").count(100); + Collection list = new LinkedList<>(); + String cursor = "0"; + do { + ScanResult res = j.scan(cursor.getBytes(), params); + for (byte[] key : res.getResult()) { + byte[] element = j.get(key); + list.add(deserialize(element)); + } + cursor = res.getCursor(); + } while (!"0".equals(cursor)); + return list; + } + } + + @Override + public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { + byte[] data = serialize(info); + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + if (info.getIdentity() != null) { + // populate the secondary index (security info by PSK id) + String oldEndpoint = j.hget(PSKID_SEC, info.getIdentity()); + if (oldEndpoint != null && !oldEndpoint.equals(info.getEndpoint())) { + throw new NonUniqueSecurityInfoException("PSK Identity " + info.getIdentity() + " is already used"); + } + j.hset(PSKID_SEC.getBytes(), info.getIdentity().getBytes(), info.getEndpoint().getBytes()); + } + + byte[] previousData = j.getSet((SEC_EP + info.getEndpoint()).getBytes(), data); + SecurityInfo previous = previousData == null ? null : deserialize(previousData); + String previousIdentity = previous == null ? null : previous.getIdentity(); + if (previousIdentity != null && !previousIdentity.equals(info.getIdentity())) { + j.hdel(PSKID_SEC, previousIdentity); + } + + return previous; + } + } + + @Override + public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { + try (Jedis j = (Jedis) connectionFactory.getConnection().getNativeConnection()) { + byte[] data = j.get((SEC_EP + endpoint).getBytes()); + + if (data != null) { + SecurityInfo info = deserialize(data); + if (info.getIdentity() != null) { + j.hdel(PSKID_SEC.getBytes(), info.getIdentity().getBytes()); + } + j.del((SEC_EP + endpoint).getBytes()); + if (listener != null) { + listener.securityInfoRemoved(infosAreCompromised, info); + } + return info; + } + } + return null; + } + + private byte[] serialize(SecurityInfo secInfo) { + return SecurityInfoSerDes.serialize(secInfo); + } + + private SecurityInfo deserialize(byte[] data) { + return SecurityInfoSerDes.deserialize(data); + } + + @Override + public void setListener(SecurityStoreListener listener) { + this.listener = listener; + } +} diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java new file mode 100644 index 0000000000..9e4b7e442a --- /dev/null +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mStoreConfiguration.java @@ -0,0 +1,123 @@ +/** + * 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.store; + +import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; +import org.eclipse.leshan.server.californium.registration.InMemoryRegistrationStore; +import org.eclipse.leshan.server.security.EditableSecurityStore; +import org.eclipse.leshan.server.security.InMemorySecurityStore; +import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; +import org.eclipse.leshan.server.security.SecurityInfo; +import org.eclipse.leshan.server.security.SecurityStoreListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.thingsboard.server.cache.TBRedisCacheConfiguration; +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent; +import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientContext; + +import java.util.Collection; +import java.util.Optional; + +@Service +@TbLwM2mTransportComponent +public class TbLwM2mStoreConfiguration { + + @Autowired(required = false) + private Optional redisConfiguration; + + @Autowired + @Lazy + private LwM2mClientContext clientContext; + + @Value("${transport.lwm2m.redis.enabled:false}") + private boolean useRedis; + + @Bean + private CaliforniumRegistrationStore registrationStore() { + return redisConfiguration.isPresent() && useRedis ? + new TbLwM2mRedisRegistrationStore(redisConfiguration.get().redisConnectionFactory()) : new InMemoryRegistrationStore(); + } + + @Bean + private EditableSecurityStore securityStore() { + return new TbLwM2mSecurityStoreWrapper(redisConfiguration.isPresent() && useRedis ? + new TbLwM2mRedisSecurityStore(redisConfiguration.get().redisConnectionFactory()) : new InMemorySecurityStore()); + } + + public class TbLwM2mSecurityStoreWrapper implements EditableSecurityStore { + + private final EditableSecurityStore securityStore; + + public TbLwM2mSecurityStoreWrapper(EditableSecurityStore securityStore) { + this.securityStore = securityStore; + } + + @Override + public Collection getAll() { + return securityStore.getAll(); + } + + @Override + public SecurityInfo add(SecurityInfo info) throws NonUniqueSecurityInfoException { + return securityStore.add(info); + } + + @Override + public SecurityInfo remove(String endpoint, boolean infosAreCompromised) { + return securityStore.remove(endpoint, infosAreCompromised); + } + + @Override + public void setListener(SecurityStoreListener listener) { + securityStore.setListener(listener); + } + + @Override + public SecurityInfo getByEndpoint(String endpoint) { + SecurityInfo securityInfo = securityStore.getByEndpoint(endpoint); + if (securityInfo == null) { + securityInfo = clientContext.addLwM2mClientToSession(endpoint).getSecurityInfo(); + try { + if (securityInfo != null) { + add(securityInfo); + } + } catch (NonUniqueSecurityInfoException e) { + e.printStackTrace(); + } + } + return securityInfo; + } + + @Override + public SecurityInfo getByIdentity(String pskIdentity) { + SecurityInfo securityInfo = securityStore.getByIdentity(pskIdentity); + if (securityInfo == null) { + securityInfo = clientContext.addLwM2mClientToSession(pskIdentity).getSecurityInfo(); + try { + if (securityInfo != null) { + add(securityInfo); + } + } catch (NonUniqueSecurityInfoException e) { + e.printStackTrace(); + } + } + return securityInfo; + } + } +} diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index c4f042d67d..491adc189e 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -52,6 +52,10 @@ org.thingsboard.common message + + org.thingsboard.common + cache + org.thingsboard.common util diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java index b835f7ba84..75f20cc825 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/TransportContext.java @@ -20,10 +20,10 @@ import lombok.Data; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Service; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.scheduler.SchedulerComponent; +import org.thingsboard.server.queue.util.TbTransportComponent; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -35,8 +35,6 @@ import java.util.concurrent.Executors; */ @Slf4j @Data -@Service -@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true')") public abstract class TransportContext { protected final ObjectMapper mapper = new ObjectMapper(); 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 248475a002..810848a5ca 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 @@ -186,10 +186,6 @@ public class LwM2MTransportConfigServer { @Value("${transport.lwm2m.server.secure.alias:}") private String serverAlias; - @Getter - @Value("${transport.lwm2m.secure.redis_url:}") - private String redisUrl; - @PostConstruct public void init() { modelsValue = ObjectLoader.loadDefault(); diff --git a/common/util/pom.xml b/common/util/pom.xml index 13afe4663a..6f66da5790 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -45,6 +45,10 @@ javax.annotation javax.annotation-api + + com.fasterxml.jackson.core + jackson-databind + org.slf4j slf4j-api diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java similarity index 98% rename from common/dao-api/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java rename to common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java index 43c7318470..b48030f714 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/util/mapping/JacksonUtil.java +++ b/common/util/src/main/java/org/thingsboard/common/util/JacksonUtil.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.dao.util.mapping; +package org.thingsboard.common.util; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; diff --git a/dao/pom.xml b/dao/pom.xml index cbd3899f25..e1a08cb74d 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -39,6 +39,10 @@ org.thingsboard.common data + + org.thingsboard.common + cache + org.thingsboard.common message diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index 27eca316f9..7bf13871c5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -49,7 +49,7 @@ import org.thingsboard.server.dao.device.provision.ProvisionRequest; import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.io.PrintWriter; import java.io.StringWriter; diff --git a/dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java b/dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java index b0c5a5b74f..038ff2bd23 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/cache/PreviousDeviceCredentialsIdKeyGenerator.java @@ -16,6 +16,7 @@ package org.thingsboard.server.dao.cache; import org.springframework.cache.interceptor.KeyGenerator; +import org.springframework.stereotype.Component; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.device.DeviceCredentialsService; @@ -24,6 +25,7 @@ import java.lang.reflect.Method; import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; +@Component("previousDeviceCredentialsId") public class PreviousDeviceCredentialsIdKeyGenerator implements KeyGenerator { private static final String NOT_VALID_DEVICE = DEVICE_CREDENTIALS_CACHE + "_notValidDeviceCredentialsId"; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java index ccd9bffcf5..f9b3b23ff0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceCredentialsServiceImpl.java @@ -33,7 +33,7 @@ import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.dao.entity.AbstractEntityService; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.service.DataValidator; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import static org.thingsboard.server.common.data.CacheConstants.DEVICE_CREDENTIALS_CACHE; import static org.thingsboard.server.dao.service.Validator.validateId; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index c08e49f8e1..aed6f00678 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -71,7 +71,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import javax.annotation.Nullable; import java.util.ArrayList; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java index 956a244b7e..5a4381fa24 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/AbstractDeviceEntity.java @@ -31,7 +31,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import org.thingsboard.server.dao.util.mapping.JsonStringType; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java index b71f608ef1..0ddf78c8ce 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/DeviceProfileEntity.java @@ -32,7 +32,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import javax.persistence.Column; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java index 0db72f317b..4749af9f6c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/TenantProfileEntity.java @@ -27,7 +27,7 @@ import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.dao.model.BaseSqlEntity; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.model.SearchTextEntity; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.dao.util.mapping.JsonBinaryType; import javax.persistence.Column; diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 4efff2582e..5cb4c693fc 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -48,7 +48,7 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantDao; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.util.HashMap; import java.util.Map; diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonTypeDescriptor.java index 46a666a20c..6ba92c54c1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonTypeDescriptor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/JsonTypeDescriptor.java @@ -19,6 +19,7 @@ import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; import org.hibernate.type.descriptor.java.MutableMutabilityPlan; import org.hibernate.usertype.DynamicParameterizedType; +import org.thingsboard.common.util.JacksonUtil; import java.util.Properties; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java index 3fd416f28c..a798133ad4 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseAlarmServiceTest.java @@ -46,7 +46,7 @@ import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.dao.alarm.AlarmOperationResult; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.util.Arrays; import java.util.Collections; diff --git a/pom.xml b/pom.xml index e1a9b48782..c7d70794eb 100755 --- a/pom.xml +++ b/pom.xml @@ -857,6 +857,11 @@ util ${project.version} + + org.thingsboard.common + cache + ${project.version} + org.thingsboard.common actor diff --git a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java index f1e45d2e8d..11687e0415 100644 --- a/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java +++ b/rule-engine/rule-engine-api/src/test/java/org/thingsboard/rule/engine/api/util/TbNodeUtilsTest.java @@ -23,7 +23,7 @@ import org.mockito.junit.MockitoJUnitRunner; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; @RunWith(MockitoJUnitRunner.class) public class TbNodeUtilsTest { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java index 73ca51f1e9..b2ec1cf7af 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAbstractAlarmNode.java @@ -28,7 +28,7 @@ import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import static org.thingsboard.common.util.DonAsynchron.withCallback; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java index 63b326a816..31f3aa969e 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/CalculateDeltaNode.java @@ -35,7 +35,7 @@ import org.thingsboard.server.common.data.plugin.ComponentType; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.dao.timeseries.TimeseriesService; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.math.BigDecimal; import java.math.RoundingMode; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 7af0beb505..b1c21f08f0 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -25,20 +25,17 @@ import org.thingsboard.rule.engine.api.TbContext; import org.thingsboard.rule.engine.profile.state.PersistedAlarmRuleState; import org.thingsboard.rule.engine.profile.state.PersistedAlarmState; import org.thingsboard.server.common.data.DataConstants; -import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; -import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.KeyFilter; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.ServiceQueue; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.util.ArrayList; import java.util.Comparator; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java index bb7d5f8862..3e1443a274 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/DeviceState.java @@ -40,7 +40,7 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.dao.sql.query.EntityKeyMapping; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.util.ArrayList; import java.util.HashMap; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java index 9b891ea8eb..a733fd104a 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNode.java @@ -38,7 +38,7 @@ import org.thingsboard.server.common.data.rule.RuleNodeState; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; +import org.thingsboard.common.util.JacksonUtil; import java.util.Map; import java.util.UUID; diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeConfiguration.java index 3e03da287c..dac49c25cd 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/TbDeviceProfileNodeConfiguration.java @@ -16,31 +16,8 @@ package org.thingsboard.rule.engine.profile; import lombok.Data; -import lombok.extern.slf4j.Slf4j; import org.codehaus.jackson.annotate.JsonIgnoreProperties; -import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; import org.thingsboard.rule.engine.api.NodeConfiguration; -import org.thingsboard.rule.engine.api.RuleEngineDeviceProfileCache; -import org.thingsboard.rule.engine.api.RuleNode; -import org.thingsboard.rule.engine.api.TbContext; -import org.thingsboard.rule.engine.api.TbNode; -import org.thingsboard.rule.engine.api.TbNodeConfiguration; -import org.thingsboard.rule.engine.api.TbNodeException; -import org.thingsboard.server.common.data.DataConstants; -import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.EntityType; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.data.plugin.ComponentType; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.dao.util.mapping.JacksonUtil; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; @Data @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index 27dad89bb3..1b4a68a906 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -45,9 +45,21 @@ + + + + org.thingsboard.common.transport - transport-api + lwm2m + + + org.thingsboard.common + queue + + + org.thingsboard.common + cache org.springframework diff --git a/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java index ed8ebb3f68..90a5282253 100644 --- a/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java +++ b/transport/lwm2m/src/main/java/org/thingsboard/server/lwm2m/ThingsboardLwm2mTransportApplication.java @@ -26,7 +26,7 @@ import java.util.Arrays; @SpringBootConfiguration @EnableAsync @EnableScheduling -@ComponentScan({"org.thingsboard.server.lwm2m", "org.thingsboard.server.common", "org.thingsboard.server.transport.lwm2m", "org.thingsboard.server.queue"}) +@ComponentScan({"org.thingsboard.server.lwm2m", "org.thingsboard.server.common", "org.thingsboard.server.transport.lwm2m", "org.thingsboard.server.queue", "org.thingsboard.server.cache"}) public class ThingsboardLwm2mTransportApplication { private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name"; diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 3c6c9b2afa..8617868771 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -40,6 +40,83 @@ zk: # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" +cache: + # caffeine or redis + type: "${CACHE_TYPE:caffeine}" + +caffeine: + specs: + relations: + timeToLiveInMinutes: 1440 + maxSize: 0 + deviceCredentials: + timeToLiveInMinutes: 1440 + maxSize: 0 + devices: + timeToLiveInMinutes: 1440 + maxSize: 0 + sessions: + timeToLiveInMinutes: 1440 + maxSize: 0 + assets: + timeToLiveInMinutes: 1440 + maxSize: 0 + entityViews: + timeToLiveInMinutes: 1440 + maxSize: 0 + claimDevices: + timeToLiveInMinutes: 1 + maxSize: 0 + securitySettings: + timeToLiveInMinutes: 1440 + maxSize: 0 + tenantProfiles: + timeToLiveInMinutes: 1440 + maxSize: 0 + deviceProfiles: + timeToLiveInMinutes: 1440 + maxSize: 0 + +redis: + # standalone or cluster + connection: + type: "${REDIS_CONNECTION_TYPE:standalone}" + standalone: + host: "${REDIS_HOST:localhost}" + port: "${REDIS_PORT:6379}" + useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" + # this value may be used only if you used not default ClientConfig + clientName: "${REDIS_CLIENT_NAME:standalone}" + # this value may be used only if you used not default ClientConfig + connectTimeout: "${REDIS_CLIENT_CONNECT_TIMEOUT:30000}" + # this value may be used only if you used not default ClientConfig + readTimeout: "${REDIS_CLIENT_READ_TIMEOUT:60000}" + # this value may be used only if you used not default ClientConfig + usePoolConfig: "${REDIS_CLIENT_USE_POOL_CONFIG:false}" + cluster: + # Comma-separated list of "host:port" pairs to bootstrap from. + nodes: "${REDIS_NODES:}" + # Maximum number of redirects to follow when executing commands across the cluster. + max-redirects: "${REDIS_MAX_REDIRECTS:12}" + useDefaultPoolConfig: "${REDIS_USE_DEFAULT_POOL_CONFIG:true}" + # db index + db: "${REDIS_DB:0}" + # db password + password: "${REDIS_PASSWORD:}" + # pool config + pool_config: + maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" + # LWM2M server parameters transport: # Local LwM2M transport parameters @@ -102,8 +179,8 @@ transport: public_y: "${LWM2M_SERVER_PUBLIC_Y_BS:3fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" private_encoded: "${LWM2M_SERVER_PRIVATE_ENCODED_BS:308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104205ecafd90caa7be45c42e1f3f32571632b8409e6e6249d7124f4ba56fab3c8083a00a06082a8648ce3d030107a144034200045017c87a1c1768264656b3b355434b0def6edb8b9bf166a4762d9930cd730f913fc4e61bcd8901ec27c424114c3e887ed372497f0c2cf85839b8443e76988b34}" # Only Certificate_x509: alias: "${LWM2M_KEYSTORE_ALIAS_BOOTSTRAP:bootstrap}" - # Redis - redis_url: "${LWM2M_REDIS_URL:''}" + # Use redis for Security and Registration stores + redis.enabled: "${LWM2M_REDIS_ENABLED:false}" sessions: inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"