Showing
96 changed files
with
2840 additions
and
346 deletions
Too many changes to show.
To preserve performance only 96 of 221 files are displayed.
@@ -90,6 +90,10 @@ | @@ -90,6 +90,10 @@ | ||
90 | <artifactId>lwm2m</artifactId> | 90 | <artifactId>lwm2m</artifactId> |
91 | </dependency> | 91 | </dependency> |
92 | <dependency> | 92 | <dependency> |
93 | + <groupId>org.thingsboard.common.transport</groupId> | ||
94 | + <artifactId>snmp</artifactId> | ||
95 | + </dependency> | ||
96 | + <dependency> | ||
93 | <groupId>org.thingsboard</groupId> | 97 | <groupId>org.thingsboard</groupId> |
94 | <artifactId>dao</artifactId> | 98 | <artifactId>dao</artifactId> |
95 | </dependency> | 99 | </dependency> |
@@ -22,10 +22,10 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | @@ -22,10 +22,10 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
22 | import org.springframework.context.event.EventListener; | 22 | import org.springframework.context.event.EventListener; |
23 | import org.springframework.core.annotation.Order; | 23 | import org.springframework.core.annotation.Order; |
24 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
25 | +import org.thingsboard.common.util.ThingsBoardExecutors; | ||
25 | import org.thingsboard.common.util.ThingsBoardThreadFactory; | 26 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
26 | import org.thingsboard.server.actors.ActorSystemContext; | 27 | import org.thingsboard.server.actors.ActorSystemContext; |
27 | import org.thingsboard.server.actors.DefaultTbActorSystem; | 28 | import org.thingsboard.server.actors.DefaultTbActorSystem; |
28 | -import org.thingsboard.server.actors.TbActorId; | ||
29 | import org.thingsboard.server.actors.TbActorRef; | 29 | import org.thingsboard.server.actors.TbActorRef; |
30 | import org.thingsboard.server.actors.TbActorSystem; | 30 | import org.thingsboard.server.actors.TbActorSystem; |
31 | import org.thingsboard.server.actors.TbActorSystemSettings; | 31 | import org.thingsboard.server.actors.TbActorSystemSettings; |
@@ -33,14 +33,13 @@ import org.thingsboard.server.actors.app.AppActor; | @@ -33,14 +33,13 @@ import org.thingsboard.server.actors.app.AppActor; | ||
33 | import org.thingsboard.server.actors.app.AppInitMsg; | 33 | import org.thingsboard.server.actors.app.AppInitMsg; |
34 | import org.thingsboard.server.actors.stats.StatsActor; | 34 | import org.thingsboard.server.actors.stats.StatsActor; |
35 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; | 35 | import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; |
36 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | ||
37 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 36 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
37 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | ||
38 | 38 | ||
39 | import javax.annotation.PostConstruct; | 39 | import javax.annotation.PostConstruct; |
40 | import javax.annotation.PreDestroy; | 40 | import javax.annotation.PreDestroy; |
41 | import java.util.concurrent.ExecutorService; | 41 | import java.util.concurrent.ExecutorService; |
42 | import java.util.concurrent.Executors; | 42 | import java.util.concurrent.Executors; |
43 | -import java.util.concurrent.ScheduledExecutorService; | ||
44 | 43 | ||
45 | @Service | 44 | @Service |
46 | @Slf4j | 45 | @Slf4j |
@@ -110,7 +109,7 @@ public class DefaultActorService extends TbApplicationEventListener<PartitionCha | @@ -110,7 +109,7 @@ public class DefaultActorService extends TbApplicationEventListener<PartitionCha | ||
110 | if (poolSize == 1) { | 109 | if (poolSize == 1) { |
111 | return Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(dispatcherName)); | 110 | return Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName(dispatcherName)); |
112 | } else { | 111 | } else { |
113 | - return Executors.newWorkStealingPool(poolSize); | 112 | + return ThingsBoardExecutors.newWorkStealingPool(poolSize, dispatcherName); |
114 | } | 113 | } |
115 | } | 114 | } |
116 | 115 |
@@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam; | @@ -32,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam; | ||
32 | import org.springframework.web.bind.annotation.ResponseBody; | 32 | import org.springframework.web.bind.annotation.ResponseBody; |
33 | import org.springframework.web.bind.annotation.ResponseStatus; | 33 | import org.springframework.web.bind.annotation.ResponseStatus; |
34 | import org.springframework.web.bind.annotation.RestController; | 34 | import org.springframework.web.bind.annotation.RestController; |
35 | +import org.thingsboard.common.util.JacksonUtil; | ||
35 | import org.thingsboard.rule.engine.api.MailService; | 36 | import org.thingsboard.rule.engine.api.MailService; |
36 | import org.thingsboard.server.common.data.EntityType; | 37 | import org.thingsboard.server.common.data.EntityType; |
37 | import org.thingsboard.server.common.data.User; | 38 | import org.thingsboard.server.common.data.User; |
@@ -89,13 +90,14 @@ public class UserController extends BaseController { | @@ -89,13 +90,14 @@ public class UserController extends BaseController { | ||
89 | try { | 90 | try { |
90 | UserId userId = new UserId(toUUID(strUserId)); | 91 | UserId userId = new UserId(toUUID(strUserId)); |
91 | User user = checkUserId(userId, Operation.READ); | 92 | User user = checkUserId(userId, Operation.READ); |
92 | - if(!user.getAdditionalInfo().isNull()) { | ||
93 | - processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), DEFAULT_DASHBOARD); | ||
94 | - processDashboardIdFromAdditionalInfo((ObjectNode) user.getAdditionalInfo(), HOME_DASHBOARD); | ||
95 | - } | ||
96 | - UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); | ||
97 | - if(userCredentials.isEnabled()) { | ||
98 | - addUserCredentialsEnabled((ObjectNode) user.getAdditionalInfo()); | 93 | + if(user.getAdditionalInfo().isObject()) { |
94 | + ObjectNode additionalInfo = (ObjectNode) user.getAdditionalInfo(); | ||
95 | + processDashboardIdFromAdditionalInfo(additionalInfo, DEFAULT_DASHBOARD); | ||
96 | + processDashboardIdFromAdditionalInfo(additionalInfo, HOME_DASHBOARD); | ||
97 | + UserCredentials userCredentials = userService.findUserCredentialsByUserId(user.getTenantId(), user.getId()); | ||
98 | + if(userCredentials.isEnabled() && !additionalInfo.has("userCredentialsEnabled")) { | ||
99 | + additionalInfo.put("userCredentialsEnabled", true); | ||
100 | + } | ||
99 | } | 101 | } |
100 | return user; | 102 | return user; |
101 | } catch (Exception e) { | 103 | } catch (Exception e) { |
@@ -103,14 +105,6 @@ public class UserController extends BaseController { | @@ -103,14 +105,6 @@ public class UserController extends BaseController { | ||
103 | } | 105 | } |
104 | } | 106 | } |
105 | 107 | ||
106 | - private void addUserCredentialsEnabled(ObjectNode additionalInfo) { | ||
107 | - if(!additionalInfo.isNull()) { | ||
108 | - if(!additionalInfo.has("userCredentialsEnabled")) { | ||
109 | - additionalInfo.put("userCredentialsEnabled", true); | ||
110 | - } | ||
111 | - } | ||
112 | - } | ||
113 | - | ||
114 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") | 108 | @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") |
115 | @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET) | 109 | @RequestMapping(value = "/user/tokenAccessEnabled", method = RequestMethod.GET) |
116 | @ResponseBody | 110 | @ResponseBody |
application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java
@@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
23 | import org.springframework.beans.factory.annotation.Value; | 23 | import org.springframework.beans.factory.annotation.Value; |
24 | import org.springframework.context.annotation.Lazy; | 24 | import org.springframework.context.annotation.Lazy; |
25 | import org.springframework.stereotype.Service; | 25 | import org.springframework.stereotype.Service; |
26 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
26 | import org.thingsboard.rule.engine.api.MailService; | 27 | import org.thingsboard.rule.engine.api.MailService; |
27 | import org.thingsboard.server.common.data.ApiFeature; | 28 | import org.thingsboard.server.common.data.ApiFeature; |
28 | import org.thingsboard.server.common.data.ApiUsageRecordKey; | 29 | import org.thingsboard.server.common.data.ApiUsageRecordKey; |
@@ -56,7 +57,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; | @@ -56,7 +57,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; | ||
56 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; | 57 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
57 | import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; | 58 | import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; |
58 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 59 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
59 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 60 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
60 | import org.thingsboard.server.queue.discovery.PartitionService; | 61 | import org.thingsboard.server.queue.discovery.PartitionService; |
61 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 62 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
62 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; | 63 | import org.thingsboard.server.queue.scheduler.SchedulerComponent; |
@@ -146,7 +147,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa | @@ -146,7 +147,7 @@ public class DefaultTbApiUsageStateService extends TbApplicationEventListener<Pa | ||
146 | this.scheduler = scheduler; | 147 | this.scheduler = scheduler; |
147 | this.tenantProfileCache = tenantProfileCache; | 148 | this.tenantProfileCache = tenantProfileCache; |
148 | this.mailService = mailService; | 149 | this.mailService = mailService; |
149 | - this.mailExecutor = Executors.newSingleThreadExecutor(); | 150 | + this.mailExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("api-usage-svc-mail")); |
150 | } | 151 | } |
151 | 152 | ||
152 | @PostConstruct | 153 | @PostConstruct |
@@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId; | @@ -23,7 +23,7 @@ import org.thingsboard.server.common.data.id.TenantProfileId; | ||
23 | import org.thingsboard.server.common.msg.queue.TbCallback; | 23 | import org.thingsboard.server.common.msg.queue.TbCallback; |
24 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; | 24 | import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; |
25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
26 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 26 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
27 | 27 | ||
28 | public interface TbApiUsageStateService extends ApplicationListener<PartitionChangeEvent> { | 28 | public interface TbApiUsageStateService extends ApplicationListener<PartitionChangeEvent> { |
29 | 29 |
@@ -55,7 +55,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceM | @@ -55,7 +55,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceM | ||
55 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; | 55 | import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; |
56 | import org.thingsboard.server.queue.TbQueueConsumer; | 56 | import org.thingsboard.server.queue.TbQueueConsumer; |
57 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 57 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
58 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 58 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
59 | import org.thingsboard.server.queue.provider.TbCoreQueueFactory; | 59 | import org.thingsboard.server.queue.provider.TbCoreQueueFactory; |
60 | import org.thingsboard.server.queue.util.TbCoreComponent; | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; |
61 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 61 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
@@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -20,6 +20,7 @@ import lombok.extern.slf4j.Slf4j; | ||
20 | import org.springframework.beans.factory.annotation.Value; | 20 | import org.springframework.beans.factory.annotation.Value; |
21 | import org.springframework.scheduling.annotation.Scheduled; | 21 | import org.springframework.scheduling.annotation.Scheduled; |
22 | import org.springframework.stereotype.Service; | 22 | import org.springframework.stereotype.Service; |
23 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
23 | import org.thingsboard.rule.engine.api.RpcError; | 24 | import org.thingsboard.rule.engine.api.RpcError; |
24 | import org.thingsboard.server.actors.ActorSystemContext; | 25 | import org.thingsboard.server.actors.ActorSystemContext; |
25 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -38,7 +39,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | @@ -38,7 +39,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; | ||
38 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; | 39 | import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; |
39 | import org.thingsboard.server.queue.TbQueueConsumer; | 40 | import org.thingsboard.server.queue.TbQueueConsumer; |
40 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 41 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
41 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 42 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
42 | import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; | 43 | import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; |
43 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; | 44 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
44 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; | 45 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; |
@@ -127,7 +128,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< | @@ -127,7 +128,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< | ||
127 | consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); | 128 | consumers.computeIfAbsent(configuration.getName(), queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); |
128 | consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); | 129 | consumerStats.put(configuration.getName(), new TbRuleEngineConsumerStats(configuration.getName(), statsFactory)); |
129 | } | 130 | } |
130 | - submitExecutor = Executors.newSingleThreadExecutor(); | 131 | + submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-service-submit-executor")); |
131 | } | 132 | } |
132 | 133 | ||
133 | @PreDestroy | 134 | @PreDestroy |
@@ -160,6 +161,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< | @@ -160,6 +161,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< | ||
160 | 161 | ||
161 | private void launchConsumer(TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> consumer, TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats) { | 162 | private void launchConsumer(TbQueueConsumer<TbProtoQueueMsg<ToRuleEngineMsg>> consumer, TbRuleEngineQueueConfiguration configuration, TbRuleEngineConsumerStats stats) { |
162 | consumersExecutor.execute(() -> { | 163 | consumersExecutor.execute(() -> { |
164 | + Thread.currentThread().setName("" + Thread.currentThread().getName() + "-" + configuration.getName()); | ||
163 | while (!stopped) { | 165 | while (!stopped) { |
164 | try { | 166 | try { |
165 | List<TbProtoQueueMsg<ToRuleEngineMsg>> msgs = consumer.poll(pollDuration); | 167 | List<TbProtoQueueMsg<ToRuleEngineMsg>> msgs = consumer.poll(pollDuration); |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | package org.thingsboard.server.service.queue; | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | ||
18 | import org.springframework.context.ApplicationListener; | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
20 | 20 | ||
21 | public interface TbCoreConsumerService extends ApplicationListener<PartitionChangeEvent> { | 21 | public interface TbCoreConsumerService extends ApplicationListener<PartitionChangeEvent> { |
22 | 22 |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | package org.thingsboard.server.service.queue; | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | ||
18 | import org.springframework.context.ApplicationListener; | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
20 | 20 | ||
21 | public interface TbRuleEngineConsumerService extends ApplicationListener<PartitionChangeEvent> { | 21 | public interface TbRuleEngineConsumerService extends ApplicationListener<PartitionChangeEvent> { |
22 | 22 |
@@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | @@ -35,7 +35,7 @@ import org.thingsboard.server.common.msg.queue.ServiceType; | ||
35 | import org.thingsboard.server.common.msg.queue.TbCallback; | 35 | import org.thingsboard.server.common.msg.queue.TbCallback; |
36 | import org.thingsboard.server.queue.TbQueueConsumer; | 36 | import org.thingsboard.server.queue.TbQueueConsumer; |
37 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 37 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
38 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 38 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
39 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | 39 | import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; |
40 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 40 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
41 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 41 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
@@ -185,7 +185,7 @@ public class DefaultTbResourceService implements TbResourceService { | @@ -185,7 +185,7 @@ public class DefaultTbResourceService implements TbResourceService { | ||
185 | instance.setId(0); | 185 | instance.setId(0); |
186 | List<LwM2mResourceObserve> resources = new ArrayList<>(); | 186 | List<LwM2mResourceObserve> resources = new ArrayList<>(); |
187 | obj.resources.forEach((k, v) -> { | 187 | obj.resources.forEach((k, v) -> { |
188 | - if (!v.operations.isExecutable()) { | 188 | + if (v.operations.isReadable()) { |
189 | LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); | 189 | LwM2mResourceObserve lwM2MResourceObserve = new LwM2mResourceObserve(k, v.name, false, false, false); |
190 | resources.add(lwM2MResourceObserve); | 190 | resources.add(lwM2MResourceObserve); |
191 | } | 191 | } |
@@ -25,6 +25,7 @@ import lombok.Getter; | @@ -25,6 +25,7 @@ import lombok.Getter; | ||
25 | import lombok.extern.slf4j.Slf4j; | 25 | import lombok.extern.slf4j.Slf4j; |
26 | import org.springframework.beans.factory.annotation.Value; | 26 | import org.springframework.beans.factory.annotation.Value; |
27 | import org.springframework.scheduling.annotation.Scheduled; | 27 | import org.springframework.scheduling.annotation.Scheduled; |
28 | +import org.thingsboard.common.util.ThingsBoardExecutors; | ||
28 | import org.thingsboard.server.queue.usagestats.TbApiUsageClient; | 29 | import org.thingsboard.server.queue.usagestats.TbApiUsageClient; |
29 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; | 30 | import org.thingsboard.server.service.apiusage.TbApiUsageStateService; |
30 | 31 | ||
@@ -93,7 +94,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer | @@ -93,7 +94,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer | ||
93 | super.init(maxRequestsTimeout); | 94 | super.init(maxRequestsTimeout); |
94 | if (useJsSandbox()) { | 95 | if (useJsSandbox()) { |
95 | sandbox = NashornSandboxes.create(); | 96 | sandbox = NashornSandboxes.create(); |
96 | - monitorExecutorService = Executors.newWorkStealingPool(getMonitorThreadPoolSize()); | 97 | + monitorExecutorService = ThingsBoardExecutors.newWorkStealingPool(getMonitorThreadPoolSize(), "nashorn-js-monitor"); |
97 | sandbox.setExecutor(monitorExecutorService); | 98 | sandbox.setExecutor(monitorExecutorService); |
98 | sandbox.setMaxCPUTime(getMaxCpuTime()); | 99 | sandbox.setMaxCPUTime(getMaxCpuTime()); |
99 | sandbox.allowNoBraces(false); | 100 | sandbox.allowNoBraces(false); |
@@ -54,7 +54,7 @@ import org.thingsboard.server.dao.tenant.TenantService; | @@ -54,7 +54,7 @@ import org.thingsboard.server.dao.tenant.TenantService; | ||
54 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 54 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
55 | import org.thingsboard.common.util.JacksonUtil; | 55 | import org.thingsboard.common.util.JacksonUtil; |
56 | import org.thingsboard.server.gen.transport.TransportProtos; | 56 | import org.thingsboard.server.gen.transport.TransportProtos; |
57 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 57 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
58 | import org.thingsboard.server.queue.discovery.PartitionService; | 58 | import org.thingsboard.server.queue.discovery.PartitionService; |
59 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 59 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
60 | import org.thingsboard.server.queue.util.TbCoreComponent; | 60 | import org.thingsboard.server.queue.util.TbCoreComponent; |
@@ -18,7 +18,7 @@ package org.thingsboard.server.service.state; | @@ -18,7 +18,7 @@ package org.thingsboard.server.service.state; | ||
18 | import org.springframework.context.ApplicationListener; | 18 | import org.springframework.context.ApplicationListener; |
19 | import org.thingsboard.server.common.data.Device; | 19 | import org.thingsboard.server.common.data.Device; |
20 | import org.thingsboard.server.common.data.id.DeviceId; | 20 | import org.thingsboard.server.common.data.id.DeviceId; |
21 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 21 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
22 | import org.thingsboard.server.gen.transport.TransportProtos; | 22 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | import org.thingsboard.server.common.msg.queue.TbCallback; | 23 | import org.thingsboard.server.common.msg.queue.TbCallback; |
24 | 24 |
@@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdate | @@ -46,7 +46,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdate | ||
46 | import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateValueListProto; | 46 | import org.thingsboard.server.gen.transport.TransportProtos.TbSubscriptionUpdateValueListProto; |
47 | import org.thingsboard.server.queue.TbQueueProducer; | 47 | import org.thingsboard.server.queue.TbQueueProducer; |
48 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 48 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
49 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 49 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
50 | import org.thingsboard.server.queue.discovery.PartitionService; | 50 | import org.thingsboard.server.queue.discovery.PartitionService; |
51 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 51 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
52 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 52 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
@@ -20,10 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -20,10 +20,10 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
20 | import org.springframework.context.annotation.Lazy; | 20 | import org.springframework.context.annotation.Lazy; |
21 | import org.springframework.context.event.EventListener; | 21 | import org.springframework.context.event.EventListener; |
22 | import org.springframework.stereotype.Service; | 22 | import org.springframework.stereotype.Service; |
23 | -import org.thingsboard.common.util.ThingsBoardThreadFactory; | 23 | +import org.thingsboard.common.util.ThingsBoardExecutors; |
24 | import org.thingsboard.server.gen.transport.TransportProtos; | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
25 | -import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent; | ||
26 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 25 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; |
26 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | ||
27 | import org.thingsboard.server.queue.discovery.PartitionService; | 27 | import org.thingsboard.server.queue.discovery.PartitionService; |
28 | import org.thingsboard.server.common.msg.queue.ServiceType; | 28 | import org.thingsboard.server.common.msg.queue.ServiceType; |
29 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 29 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
@@ -63,7 +63,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer | @@ -63,7 +63,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer | ||
63 | private SubscriptionManagerService subscriptionManagerService; | 63 | private SubscriptionManagerService subscriptionManagerService; |
64 | 64 | ||
65 | private ExecutorService subscriptionUpdateExecutor; | 65 | private ExecutorService subscriptionUpdateExecutor; |
66 | - | 66 | + |
67 | private TbApplicationEventListener<PartitionChangeEvent> partitionChangeListener = new TbApplicationEventListener<>() { | 67 | private TbApplicationEventListener<PartitionChangeEvent> partitionChangeListener = new TbApplicationEventListener<>() { |
68 | @Override | 68 | @Override |
69 | protected void onTbApplicationEvent(PartitionChangeEvent event) { | 69 | protected void onTbApplicationEvent(PartitionChangeEvent event) { |
@@ -94,7 +94,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer | @@ -94,7 +94,7 @@ public class DefaultTbLocalSubscriptionService implements TbLocalSubscriptionSer | ||
94 | 94 | ||
95 | @PostConstruct | 95 | @PostConstruct |
96 | public void initExecutor() { | 96 | public void initExecutor() { |
97 | - subscriptionUpdateExecutor = Executors.newWorkStealingPool(20); | 97 | + subscriptionUpdateExecutor = ThingsBoardExecutors.newWorkStealingPool(20, getClass()); |
98 | } | 98 | } |
99 | 99 | ||
100 | @PreDestroy | 100 | @PreDestroy |
@@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.id.TenantId; | @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.id.TenantId; | ||
22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 22 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
23 | import org.thingsboard.server.common.data.kv.TsKvEntry; | 23 | import org.thingsboard.server.common.data.kv.TsKvEntry; |
24 | import org.thingsboard.server.common.msg.queue.TbCallback; | 24 | import org.thingsboard.server.common.msg.queue.TbCallback; |
25 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 25 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
26 | 26 | ||
27 | import java.util.List; | 27 | import java.util.List; |
28 | 28 |
@@ -15,8 +15,8 @@ | @@ -15,8 +15,8 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.subscription; | 16 | package org.thingsboard.server.service.subscription; |
17 | 17 | ||
18 | -import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent; | ||
19 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 18 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; |
19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | ||
20 | import org.thingsboard.server.common.msg.queue.TbCallback; | 20 | import org.thingsboard.server.common.msg.queue.TbCallback; |
21 | import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; | 21 | import org.thingsboard.server.service.telemetry.sub.AlarmSubscriptionUpdate; |
22 | import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; | 22 | import org.thingsboard.server.service.telemetry.sub.TelemetrySubscriptionUpdate; |
@@ -22,35 +22,18 @@ import lombok.extern.slf4j.Slf4j; | @@ -22,35 +22,18 @@ import lombok.extern.slf4j.Slf4j; | ||
22 | import org.springframework.beans.factory.annotation.Autowired; | 22 | import org.springframework.beans.factory.annotation.Autowired; |
23 | import org.springframework.context.ApplicationListener; | 23 | import org.springframework.context.ApplicationListener; |
24 | import org.springframework.context.event.EventListener; | 24 | import org.springframework.context.event.EventListener; |
25 | -import org.springframework.stereotype.Service; | ||
26 | import org.thingsboard.common.util.ThingsBoardThreadFactory; | 25 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
27 | -import org.thingsboard.server.common.data.id.EntityId; | ||
28 | -import org.thingsboard.server.common.data.id.TenantId; | ||
29 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
30 | -import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | ||
31 | -import org.thingsboard.server.common.data.kv.BooleanDataEntry; | ||
32 | -import org.thingsboard.server.common.data.kv.DoubleDataEntry; | ||
33 | -import org.thingsboard.server.common.data.kv.LongDataEntry; | ||
34 | -import org.thingsboard.server.common.data.kv.StringDataEntry; | ||
35 | -import org.thingsboard.server.common.data.kv.TsKvEntry; | ||
36 | import org.thingsboard.server.common.msg.queue.ServiceType; | 26 | import org.thingsboard.server.common.msg.queue.ServiceType; |
37 | -import org.thingsboard.server.common.msg.queue.TbCallback; | ||
38 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 27 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
39 | -import org.thingsboard.server.dao.attributes.AttributesService; | ||
40 | -import org.thingsboard.server.dao.timeseries.TimeseriesService; | ||
41 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
42 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 28 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
43 | import org.thingsboard.server.queue.discovery.PartitionService; | 29 | import org.thingsboard.server.queue.discovery.PartitionService; |
44 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | 30 | import org.thingsboard.server.queue.discovery.TbApplicationEventListener; |
45 | import org.thingsboard.server.service.queue.TbClusterService; | 31 | import org.thingsboard.server.service.queue.TbClusterService; |
46 | import org.thingsboard.server.service.subscription.SubscriptionManagerService; | 32 | import org.thingsboard.server.service.subscription.SubscriptionManagerService; |
47 | -import org.thingsboard.server.service.subscription.TbSubscriptionUtils; | ||
48 | 33 | ||
49 | import javax.annotation.Nullable; | 34 | import javax.annotation.Nullable; |
50 | import javax.annotation.PostConstruct; | 35 | import javax.annotation.PostConstruct; |
51 | import javax.annotation.PreDestroy; | 36 | import javax.annotation.PreDestroy; |
52 | -import java.util.Collections; | ||
53 | -import java.util.List; | ||
54 | import java.util.Optional; | 37 | import java.util.Optional; |
55 | import java.util.Set; | 38 | import java.util.Set; |
56 | import java.util.concurrent.ConcurrentHashMap; | 39 | import java.util.concurrent.ConcurrentHashMap; |
@@ -17,8 +17,7 @@ package org.thingsboard.server.service.telemetry; | @@ -17,8 +17,7 @@ package org.thingsboard.server.service.telemetry; | ||
17 | 17 | ||
18 | import org.springframework.context.ApplicationListener; | 18 | import org.springframework.context.ApplicationListener; |
19 | import org.thingsboard.rule.engine.api.RuleEngineAlarmService; | 19 | import org.thingsboard.rule.engine.api.RuleEngineAlarmService; |
20 | -import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | ||
21 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 20 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
22 | 21 | ||
23 | /** | 22 | /** |
24 | * Created by ashvayka on 27.03.18. | 23 | * Created by ashvayka on 27.03.18. |
@@ -28,6 +28,8 @@ import org.springframework.beans.factory.annotation.Value; | @@ -28,6 +28,8 @@ import org.springframework.beans.factory.annotation.Value; | ||
28 | import org.springframework.stereotype.Service; | 28 | import org.springframework.stereotype.Service; |
29 | import org.springframework.util.StringUtils; | 29 | import org.springframework.util.StringUtils; |
30 | import org.springframework.web.socket.CloseStatus; | 30 | import org.springframework.web.socket.CloseStatus; |
31 | +import org.thingsboard.common.util.ThingsBoardExecutors; | ||
32 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
31 | import org.thingsboard.server.common.data.DataConstants; | 33 | import org.thingsboard.server.common.data.DataConstants; |
32 | import org.thingsboard.server.common.data.id.CustomerId; | 34 | import org.thingsboard.server.common.data.id.CustomerId; |
33 | import org.thingsboard.server.common.data.id.EntityId; | 35 | import org.thingsboard.server.common.data.id.EntityId; |
@@ -157,9 +159,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | @@ -157,9 +159,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi | ||
157 | @PostConstruct | 159 | @PostConstruct |
158 | public void initExecutor() { | 160 | public void initExecutor() { |
159 | serviceId = serviceInfoProvider.getServiceId(); | 161 | serviceId = serviceInfoProvider.getServiceId(); |
160 | - executor = Executors.newWorkStealingPool(50); | 162 | + executor = ThingsBoardExecutors.newWorkStealingPool(50, getClass()); |
161 | 163 | ||
162 | - pingExecutor = Executors.newSingleThreadScheduledExecutor(); | 164 | + pingExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("telemetry-web-socket-ping")); |
163 | pingExecutor.scheduleWithFixedDelay(this::sendPing, 10000, 10000, TimeUnit.MILLISECONDS); | 165 | pingExecutor.scheduleWithFixedDelay(this::sendPing, 10000, 10000, TimeUnit.MILLISECONDS); |
164 | } | 166 | } |
165 | 167 |
application/src/main/java/org/thingsboard/server/service/telemetry/TelemetrySubscriptionService.java
@@ -16,8 +16,7 @@ | @@ -16,8 +16,7 @@ | ||
16 | package org.thingsboard.server.service.telemetry; | 16 | package org.thingsboard.server.service.telemetry; |
17 | 17 | ||
18 | import org.springframework.context.ApplicationListener; | 18 | import org.springframework.context.ApplicationListener; |
19 | -import org.thingsboard.rule.engine.api.RuleEngineTelemetryService; | ||
20 | -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 19 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; |
21 | 20 | ||
22 | /** | 21 | /** |
23 | * Created by ashvayka on 27.03.18. | 22 | * Created by ashvayka on 27.03.18. |
@@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.ApiUsageState; | @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.ApiUsageState; | ||
31 | import org.thingsboard.server.common.data.DataConstants; | 31 | import org.thingsboard.server.common.data.DataConstants; |
32 | import org.thingsboard.server.common.data.Device; | 32 | import org.thingsboard.server.common.data.Device; |
33 | import org.thingsboard.server.common.data.DeviceProfile; | 33 | import org.thingsboard.server.common.data.DeviceProfile; |
34 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
34 | import org.thingsboard.server.common.data.EntityType; | 35 | import org.thingsboard.server.common.data.EntityType; |
35 | import org.thingsboard.server.common.data.Firmware; | 36 | import org.thingsboard.server.common.data.Firmware; |
36 | import org.thingsboard.server.common.data.FirmwareInfo; | 37 | import org.thingsboard.server.common.data.FirmwareInfo; |
@@ -47,6 +48,8 @@ import org.thingsboard.server.common.data.id.DeviceId; | @@ -47,6 +48,8 @@ import org.thingsboard.server.common.data.id.DeviceId; | ||
47 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 48 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
48 | import org.thingsboard.server.common.data.id.FirmwareId; | 49 | import org.thingsboard.server.common.data.id.FirmwareId; |
49 | import org.thingsboard.server.common.data.id.TenantId; | 50 | import org.thingsboard.server.common.data.id.TenantId; |
51 | +import org.thingsboard.server.common.data.page.PageData; | ||
52 | +import org.thingsboard.server.common.data.page.PageLink; | ||
50 | import org.thingsboard.server.common.data.relation.EntityRelation; | 53 | import org.thingsboard.server.common.data.relation.EntityRelation; |
51 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 54 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
52 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 55 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
@@ -66,11 +69,15 @@ import org.thingsboard.server.dao.relation.RelationService; | @@ -66,11 +69,15 @@ import org.thingsboard.server.dao.relation.RelationService; | ||
66 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; | 69 | import org.thingsboard.server.dao.tenant.TbTenantProfileCache; |
67 | import org.thingsboard.server.gen.transport.TransportProtos; | 70 | import org.thingsboard.server.gen.transport.TransportProtos; |
68 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; | 71 | import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; |
72 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsRequestMsg; | ||
73 | +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg; | ||
69 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; | 74 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; |
70 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; | 75 | import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; |
71 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; | 76 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; |
72 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; | 77 | import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; |
73 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; | 78 | import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; |
79 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRequestMsg; | ||
80 | +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesResponseMsg; | ||
74 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; | 81 | import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; |
75 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; | 82 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; |
76 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; | 83 | import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; |
@@ -93,6 +100,7 @@ import java.util.concurrent.ConcurrentHashMap; | @@ -93,6 +100,7 @@ import java.util.concurrent.ConcurrentHashMap; | ||
93 | import java.util.concurrent.ConcurrentMap; | 100 | import java.util.concurrent.ConcurrentMap; |
94 | import java.util.concurrent.locks.Lock; | 101 | import java.util.concurrent.locks.Lock; |
95 | import java.util.concurrent.locks.ReentrantLock; | 102 | import java.util.concurrent.locks.ReentrantLock; |
103 | +import java.util.stream.Collectors; | ||
96 | 104 | ||
97 | /** | 105 | /** |
98 | * Created by ashvayka on 05.10.18. | 106 | * Created by ashvayka on 05.10.18. |
@@ -146,43 +154,43 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -146,43 +154,43 @@ public class DefaultTransportApiService implements TransportApiService { | ||
146 | @Override | 154 | @Override |
147 | public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { | 155 | public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { |
148 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); | 156 | TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); |
157 | + ListenableFuture<TransportApiResponseMsg> result = null; | ||
158 | + | ||
149 | if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { | 159 | if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { |
150 | ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); | 160 | ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); |
151 | - return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN), | ||
152 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 161 | + result = validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN); |
153 | } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) { | 162 | } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) { |
154 | TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg(); | 163 | TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg(); |
155 | - return Futures.transform(validateCredentials(msg), | ||
156 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 164 | + result = validateCredentials(msg); |
157 | } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { | 165 | } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { |
158 | ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); | 166 | ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); |
159 | - return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE), | ||
160 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 167 | + result = validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE); |
161 | } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { | 168 | } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { |
162 | - return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()), | ||
163 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 169 | + result = handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()); |
164 | } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { | 170 | } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { |
165 | - return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()), | ||
166 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 171 | + result = handle(transportApiRequestMsg.getEntityProfileRequestMsg()); |
167 | } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) { | 172 | } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) { |
168 | - return Futures.transform(handle(transportApiRequestMsg.getLwM2MRequestMsg()), | ||
169 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 173 | + result = handle(transportApiRequestMsg.getLwM2MRequestMsg()); |
170 | } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) { | 174 | } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) { |
171 | ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg(); | 175 | ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg(); |
172 | - return Futures.transform(validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS), | ||
173 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 176 | + result = validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS); |
174 | } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { | 177 | } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { |
175 | - return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), | ||
176 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 178 | + result = handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()); |
177 | } else if (transportApiRequestMsg.hasResourceRequestMsg()) { | 179 | } else if (transportApiRequestMsg.hasResourceRequestMsg()) { |
178 | - return Futures.transform(handle(transportApiRequestMsg.getResourceRequestMsg()), | ||
179 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 180 | + result = handle(transportApiRequestMsg.getResourceRequestMsg()); |
181 | + } else if (transportApiRequestMsg.hasSnmpDevicesRequestMsg()) { | ||
182 | + result = handle(transportApiRequestMsg.getSnmpDevicesRequestMsg()); | ||
183 | + } else if (transportApiRequestMsg.hasDeviceRequestMsg()) { | ||
184 | + result = handle(transportApiRequestMsg.getDeviceRequestMsg()); | ||
185 | + } else if (transportApiRequestMsg.hasDeviceCredentialsRequestMsg()) { | ||
186 | + result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg()); | ||
180 | } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) { | 187 | } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) { |
181 | - return Futures.transform(handle(transportApiRequestMsg.getFirmwareRequestMsg()), | ||
182 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 188 | + result = handle(transportApiRequestMsg.getFirmwareRequestMsg()); |
183 | } | 189 | } |
184 | - return Futures.transform(getEmptyTransportApiResponseFuture(), | ||
185 | - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); | 190 | + |
191 | + return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture), | ||
192 | + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), | ||
193 | + MoreExecutors.directExecutor()); | ||
186 | } | 194 | } |
187 | 195 | ||
188 | private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { | 196 | private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { |
@@ -376,6 +384,39 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -376,6 +384,39 @@ public class DefaultTransportApiService implements TransportApiService { | ||
376 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build()); | 384 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build()); |
377 | } | 385 | } |
378 | 386 | ||
387 | + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceRequestMsg requestMsg) { | ||
388 | + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); | ||
389 | + Device device = deviceService.findDeviceById(TenantId.SYS_TENANT_ID, deviceId); | ||
390 | + | ||
391 | + TransportApiResponseMsg responseMsg; | ||
392 | + if (device != null) { | ||
393 | + UUID deviceProfileId = device.getDeviceProfileId().getId(); | ||
394 | + responseMsg = TransportApiResponseMsg.newBuilder() | ||
395 | + .setDeviceResponseMsg(TransportProtos.GetDeviceResponseMsg.newBuilder() | ||
396 | + .setDeviceProfileIdMSB(deviceProfileId.getMostSignificantBits()) | ||
397 | + .setDeviceProfileIdLSB(deviceProfileId.getLeastSignificantBits()) | ||
398 | + .setDeviceTransportConfiguration(ByteString.copyFrom( | ||
399 | + dataDecodingEncodingService.encode(device.getDeviceData().getTransportConfiguration()) | ||
400 | + ))) | ||
401 | + .build(); | ||
402 | + } else { | ||
403 | + responseMsg = TransportApiResponseMsg.getDefaultInstance(); | ||
404 | + } | ||
405 | + | ||
406 | + return Futures.immediateFuture(responseMsg); | ||
407 | + } | ||
408 | + | ||
409 | + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceCredentialsRequestMsg requestMsg) { | ||
410 | + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB())); | ||
411 | + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, deviceId); | ||
412 | + | ||
413 | + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() | ||
414 | + .setDeviceCredentialsResponseMsg(TransportProtos.GetDeviceCredentialsResponseMsg.newBuilder() | ||
415 | + .setDeviceCredentialsData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceCredentials)))) | ||
416 | + .build()); | ||
417 | + } | ||
418 | + | ||
419 | + | ||
379 | private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) { | 420 | private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) { |
380 | TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); | 421 | TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); |
381 | ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType()); | 422 | ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType()); |
@@ -394,6 +435,22 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -394,6 +435,22 @@ public class DefaultTransportApiService implements TransportApiService { | ||
394 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourceResponseMsg(builder).build()); | 435 | return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourceResponseMsg(builder).build()); |
395 | } | 436 | } |
396 | 437 | ||
438 | + private ListenableFuture<TransportApiResponseMsg> handle(GetSnmpDevicesRequestMsg requestMsg) { | ||
439 | + PageLink pageLink = new PageLink(requestMsg.getPageSize(), requestMsg.getPage()); | ||
440 | + PageData<UUID> result = deviceService.findDevicesIdsByDeviceProfileTransportType(DeviceTransportType.SNMP, pageLink); | ||
441 | + | ||
442 | + GetSnmpDevicesResponseMsg responseMsg = GetSnmpDevicesResponseMsg.newBuilder() | ||
443 | + .addAllIds(result.getData().stream() | ||
444 | + .map(UUID::toString) | ||
445 | + .collect(Collectors.toList())) | ||
446 | + .setHasNextPage(result.hasNext()) | ||
447 | + .build(); | ||
448 | + | ||
449 | + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder() | ||
450 | + .setSnmpDevicesResponseMsg(responseMsg) | ||
451 | + .build()); | ||
452 | + } | ||
453 | + | ||
397 | private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { | 454 | private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { |
398 | return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { | 455 | return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { |
399 | if (device == null) { | 456 | if (device == null) { |
@@ -21,6 +21,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | @@ -21,6 +21,7 @@ import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
21 | import org.springframework.context.event.EventListener; | 21 | import org.springframework.context.event.EventListener; |
22 | import org.springframework.core.annotation.Order; | 22 | import org.springframework.core.annotation.Order; |
23 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
24 | +import org.thingsboard.common.util.ThingsBoardExecutors; | ||
24 | import org.thingsboard.server.common.stats.MessagesStats; | 25 | import org.thingsboard.server.common.stats.MessagesStats; |
25 | import org.thingsboard.server.common.stats.StatsFactory; | 26 | import org.thingsboard.server.common.stats.StatsFactory; |
26 | import org.thingsboard.server.common.stats.StatsType; | 27 | import org.thingsboard.server.common.stats.StatsType; |
@@ -70,7 +71,7 @@ public class TbCoreTransportApiService { | @@ -70,7 +71,7 @@ public class TbCoreTransportApiService { | ||
70 | 71 | ||
71 | @PostConstruct | 72 | @PostConstruct |
72 | public void init() { | 73 | public void init() { |
73 | - this.transportCallbackExecutor = Executors.newWorkStealingPool(maxCallbackThreads); | 74 | + this.transportCallbackExecutor = ThingsBoardExecutors.newWorkStealingPool(maxCallbackThreads, getClass()); |
74 | TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = tbCoreQueueFactory.createTransportApiResponseProducer(); | 75 | TbQueueProducer<TbProtoQueueMsg<TransportApiResponseMsg>> producer = tbCoreQueueFactory.createTransportApiResponseProducer(); |
75 | TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = tbCoreQueueFactory.createTransportApiRequestConsumer(); | 76 | TbQueueConsumer<TbProtoQueueMsg<TransportApiRequestMsg>> consumer = tbCoreQueueFactory.createTransportApiRequestConsumer(); |
76 | 77 |
@@ -26,6 +26,7 @@ | @@ -26,6 +26,7 @@ | ||
26 | </appender> | 26 | </appender> |
27 | 27 | ||
28 | <logger name="org.thingsboard.server" level="INFO" /> | 28 | <logger name="org.thingsboard.server" level="INFO" /> |
29 | + <logger name="org.thingsboard.server.transport.snmp" level="TRACE" /> | ||
29 | 30 | ||
30 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> | 31 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> |
31 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> | 32 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> |
@@ -621,9 +621,9 @@ transport: | @@ -621,9 +621,9 @@ transport: | ||
621 | key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" | 621 | key_password: "${COAP_DTLS_KEY_PASSWORD:server_key_password}" |
622 | # Key alias | 622 | # Key alias |
623 | key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" | 623 | key_alias: "${COAP_DTLS_KEY_ALIAS:serveralias}" |
624 | - # Skip certificate validity check for client certificates. | ||
625 | - skip_validity_check_for_client_cert: "${COAP_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | ||
626 | x509: | 624 | x509: |
625 | + # Skip certificate validity check for client certificates. | ||
626 | + skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" | ||
627 | dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" | 627 | dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" |
628 | dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" | 628 | dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" |
629 | # Local LwM2M transport parameters | 629 | # Local LwM2M transport parameters |
@@ -686,6 +686,13 @@ transport: | @@ -686,6 +686,13 @@ transport: | ||
686 | alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}" | 686 | alias: "${LWM2M_KEYSTORE_ALIAS_BS:bootstrap}" |
687 | # Use redis for Security and Registration stores | 687 | # Use redis for Security and Registration stores |
688 | redis.enabled: "${LWM2M_REDIS_ENABLED:false}" | 688 | redis.enabled: "${LWM2M_REDIS_ENABLED:false}" |
689 | + snmp: | ||
690 | + enabled: "${SNMP_ENABLED:true}" | ||
691 | + response_processing: | ||
692 | + # parallelism level for executor (workStealingPool) that is responsible for handling responses from SNMP devices | ||
693 | + parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}" | ||
694 | + # to configure SNMP to work over UDP or TCP | ||
695 | + underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}" | ||
689 | 696 | ||
690 | # Edges parameters | 697 | # Edges parameters |
691 | edges: | 698 | edges: |
@@ -16,10 +16,10 @@ | @@ -16,10 +16,10 @@ | ||
16 | package org.thingsboard.server.service.queue; | 16 | package org.thingsboard.server.service.queue; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.junit.After; | ||
19 | import org.junit.Assert; | 20 | import org.junit.Assert; |
20 | import org.junit.Test; | 21 | import org.junit.Test; |
21 | import org.junit.runner.RunWith; | 22 | import org.junit.runner.RunWith; |
22 | -import org.mockito.Mockito; | ||
23 | import org.mockito.junit.MockitoJUnitRunner; | 23 | import org.mockito.junit.MockitoJUnitRunner; |
24 | import org.thingsboard.server.gen.transport.TransportProtos; | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 25 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
@@ -28,39 +28,74 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrateg | @@ -28,39 +28,74 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrateg | ||
28 | import java.util.UUID; | 28 | import java.util.UUID; |
29 | import java.util.concurrent.ConcurrentHashMap; | 29 | import java.util.concurrent.ConcurrentHashMap; |
30 | import java.util.concurrent.ConcurrentMap; | 30 | import java.util.concurrent.ConcurrentMap; |
31 | +import java.util.concurrent.CountDownLatch; | ||
31 | import java.util.concurrent.ExecutorService; | 32 | import java.util.concurrent.ExecutorService; |
32 | import java.util.concurrent.Executors; | 33 | import java.util.concurrent.Executors; |
33 | import java.util.concurrent.TimeUnit; | 34 | import java.util.concurrent.TimeUnit; |
34 | 35 | ||
36 | +import static org.junit.Assert.assertTrue; | ||
37 | +import static org.mockito.ArgumentMatchers.any; | ||
35 | import static org.mockito.Mockito.mock; | 38 | import static org.mockito.Mockito.mock; |
39 | +import static org.mockito.Mockito.times; | ||
40 | +import static org.mockito.Mockito.verify; | ||
36 | import static org.mockito.Mockito.when; | 41 | import static org.mockito.Mockito.when; |
37 | 42 | ||
38 | @Slf4j | 43 | @Slf4j |
39 | @RunWith(MockitoJUnitRunner.class) | 44 | @RunWith(MockitoJUnitRunner.class) |
40 | public class TbMsgPackProcessingContextTest { | 45 | public class TbMsgPackProcessingContextTest { |
41 | 46 | ||
47 | + public static final int TIMEOUT = 10; | ||
48 | + ExecutorService executorService; | ||
49 | + | ||
50 | + @After | ||
51 | + public void tearDown() { | ||
52 | + if (executorService != null) { | ||
53 | + executorService.shutdownNow(); | ||
54 | + } | ||
55 | + } | ||
56 | + | ||
42 | @Test | 57 | @Test |
43 | public void testHighConcurrencyCase() throws InterruptedException { | 58 | public void testHighConcurrencyCase() throws InterruptedException { |
44 | - TbRuleEngineSubmitStrategy strategyMock = mock(TbRuleEngineSubmitStrategy.class); | 59 | + //log.warn("preparing the test..."); |
45 | int msgCount = 1000; | 60 | int msgCount = 1000; |
46 | int parallelCount = 5; | 61 | int parallelCount = 5; |
47 | - ExecutorService executorService = Executors.newFixedThreadPool(parallelCount); | ||
48 | - try { | ||
49 | - ConcurrentMap<UUID, TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> messages = new ConcurrentHashMap<>(); | ||
50 | - for (int i = 0; i < msgCount; i++) { | ||
51 | - messages.put(UUID.randomUUID(), new TbProtoQueueMsg<>(UUID.randomUUID(), null)); | ||
52 | - } | ||
53 | - when(strategyMock.getPendingMap()).thenReturn(messages); | ||
54 | - TbMsgPackProcessingContext context = new TbMsgPackProcessingContext("Main", strategyMock); | ||
55 | - for (UUID uuid : messages.keySet()) { | ||
56 | - for (int i = 0; i < parallelCount; i++) { | ||
57 | - executorService.submit(() -> context.onSuccess(uuid)); | ||
58 | - } | 62 | + executorService = Executors.newFixedThreadPool(parallelCount); |
63 | + | ||
64 | + ConcurrentMap<UUID, TbProtoQueueMsg<TransportProtos.ToRuleEngineMsg>> messages = new ConcurrentHashMap<>(msgCount); | ||
65 | + for (int i = 0; i < msgCount; i++) { | ||
66 | + messages.put(UUID.randomUUID(), new TbProtoQueueMsg<>(UUID.randomUUID(), null)); | ||
67 | + } | ||
68 | + TbRuleEngineSubmitStrategy strategyMock = mock(TbRuleEngineSubmitStrategy.class); | ||
69 | + when(strategyMock.getPendingMap()).thenReturn(messages); | ||
70 | + | ||
71 | + TbMsgPackProcessingContext context = new TbMsgPackProcessingContext("Main", strategyMock); | ||
72 | + for (UUID uuid : messages.keySet()) { | ||
73 | + final CountDownLatch readyLatch = new CountDownLatch(parallelCount); | ||
74 | + final CountDownLatch startLatch = new CountDownLatch(1); | ||
75 | + final CountDownLatch finishLatch = new CountDownLatch(parallelCount); | ||
76 | + for (int i = 0; i < parallelCount; i++) { | ||
77 | + //final String taskName = "" + uuid + " " + i; | ||
78 | + executorService.submit(() -> { | ||
79 | + //log.warn("ready {}", taskName); | ||
80 | + readyLatch.countDown(); | ||
81 | + try { | ||
82 | + startLatch.await(); | ||
83 | + } catch (InterruptedException e) { | ||
84 | + Assert.fail("failed to await"); | ||
85 | + } | ||
86 | + //log.warn("go {}", taskName); | ||
87 | + | ||
88 | + context.onSuccess(uuid); | ||
89 | + | ||
90 | + finishLatch.countDown(); | ||
91 | + }); | ||
59 | } | 92 | } |
60 | - Assert.assertTrue(context.await(10, TimeUnit.SECONDS)); | ||
61 | - Mockito.verify(strategyMock, Mockito.times(msgCount)).onSuccess(Mockito.any(UUID.class)); | ||
62 | - } finally { | ||
63 | - executorService.shutdownNow(); | 93 | + assertTrue(readyLatch.await(TIMEOUT, TimeUnit.SECONDS)); |
94 | + Thread.yield(); | ||
95 | + startLatch.countDown(); //run all-at-once submitted tasks | ||
96 | + assertTrue(finishLatch.await(TIMEOUT, TimeUnit.SECONDS)); | ||
64 | } | 97 | } |
98 | + assertTrue(context.await(TIMEOUT, TimeUnit.SECONDS)); | ||
99 | + verify(strategyMock, times(msgCount)).onSuccess(any(UUID.class)); | ||
65 | } | 100 | } |
66 | } | 101 | } |
@@ -19,11 +19,10 @@ import lombok.Getter; | @@ -19,11 +19,10 @@ import lombok.Getter; | ||
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | import org.springframework.beans.factory.annotation.Autowired; | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | import org.springframework.beans.factory.annotation.Value; | 21 | import org.springframework.beans.factory.annotation.Value; |
22 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
23 | import org.springframework.stereotype.Component; | 22 | import org.springframework.stereotype.Component; |
24 | 23 | ||
25 | @Slf4j | 24 | @Slf4j |
26 | -@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") | 25 | +@TbCoapServerComponent |
27 | @Component | 26 | @Component |
28 | public class CoapServerContext { | 27 | public class CoapServerContext { |
29 | 28 |
@@ -23,7 +23,6 @@ import org.eclipse.californium.core.server.resources.Resource; | @@ -23,7 +23,6 @@ import org.eclipse.californium.core.server.resources.Resource; | ||
23 | import org.eclipse.californium.scandium.DTLSConnector; | 23 | import org.eclipse.californium.scandium.DTLSConnector; |
24 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; | 24 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
25 | import org.springframework.beans.factory.annotation.Autowired; | 25 | import org.springframework.beans.factory.annotation.Autowired; |
26 | -import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
27 | import org.springframework.stereotype.Component; | 26 | import org.springframework.stereotype.Component; |
28 | 27 | ||
29 | import javax.annotation.PostConstruct; | 28 | import javax.annotation.PostConstruct; |
@@ -39,7 +38,7 @@ import java.util.concurrent.TimeUnit; | @@ -39,7 +38,7 @@ import java.util.concurrent.TimeUnit; | ||
39 | 38 | ||
40 | @Slf4j | 39 | @Slf4j |
41 | @Component | 40 | @Component |
42 | -@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") | 41 | +@TbCoapServerComponent |
43 | public class DefaultCoapServerService implements CoapServerService { | 42 | public class DefaultCoapServerService implements CoapServerService { |
44 | 43 | ||
45 | @Autowired | 44 | @Autowired |
@@ -39,7 +39,6 @@ import java.util.Collections; | @@ -39,7 +39,6 @@ import java.util.Collections; | ||
39 | import java.util.Optional; | 39 | import java.util.Optional; |
40 | 40 | ||
41 | @Slf4j | 41 | @Slf4j |
42 | -@ConditionalOnExpression("'${transport.coap.enabled}'=='true'") | ||
43 | @ConditionalOnProperty(prefix = "transport.coap.dtls", value = "enabled", havingValue = "true", matchIfMissing = false) | 42 | @ConditionalOnProperty(prefix = "transport.coap.dtls", value = "enabled", havingValue = "true", matchIfMissing = false) |
44 | @Component | 43 | @Component |
45 | public class TbCoapDtlsSettings { | 44 | public class TbCoapDtlsSettings { |
@@ -50,7 +49,7 @@ public class TbCoapDtlsSettings { | @@ -50,7 +49,7 @@ public class TbCoapDtlsSettings { | ||
50 | @Value("${transport.coap.dtls.bind_port}") | 49 | @Value("${transport.coap.dtls.bind_port}") |
51 | private Integer port; | 50 | private Integer port; |
52 | 51 | ||
53 | - @Value("${transport.coap.dtls.mode}") | 52 | + @Value("${transport.coap.dtls.mode:NO_AUTH}") |
54 | private String mode; | 53 | private String mode; |
55 | 54 | ||
56 | @Value("${transport.coap.dtls.key_store}") | 55 | @Value("${transport.coap.dtls.key_store}") |
@@ -65,13 +64,13 @@ public class TbCoapDtlsSettings { | @@ -65,13 +64,13 @@ public class TbCoapDtlsSettings { | ||
65 | @Value("${transport.coap.dtls.key_alias}") | 64 | @Value("${transport.coap.dtls.key_alias}") |
66 | private String keyAlias; | 65 | private String keyAlias; |
67 | 66 | ||
68 | - @Value("${transport.coap.dtls.skip_validity_check_for_client_cert}") | 67 | + @Value("${transport.coap.dtls.x509.skip_validity_check_for_client_cert:false}") |
69 | private boolean skipValidityCheckForClientCert; | 68 | private boolean skipValidityCheckForClientCert; |
70 | 69 | ||
71 | - @Value("${transport.coap.dtls.x509.dtls_session_inactivity_timeout}") | 70 | + @Value("${transport.coap.dtls.x509.dtls_session_inactivity_timeout:86400000}") |
72 | private long dtlsSessionInactivityTimeout; | 71 | private long dtlsSessionInactivityTimeout; |
73 | 72 | ||
74 | - @Value("${transport.coap.dtls.x509.dtls_session_report_timeout}") | 73 | + @Value("${transport.coap.dtls.x509.dtls_session_report_timeout:1800000}") |
75 | private long dtlsSessionReportTimeout; | 74 | private long dtlsSessionReportTimeout; |
76 | 75 | ||
77 | @Autowired | 76 | @Autowired |
common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerComponent.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.coapserver; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | + | ||
20 | +import java.lang.annotation.Retention; | ||
21 | +import java.lang.annotation.RetentionPolicy; | ||
22 | + | ||
23 | +@Retention(RetentionPolicy.RUNTIME) | ||
24 | +@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") | ||
25 | +public @interface TbCoapServerComponent { | ||
26 | +} |
@@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; | @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.ListenableFuture; | ||
19 | import org.thingsboard.server.common.data.Device; | 19 | import org.thingsboard.server.common.data.Device; |
20 | import org.thingsboard.server.common.data.DeviceInfo; | 20 | import org.thingsboard.server.common.data.DeviceInfo; |
21 | import org.thingsboard.server.common.data.DeviceProfile; | 21 | import org.thingsboard.server.common.data.DeviceProfile; |
22 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
22 | import org.thingsboard.server.common.data.EntitySubtype; | 23 | import org.thingsboard.server.common.data.EntitySubtype; |
23 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; | 24 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
24 | import org.thingsboard.server.common.data.id.CustomerId; | 25 | import org.thingsboard.server.common.data.id.CustomerId; |
@@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; | @@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; | ||
32 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; | 33 | import org.thingsboard.server.dao.device.provision.ProvisionRequest; |
33 | 34 | ||
34 | import java.util.List; | 35 | import java.util.List; |
36 | +import java.util.UUID; | ||
35 | 37 | ||
36 | public interface DeviceService { | 38 | public interface DeviceService { |
37 | 39 | ||
@@ -95,6 +97,8 @@ public interface DeviceService { | @@ -95,6 +97,8 @@ public interface DeviceService { | ||
95 | 97 | ||
96 | Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile); | 98 | Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile); |
97 | 99 | ||
100 | + PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink); | ||
101 | + | ||
98 | Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); | 102 | Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); |
99 | 103 | ||
100 | Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); | 104 | Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); |
@@ -87,6 +87,10 @@ | @@ -87,6 +87,10 @@ | ||
87 | <groupId>org.thingsboard</groupId> | 87 | <groupId>org.thingsboard</groupId> |
88 | <artifactId>protobuf-dynamic</artifactId> | 88 | <artifactId>protobuf-dynamic</artifactId> |
89 | </dependency> | 89 | </dependency> |
90 | + <dependency> | ||
91 | + <groupId>org.apache.commons</groupId> | ||
92 | + <artifactId>commons-lang3</artifactId> | ||
93 | + </dependency> | ||
90 | </dependencies> | 94 | </dependencies> |
91 | 95 | ||
92 | <build> | 96 | <build> |
@@ -93,6 +93,25 @@ public class DataConstants { | @@ -93,6 +93,25 @@ public class DataConstants { | ||
93 | public static final String USERNAME = "username"; | 93 | public static final String USERNAME = "username"; |
94 | public static final String PASSWORD = "password"; | 94 | public static final String PASSWORD = "password"; |
95 | 95 | ||
96 | +//<<<<<<< HEAD | ||
97 | +//======= | ||
98 | +// //firmware | ||
99 | +// //telemetry | ||
100 | +// public static final String CURRENT_FIRMWARE_TITLE = "current_fw_title"; | ||
101 | +// public static final String CURRENT_FIRMWARE_VERSION = "current_fw_version"; | ||
102 | +// public static final String TARGET_FIRMWARE_TITLE = "target_fw_title"; | ||
103 | +// public static final String TARGET_FIRMWARE_VERSION = "target_fw_version"; | ||
104 | +// public static final String TARGET_FIRMWARE_TS = "target_fw_ts"; | ||
105 | +// public static final String FIRMWARE_STATE = "fw_state"; | ||
106 | +// | ||
107 | +// //attributes | ||
108 | +// //telemetry | ||
109 | +// public static final String FIRMWARE_TITLE = "fw_title"; | ||
110 | +// public static final String FIRMWARE_VERSION = "fw_version"; | ||
111 | +// public static final String FIRMWARE_SIZE = "fw_size"; | ||
112 | +// public static final String FIRMWARE_CHECKSUM = "fw_checksum"; | ||
113 | +// public static final String FIRMWARE_CHECKSUM_ALGORITHM = "fw_checksum_algorithm"; | ||
114 | +//>>>>>>> origin/master | ||
96 | public static final String EDGE_MSG_SOURCE = "edge"; | 115 | public static final String EDGE_MSG_SOURCE = "edge"; |
97 | public static final String MSG_SOURCE_KEY = "source"; | 116 | public static final String MSG_SOURCE_KEY = "source"; |
98 | 117 |
@@ -18,6 +18,7 @@ package org.thingsboard.server.common.data; | @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data; | ||
18 | public enum DeviceTransportType { | 18 | public enum DeviceTransportType { |
19 | DEFAULT, | 19 | DEFAULT, |
20 | MQTT, | 20 | MQTT, |
21 | + COAP, | ||
21 | LWM2M, | 22 | LWM2M, |
22 | - COAP | 23 | + SNMP |
23 | } | 24 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data; | ||
17 | + | ||
18 | +public interface TbTransportService { | ||
19 | + String getName(); | ||
20 | +} |
@@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; | @@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
21 | import com.fasterxml.jackson.annotation.JsonTypeInfo; | 21 | import com.fasterxml.jackson.annotation.JsonTypeInfo; |
22 | import org.thingsboard.server.common.data.DeviceTransportType; | 22 | import org.thingsboard.server.common.data.DeviceTransportType; |
23 | 23 | ||
24 | +import java.io.Serializable; | ||
25 | + | ||
24 | @JsonIgnoreProperties(ignoreUnknown = true) | 26 | @JsonIgnoreProperties(ignoreUnknown = true) |
25 | @JsonTypeInfo( | 27 | @JsonTypeInfo( |
26 | use = JsonTypeInfo.Id.NAME, | 28 | use = JsonTypeInfo.Id.NAME, |
@@ -29,11 +31,14 @@ import org.thingsboard.server.common.data.DeviceTransportType; | @@ -29,11 +31,14 @@ import org.thingsboard.server.common.data.DeviceTransportType; | ||
29 | @JsonSubTypes({ | 31 | @JsonSubTypes({ |
30 | @JsonSubTypes.Type(value = DefaultDeviceTransportConfiguration.class, name = "DEFAULT"), | 32 | @JsonSubTypes.Type(value = DefaultDeviceTransportConfiguration.class, name = "DEFAULT"), |
31 | @JsonSubTypes.Type(value = MqttDeviceTransportConfiguration.class, name = "MQTT"), | 33 | @JsonSubTypes.Type(value = MqttDeviceTransportConfiguration.class, name = "MQTT"), |
34 | + @JsonSubTypes.Type(value = CoapDeviceTransportConfiguration.class, name = "COAP"), | ||
32 | @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"), | 35 | @JsonSubTypes.Type(value = Lwm2mDeviceTransportConfiguration.class, name = "LWM2M"), |
33 | - @JsonSubTypes.Type(value = CoapDeviceTransportConfiguration.class, name = "COAP")}) | ||
34 | -public interface DeviceTransportConfiguration { | ||
35 | - | 36 | + @JsonSubTypes.Type(value = SnmpDeviceTransportConfiguration.class, name = "SNMP")}) |
37 | +public interface DeviceTransportConfiguration extends Serializable { | ||
36 | @JsonIgnore | 38 | @JsonIgnore |
37 | DeviceTransportType getType(); | 39 | DeviceTransportType getType(); |
38 | 40 | ||
41 | + default void validate() { | ||
42 | + } | ||
43 | + | ||
39 | } | 44 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.device.data; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.Data; | ||
20 | +import lombok.ToString; | ||
21 | +import org.apache.commons.lang3.ObjectUtils; | ||
22 | +import org.apache.commons.lang3.StringUtils; | ||
23 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
24 | +import org.thingsboard.server.common.data.transport.snmp.AuthenticationProtocol; | ||
25 | +import org.thingsboard.server.common.data.transport.snmp.PrivacyProtocol; | ||
26 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | ||
27 | + | ||
28 | +import java.util.Objects; | ||
29 | + | ||
30 | +@Data | ||
31 | +@ToString(of = {"host", "port", "protocolVersion"}) | ||
32 | +public class SnmpDeviceTransportConfiguration implements DeviceTransportConfiguration { | ||
33 | + private String host; | ||
34 | + private Integer port; | ||
35 | + private SnmpProtocolVersion protocolVersion; | ||
36 | + | ||
37 | + /* | ||
38 | + * For SNMP v1 and v2c | ||
39 | + * */ | ||
40 | + private String community; | ||
41 | + | ||
42 | + /* | ||
43 | + * For SNMP v3 | ||
44 | + * */ | ||
45 | + private String username; | ||
46 | + private String securityName; | ||
47 | + private String contextName; | ||
48 | + private AuthenticationProtocol authenticationProtocol; | ||
49 | + private String authenticationPassphrase; | ||
50 | + private PrivacyProtocol privacyProtocol; | ||
51 | + private String privacyPassphrase; | ||
52 | + private String engineId; | ||
53 | + | ||
54 | + @Override | ||
55 | + public DeviceTransportType getType() { | ||
56 | + return DeviceTransportType.SNMP; | ||
57 | + } | ||
58 | + | ||
59 | + @Override | ||
60 | + public void validate() { | ||
61 | + if (!isValid()) { | ||
62 | + throw new IllegalArgumentException("Transport configuration is not valid"); | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + @JsonIgnore | ||
67 | + private boolean isValid() { | ||
68 | + boolean isValid = StringUtils.isNotBlank(host) && port != null && protocolVersion != null; | ||
69 | + if (isValid) { | ||
70 | + switch (protocolVersion) { | ||
71 | + case V1: | ||
72 | + case V2C: | ||
73 | + isValid = StringUtils.isNotEmpty(community); | ||
74 | + break; | ||
75 | + case V3: | ||
76 | + isValid = StringUtils.isNotBlank(username) && StringUtils.isNotBlank(securityName) | ||
77 | + && contextName != null && authenticationProtocol != null | ||
78 | + && StringUtils.isNotBlank(authenticationPassphrase) | ||
79 | + && privacyProtocol != null && privacyPassphrase != null && engineId != null; | ||
80 | + break; | ||
81 | + } | ||
82 | + } | ||
83 | + return isValid; | ||
84 | + } | ||
85 | +} |
@@ -29,13 +29,18 @@ import java.io.Serializable; | @@ -29,13 +29,18 @@ import java.io.Serializable; | ||
29 | include = JsonTypeInfo.As.PROPERTY, | 29 | include = JsonTypeInfo.As.PROPERTY, |
30 | property = "type") | 30 | property = "type") |
31 | @JsonSubTypes({ | 31 | @JsonSubTypes({ |
32 | - @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), | ||
33 | - @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), | ||
34 | - @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M"), | ||
35 | - @JsonSubTypes.Type(value = CoapDeviceProfileTransportConfiguration.class, name = "COAP")}) | 32 | + @JsonSubTypes.Type(value = DefaultDeviceProfileTransportConfiguration.class, name = "DEFAULT"), |
33 | + @JsonSubTypes.Type(value = MqttDeviceProfileTransportConfiguration.class, name = "MQTT"), | ||
34 | + @JsonSubTypes.Type(value = Lwm2mDeviceProfileTransportConfiguration.class, name = "LWM2M"), | ||
35 | + @JsonSubTypes.Type(value = CoapDeviceProfileTransportConfiguration.class, name = "COAP"), | ||
36 | + @JsonSubTypes.Type(value = SnmpDeviceProfileTransportConfiguration.class, name = "SNMP") | ||
37 | +}) | ||
36 | public interface DeviceProfileTransportConfiguration extends Serializable { | 38 | public interface DeviceProfileTransportConfiguration extends Serializable { |
37 | 39 | ||
38 | @JsonIgnore | 40 | @JsonIgnore |
39 | DeviceTransportType getType(); | 41 | DeviceTransportType getType(); |
40 | 42 | ||
43 | + default void validate() { | ||
44 | + } | ||
45 | + | ||
41 | } | 46 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.device.profile; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.Data; | ||
20 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
21 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | ||
22 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | ||
23 | + | ||
24 | +import java.util.List; | ||
25 | + | ||
26 | +@Data | ||
27 | +public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { | ||
28 | + private Integer timeoutMs; | ||
29 | + private Integer retries; | ||
30 | + private List<SnmpCommunicationConfig> communicationConfigs; | ||
31 | + | ||
32 | + @Override | ||
33 | + public DeviceTransportType getType() { | ||
34 | + return DeviceTransportType.SNMP; | ||
35 | + } | ||
36 | + | ||
37 | + @Override | ||
38 | + public void validate() { | ||
39 | + if (!isValid()) { | ||
40 | + throw new IllegalArgumentException("SNMP transport configuration is not valid"); | ||
41 | + } | ||
42 | + } | ||
43 | + | ||
44 | + @JsonIgnore | ||
45 | + private boolean isValid() { | ||
46 | + return timeoutMs != null && timeoutMs >= 0 && retries != null && retries >= 0 | ||
47 | + && communicationConfigs != null | ||
48 | + && communicationConfigs.stream().allMatch(config -> config != null && config.isValid()) | ||
49 | + && communicationConfigs.stream().flatMap(config -> config.getAllMappings().stream()).map(SnmpMapping::getOid) | ||
50 | + .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getAllMappings().size()).sum(); | ||
51 | + } | ||
52 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +import java.util.Arrays; | ||
19 | +import java.util.Optional; | ||
20 | + | ||
21 | +public enum AuthenticationProtocol { | ||
22 | + SHA_1("1.3.6.1.6.3.10.1.1.3"), | ||
23 | + SHA_224("1.3.6.1.6.3.10.1.1.4"), | ||
24 | + SHA_256("1.3.6.1.6.3.10.1.1.5"), | ||
25 | + SHA_384("1.3.6.1.6.3.10.1.1.6"), | ||
26 | + SHA_512("1.3.6.1.6.3.10.1.1.7"), | ||
27 | + MD5("1.3.6.1.6.3.10.1.1.2"); | ||
28 | + | ||
29 | + // oids taken from org.snmp4j.security.SecurityProtocol implementations | ||
30 | + private final String oid; | ||
31 | + | ||
32 | + AuthenticationProtocol(String oid) { | ||
33 | + this.oid = oid; | ||
34 | + } | ||
35 | + | ||
36 | + public String getOid() { | ||
37 | + return oid; | ||
38 | + } | ||
39 | + | ||
40 | + public static Optional<AuthenticationProtocol> forName(String name) { | ||
41 | + return Arrays.stream(values()) | ||
42 | + .filter(protocol -> protocol.name().equalsIgnoreCase(name)) | ||
43 | + .findFirst(); | ||
44 | + } | ||
45 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/PrivacyProtocol.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +import java.util.Arrays; | ||
19 | +import java.util.Optional; | ||
20 | + | ||
21 | +public enum PrivacyProtocol { | ||
22 | + DES("1.3.6.1.6.3.10.1.2.2"), | ||
23 | + AES_128("1.3.6.1.6.3.10.1.2.4"), | ||
24 | + AES_192("1.3.6.1.4.1.4976.2.2.1.1.1"), | ||
25 | + AES_256("1.3.6.1.4.1.4976.2.2.1.1.2"); | ||
26 | + | ||
27 | + // oids taken from org.snmp4j.security.SecurityProtocol implementations | ||
28 | + private final String oid; | ||
29 | + | ||
30 | + PrivacyProtocol(String oid) { | ||
31 | + this.oid = oid; | ||
32 | + } | ||
33 | + | ||
34 | + public String getOid() { | ||
35 | + return oid; | ||
36 | + } | ||
37 | + | ||
38 | + public static Optional<PrivacyProtocol> forName(String name) { | ||
39 | + return Arrays.stream(values()) | ||
40 | + .filter(protocol -> protocol.name().equalsIgnoreCase(name)) | ||
41 | + .findFirst(); | ||
42 | + } | ||
43 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +public enum SnmpCommunicationSpec { | ||
19 | + TELEMETRY_QUERYING, | ||
20 | + | ||
21 | + CLIENT_ATTRIBUTES_QUERYING, | ||
22 | + SHARED_ATTRIBUTES_SETTING, | ||
23 | + | ||
24 | + TO_DEVICE_RPC_REQUEST, | ||
25 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import lombok.AllArgsConstructor; | ||
20 | +import lombok.Data; | ||
21 | +import lombok.NoArgsConstructor; | ||
22 | +import org.apache.commons.lang3.StringUtils; | ||
23 | +import org.thingsboard.server.common.data.kv.DataType; | ||
24 | + | ||
25 | +import java.util.regex.Pattern; | ||
26 | + | ||
27 | +@Data | ||
28 | +@AllArgsConstructor | ||
29 | +@NoArgsConstructor | ||
30 | +public class SnmpMapping { | ||
31 | + private String oid; | ||
32 | + private String key; | ||
33 | + private DataType dataType; | ||
34 | + | ||
35 | + private static final Pattern OID_PATTERN = Pattern.compile("^\\.?([0-2])((\\.0)|(\\.[1-9][0-9]*))*$"); | ||
36 | + | ||
37 | + @JsonIgnore | ||
38 | + public boolean isValid() { | ||
39 | + return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && StringUtils.isNotBlank(key); | ||
40 | + } | ||
41 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMethod.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +public enum SnmpMethod { | ||
19 | + GET(-96), | ||
20 | + SET(-93); | ||
21 | + | ||
22 | + // codes taken from org.snmp4j.PDU class | ||
23 | + private final int code; | ||
24 | + | ||
25 | + SnmpMethod(int code) { | ||
26 | + this.code = code; | ||
27 | + } | ||
28 | + | ||
29 | + public int getCode() { | ||
30 | + return code; | ||
31 | + } | ||
32 | +} |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpProtocolVersion.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp; | ||
17 | + | ||
18 | +public enum SnmpProtocolVersion { | ||
19 | + V1(0), | ||
20 | + V2C(1), | ||
21 | + V3(3); | ||
22 | + | ||
23 | + private final int code; | ||
24 | + | ||
25 | + SnmpProtocolVersion(int code) { | ||
26 | + this.code = code; | ||
27 | + } | ||
28 | + | ||
29 | + public int getCode() { | ||
30 | + return code; | ||
31 | + } | ||
32 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | ||
20 | + | ||
21 | +import java.util.List; | ||
22 | + | ||
23 | +@Data | ||
24 | +public abstract class MultipleMappingsSnmpCommunicationConfig implements SnmpCommunicationConfig { | ||
25 | + protected List<SnmpMapping> mappings; | ||
26 | + | ||
27 | + @Override | ||
28 | + public boolean isValid() { | ||
29 | + return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid()); | ||
30 | + } | ||
31 | + | ||
32 | + @Override | ||
33 | + public List<SnmpMapping> getAllMappings() { | ||
34 | + return mappings; | ||
35 | + } | ||
36 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.EqualsAndHashCode; | ||
20 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | ||
21 | + | ||
22 | +@EqualsAndHashCode(callSuper = true) | ||
23 | +@Data | ||
24 | +public abstract class RepeatingQueryingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | ||
25 | + private Long queryingFrequencyMs; | ||
26 | + | ||
27 | + @Override | ||
28 | + public SnmpMethod getMethod() { | ||
29 | + return SnmpMethod.GET; | ||
30 | + } | ||
31 | + | ||
32 | + @Override | ||
33 | + public boolean isValid() { | ||
34 | + return queryingFrequencyMs != null && queryingFrequencyMs > 0 && super.isValid(); | ||
35 | + } | ||
36 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.annotation.JsonIgnore; | ||
19 | +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | ||
20 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
21 | +import com.fasterxml.jackson.annotation.JsonSubTypes.Type; | ||
22 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
23 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
24 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | ||
25 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | ||
26 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.ClientAttributesQueryingSnmpCommunicationConfig; | ||
27 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.SharedAttributesSettingSnmpCommunicationConfig; | ||
28 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.TelemetryQueryingSnmpCommunicationConfig; | ||
29 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.ToDeviceRpcRequestSnmpCommunicationConfig; | ||
30 | + | ||
31 | +import java.util.List; | ||
32 | + | ||
33 | +@JsonIgnoreProperties(ignoreUnknown = true) | ||
34 | +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "spec") | ||
35 | +@JsonSubTypes({ | ||
36 | + @Type(value = TelemetryQueryingSnmpCommunicationConfig.class, name = "TELEMETRY_QUERYING"), | ||
37 | + @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"), | ||
38 | + @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING"), | ||
39 | + @Type(value = ToDeviceRpcRequestSnmpCommunicationConfig.class, name = "TO_DEVICE_RPC_REQUEST") | ||
40 | +}) | ||
41 | +public interface SnmpCommunicationConfig { | ||
42 | + | ||
43 | + SnmpCommunicationSpec getSpec(); | ||
44 | + | ||
45 | + @JsonIgnore | ||
46 | + default SnmpMethod getMethod() { | ||
47 | + return null; | ||
48 | + } | ||
49 | + | ||
50 | + @JsonIgnore | ||
51 | + List<SnmpMapping> getAllMappings(); | ||
52 | + | ||
53 | + @JsonIgnore | ||
54 | + boolean isValid(); | ||
55 | + | ||
56 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
19 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | ||
20 | + | ||
21 | +public class ClientAttributesQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { | ||
22 | + | ||
23 | + @Override | ||
24 | + public SnmpCommunicationSpec getSpec() { | ||
25 | + return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING; | ||
26 | + } | ||
27 | + | ||
28 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
19 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | ||
20 | +import org.thingsboard.server.common.data.transport.snmp.config.MultipleMappingsSnmpCommunicationConfig; | ||
21 | + | ||
22 | +public class SharedAttributesSettingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | ||
23 | + | ||
24 | + @Override | ||
25 | + public SnmpCommunicationSpec getSpec() { | ||
26 | + return SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING; | ||
27 | + } | ||
28 | + | ||
29 | + @Override | ||
30 | + public SnmpMethod getMethod() { | ||
31 | + return SnmpMethod.SET; | ||
32 | + } | ||
33 | + | ||
34 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | +import lombok.EqualsAndHashCode; | ||
20 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
21 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | ||
22 | + | ||
23 | +@EqualsAndHashCode(callSuper = true) | ||
24 | +@Data | ||
25 | +public class TelemetryQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { | ||
26 | + | ||
27 | + @Override | ||
28 | + public SnmpCommunicationSpec getSpec() { | ||
29 | + return SnmpCommunicationSpec.TELEMETRY_QUERYING; | ||
30 | + } | ||
31 | + | ||
32 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | ||
17 | + | ||
18 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
19 | +import org.thingsboard.server.common.data.transport.snmp.config.MultipleMappingsSnmpCommunicationConfig; | ||
20 | + | ||
21 | +public class ToDeviceRpcRequestSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | ||
22 | + @Override | ||
23 | + public SnmpCommunicationSpec getSpec() { | ||
24 | + return SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST; | ||
25 | + } | ||
26 | +} |
@@ -38,6 +38,7 @@ import static java.util.Collections.emptyList; | @@ -38,6 +38,7 @@ import static java.util.Collections.emptyList; | ||
38 | @Slf4j | 38 | @Slf4j |
39 | public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> implements TbQueueConsumer<T> { | 39 | public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> implements TbQueueConsumer<T> { |
40 | 40 | ||
41 | + public static final long ONE_MILLISECOND_IN_NANOS = TimeUnit.MILLISECONDS.toNanos(1); | ||
41 | private volatile boolean subscribed; | 42 | private volatile boolean subscribed; |
42 | protected volatile boolean stopped = false; | 43 | protected volatile boolean stopped = false; |
43 | protected volatile Set<TopicPartitionInfo> partitions; | 44 | protected volatile Set<TopicPartitionInfo> partitions; |
@@ -83,7 +84,7 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | @@ -83,7 +84,7 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | ||
83 | } | 84 | } |
84 | 85 | ||
85 | if (consumerLock.isLocked()) { | 86 | if (consumerLock.isLocked()) { |
86 | - log.error("poll. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock", new RuntimeException("stacktrace")); | 87 | + log.error("poll. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock topic " + topic, new RuntimeException("stacktrace")); |
87 | } | 88 | } |
88 | 89 | ||
89 | consumerLock.lock(); | 90 | consumerLock.lock(); |
@@ -131,9 +132,12 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | @@ -131,9 +132,12 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | ||
131 | List<T> sleepAndReturnEmpty(final long startNanos, final long durationInMillis) { | 132 | List<T> sleepAndReturnEmpty(final long startNanos, final long durationInMillis) { |
132 | long durationNanos = TimeUnit.MILLISECONDS.toNanos(durationInMillis); | 133 | long durationNanos = TimeUnit.MILLISECONDS.toNanos(durationInMillis); |
133 | long spentNanos = System.nanoTime() - startNanos; | 134 | long spentNanos = System.nanoTime() - startNanos; |
134 | - if (spentNanos < durationNanos) { | 135 | + long nanosLeft = durationNanos - spentNanos; |
136 | + if (nanosLeft >= ONE_MILLISECOND_IN_NANOS) { | ||
135 | try { | 137 | try { |
136 | - Thread.sleep(Math.max(TimeUnit.NANOSECONDS.toMillis(durationNanos - spentNanos), 1)); | 138 | + long sleepMs = TimeUnit.NANOSECONDS.toMillis(nanosLeft); |
139 | + log.trace("Going to sleep after poll: topic {} for {}ms", topic, sleepMs); | ||
140 | + Thread.sleep(sleepMs); | ||
137 | } catch (InterruptedException e) { | 141 | } catch (InterruptedException e) { |
138 | if (!stopped) { | 142 | if (!stopped) { |
139 | log.error("Failed to wait", e); | 143 | log.error("Failed to wait", e); |
@@ -146,7 +150,7 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | @@ -146,7 +150,7 @@ public abstract class AbstractTbQueueConsumerTemplate<R, T extends TbQueueMsg> i | ||
146 | @Override | 150 | @Override |
147 | public void commit() { | 151 | public void commit() { |
148 | if (consumerLock.isLocked()) { | 152 | if (consumerLock.isLocked()) { |
149 | - log.error("commit. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock", new RuntimeException("stacktrace")); | 153 | + log.error("commit. consumerLock is locked. will wait with no timeout. it looks like a race conditions or deadlock topic " + topic, new RuntimeException("stacktrace")); |
150 | } | 154 | } |
151 | consumerLock.lock(); | 155 | consumerLock.lock(); |
152 | try { | 156 | try { |
@@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture; | @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture; | ||
20 | import com.google.common.util.concurrent.SettableFuture; | 20 | import com.google.common.util.concurrent.SettableFuture; |
21 | import lombok.Builder; | 21 | import lombok.Builder; |
22 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
23 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
23 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 24 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
24 | import org.thingsboard.server.queue.TbQueueAdmin; | 25 | import org.thingsboard.server.queue.TbQueueAdmin; |
25 | import org.thingsboard.server.queue.TbQueueCallback; | 26 | import org.thingsboard.server.queue.TbQueueCallback; |
@@ -77,7 +78,7 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response | @@ -77,7 +78,7 @@ public class DefaultTbQueueRequestTemplate<Request extends TbQueueMsg, Response | ||
77 | this.executor = executor; | 78 | this.executor = executor; |
78 | } else { | 79 | } else { |
79 | internalExecutor = true; | 80 | internalExecutor = true; |
80 | - this.executor = Executors.newSingleThreadExecutor(); | 81 | + this.executor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-queue-request-template-" + responseTemplate.getTopic())); |
81 | } | 82 | } |
82 | } | 83 | } |
83 | 84 |
@@ -17,6 +17,7 @@ package org.thingsboard.server.queue.common; | @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.common; | ||
17 | 17 | ||
18 | import lombok.Builder; | 18 | import lombok.Builder; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
20 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
21 | import org.thingsboard.server.queue.TbQueueConsumer; | 22 | import org.thingsboard.server.queue.TbQueueConsumer; |
22 | import org.thingsboard.server.queue.TbQueueHandler; | 23 | import org.thingsboard.server.queue.TbQueueHandler; |
@@ -70,8 +71,8 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response | @@ -70,8 +71,8 @@ public class DefaultTbQueueResponseTemplate<Request extends TbQueueMsg, Response | ||
70 | this.requestTimeout = requestTimeout; | 71 | this.requestTimeout = requestTimeout; |
71 | this.callbackExecutor = executor; | 72 | this.callbackExecutor = executor; |
72 | this.stats = stats; | 73 | this.stats = stats; |
73 | - this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); | ||
74 | - this.loopExecutor = Executors.newSingleThreadExecutor(); | 74 | + this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-queue-response-template-timeout-" + requestTemplate.getTopic())); |
75 | + this.loopExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-queue-response-template-loop-" + requestTemplate.getTopic())); | ||
75 | } | 76 | } |
76 | 77 | ||
77 | @Override | 78 | @Override |
@@ -19,19 +19,23 @@ import lombok.Getter; | @@ -19,19 +19,23 @@ import lombok.Getter; | ||
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | import org.springframework.beans.factory.annotation.Autowired; | 20 | import org.springframework.beans.factory.annotation.Autowired; |
21 | import org.springframework.beans.factory.annotation.Value; | 21 | import org.springframework.beans.factory.annotation.Value; |
22 | +import org.springframework.context.ApplicationContext; | ||
22 | import org.springframework.stereotype.Component; | 23 | import org.springframework.stereotype.Component; |
23 | import org.springframework.util.StringUtils; | 24 | import org.springframework.util.StringUtils; |
25 | +import org.thingsboard.server.common.data.TbTransportService; | ||
24 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
25 | import org.thingsboard.server.common.msg.queue.ServiceType; | 27 | import org.thingsboard.server.common.msg.queue.ServiceType; |
26 | import org.thingsboard.server.gen.transport.TransportProtos; | 28 | import org.thingsboard.server.gen.transport.TransportProtos; |
27 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | 29 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; |
28 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; | 30 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
29 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; | 31 | import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; |
32 | +import org.thingsboard.server.queue.util.AfterContextReady; | ||
30 | 33 | ||
31 | import javax.annotation.PostConstruct; | 34 | import javax.annotation.PostConstruct; |
32 | import java.net.InetAddress; | 35 | import java.net.InetAddress; |
33 | import java.net.UnknownHostException; | 36 | import java.net.UnknownHostException; |
34 | import java.util.Arrays; | 37 | import java.util.Arrays; |
38 | +import java.util.Collection; | ||
35 | import java.util.Collections; | 39 | import java.util.Collections; |
36 | import java.util.List; | 40 | import java.util.List; |
37 | import java.util.Optional; | 41 | import java.util.Optional; |
@@ -56,6 +60,8 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { | @@ -56,6 +60,8 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { | ||
56 | 60 | ||
57 | @Autowired(required = false) | 61 | @Autowired(required = false) |
58 | private TbQueueRuleEngineSettings ruleEngineSettings; | 62 | private TbQueueRuleEngineSettings ruleEngineSettings; |
63 | + @Autowired | ||
64 | + private ApplicationContext applicationContext; | ||
59 | 65 | ||
60 | private List<ServiceType> serviceTypes; | 66 | private List<ServiceType> serviceTypes; |
61 | private ServiceInfo serviceInfo; | 67 | private ServiceInfo serviceInfo; |
@@ -102,6 +108,19 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { | @@ -102,6 +108,19 @@ public class DefaultTbServiceInfoProvider implements TbServiceInfoProvider { | ||
102 | serviceInfo = builder.build(); | 108 | serviceInfo = builder.build(); |
103 | } | 109 | } |
104 | 110 | ||
111 | + @AfterContextReady | ||
112 | + public void setTransports() { | ||
113 | + serviceInfo = ServiceInfo.newBuilder(serviceInfo) | ||
114 | + .addAllTransports(getTransportServices().stream() | ||
115 | + .map(TbTransportService::getName) | ||
116 | + .collect(Collectors.toSet())) | ||
117 | + .build(); | ||
118 | + } | ||
119 | + | ||
120 | + private Collection<TbTransportService> getTransportServices() { | ||
121 | + return applicationContext.getBeansOfType(TbTransportService.class).values(); | ||
122 | + } | ||
123 | + | ||
105 | @Override | 124 | @Override |
106 | public ServiceInfo getServiceInfo() { | 125 | public ServiceInfo getServiceInfo() { |
107 | return serviceInfo; | 126 | return serviceInfo; |
@@ -15,26 +15,27 @@ | @@ -15,26 +15,27 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.queue.discovery; | 16 | package org.thingsboard.server.queue.discovery; |
17 | 17 | ||
18 | -import com.google.common.hash.HashCode; | ||
19 | import com.google.common.hash.HashFunction; | 18 | import com.google.common.hash.HashFunction; |
19 | +import com.google.common.hash.Hasher; | ||
20 | import com.google.common.hash.Hashing; | 20 | import com.google.common.hash.Hashing; |
21 | -import lombok.Getter; | ||
22 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
23 | import org.springframework.beans.factory.annotation.Value; | 22 | import org.springframework.beans.factory.annotation.Value; |
24 | import org.springframework.context.ApplicationEventPublisher; | 23 | import org.springframework.context.ApplicationEventPublisher; |
25 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
26 | import org.thingsboard.server.common.data.id.EntityId; | 25 | import org.thingsboard.server.common.data.id.EntityId; |
27 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
28 | -import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | ||
29 | import org.thingsboard.server.common.msg.queue.ServiceQueue; | 27 | import org.thingsboard.server.common.msg.queue.ServiceQueue; |
28 | +import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | ||
30 | import org.thingsboard.server.common.msg.queue.ServiceType; | 29 | import org.thingsboard.server.common.msg.queue.ServiceType; |
31 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 30 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
32 | import org.thingsboard.server.gen.transport.TransportProtos; | 31 | import org.thingsboard.server.gen.transport.TransportProtos; |
33 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | 32 | import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; |
33 | +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent; | ||
34 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | ||
35 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | ||
34 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; | 36 | import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; |
35 | 37 | ||
36 | import javax.annotation.PostConstruct; | 38 | import javax.annotation.PostConstruct; |
37 | -import java.nio.charset.StandardCharsets; | ||
38 | import java.util.ArrayList; | 39 | import java.util.ArrayList; |
39 | import java.util.Collections; | 40 | import java.util.Collections; |
40 | import java.util.Comparator; | 41 | import java.util.Comparator; |
@@ -46,7 +47,6 @@ import java.util.Set; | @@ -46,7 +47,6 @@ import java.util.Set; | ||
46 | import java.util.UUID; | 47 | import java.util.UUID; |
47 | import java.util.concurrent.ConcurrentHashMap; | 48 | import java.util.concurrent.ConcurrentHashMap; |
48 | import java.util.concurrent.ConcurrentMap; | 49 | import java.util.concurrent.ConcurrentMap; |
49 | -import java.util.concurrent.ConcurrentNavigableMap; | ||
50 | import java.util.stream.Collectors; | 50 | import java.util.stream.Collectors; |
51 | 51 | ||
52 | @Service | 52 | @Service |
@@ -186,6 +186,8 @@ public class HashPartitionService implements PartitionService { | @@ -186,6 +186,8 @@ public class HashPartitionService implements PartitionService { | ||
186 | applicationEventPublisher.publishEvent(new ClusterTopologyChangeEvent(this, changes)); | 186 | applicationEventPublisher.publishEvent(new ClusterTopologyChangeEvent(this, changes)); |
187 | } | 187 | } |
188 | } | 188 | } |
189 | + | ||
190 | + applicationEventPublisher.publishEvent(new ServiceListChangedEvent(otherServices, currentService)); | ||
189 | } | 191 | } |
190 | 192 | ||
191 | @Override | 193 | @Override |
@@ -219,6 +221,14 @@ public class HashPartitionService implements PartitionService { | @@ -219,6 +221,14 @@ public class HashPartitionService implements PartitionService { | ||
219 | } | 221 | } |
220 | } | 222 | } |
221 | 223 | ||
224 | + @Override | ||
225 | + public int resolvePartitionIndex(UUID entityId, int partitions) { | ||
226 | + int hash = hashFunction.newHasher() | ||
227 | + .putLong(entityId.getMostSignificantBits()) | ||
228 | + .putLong(entityId.getLeastSignificantBits()).hash().asInt(); | ||
229 | + return Math.abs(hash % partitions); | ||
230 | + } | ||
231 | + | ||
222 | private Map<ServiceQueueKey, List<ServiceInfo>> getServiceKeyListMap(List<ServiceInfo> services) { | 232 | private Map<ServiceQueueKey, List<ServiceInfo>> getServiceKeyListMap(List<ServiceInfo> services) { |
223 | final Map<ServiceQueueKey, List<ServiceInfo>> currentMap = new HashMap<>(); | 233 | final Map<ServiceQueueKey, List<ServiceInfo>> currentMap = new HashMap<>(); |
224 | services.forEach(serviceInfo -> { | 234 | services.forEach(serviceInfo -> { |
@@ -20,9 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId; | @@ -20,9 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId; | ||
20 | import org.thingsboard.server.common.msg.queue.ServiceType; | 20 | import org.thingsboard.server.common.msg.queue.ServiceType; |
21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
22 | import org.thingsboard.server.gen.transport.TransportProtos; | 22 | import org.thingsboard.server.gen.transport.TransportProtos; |
23 | +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; | ||
23 | 24 | ||
24 | import java.util.List; | 25 | import java.util.List; |
25 | import java.util.Set; | 26 | import java.util.Set; |
27 | +import java.util.UUID; | ||
26 | 28 | ||
27 | /** | 29 | /** |
28 | * Once application is ready or cluster topology changes, this Service will produce {@link PartitionChangeEvent} | 30 | * Once application is ready or cluster topology changes, this Service will produce {@link PartitionChangeEvent} |
@@ -55,4 +57,6 @@ public interface PartitionService { | @@ -55,4 +57,6 @@ public interface PartitionService { | ||
55 | * @return | 57 | * @return |
56 | */ | 58 | */ |
57 | TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId); | 59 | TopicPartitionInfo getNotificationsTopic(ServiceType serviceType, String serviceId); |
60 | + | ||
61 | + int resolvePartitionIndex(UUID entityId, int partitions); | ||
58 | } | 62 | } |
@@ -17,6 +17,7 @@ package org.thingsboard.server.queue.discovery; | @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.discovery; | ||
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.context.ApplicationListener; | 19 | import org.springframework.context.ApplicationListener; |
20 | +import org.thingsboard.server.queue.discovery.event.TbApplicationEvent; | ||
20 | 21 | ||
21 | import java.util.concurrent.locks.Lock; | 22 | import java.util.concurrent.locks.Lock; |
22 | import java.util.concurrent.locks.ReentrantLock; | 23 | import java.util.concurrent.locks.ReentrantLock; |
@@ -33,12 +33,14 @@ import org.apache.zookeeper.KeeperException; | @@ -33,12 +33,14 @@ import org.apache.zookeeper.KeeperException; | ||
33 | import org.springframework.beans.factory.annotation.Value; | 33 | import org.springframework.beans.factory.annotation.Value; |
34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 34 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
35 | import org.springframework.boot.context.event.ApplicationReadyEvent; | 35 | import org.springframework.boot.context.event.ApplicationReadyEvent; |
36 | +import org.springframework.context.ApplicationEventPublisher; | ||
36 | import org.springframework.context.event.EventListener; | 37 | import org.springframework.context.event.EventListener; |
37 | import org.springframework.core.annotation.Order; | 38 | import org.springframework.core.annotation.Order; |
38 | import org.springframework.stereotype.Service; | 39 | import org.springframework.stereotype.Service; |
39 | import org.springframework.util.Assert; | 40 | import org.springframework.util.Assert; |
40 | import org.thingsboard.common.util.ThingsBoardThreadFactory; | 41 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
41 | import org.thingsboard.server.gen.transport.TransportProtos; | 42 | import org.thingsboard.server.gen.transport.TransportProtos; |
43 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | ||
42 | 44 | ||
43 | import javax.annotation.PostConstruct; | 45 | import javax.annotation.PostConstruct; |
44 | import javax.annotation.PreDestroy; | 46 | import javax.annotation.PreDestroy; |
@@ -77,7 +79,8 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi | @@ -77,7 +79,8 @@ public class ZkDiscoveryService implements DiscoveryService, PathChildrenCacheLi | ||
77 | 79 | ||
78 | private volatile boolean stopped = true; | 80 | private volatile boolean stopped = true; |
79 | 81 | ||
80 | - public ZkDiscoveryService(TbServiceInfoProvider serviceInfoProvider, PartitionService partitionService) { | 82 | + public ZkDiscoveryService(TbServiceInfoProvider serviceInfoProvider, |
83 | + PartitionService partitionService) { | ||
81 | this.serviceInfoProvider = serviceInfoProvider; | 84 | this.serviceInfoProvider = serviceInfoProvider; |
82 | this.partitionService = partitionService; | 85 | this.partitionService = partitionService; |
83 | } | 86 | } |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ClusterTopologyChangeEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/ClusterTopologyChangeEvent.java
@@ -13,10 +13,9 @@ | @@ -13,10 +13,9 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | 16 | +package org.thingsboard.server.queue.discovery.event; |
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | -import org.springframework.context.ApplicationEvent; | ||
20 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | 19 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; |
21 | 20 | ||
22 | import java.util.Set; | 21 | import java.util.Set; |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/PartitionChangeEvent.java
@@ -13,10 +13,9 @@ | @@ -13,10 +13,9 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | 16 | +package org.thingsboard.server.queue.discovery.event; |
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | -import org.springframework.context.ApplicationEvent; | ||
20 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; | 19 | import org.thingsboard.server.common.msg.queue.ServiceQueueKey; |
21 | import org.thingsboard.server.common.msg.queue.ServiceType; | 20 | import org.thingsboard.server.common.msg.queue.ServiceType; |
22 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | 21 | import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/ServiceListChangedEvent.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.queue.discovery.event; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import lombok.ToString; | ||
20 | +import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | ||
21 | + | ||
22 | +import java.util.List; | ||
23 | + | ||
24 | +@Getter | ||
25 | +@ToString | ||
26 | +public class ServiceListChangedEvent extends TbApplicationEvent { | ||
27 | + private final List<ServiceInfo> otherServices; | ||
28 | + private final ServiceInfo currentService; | ||
29 | + | ||
30 | + public ServiceListChangedEvent(List<ServiceInfo> otherServices, ServiceInfo currentService) { | ||
31 | + super(otherServices); | ||
32 | + this.otherServices = otherServices; | ||
33 | + this.currentService = currentService; | ||
34 | + } | ||
35 | +} |
common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/TbApplicationEvent.java
renamed from
common/queue/src/main/java/org/thingsboard/server/queue/discovery/TbApplicationEvent.java
@@ -13,7 +13,7 @@ | @@ -13,7 +13,7 @@ | ||
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.thingsboard.server.queue.discovery; | 16 | +package org.thingsboard.server.queue.discovery.event; |
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | import org.springframework.context.ApplicationEvent; | 19 | import org.springframework.context.ApplicationEvent; |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.queue.util; | ||
17 | + | ||
18 | +import org.springframework.context.event.ContextRefreshedEvent; | ||
19 | +import org.springframework.context.event.EventListener; | ||
20 | +import org.springframework.core.annotation.AliasFor; | ||
21 | +import org.springframework.core.annotation.Order; | ||
22 | + | ||
23 | +import java.lang.annotation.ElementType; | ||
24 | +import java.lang.annotation.Retention; | ||
25 | +import java.lang.annotation.RetentionPolicy; | ||
26 | +import java.lang.annotation.Target; | ||
27 | + | ||
28 | +@Retention(RetentionPolicy.RUNTIME) | ||
29 | +@Target(ElementType.METHOD) | ||
30 | +@EventListener(ContextRefreshedEvent.class) | ||
31 | +@Order | ||
32 | +public @interface AfterContextReady { | ||
33 | + @AliasFor(annotation = Order.class, attribute = "value") | ||
34 | + int order() default Integer.MAX_VALUE; | ||
35 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.queue.util; | ||
17 | + | ||
18 | +import org.springframework.boot.context.event.ApplicationReadyEvent; | ||
19 | +import org.springframework.context.event.EventListener; | ||
20 | +import org.springframework.core.annotation.AliasFor; | ||
21 | +import org.springframework.core.annotation.Order; | ||
22 | + | ||
23 | +import java.lang.annotation.ElementType; | ||
24 | +import java.lang.annotation.Retention; | ||
25 | +import java.lang.annotation.RetentionPolicy; | ||
26 | +import java.lang.annotation.Target; | ||
27 | + | ||
28 | +@Retention(RetentionPolicy.RUNTIME) | ||
29 | +@Target(ElementType.METHOD) | ||
30 | +@EventListener(ApplicationReadyEvent.class) | ||
31 | +@Order | ||
32 | +public @interface AfterStartUp { | ||
33 | + @AliasFor(annotation = Order.class, attribute = "value") | ||
34 | + int order() default Integer.MAX_VALUE; | ||
35 | +} |
common/queue/src/main/java/org/thingsboard/server/queue/util/TbSnmpTransportComponent.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.queue.util; | ||
17 | + | ||
18 | +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | ||
19 | + | ||
20 | +import java.lang.annotation.ElementType; | ||
21 | +import java.lang.annotation.Retention; | ||
22 | +import java.lang.annotation.RetentionPolicy; | ||
23 | +import java.lang.annotation.Target; | ||
24 | + | ||
25 | +@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.snmp.enabled}'=='true')") | ||
26 | +@Retention(RetentionPolicy.RUNTIME) | ||
27 | +@Target({ElementType.TYPE, ElementType.METHOD}) | ||
28 | +public @interface TbSnmpTransportComponent { | ||
29 | +} |
@@ -34,6 +34,7 @@ message ServiceInfo { | @@ -34,6 +34,7 @@ message ServiceInfo { | ||
34 | int64 tenantIdMSB = 3; | 34 | int64 tenantIdMSB = 3; |
35 | int64 tenantIdLSB = 4; | 35 | int64 tenantIdLSB = 4; |
36 | repeated QueueInfo ruleEngineQueues = 5; | 36 | repeated QueueInfo ruleEngineQueues = 5; |
37 | + repeated string transports = 6; | ||
37 | } | 38 | } |
38 | 39 | ||
39 | /** | 40 | /** |
@@ -246,6 +247,36 @@ message GetEntityProfileResponseMsg { | @@ -246,6 +247,36 @@ message GetEntityProfileResponseMsg { | ||
246 | bytes apiState = 3; | 247 | bytes apiState = 3; |
247 | } | 248 | } |
248 | 249 | ||
250 | +message GetDeviceRequestMsg { | ||
251 | + int64 deviceIdMSB = 1; | ||
252 | + int64 deviceIdLSB = 2; | ||
253 | +} | ||
254 | + | ||
255 | +message GetDeviceResponseMsg { | ||
256 | + int64 deviceProfileIdMSB = 1; | ||
257 | + int64 deviceProfileIdLSB = 2; | ||
258 | + bytes deviceTransportConfiguration = 3; | ||
259 | +} | ||
260 | + | ||
261 | +message GetDeviceCredentialsRequestMsg { | ||
262 | + int64 deviceIdMSB = 1; | ||
263 | + int64 deviceIdLSB = 2; | ||
264 | +} | ||
265 | + | ||
266 | +message GetDeviceCredentialsResponseMsg { | ||
267 | + bytes deviceCredentialsData = 1; | ||
268 | +} | ||
269 | + | ||
270 | +message GetSnmpDevicesRequestMsg { | ||
271 | + int32 page = 1; | ||
272 | + int32 pageSize = 2; | ||
273 | +} | ||
274 | + | ||
275 | +message GetSnmpDevicesResponseMsg { | ||
276 | + repeated string ids = 1; | ||
277 | + bool hasNextPage = 2; | ||
278 | +} | ||
279 | + | ||
249 | message EntityUpdateMsg { | 280 | message EntityUpdateMsg { |
250 | string entityType = 1; | 281 | string entityType = 1; |
251 | bytes data = 2; | 282 | bytes data = 2; |
@@ -592,6 +623,9 @@ message TransportApiRequestMsg { | @@ -592,6 +623,9 @@ message TransportApiRequestMsg { | ||
592 | ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; | 623 | ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; |
593 | GetResourceRequestMsg resourceRequestMsg = 9; | 624 | GetResourceRequestMsg resourceRequestMsg = 9; |
594 | GetFirmwareRequestMsg firmwareRequestMsg = 10; | 625 | GetFirmwareRequestMsg firmwareRequestMsg = 10; |
626 | + GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11; | ||
627 | + GetDeviceRequestMsg deviceRequestMsg = 12; | ||
628 | + GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13; | ||
595 | } | 629 | } |
596 | 630 | ||
597 | /* Response from ThingsBoard Core Service to Transport Service */ | 631 | /* Response from ThingsBoard Core Service to Transport Service */ |
@@ -600,9 +634,12 @@ message TransportApiResponseMsg { | @@ -600,9 +634,12 @@ message TransportApiResponseMsg { | ||
600 | GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; | 634 | GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; |
601 | GetEntityProfileResponseMsg entityProfileResponseMsg = 3; | 635 | GetEntityProfileResponseMsg entityProfileResponseMsg = 3; |
602 | ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; | 636 | ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; |
637 | + GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 5; | ||
603 | LwM2MResponseMsg lwM2MResponseMsg = 6; | 638 | LwM2MResponseMsg lwM2MResponseMsg = 6; |
604 | GetResourceResponseMsg resourceResponseMsg = 7; | 639 | GetResourceResponseMsg resourceResponseMsg = 7; |
605 | GetFirmwareResponseMsg firmwareResponseMsg = 8; | 640 | GetFirmwareResponseMsg firmwareResponseMsg = 8; |
641 | + GetDeviceResponseMsg deviceResponseMsg = 9; | ||
642 | + GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10; | ||
606 | } | 643 | } |
607 | 644 | ||
608 | /* Messages that are handled by ThingsBoard Core Service */ | 645 | /* Messages that are handled by ThingsBoard Core Service */ |
@@ -21,7 +21,9 @@ import org.eclipse.californium.core.CoapServer; | @@ -21,7 +21,9 @@ import org.eclipse.californium.core.CoapServer; | ||
21 | import org.springframework.beans.factory.annotation.Autowired; | 21 | import org.springframework.beans.factory.annotation.Autowired; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
23 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
24 | +import org.thingsboard.server.common.data.TbTransportService; | ||
24 | import org.thingsboard.server.coapserver.CoapServerService; | 25 | import org.thingsboard.server.coapserver.CoapServerService; |
26 | +import org.thingsboard.server.coapserver.TbCoapServerComponent; | ||
25 | import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; | 27 | import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; |
26 | 28 | ||
27 | import javax.annotation.PostConstruct; | 29 | import javax.annotation.PostConstruct; |
@@ -29,9 +31,9 @@ import javax.annotation.PreDestroy; | @@ -29,9 +31,9 @@ import javax.annotation.PreDestroy; | ||
29 | import java.net.UnknownHostException; | 31 | import java.net.UnknownHostException; |
30 | 32 | ||
31 | @Service("CoapTransportService") | 33 | @Service("CoapTransportService") |
32 | -@ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") | 34 | +@TbCoapServerComponent |
33 | @Slf4j | 35 | @Slf4j |
34 | -public class CoapTransportService { | 36 | +public class CoapTransportService implements TbTransportService { |
35 | 37 | ||
36 | private static final String V1 = "v1"; | 38 | private static final String V1 = "v1"; |
37 | private static final String API = "api"; | 39 | private static final String API = "api"; |
@@ -65,4 +67,9 @@ public class CoapTransportService { | @@ -65,4 +67,9 @@ public class CoapTransportService { | ||
65 | public void shutdown() { | 67 | public void shutdown() { |
66 | log.info("CoAP transport stopped!"); | 68 | log.info("CoAP transport stopped!"); |
67 | } | 69 | } |
70 | + | ||
71 | + @Override | ||
72 | + public String getName() { | ||
73 | + return "COAP"; | ||
74 | + } | ||
68 | } | 75 | } |
@@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController; | @@ -35,6 +35,7 @@ import org.springframework.web.bind.annotation.RestController; | ||
35 | import org.springframework.web.context.request.async.DeferredResult; | 35 | import org.springframework.web.context.request.async.DeferredResult; |
36 | import org.thingsboard.server.common.data.DeviceTransportType; | 36 | import org.thingsboard.server.common.data.DeviceTransportType; |
37 | import org.thingsboard.server.common.data.firmware.FirmwareType; | 37 | import org.thingsboard.server.common.data.firmware.FirmwareType; |
38 | +import org.thingsboard.server.common.data.TbTransportService; | ||
38 | import org.thingsboard.server.common.data.id.DeviceId; | 39 | import org.thingsboard.server.common.data.id.DeviceId; |
39 | import org.thingsboard.server.common.transport.SessionMsgListener; | 40 | import org.thingsboard.server.common.transport.SessionMsgListener; |
40 | import org.thingsboard.server.common.transport.TransportContext; | 41 | import org.thingsboard.server.common.transport.TransportContext; |
@@ -71,7 +72,7 @@ import java.util.function.Consumer; | @@ -71,7 +72,7 @@ import java.util.function.Consumer; | ||
71 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')") | 72 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')") |
72 | @RequestMapping("/api/v1") | 73 | @RequestMapping("/api/v1") |
73 | @Slf4j | 74 | @Slf4j |
74 | -public class DeviceApiController { | 75 | +public class DeviceApiController implements TbTransportService { |
75 | 76 | ||
76 | @Autowired | 77 | @Autowired |
77 | private HttpTransportContext transportContext; | 78 | private HttpTransportContext transportContext; |
@@ -422,4 +423,9 @@ public class DeviceApiController { | @@ -422,4 +423,9 @@ public class DeviceApiController { | ||
422 | } | 423 | } |
423 | } | 424 | } |
424 | 425 | ||
426 | + @Override | ||
427 | + public String getName() { | ||
428 | + return "HTTP"; | ||
429 | + } | ||
430 | + | ||
425 | } | 431 | } |
@@ -55,7 +55,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | @@ -55,7 +55,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | ||
55 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; | 55 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
56 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; | 56 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; |
57 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; | 57 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; |
58 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; | 58 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; |
59 | 59 | ||
60 | @Slf4j | 60 | @Slf4j |
61 | @Component | 61 | @Component |
@@ -93,7 +93,6 @@ public class LwM2MTransportBootstrapServerConfiguration { | @@ -93,7 +93,6 @@ public class LwM2MTransportBootstrapServerConfiguration { | ||
93 | builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); | 93 | builder.setCoapConfig(getCoapConfig(bootstrapPortNoSec, bootstrapSecurePort)); |
94 | 94 | ||
95 | /** Define model provider (Create Models )*/ | 95 | /** Define model provider (Create Models )*/ |
96 | -// builder.setModel(new StaticModel(contextS.getLwM2MTransportConfigServer().getModelsValueCommon())); | ||
97 | 96 | ||
98 | /** Create credentials */ | 97 | /** Create credentials */ |
99 | this.setServerWithCredentials(builder); | 98 | this.setServerWithCredentials(builder); |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server; | ||
17 | + | ||
18 | +import org.eclipse.californium.core.network.config.NetworkConfig; | ||
19 | + | ||
20 | +public class LwM2mNetworkConfig { | ||
21 | + | ||
22 | + public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { | ||
23 | + NetworkConfig coapConfig = new NetworkConfig(); | ||
24 | + coapConfig.setInt(NetworkConfig.Keys.COAP_PORT,serverPortNoSec); | ||
25 | + coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT,serverSecurePort); | ||
26 | + /** | ||
27 | + * Example:Property for large packet: | ||
28 | + * #NetworkConfig config = new NetworkConfig(); | ||
29 | + * #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32); | ||
30 | + * #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32); | ||
31 | + * #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048); | ||
32 | + * #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3); | ||
33 | + * #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000); | ||
34 | + */ | ||
35 | + | ||
36 | + /** | ||
37 | + * Property to indicate if the response should always include the Block2 option \ | ||
38 | + * when client request early blockwise negociation but the response can be sent on one packet. | ||
39 | + * - value of false indicate that the server will respond without block2 option if no further blocks are required. | ||
40 | + * - value of true indicate that the server will response with block2 option event if no further blocks are required. | ||
41 | + * CoAP client will try to use block mode | ||
42 | + * or adapt the block size when receiving a 4.13 Entity too large response code | ||
43 | + */ | ||
44 | + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); | ||
45 | + /*** | ||
46 | + * Property to indicate if the response should always include the Block2 option \ | ||
47 | + * when client request early blockwise negociation but the response can be sent on one packet. | ||
48 | + * - value of false indicate that the server will respond without block2 option if no further blocks are required. | ||
49 | + * - value of true indicate that the server will response with block2 option event if no further blocks are required. | ||
50 | + */ | ||
51 | + coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); | ||
52 | + | ||
53 | + coapConfig.setInt(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, 300000); | ||
54 | + /** | ||
55 | + * !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13 | ||
56 | + * The maximum size of a resource body (in bytes) that will be accepted | ||
57 | + * as the payload of a POST/PUT or the response to a GET request in a | ||
58 | + * transparent> blockwise transfer. | ||
59 | + * This option serves as a safeguard against excessive memory | ||
60 | + * consumption when many resources contain large bodies that cannot be | ||
61 | + * transferred in a single CoAP message. This option has no impact on | ||
62 | + * *manually* managed blockwise transfers in which the blocks are handled individually. | ||
63 | + * Note that this option does not prevent local clients or resource | ||
64 | + * implementations from sending large bodies as part of a request or response to a peer. | ||
65 | + * The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192 | ||
66 | + * A value of {@code 0} turns off transparent handling of blockwise transfers altogether. | ||
67 | + */ | ||
68 | +// coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 8192); | ||
69 | + coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 16384); | ||
70 | + /** | ||
71 | + * The default DTLS response matcher. | ||
72 | + * Supported values are STRICT, RELAXED, or PRINCIPAL. | ||
73 | + * The default value is STRICT. | ||
74 | + * Create new instance of udp endpoint context matcher. | ||
75 | + * Params: | ||
76 | + * checkAddress | ||
77 | + * – true with address check, (STRICT, UDP) | ||
78 | + * - false, without | ||
79 | + */ | ||
80 | + coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "STRICT"); | ||
81 | + /** | ||
82 | + * https://tools.ietf.org/html/rfc7959#section-2.9.3 | ||
83 | + * The block size (number of bytes) to use when doing a blockwise transfer. \ | ||
84 | + * This value serves as the upper limit for block size in blockwise transfers | ||
85 | + */ | ||
86 | + coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 512); | ||
87 | + /** | ||
88 | + * The maximum payload size (in bytes) that can be transferred in a | ||
89 | + * single message, i.e. without requiring a blockwise transfer. | ||
90 | + * NB: this value MUST be adapted to the maximum message size supported by the transport layer. | ||
91 | + * In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol | ||
92 | + * DEFAULT_VALUE = 1024 | ||
93 | + */ | ||
94 | + coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 512); | ||
95 | + | ||
96 | + coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); | ||
97 | + | ||
98 | + return coapConfig; | ||
99 | + } | ||
100 | +} |
@@ -26,6 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate; | @@ -26,6 +26,7 @@ import org.eclipse.leshan.server.registration.RegistrationUpdate; | ||
26 | 26 | ||
27 | import java.util.Collection; | 27 | import java.util.Collection; |
28 | 28 | ||
29 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; | ||
29 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer; | 30 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.convertPathFromObjectIdToIdVer; |
30 | 31 | ||
31 | @Slf4j | 32 | @Slf4j |
@@ -85,17 +86,19 @@ public class LwM2mServerListener { | @@ -85,17 +86,19 @@ public class LwM2mServerListener { | ||
85 | 86 | ||
86 | @Override | 87 | @Override |
87 | public void cancelled(Observation observation) { | 88 | public void cancelled(Observation observation) { |
88 | - log.info("Received notification cancelled from [{}] ", observation.getPath()); | 89 | + String msg = String.format("%s: Cancel Observation %s.", LOG_LW2M_INFO, observation.getPath()); |
90 | + service.sendLogsToThingsboard(msg, observation.getRegistrationId()); | ||
91 | + log.trace(msg); | ||
89 | } | 92 | } |
90 | 93 | ||
91 | @Override | 94 | @Override |
92 | public void onResponse(Observation observation, Registration registration, ObserveResponse response) { | 95 | public void onResponse(Observation observation, Registration registration, ObserveResponse response) { |
93 | if (registration != null) { | 96 | if (registration != null) { |
94 | try { | 97 | try { |
95 | - service.onObservationResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), | 98 | + service.onUpdateValueAfterReadResponse(registration, convertPathFromObjectIdToIdVer(observation.getPath().toString(), |
96 | registration), response, null); | 99 | registration), response, null); |
97 | } catch (Exception e) { | 100 | } catch (Exception e) { |
98 | - log.error("[{}] onResponse", e.toString()); | 101 | + log.error("Observation/Read onResponse", e); |
99 | 102 | ||
100 | } | 103 | } |
101 | } | 104 | } |
@@ -108,7 +111,10 @@ public class LwM2mServerListener { | @@ -108,7 +111,10 @@ public class LwM2mServerListener { | ||
108 | 111 | ||
109 | @Override | 112 | @Override |
110 | public void newObservation(Observation observation, Registration registration) { | 113 | public void newObservation(Observation observation, Registration registration) { |
111 | - log.info("Received newObservation from [{}] endpoint [{}] ", observation.getPath(), registration.getEndpoint()); | 114 | + String msg = String.format("%s: Successful start newObservation %s.", LOG_LW2M_INFO, |
115 | + observation.getPath()); | ||
116 | + service.sendLogsToThingsboard(msg, registration.getId()); | ||
117 | + log.trace(msg); | ||
112 | } | 118 | } |
113 | }; | 119 | }; |
114 | 120 |
@@ -25,7 +25,6 @@ import com.google.gson.JsonSyntaxException; | @@ -25,7 +25,6 @@ import com.google.gson.JsonSyntaxException; | ||
25 | import com.google.gson.reflect.TypeToken; | 25 | import com.google.gson.reflect.TypeToken; |
26 | import lombok.extern.slf4j.Slf4j; | 26 | import lombok.extern.slf4j.Slf4j; |
27 | import org.apache.commons.lang3.StringUtils; | 27 | import org.apache.commons.lang3.StringUtils; |
28 | -import org.eclipse.californium.core.network.config.NetworkConfig; | ||
29 | import org.eclipse.leshan.core.attributes.Attribute; | 28 | import org.eclipse.leshan.core.attributes.Attribute; |
30 | import org.eclipse.leshan.core.attributes.AttributeSet; | 29 | import org.eclipse.leshan.core.attributes.AttributeSet; |
31 | import org.eclipse.leshan.core.model.ObjectModel; | 30 | import org.eclipse.leshan.core.model.ObjectModel; |
@@ -40,7 +39,6 @@ import org.eclipse.leshan.core.node.codec.CodecException; | @@ -40,7 +39,6 @@ import org.eclipse.leshan.core.node.codec.CodecException; | ||
40 | import org.eclipse.leshan.core.request.DownlinkRequest; | 39 | import org.eclipse.leshan.core.request.DownlinkRequest; |
41 | import org.eclipse.leshan.core.request.WriteAttributesRequest; | 40 | import org.eclipse.leshan.core.request.WriteAttributesRequest; |
42 | import org.eclipse.leshan.core.util.Hex; | 41 | import org.eclipse.leshan.core.util.Hex; |
43 | -import org.eclipse.leshan.server.californium.LeshanServerBuilder; | ||
44 | import org.eclipse.leshan.server.registration.Registration; | 42 | import org.eclipse.leshan.server.registration.Registration; |
45 | import org.nustaq.serialization.FSTConfiguration; | 43 | import org.nustaq.serialization.FSTConfiguration; |
46 | import org.thingsboard.server.common.data.DeviceProfile; | 44 | import org.thingsboard.server.common.data.DeviceProfile; |
@@ -50,7 +48,6 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; | @@ -50,7 +48,6 @@ import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
50 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; | 48 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; |
51 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; | 49 | import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClientProfile; |
52 | 50 | ||
53 | -import java.io.File; | ||
54 | import java.io.IOException; | 51 | import java.io.IOException; |
55 | import java.util.ArrayList; | 52 | import java.util.ArrayList; |
56 | import java.util.Arrays; | 53 | import java.util.Arrays; |
@@ -72,7 +69,6 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA | @@ -72,7 +69,6 @@ import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPA | ||
72 | @Slf4j | 69 | @Slf4j |
73 | public class LwM2mTransportHandler { | 70 | public class LwM2mTransportHandler { |
74 | 71 | ||
75 | - // public static final String BASE_DEVICE_API_TOPIC = "v1/devices/me"; | ||
76 | public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0"; | 72 | public static final String TRANSPORT_DEFAULT_LWM2M_VERSION = "1.0"; |
77 | public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings"; | 73 | public static final String CLIENT_LWM2M_SETTINGS = "clientLwM2mSettings"; |
78 | public static final String BOOTSTRAP = "bootstrap"; | 74 | public static final String BOOTSTRAP = "bootstrap"; |
@@ -85,19 +81,12 @@ public class LwM2mTransportHandler { | @@ -85,19 +81,12 @@ public class LwM2mTransportHandler { | ||
85 | public static final String KEY_NAME = "keyName"; | 81 | public static final String KEY_NAME = "keyName"; |
86 | public static final String OBSERVE_LWM2M = "observe"; | 82 | public static final String OBSERVE_LWM2M = "observe"; |
87 | public static final String ATTRIBUTE_LWM2M = "attributeLwm2m"; | 83 | public static final String ATTRIBUTE_LWM2M = "attributeLwm2m"; |
88 | -// public static final String RESOURCE_VALUE = "resValue"; | ||
89 | -// public static final String RESOURCE_TYPE = "resType"; | ||
90 | 84 | ||
91 | private static final String REQUEST = "/request"; | 85 | private static final String REQUEST = "/request"; |
92 | - // private static final String RESPONSE = "/response"; | ||
93 | private static final String ATTRIBUTES = "/" + ATTRIBUTE; | 86 | private static final String ATTRIBUTES = "/" + ATTRIBUTE; |
94 | public static final String TELEMETRIES = "/" + TELEMETRY; | 87 | public static final String TELEMETRIES = "/" + TELEMETRY; |
95 | - // public static final String ATTRIBUTES_RESPONSE = ATTRIBUTES + RESPONSE; | ||
96 | public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; | 88 | public static final String ATTRIBUTES_REQUEST = ATTRIBUTES + REQUEST; |
97 | - // public static final String DEVICE_ATTRIBUTES_RESPONSE = ATTRIBUTES_RESPONSE + "/"; | ||
98 | public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/"; | 89 | public static final String DEVICE_ATTRIBUTES_REQUEST = ATTRIBUTES_REQUEST + "/"; |
99 | -// public static final String DEVICE_ATTRIBUTES_TOPIC = BASE_DEVICE_API_TOPIC + ATTRIBUTES; | ||
100 | -// public static final String DEVICE_TELEMETRY_TOPIC = BASE_DEVICE_API_TOPIC + TELEMETRIES; | ||
101 | 90 | ||
102 | public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms | 91 | public static final long DEFAULT_TIMEOUT = 2 * 60 * 1000L; // 2min in ms |
103 | 92 | ||
@@ -112,6 +101,11 @@ public class LwM2mTransportHandler { | @@ -112,6 +101,11 @@ public class LwM2mTransportHandler { | ||
112 | 101 | ||
113 | public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; | 102 | public static final String CLIENT_NOT_AUTHORIZED = "Client not authorized"; |
114 | 103 | ||
104 | + public static final Integer FR_OBJECT_ID = 5; | ||
105 | + public static final Integer FR_RESOURCE_VER_ID = 7; | ||
106 | + public static final String FR_PATH_RESOURCE_VER_ID = LWM2M_SEPARATOR_PATH + FR_OBJECT_ID + LWM2M_SEPARATOR_PATH | ||
107 | + + "0" + LWM2M_SEPARATOR_PATH + FR_RESOURCE_VER_ID; | ||
108 | + | ||
115 | public enum LwM2mTypeServer { | 109 | public enum LwM2mTypeServer { |
116 | BOOTSTRAP(0, "bootstrap"), | 110 | BOOTSTRAP(0, "bootstrap"), |
117 | CLIENT(1, "client"); | 111 | CLIENT(1, "client"); |
@@ -168,6 +162,8 @@ public class LwM2mTransportHandler { | @@ -168,6 +162,8 @@ public class LwM2mTransportHandler { | ||
168 | WRITE_ATTRIBUTES(8, "WriteAttributes"), | 162 | WRITE_ATTRIBUTES(8, "WriteAttributes"), |
169 | DELETE(9, "Delete"); | 163 | DELETE(9, "Delete"); |
170 | 164 | ||
165 | +// READ_INFO_FW(10, "ReadInfoFirmware"); | ||
166 | + | ||
171 | public int code; | 167 | public int code; |
172 | public String type; | 168 | public String type; |
173 | 169 | ||
@@ -190,21 +186,6 @@ public class LwM2mTransportHandler { | @@ -190,21 +186,6 @@ public class LwM2mTransportHandler { | ||
190 | public static final String SERVICE_CHANNEL = "SERVICE"; | 186 | public static final String SERVICE_CHANNEL = "SERVICE"; |
191 | public static final String RESPONSE_CHANNEL = "RESP"; | 187 | public static final String RESPONSE_CHANNEL = "RESP"; |
192 | 188 | ||
193 | - public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort) { | ||
194 | - NetworkConfig coapConfig; | ||
195 | - File configFile = new File(NetworkConfig.DEFAULT_FILE_NAME); | ||
196 | - if (configFile.isFile()) { | ||
197 | - coapConfig = new NetworkConfig(); | ||
198 | - coapConfig.load(configFile); | ||
199 | - } else { | ||
200 | - coapConfig = LeshanServerBuilder.createDefaultNetworkConfig(); | ||
201 | - coapConfig.store(configFile); | ||
202 | - } | ||
203 | - coapConfig.setString("COAP_PORT", Integer.toString(serverPortNoSec)); | ||
204 | - coapConfig.setString("COAP_SECURE_PORT", Integer.toString(serverSecurePort)); | ||
205 | - return coapConfig; | ||
206 | - } | ||
207 | - | ||
208 | public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { | 189 | public static boolean equalsResourceValue(Object valueOld, Object valueNew, ResourceModel.Type type, LwM2mPath resourcePath) throws CodecException { |
209 | switch (type) { | 190 | switch (type) { |
210 | case BOOLEAN: | 191 | case BOOLEAN: |
@@ -67,6 +67,7 @@ import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT; | @@ -67,6 +67,7 @@ import static org.eclipse.californium.core.coap.CoAP.ResponseCode.CONTENT; | ||
67 | import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST; | 67 | import static org.eclipse.leshan.core.ResponseCode.BAD_REQUEST; |
68 | import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND; | 68 | import static org.eclipse.leshan.core.ResponseCode.NOT_FOUND; |
69 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT; | 69 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEFAULT_TIMEOUT; |
70 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.FR_PATH_RESOURCE_VER_ID; | ||
70 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; | 71 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; |
71 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; | 72 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; |
72 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; | 73 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; |
@@ -125,7 +126,6 @@ public class LwM2mTransportRequest { | @@ -125,7 +126,6 @@ public class LwM2mTransportRequest { | ||
125 | public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, | 126 | public void sendAllRequest(Registration registration, String targetIdVer, LwM2mTypeOper typeOper, |
126 | String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { | 127 | String contentFormatName, Object params, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { |
127 | try { | 128 | try { |
128 | - | ||
129 | String target = convertPathFromIdVerToObjectId(targetIdVer); | 129 | String target = convertPathFromIdVerToObjectId(targetIdVer); |
130 | DownlinkRequest request = null; | 130 | DownlinkRequest request = null; |
131 | ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; | 131 | ContentFormat contentFormat = contentFormatName != null ? ContentFormat.fromName(contentFormatName.toUpperCase()) : ContentFormat.DEFAULT; |
@@ -145,11 +145,11 @@ public class LwM2mTransportRequest { | @@ -145,11 +145,11 @@ public class LwM2mTransportRequest { | ||
145 | break; | 145 | break; |
146 | case OBSERVE: | 146 | case OBSERVE: |
147 | if (resultIds.isResource()) { | 147 | if (resultIds.isResource()) { |
148 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); | 148 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId(), resultIds.getResourceId()); |
149 | } else if (resultIds.isObjectInstance()) { | 149 | } else if (resultIds.isObjectInstance()) { |
150 | - request = new ObserveRequest(resultIds.getObjectId(), resultIds.getObjectInstanceId()); | 150 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId(), resultIds.getObjectInstanceId()); |
151 | } else if (resultIds.getObjectId() >= 0) { | 151 | } else if (resultIds.getObjectId() >= 0) { |
152 | - request = new ObserveRequest(resultIds.getObjectId()); | 152 | + request = new ObserveRequest(contentFormat, resultIds.getObjectId()); |
153 | } | 153 | } |
154 | break; | 154 | break; |
155 | case OBSERVE_CANCEL: | 155 | case OBSERVE_CANCEL: |
@@ -171,8 +171,6 @@ public class LwM2mTransportRequest { | @@ -171,8 +171,6 @@ public class LwM2mTransportRequest { | ||
171 | break; | 171 | break; |
172 | case WRITE_REPLACE: | 172 | case WRITE_REPLACE: |
173 | // Request to write a <b>String Single-Instance Resource</b> using the TLV content format. | 173 | // Request to write a <b>String Single-Instance Resource</b> using the TLV content format. |
174 | -// resource = lwM2MClient.getResourceModel(targetIdVer); | ||
175 | -// if (contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { | ||
176 | resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() | 174 | resourceModel = lwM2MClient.getResourceModel(targetIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
177 | .getModelProvider()); | 175 | .getModelProvider()); |
178 | if (contentFormat.equals(ContentFormat.TLV)) { | 176 | if (contentFormat.equals(ContentFormat.TLV)) { |
@@ -181,7 +179,6 @@ public class LwM2mTransportRequest { | @@ -181,7 +179,6 @@ public class LwM2mTransportRequest { | ||
181 | registration, rpcRequest); | 179 | registration, rpcRequest); |
182 | } | 180 | } |
183 | // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON) | 181 | // Mode.REPLACE && Request to write a <b>String Single-Instance Resource</b> using the given content format (TEXT, TLV, JSON) |
184 | -// else if (!contentFormat.equals(ContentFormat.TLV) && !resource.multiple) { | ||
185 | else if (!contentFormat.equals(ContentFormat.TLV)) { | 182 | else if (!contentFormat.equals(ContentFormat.TLV)) { |
186 | request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), | 183 | request = this.getWriteRequestSingleResource(contentFormat, resultIds.getObjectId(), |
187 | resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type, | 184 | resultIds.getObjectInstanceId(), resultIds.getResourceId(), params, resourceModel.type, |
@@ -215,13 +212,16 @@ public class LwM2mTransportRequest { | @@ -215,13 +212,16 @@ public class LwM2mTransportRequest { | ||
215 | long finalTimeoutInMs = timeoutInMs; | 212 | long finalTimeoutInMs = timeoutInMs; |
216 | lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest)); | 213 | lwM2MClient.getQueuedRequests().add(() -> sendRequest(registration, lwM2MClient, finalRequest, finalTimeoutInMs, rpcRequest)); |
217 | } catch (Exception e) { | 214 | } catch (Exception e) { |
218 | - log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper, e); | 215 | + log.error("[{}] [{}] [{}] Failed to send downlink.", registration.getEndpoint(), targetIdVer, typeOper.name(), e); |
216 | + } | ||
217 | + } else if (OBSERVE_CANCEL == typeOper) { | ||
218 | + log.trace("[{}], [{}] - [{}] SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); | ||
219 | + if (rpcRequest != null) { | ||
220 | + rpcRequest.setInfoMsg(null); | ||
221 | + serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null); | ||
219 | } | 222 | } |
220 | - } else if (OBSERVE_CANCEL == typeOper && rpcRequest != null) { | ||
221 | - rpcRequest.setInfoMsg(null); | ||
222 | - serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), null, null); | ||
223 | } else { | 223 | } else { |
224 | - log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper, targetIdVer); | 224 | + log.error("[{}], [{}] - [{}] error SendRequest", registration.getEndpoint(), typeOper.name(), targetIdVer); |
225 | if (rpcRequest != null) { | 225 | if (rpcRequest != null) { |
226 | String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; | 226 | String errorMsg = resourceModel == null ? String.format("Path %s not found in object version", targetIdVer) : "SendRequest - null"; |
227 | serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); | 227 | serviceImpl.sentRpcRequest(rpcRequest, NOT_FOUND.getName(), errorMsg, LOG_LW2M_ERROR); |
@@ -236,8 +236,8 @@ public class LwM2mTransportRequest { | @@ -236,8 +236,8 @@ public class LwM2mTransportRequest { | ||
236 | Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); | 236 | Set<String> observationPaths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); |
237 | String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO, | 237 | String msg = String.format("%s: type operation %s observation paths - %s", LOG_LW2M_INFO, |
238 | OBSERVE_READ_ALL.type, observationPaths); | 238 | OBSERVE_READ_ALL.type, observationPaths); |
239 | - serviceImpl.sendLogsToThingsboard(msg, registration); | ||
240 | - log.info("[{}], [{}]", registration.getEndpoint(), msg); | 239 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); |
240 | + log.trace("[{}] [{}], [{}]", typeOper.name(), registration.getEndpoint(), msg); | ||
241 | if (rpcRequest != null) { | 241 | if (rpcRequest != null) { |
242 | String valueMsg = String.format("Observation paths - %s", observationPaths); | 242 | String valueMsg = String.format("Observation paths - %s", observationPaths); |
243 | serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); | 243 | serviceImpl.sentRpcRequest(rpcRequest, CONTENT.name(), valueMsg, LOG_LW2M_VALUE); |
@@ -246,7 +246,7 @@ public class LwM2mTransportRequest { | @@ -246,7 +246,7 @@ public class LwM2mTransportRequest { | ||
246 | } catch (Exception e) { | 246 | } catch (Exception e) { |
247 | String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, | 247 | String msg = String.format("%s: type operation %s %s", LOG_LW2M_ERROR, |
248 | typeOper.name(), e.getMessage()); | 248 | typeOper.name(), e.getMessage()); |
249 | - serviceImpl.sendLogsToThingsboard(msg, registration); | 249 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); |
250 | throw new Exception(e); | 250 | throw new Exception(e); |
251 | } | 251 | } |
252 | } | 252 | } |
@@ -261,45 +261,53 @@ public class LwM2mTransportRequest { | @@ -261,45 +261,53 @@ public class LwM2mTransportRequest { | ||
261 | private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { | 261 | private void sendRequest(Registration registration, LwM2mClient lwM2MClient, DownlinkRequest request, long timeoutInMs, Lwm2mClientRpcRequest rpcRequest) { |
262 | leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { | 262 | leshanServer.send(registration, request, timeoutInMs, (ResponseCallback<?>) response -> { |
263 | if (!lwM2MClient.isInit()) { | 263 | if (!lwM2MClient.isInit()) { |
264 | - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | 264 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); |
265 | } | 265 | } |
266 | if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { | 266 | if (CoAP.ResponseCode.isSuccess(((Response) response.getCoapResponse()).getCode())) { |
267 | this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); | 267 | this.handleResponse(registration, request.getPath().toString(), response, request, rpcRequest); |
268 | - if (request instanceof WriteRequest && ((WriteRequest) request).isReplaceRequest()) { | ||
269 | - LwM2mNode node = ((WriteRequest) request).getNode(); | ||
270 | - Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(), | ||
271 | - ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath()); | ||
272 | - String msg = String.format("%s: sendRequest Replace: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s SendRequest to Client", | ||
273 | - LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), | ||
274 | - response.getCode().getName(), request.getPath().toString(), value); | ||
275 | - serviceImpl.sendLogsToThingsboard(msg, registration); | ||
276 | - log.info("[{}] [{}] - [{}] [{}] Update SendRequest[{}]", registration.getEndpoint(), | ||
277 | - ((Response) response.getCoapResponse()).getCode(), response.getCode(), | ||
278 | - request.getPath().toString(), value); | ||
279 | - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO); | ||
280 | - } | ||
281 | } else { | 268 | } else { |
282 | - String msg = String.format("%s: sendRequest: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s SendRequest to Client", LOG_LW2M_ERROR, | 269 | + String msg = String.format("%s: SendRequest %s: CoapCode - %s Lwm2m code - %d name - %s Resource path - %s", LOG_LW2M_ERROR, request.getClass().getName().toString(), |
283 | ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); | 270 | ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), response.getCode().getName(), request.getPath().toString()); |
284 | - serviceImpl.sendLogsToThingsboard(msg, registration); | ||
285 | - log.error("[{}], [{}] - [{}] [{}] error SendRequest", registration.getEndpoint(), ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); | 271 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); |
272 | + log.error("[{}] [{}], [{}] - [{}] [{}] error SendRequest", request.getClass().getName().toString(), registration.getEndpoint(), | ||
273 | + ((Response) response.getCoapResponse()).getCode(), response.getCode(), request.getPath().toString()); | ||
274 | + if (!lwM2MClient.isInit()) { | ||
275 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | ||
276 | + } | ||
286 | if (rpcRequest != null) { | 277 | if (rpcRequest != null) { |
287 | serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR); | 278 | serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), response.getErrorMessage(), LOG_LW2M_ERROR); |
288 | } | 279 | } |
280 | + /** Not Found | ||
281 | + * set setClient_fw_version = empty | ||
282 | + **/ | ||
283 | + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) { | ||
284 | + lwM2MClient.setUpdateFw(false); | ||
285 | + lwM2MClient.getFrUpdate().setClientFwVersion(""); | ||
286 | + log.warn("updateFirmwareClient1"); | ||
287 | + serviceImpl.updateFirmwareClient(lwM2MClient); | ||
288 | + } | ||
289 | } | 289 | } |
290 | }, e -> { | 290 | }, e -> { |
291 | + /** version == null | ||
292 | + * set setClient_fw_version = empty | ||
293 | + **/ | ||
294 | + if (FR_PATH_RESOURCE_VER_ID.equals(request.getPath().toString()) && lwM2MClient.isUpdateFw()) { | ||
295 | + lwM2MClient.setUpdateFw(false); | ||
296 | + lwM2MClient.getFrUpdate().setClientFwVersion(""); | ||
297 | + log.warn("updateFirmwareClient2"); | ||
298 | + serviceImpl.updateFirmwareClient(lwM2MClient); | ||
299 | + } | ||
291 | if (!lwM2MClient.isInit()) { | 300 | if (!lwM2MClient.isInit()) { |
292 | - lwM2MClient.initValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); | 301 | + lwM2MClient.initReadValue(this.serviceImpl, convertPathFromObjectIdToIdVer(request.getPath().toString(), registration)); |
293 | } | 302 | } |
294 | - String msg = String.format("%s: sendRequest: Resource path - %s msg error - %s SendRequest to Client", | ||
295 | - LOG_LW2M_ERROR, request.getPath().toString(), e.getMessage()); | ||
296 | - serviceImpl.sendLogsToThingsboard(msg, registration); | ||
297 | - log.error("[{}] - [{}] error SendRequest", request.getPath().toString(), e.toString()); | 303 | + String msg = String.format("%s: SendRequest %s: Resource path - %s msg error - %s", |
304 | + LOG_LW2M_ERROR, request.getClass().getName().toString(), request.getPath().toString(), e.getMessage()); | ||
305 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | ||
306 | + log.error("[{}] [{}] - [{}] error SendRequest", request.getClass().getName().toString(), request.getPath().toString(), e.toString()); | ||
298 | if (rpcRequest != null) { | 307 | if (rpcRequest != null) { |
299 | serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); | 308 | serviceImpl.sentRpcRequest(rpcRequest, CoAP.CodeClass.ERROR_RESPONSE.name(), e.getMessage(), LOG_LW2M_ERROR); |
300 | } | 309 | } |
301 | }); | 310 | }); |
302 | - | ||
303 | } | 311 | } |
304 | 312 | ||
305 | private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, | 313 | private WriteRequest getWriteRequestSingleResource(ContentFormat contentFormat, Integer objectId, Integer instanceId, |
@@ -323,7 +331,9 @@ public class LwM2mTransportRequest { | @@ -323,7 +331,9 @@ public class LwM2mTransportRequest { | ||
323 | Date date = new Date(Long.decode(value.toString())); | 331 | Date date = new Date(Long.decode(value.toString())); |
324 | return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date); | 332 | return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, date) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, date); |
325 | case OPAQUE: // byte[] value, base64 | 333 | case OPAQUE: // byte[] value, base64 |
326 | - return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())) : new WriteRequest(contentFormat, objectId, instanceId, resourceId, Hex.decodeHex(value.toString().toCharArray())); | 334 | + byte[] valueRequest = value instanceof byte[] ? (byte[]) value : Hex.decodeHex(value.toString().toCharArray()); |
335 | + return (contentFormat == null) ? new WriteRequest(objectId, instanceId, resourceId, valueRequest) : | ||
336 | + new WriteRequest(contentFormat, objectId, instanceId, resourceId, valueRequest); | ||
327 | default: | 337 | default: |
328 | } | 338 | } |
329 | } | 339 | } |
@@ -337,7 +347,7 @@ public class LwM2mTransportRequest { | @@ -337,7 +347,7 @@ public class LwM2mTransportRequest { | ||
337 | String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; | 347 | String patn = "/" + objectId + "/" + instanceId + "/" + resourceId; |
338 | String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", | 348 | String msg = String.format(LOG_LW2M_ERROR + ": NumberFormatException: Resource path - %s type - %s value - %s msg error - %s SendRequest to Client", |
339 | patn, type, value, e.toString()); | 349 | patn, type, value, e.toString()); |
340 | - serviceImpl.sendLogsToThingsboard(msg, registration); | 350 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); |
341 | log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); | 351 | log.error("Path: [{}] type: [{}] value: [{}] errorMsg: [{}]]", patn, type, value, e.toString()); |
342 | if (rpcRequest != null) { | 352 | if (rpcRequest != null) { |
343 | String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); | 353 | String errorMsg = String.format("NumberFormatException: Resource path - %s type - %s value - %s", patn, type, value); |
@@ -369,7 +379,7 @@ public class LwM2mTransportRequest { | @@ -369,7 +379,7 @@ public class LwM2mTransportRequest { | ||
369 | DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { | 379 | DownlinkRequest request, Lwm2mClientRpcRequest rpcRequest) { |
370 | String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); | 380 | String pathIdVer = convertPathFromObjectIdToIdVer(path, registration); |
371 | if (response instanceof ReadResponse) { | 381 | if (response instanceof ReadResponse) { |
372 | - serviceImpl.onObservationResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest); | 382 | + serviceImpl.onUpdateValueAfterReadResponse(registration, pathIdVer, (ReadResponse) response, rpcRequest); |
373 | } else if (response instanceof CancelObservationResponse) { | 383 | } else if (response instanceof CancelObservationResponse) { |
374 | log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response); | 384 | log.info("[{}] Path [{}] CancelObservationResponse 3_Send", pathIdVer, response); |
375 | 385 | ||
@@ -389,14 +399,33 @@ public class LwM2mTransportRequest { | @@ -389,14 +399,33 @@ public class LwM2mTransportRequest { | ||
389 | } else if (response instanceof WriteAttributesResponse) { | 399 | } else if (response instanceof WriteAttributesResponse) { |
390 | log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response); | 400 | log.info("[{}] Path [{}] WriteAttributesResponse 8_Send", pathIdVer, response); |
391 | } else if (response instanceof WriteResponse) { | 401 | } else if (response instanceof WriteResponse) { |
392 | - log.info("[{}] Path [{}] WriteAttributesResponse 9_Send", pathIdVer, response); | 402 | + log.info("[{}] Path [{}] WriteResponse 9_Send", pathIdVer, response); |
403 | + this.infoWriteResponse(registration, response, request); | ||
393 | serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); | 404 | serviceImpl.onWriteResponseOk(registration, pathIdVer, (WriteRequest) request); |
394 | } | 405 | } |
395 | - if (rpcRequest != null && (response instanceof ExecuteResponse | ||
396 | - || response instanceof WriteAttributesResponse | ||
397 | - || response instanceof DeleteResponse)) { | ||
398 | - rpcRequest.setInfoMsg(null); | ||
399 | - serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null); | 406 | + if (rpcRequest != null) { |
407 | + if (response instanceof ExecuteResponse | ||
408 | + || response instanceof WriteAttributesResponse | ||
409 | + || response instanceof DeleteResponse) { | ||
410 | + rpcRequest.setInfoMsg(null); | ||
411 | + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, null); | ||
412 | + } else if (response instanceof WriteResponse) { | ||
413 | + serviceImpl.sentRpcRequest(rpcRequest, response.getCode().getName(), null, LOG_LW2M_INFO); | ||
414 | + } | ||
400 | } | 415 | } |
401 | } | 416 | } |
417 | + | ||
418 | + private void infoWriteResponse(Registration registration, LwM2mResponse response, | ||
419 | + DownlinkRequest request) { | ||
420 | + LwM2mNode node = ((WriteRequest) request).getNode(); | ||
421 | + Object value = this.converter.convertValue(((LwM2mSingleResource) node).getValue(), | ||
422 | + ((LwM2mSingleResource) node).getType(), ResourceModel.Type.STRING, request.getPath()); | ||
423 | + String msg = String.format("%s: Update finished successfully: CoapCde - %s Lwm2m code - %d name - %s Resource path - %s value - %s", | ||
424 | + LOG_LW2M_INFO, ((Response) response.getCoapResponse()).getCode(), response.getCode().getCode(), | ||
425 | + response.getCode().getName(), request.getPath().toString(), value); | ||
426 | + serviceImpl.sendLogsToThingsboard(msg, registration.getId()); | ||
427 | + log.warn("[{}] [{}] [{}] - [{}] [{}] Update finished successfully: [{}]", request.getClass().getName().toString(), registration.getEndpoint(), | ||
428 | + ((Response) response.getCoapResponse()).getCode(), response.getCode(), | ||
429 | + request.getPath().toString(), value); | ||
430 | + } | ||
402 | } | 431 | } |
@@ -16,6 +16,8 @@ | @@ -16,6 +16,8 @@ | ||
16 | package org.thingsboard.server.transport.lwm2m.server; | 16 | package org.thingsboard.server.transport.lwm2m.server; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.eclipse.californium.core.network.config.NetworkConfig; | ||
20 | +import org.eclipse.californium.core.network.stack.BlockwiseLayer; | ||
19 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; | 21 | import org.eclipse.californium.scandium.config.DtlsConnectorConfig; |
20 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; | 22 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeDecoder; |
21 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; | 23 | import org.eclipse.leshan.core.node.codec.DefaultLwM2mNodeEncoder; |
@@ -57,7 +59,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | @@ -57,7 +59,7 @@ import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE | ||
57 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; | 59 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; |
58 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; | 60 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; |
59 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; | 61 | import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CCM_8; |
60 | -import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.getCoapConfig; | 62 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mNetworkConfig.getCoapConfig; |
61 | 63 | ||
62 | @Slf4j | 64 | @Slf4j |
63 | @Component | 65 | @Component |
@@ -92,7 +94,10 @@ public class LwM2mTransportServerConfiguration { | @@ -92,7 +94,10 @@ public class LwM2mTransportServerConfiguration { | ||
92 | /** Use a magic converter to support bad type send by the UI. */ | 94 | /** Use a magic converter to support bad type send by the UI. */ |
93 | builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); | 95 | builder.setEncoder(new DefaultLwM2mNodeEncoder(LwM2mValueConverterImpl.getInstance())); |
94 | 96 | ||
97 | + | ||
95 | /** Create CoAP Config */ | 98 | /** Create CoAP Config */ |
99 | + NetworkConfig networkConfig = getCoapConfig(serverPortNoSec, serverSecurePort); | ||
100 | + BlockwiseLayer blockwiseLayer = new BlockwiseLayer(networkConfig); | ||
96 | builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); | 101 | builder.setCoapConfig(getCoapConfig(serverPortNoSec, serverSecurePort)); |
97 | 102 | ||
98 | /** Define model provider (Create Models )*/ | 103 | /** Define model provider (Create Models )*/ |
@@ -110,6 +115,7 @@ public class LwM2mTransportServerConfiguration { | @@ -110,6 +115,7 @@ public class LwM2mTransportServerConfiguration { | ||
110 | 115 | ||
111 | /** Create DTLS Config */ | 116 | /** Create DTLS Config */ |
112 | DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); | 117 | DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); |
118 | + dtlsConfig.setServerOnly(true); | ||
113 | dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getLwM2MTransportConfigServer().isRecommendedSupportedGroups()); | 119 | dtlsConfig.setRecommendedSupportedGroupsOnly(this.context.getLwM2MTransportConfigServer().isRecommendedSupportedGroups()); |
114 | dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getLwM2MTransportConfigServer().isRecommendedCiphers()); | 120 | dtlsConfig.setRecommendedCipherSuitesOnly(this.context.getLwM2MTransportConfigServer().isRecommendedCiphers()); |
115 | if (this.pskMode) { | 121 | if (this.pskMode) { |
@@ -20,13 +20,14 @@ import org.eclipse.leshan.core.response.ReadResponse; | @@ -20,13 +20,14 @@ import org.eclipse.leshan.core.response.ReadResponse; | ||
20 | import org.eclipse.leshan.server.registration.Registration; | 20 | import org.eclipse.leshan.server.registration.Registration; |
21 | import org.thingsboard.server.common.data.Device; | 21 | import org.thingsboard.server.common.data.Device; |
22 | import org.thingsboard.server.common.data.DeviceProfile; | 22 | import org.thingsboard.server.common.data.DeviceProfile; |
23 | +import org.thingsboard.server.common.data.TbTransportService; | ||
23 | import org.thingsboard.server.gen.transport.TransportProtos; | 24 | import org.thingsboard.server.gen.transport.TransportProtos; |
24 | import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; | 25 | import org.thingsboard.server.transport.lwm2m.server.client.Lwm2mClientRpcRequest; |
25 | 26 | ||
26 | import java.util.Collection; | 27 | import java.util.Collection; |
27 | import java.util.Optional; | 28 | import java.util.Optional; |
28 | 29 | ||
29 | -public interface LwM2mTransportService { | 30 | +public interface LwM2mTransportService extends TbTransportService { |
30 | 31 | ||
31 | void onRegistered(Registration registration, Collection<Observation> previousObsersations); | 32 | void onRegistered(Registration registration, Collection<Observation> previousObsersations); |
32 | 33 | ||
@@ -38,7 +39,7 @@ public interface LwM2mTransportService { | @@ -38,7 +39,7 @@ public interface LwM2mTransportService { | ||
38 | 39 | ||
39 | void setCancelObservations(Registration registration); | 40 | void setCancelObservations(Registration registration); |
40 | 41 | ||
41 | - void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest); | 42 | + void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest); |
42 | 43 | ||
43 | void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo); | 44 | void onAttributeUpdate(TransportProtos.AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo); |
44 | 45 | ||
@@ -59,6 +60,4 @@ public interface LwM2mTransportService { | @@ -59,6 +60,4 @@ public interface LwM2mTransportService { | ||
59 | void doTrigger(Registration registration, String path); | 60 | void doTrigger(Registration registration, String path); |
60 | 61 | ||
61 | void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); | 62 | void doDisconnect(TransportProtos.SessionInfoProto sessionInfo); |
62 | - | ||
63 | - | ||
64 | } | 63 | } |
@@ -38,9 +38,15 @@ import org.eclipse.leshan.server.registration.Registration; | @@ -38,9 +38,15 @@ import org.eclipse.leshan.server.registration.Registration; | ||
38 | import org.springframework.context.annotation.Lazy; | 38 | import org.springframework.context.annotation.Lazy; |
39 | import org.springframework.stereotype.Service; | 39 | import org.springframework.stereotype.Service; |
40 | import org.thingsboard.common.util.JacksonUtil; | 40 | import org.thingsboard.common.util.JacksonUtil; |
41 | +import org.thingsboard.server.cache.firmware.FirmwareDataCache; | ||
41 | import org.thingsboard.server.common.data.Device; | 42 | import org.thingsboard.server.common.data.Device; |
42 | import org.thingsboard.server.common.data.DeviceProfile; | 43 | import org.thingsboard.server.common.data.DeviceProfile; |
44 | +import org.thingsboard.server.common.data.firmware.FirmwareKey; | ||
45 | +import org.thingsboard.server.common.data.firmware.FirmwareType; | ||
46 | +import org.thingsboard.server.common.data.firmware.FirmwareUtil; | ||
47 | +import org.thingsboard.server.common.data.id.FirmwareId; | ||
43 | import org.thingsboard.server.common.transport.TransportService; | 48 | import org.thingsboard.server.common.transport.TransportService; |
49 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
44 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 50 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
45 | import org.thingsboard.server.common.transport.service.DefaultTransportService; | 51 | import org.thingsboard.server.common.transport.service.DefaultTransportService; |
46 | import org.thingsboard.server.gen.transport.TransportProtos; | 52 | import org.thingsboard.server.gen.transport.TransportProtos; |
@@ -76,9 +82,11 @@ import java.util.stream.Collectors; | @@ -76,9 +82,11 @@ import java.util.stream.Collectors; | ||
76 | 82 | ||
77 | import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; | 83 | import static org.eclipse.californium.core.coap.CoAP.ResponseCode.BAD_REQUEST; |
78 | import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; | 84 | import static org.eclipse.leshan.core.attributes.Attribute.OBJECT_VERSION; |
85 | +import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_KEY; | ||
79 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; | 86 | import static org.thingsboard.server.common.data.lwm2m.LwM2mConstants.LWM2M_SEPARATOR_PATH; |
80 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; | 87 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.CLIENT_NOT_AUTHORIZED; |
81 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST; | 88 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.DEVICE_ATTRIBUTES_REQUEST; |
89 | +import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.FR_PATH_RESOURCE_VER_ID; | ||
82 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; | 90 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_ERROR; |
83 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; | 91 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_INFO; |
84 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; | 92 | import static org.thingsboard.server.transport.lwm2m.server.LwM2mTransportHandler.LOG_LW2M_VALUE; |
@@ -109,6 +117,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -109,6 +117,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
109 | private ExecutorService executorUpdateRegistered; | 117 | private ExecutorService executorUpdateRegistered; |
110 | private ExecutorService executorUnRegistered; | 118 | private ExecutorService executorUnRegistered; |
111 | private LwM2mValueConverterImpl converter; | 119 | private LwM2mValueConverterImpl converter; |
120 | + private FirmwareDataCache firmwareDataCache; | ||
121 | + | ||
112 | 122 | ||
113 | private final TransportService transportService; | 123 | private final TransportService transportService; |
114 | 124 | ||
@@ -120,12 +130,15 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -120,12 +130,15 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
120 | 130 | ||
121 | private final LwM2mTransportRequest lwM2mTransportRequest; | 131 | private final LwM2mTransportRequest lwM2mTransportRequest; |
122 | 132 | ||
123 | - public LwM2mTransportServiceImpl(TransportService transportService, LwM2mTransportContextServer lwM2mTransportContextServer, LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, @Lazy LwM2mTransportRequest lwM2mTransportRequest) { | 133 | + public LwM2mTransportServiceImpl(TransportService transportService, LwM2mTransportContextServer lwM2mTransportContextServer, |
134 | + LwM2mClientContext lwM2mClientContext, LeshanServer leshanServer, | ||
135 | + @Lazy LwM2mTransportRequest lwM2mTransportRequest, FirmwareDataCache firmwareDataCache) { | ||
124 | this.transportService = transportService; | 136 | this.transportService = transportService; |
125 | this.lwM2mTransportContextServer = lwM2mTransportContextServer; | 137 | this.lwM2mTransportContextServer = lwM2mTransportContextServer; |
126 | this.lwM2mClientContext = lwM2mClientContext; | 138 | this.lwM2mClientContext = lwM2mClientContext; |
127 | this.leshanServer = leshanServer; | 139 | this.leshanServer = leshanServer; |
128 | this.lwM2mTransportRequest = lwM2mTransportRequest; | 140 | this.lwM2mTransportRequest = lwM2mTransportRequest; |
141 | + this.firmwareDataCache = firmwareDataCache; | ||
129 | } | 142 | } |
130 | 143 | ||
131 | @PostConstruct | 144 | @PostConstruct |
@@ -167,8 +180,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -167,8 +180,9 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
167 | transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); | 180 | transportService.process(sessionInfo, DefaultTransportService.getSessionEventMsg(SessionEvent.OPEN), null); |
168 | transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); | 181 | transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); |
169 | transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); | 182 | transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), null); |
183 | + this.getInfoFirmwareUpdate(lwM2MClient); | ||
170 | this.initLwM2mFromClientValue(registration, lwM2MClient); | 184 | this.initLwM2mFromClientValue(registration, lwM2MClient); |
171 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration); | 185 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client create after Registration", registration.getId()); |
172 | } else { | 186 | } else { |
173 | log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); | 187 | log.error("Client: [{}] onRegistered [{}] name [{}] sessionInfo ", registration.getId(), registration.getEndpoint(), null); |
174 | } | 188 | } |
@@ -223,7 +237,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -223,7 +237,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
223 | executorUnRegistered.submit(() -> { | 237 | executorUnRegistered.submit(() -> { |
224 | try { | 238 | try { |
225 | this.setCancelObservations(registration); | 239 | this.setCancelObservations(registration); |
226 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration); | 240 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client unRegistration", registration.getId()); |
227 | this.closeClientSession(registration); | 241 | this.closeClientSession(registration); |
228 | } catch (Throwable t) { | 242 | } catch (Throwable t) { |
229 | log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); | 243 | log.error("[{}] endpoint [{}] error Unable un registration.", registration.getEndpoint(), t); |
@@ -256,7 +270,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -256,7 +270,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
256 | @Override | 270 | @Override |
257 | public void onSleepingDev(Registration registration) { | 271 | public void onSleepingDev(Registration registration) { |
258 | log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); | 272 | log.info("[{}] [{}] Received endpoint Sleeping version event", registration.getId(), registration.getEndpoint()); |
259 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration); | 273 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is sleeping!", registration.getId()); |
260 | 274 | ||
261 | //TODO: associate endpointId with device information. | 275 | //TODO: associate endpointId with device information. |
262 | } | 276 | } |
@@ -279,7 +293,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -279,7 +293,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
279 | * @param response - observe | 293 | * @param response - observe |
280 | */ | 294 | */ |
281 | @Override | 295 | @Override |
282 | - public void onObservationResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { | 296 | + public void onUpdateValueAfterReadResponse(Registration registration, String path, ReadResponse response, Lwm2mClientRpcRequest rpcRequest) { |
283 | if (response.getContent() != null) { | 297 | if (response.getContent() != null) { |
284 | if (response.getContent() instanceof LwM2mObject) { | 298 | if (response.getContent() instanceof LwM2mObject) { |
285 | LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); | 299 | LwM2mObject lwM2mObject = (LwM2mObject) response.getContent(); |
@@ -303,20 +317,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -303,20 +317,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
303 | 317 | ||
304 | /** | 318 | /** |
305 | * Update - send request in change value resources in Client | 319 | * Update - send request in change value resources in Client |
306 | - * Path to resources from profile equal keyName or from ModelObject equal name | ||
307 | - * Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase) | ||
308 | - * Delete - nothing * | 320 | + * 1. FirmwareUpdate: |
321 | + * - If msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0 | ||
322 | + * 2. Shared Other AttributeUpdate | ||
323 | + * -- Path to resources from profile equal keyName or from ModelObject equal name | ||
324 | + * -- Only for resources: isWritable && isPresent as attribute in profile -> LwM2MClientProfile (format: CamelCase) | ||
325 | + * 3. Delete - nothing | ||
309 | * | 326 | * |
310 | * @param msg - | 327 | * @param msg - |
311 | */ | 328 | */ |
312 | @Override | 329 | @Override |
313 | public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { | 330 | public void onAttributeUpdate(AttributeUpdateNotificationMsg msg, TransportProtos.SessionInfoProto sessionInfo) { |
331 | + LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); | ||
314 | if (msg.getSharedUpdatedCount() > 0) { | 332 | if (msg.getSharedUpdatedCount() > 0) { |
315 | msg.getSharedUpdatedList().forEach(tsKvProto -> { | 333 | msg.getSharedUpdatedList().forEach(tsKvProto -> { |
316 | String pathName = tsKvProto.getKv().getKey(); | 334 | String pathName = tsKvProto.getKv().getKey(); |
317 | String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); | 335 | String pathIdVer = this.getPresentPathIntoProfile(sessionInfo, pathName); |
318 | Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); | 336 | Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); |
319 | - LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClient(new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB())); | 337 | + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { |
338 | + this.getInfoFirmwareUpdate(lwM2MClient); | ||
339 | + } | ||
320 | if (pathIdVer != null) { | 340 | if (pathIdVer != null) { |
321 | ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() | 341 | ResourceModel resourceModel = lwM2MClient.getResourceModel(pathIdVer, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
322 | .getModelProvider()); | 342 | .getModelProvider()); |
@@ -326,19 +346,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -326,19 +346,26 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
326 | log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew); | 346 | log.error("Resource path - [{}] value - [{}] is not Writable and cannot be updated", pathIdVer, valueNew); |
327 | String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", | 347 | String logMsg = String.format("%s: attributeUpdate: Resource path - %s value - %s is not Writable and cannot be updated", |
328 | LOG_LW2M_ERROR, pathIdVer, valueNew); | 348 | LOG_LW2M_ERROR, pathIdVer, valueNew); |
329 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | 349 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); |
330 | } | 350 | } |
331 | } else { | 351 | } else { |
332 | log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew); | 352 | log.error("Resource name name - [{}] value - [{}] is not present as attribute/telemetry in profile and cannot be updated", pathName, valueNew); |
333 | String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", | 353 | String logMsg = String.format("%s: attributeUpdate: attribute name - %s value - %s is not present as attribute in profile and cannot be updated", |
334 | LOG_LW2M_ERROR, pathName, valueNew); | 354 | LOG_LW2M_ERROR, pathName, valueNew); |
335 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | 355 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); |
336 | } | 356 | } |
357 | + | ||
337 | }); | 358 | }); |
338 | } else if (msg.getSharedDeletedCount() > 0) { | 359 | } else if (msg.getSharedDeletedCount() > 0) { |
360 | + msg.getSharedUpdatedList().forEach(tsKvProto -> { | ||
361 | + String pathName = tsKvProto.getKv().getKey(); | ||
362 | + Object valueNew = this.lwM2mTransportContextServer.getValueFromKvProto(tsKvProto.getKv()); | ||
363 | + if (FirmwareUtil.getAttributeKey(FirmwareType.FIRMWARE, FirmwareKey.VERSION).equals(pathName) && !valueNew.equals(lwM2MClient.getFrUpdate().getCurrentFwVersion())) { | ||
364 | + lwM2MClient.getFrUpdate().setCurrentFwVersion((String) valueNew); | ||
365 | + } | ||
366 | + }); | ||
339 | log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); | 367 | log.info("[{}] delete [{}] onAttributeUpdate", msg.getSharedDeletedList(), sessionInfo); |
340 | } | 368 | } |
341 | - | ||
342 | } | 369 | } |
343 | 370 | ||
344 | /** | 371 | /** |
@@ -454,23 +481,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -454,23 +481,21 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
454 | } | 481 | } |
455 | if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) { | 482 | if (rpcRequest.has(lwm2mClientRpcRequest.paramsKey) && rpcRequest.get(lwm2mClientRpcRequest.paramsKey).isJsonObject()) { |
456 | lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) | 483 | lwm2mClientRpcRequest.setParams(new Gson().fromJson(rpcRequest.get(lwm2mClientRpcRequest.paramsKey) |
457 | - .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() { | ||
458 | - }.getType())); | 484 | + .getAsJsonObject().toString(), new TypeToken<ConcurrentHashMap<String, Object>>() { |
485 | + }.getType())); | ||
459 | } | 486 | } |
460 | lwm2mClientRpcRequest.setSessionInfo(sessionInfo); | 487 | lwm2mClientRpcRequest.setSessionInfo(sessionInfo); |
461 | if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) { | 488 | if (OBSERVE_READ_ALL != lwm2mClientRpcRequest.getTypeOper() && lwm2mClientRpcRequest.getTargetIdVer() == null) { |
462 | lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " + | 489 | lwm2mClientRpcRequest.setErrorMsg(lwm2mClientRpcRequest.targetIdVerKey + " and " + |
463 | lwm2mClientRpcRequest.keyNameKey + " is null or bad format"); | 490 | lwm2mClientRpcRequest.keyNameKey + " is null or bad format"); |
464 | - } | ||
465 | - else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper() | 491 | + } else if ((EXECUTE == lwm2mClientRpcRequest.getTypeOper() |
466 | || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper()) | 492 | || WRITE_REPLACE == lwm2mClientRpcRequest.getTypeOper()) |
467 | - && lwm2mClientRpcRequest.getTargetIdVer() !=null | 493 | + && lwm2mClientRpcRequest.getTargetIdVer() != null |
468 | && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource() | 494 | && !(new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResource() |
469 | || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) { | 495 | || new LwM2mPath(convertPathFromIdVerToObjectId(lwm2mClientRpcRequest.getTargetIdVer())).isResourceInstance())) { |
470 | - lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey | 496 | + lwm2mClientRpcRequest.setErrorMsg("Invalid parameter " + lwm2mClientRpcRequest.targetIdVerKey |
471 | + ". Only Resource or ResourceInstance can be this operation"); | 497 | + ". Only Resource or ResourceInstance can be this operation"); |
472 | - } | ||
473 | - else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()){ | 498 | + } else if (WRITE_UPDATE == lwm2mClientRpcRequest.getTypeOper()) { |
474 | lwm2mClientRpcRequest.setErrorMsg("Procedures In Development..."); | 499 | lwm2mClientRpcRequest.setErrorMsg("Procedures In Development..."); |
475 | } | 500 | } |
476 | } else { | 501 | } else { |
@@ -482,23 +507,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -482,23 +507,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
482 | return lwm2mClientRpcRequest; | 507 | return lwm2mClientRpcRequest; |
483 | } | 508 | } |
484 | 509 | ||
485 | - public void sentRpcRequest (Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { | 510 | + public void sentRpcRequest(Lwm2mClientRpcRequest rpcRequest, String requestCode, String msg, String typeMsg) { |
486 | rpcRequest.setResponseCode(requestCode); | 511 | rpcRequest.setResponseCode(requestCode); |
487 | - if (LOG_LW2M_ERROR.equals(typeMsg)) { | ||
488 | - rpcRequest.setInfoMsg(null); | ||
489 | - rpcRequest.setValueMsg(null); | ||
490 | - if (rpcRequest.getErrorMsg() == null) { | ||
491 | - msg = msg.isEmpty() ? null : msg; | ||
492 | - rpcRequest.setErrorMsg(msg); | ||
493 | - } | ||
494 | - } else if (LOG_LW2M_INFO.equals(typeMsg)) { | ||
495 | - if (rpcRequest.getInfoMsg() == null) { | ||
496 | - rpcRequest.setInfoMsg(msg); | ||
497 | - } | ||
498 | - } else if (LOG_LW2M_VALUE.equals(typeMsg)) { | ||
499 | - if (rpcRequest.getValueMsg() == null) { | ||
500 | - rpcRequest.setValueMsg(msg); | ||
501 | - } | 512 | + if (LOG_LW2M_ERROR.equals(typeMsg)) { |
513 | + rpcRequest.setInfoMsg(null); | ||
514 | + rpcRequest.setValueMsg(null); | ||
515 | + if (rpcRequest.getErrorMsg() == null) { | ||
516 | + msg = msg.isEmpty() ? null : msg; | ||
517 | + rpcRequest.setErrorMsg(msg); | ||
518 | + } | ||
519 | + } else if (LOG_LW2M_INFO.equals(typeMsg)) { | ||
520 | + if (rpcRequest.getInfoMsg() == null) { | ||
521 | + rpcRequest.setInfoMsg(msg); | ||
522 | + } | ||
523 | + } else if (LOG_LW2M_VALUE.equals(typeMsg)) { | ||
524 | + if (rpcRequest.getValueMsg() == null) { | ||
525 | + rpcRequest.setValueMsg(msg); | ||
526 | + } | ||
502 | } | 527 | } |
503 | this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo()); | 528 | this.onToDeviceRpcResponse(rpcRequest.getDeviceRpcResponseResultMsg(), rpcRequest.getSessionInfo()); |
504 | } | 529 | } |
@@ -555,7 +580,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -555,7 +580,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
555 | */ | 580 | */ |
556 | protected void onAwakeDev(Registration registration) { | 581 | protected void onAwakeDev(Registration registration) { |
557 | log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); | 582 | log.info("[{}] [{}] Received endpoint Awake version event", registration.getId(), registration.getEndpoint()); |
558 | - this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration); | 583 | + this.sendLogsToThingsboard(LOG_LW2M_INFO + ": Client is awake!", registration.getId()); |
559 | //TODO: associate endpointId with device information. | 584 | //TODO: associate endpointId with device information. |
560 | } | 585 | } |
561 | 586 | ||
@@ -582,10 +607,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -582,10 +607,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
582 | 607 | ||
583 | /** | 608 | /** |
584 | * @param logMsg - text msg | 609 | * @param logMsg - text msg |
585 | - * @param registration - Id of Registration LwM2M Client | 610 | + * @param registrationId - Id of Registration LwM2M Client |
586 | */ | 611 | */ |
587 | - public void sendLogsToThingsboard(String logMsg, Registration registration) { | ||
588 | - SessionInfoProto sessionInfo = this.getValidateSessionInfo(registration); | 612 | + public void sendLogsToThingsboard(String logMsg, String registrationId) { |
613 | + SessionInfoProto sessionInfo = this.getValidateSessionInfo(registrationId); | ||
589 | if (logMsg != null && sessionInfo != null) { | 614 | if (logMsg != null && sessionInfo != null) { |
590 | this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo); | 615 | this.lwM2mTransportContextServer.sendParametersOnThingsboardTelemetry(this.lwM2mTransportContextServer.getKvLogyToThingsboard(logMsg), sessionInfo); |
591 | } | 616 | } |
@@ -609,7 +634,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -609,7 +634,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
609 | if (clientObjects != null && clientObjects.size() > 0) { | 634 | if (clientObjects != null && clientObjects.size() > 0) { |
610 | if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { | 635 | if (LWM2M_STRATEGY_2 == LwM2mTransportHandler.getClientOnlyObserveAfterConnect(lwM2MClientProfile)) { |
611 | // #2 | 636 | // #2 |
612 | - lwM2MClient.getPendingRequests().addAll(clientObjects); | 637 | + lwM2MClient.getPendingReadRequests().addAll(clientObjects); |
613 | clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(), | 638 | clientObjects.forEach(path -> lwM2mTransportRequest.sendAllRequest(registration, path, READ, ContentFormat.TLV.getName(), |
614 | null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null)); | 639 | null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null)); |
615 | } | 640 | } |
@@ -651,6 +676,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -651,6 +676,8 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
651 | * Sending observe value of resources to thingsboard | 676 | * Sending observe value of resources to thingsboard |
652 | * #1 Return old Value Resource from LwM2MClient | 677 | * #1 Return old Value Resource from LwM2MClient |
653 | * #2 Update new Resources (replace old Resource Value on new Resource Value) | 678 | * #2 Update new Resources (replace old Resource Value on new Resource Value) |
679 | + * #3 If fr_update -> UpdateFirmware | ||
680 | + * #4 updateAttrTelemetry | ||
654 | * | 681 | * |
655 | * @param registration - Registration LwM2M Client | 682 | * @param registration - Registration LwM2M Client |
656 | * @param lwM2mResource - LwM2mSingleResource response.getContent() | 683 | * @param lwM2mResource - LwM2mSingleResource response.getContent() |
@@ -660,6 +687,19 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -660,6 +687,19 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
660 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); | 687 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
661 | if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() | 688 | if (lwM2MClient.saveResourceValue(path, lwM2mResource, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer() |
662 | .getModelProvider())) { | 689 | .getModelProvider())) { |
690 | + if (FR_PATH_RESOURCE_VER_ID.equals(convertPathFromIdVerToObjectId(path)) && | ||
691 | + lwM2MClient.getFrUpdate().getCurrentFwVersion() != null | ||
692 | + && !lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion()) | ||
693 | + && lwM2MClient.isUpdateFw()) { | ||
694 | + | ||
695 | + /** version != null | ||
696 | + * set setClient_fw_version = value | ||
697 | + **/ | ||
698 | + lwM2MClient.setUpdateFw(false); | ||
699 | + lwM2MClient.getFrUpdate().setClientFwVersion(lwM2mResource.getValue().toString()); | ||
700 | + log.warn("updateFirmwareClient3"); | ||
701 | + this.updateFirmwareClient(lwM2MClient); | ||
702 | + } | ||
663 | Set<String> paths = new HashSet<>(); | 703 | Set<String> paths = new HashSet<>(); |
664 | paths.add(path); | 704 | paths.add(path); |
665 | this.updateAttrTelemetry(registration, paths); | 705 | this.updateAttrTelemetry(registration, paths); |
@@ -668,6 +708,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -668,6 +708,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
668 | } | 708 | } |
669 | } | 709 | } |
670 | 710 | ||
711 | + | ||
671 | /** | 712 | /** |
672 | * send Attribute and Telemetry to Thingsboard | 713 | * send Attribute and Telemetry to Thingsboard |
673 | * #1 - get AttrName/TelemetryName with value from LwM2MClient: | 714 | * #1 - get AttrName/TelemetryName with value from LwM2MClient: |
@@ -722,22 +763,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -722,22 +763,23 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
722 | params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()); | 763 | params = this.getPathForWriteAttributes(lwM2MClientProfile.getPostAttributeLwm2mProfile()); |
723 | result = params.keySet(); | 764 | result = params.keySet(); |
724 | } | 765 | } |
725 | - if (!result.isEmpty()) { | 766 | + if (result != null && !result.isEmpty()) { |
726 | // #1 | 767 | // #1 |
727 | Set<String> pathSend = result.stream().filter(target -> { | 768 | Set<String> pathSend = result.stream().filter(target -> { |
728 | return target.split(LWM2M_SEPARATOR_PATH).length < 3 ? | 769 | return target.split(LWM2M_SEPARATOR_PATH).length < 3 ? |
729 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) : | 770 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1]) : |
730 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]); | 771 | clientObjects.contains("/" + target.split(LWM2M_SEPARATOR_PATH)[1] + "/" + target.split(LWM2M_SEPARATOR_PATH)[2]); |
731 | } | 772 | } |
732 | - ) | ||
733 | - .collect(Collectors.toUnmodifiableSet()); | 773 | + ).collect(Collectors.toUnmodifiableSet()); |
734 | if (!pathSend.isEmpty()) { | 774 | if (!pathSend.isEmpty()) { |
735 | - lwM2MClient.getPendingRequests().addAll(pathSend); | 775 | + lwM2MClient.getPendingReadRequests().addAll(pathSend); |
736 | ConcurrentHashMap<String, Object> finalParams = params; | 776 | ConcurrentHashMap<String, Object> finalParams = params; |
737 | - pathSend.forEach(target -> lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), | ||
738 | - finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null)); | 777 | + pathSend.forEach(target -> { |
778 | + lwM2mTransportRequest.sendAllRequest(registration, target, typeOper, ContentFormat.TLV.getName(), | ||
779 | + finalParams != null ? finalParams.get(target) : null, this.lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | ||
780 | + }); | ||
739 | if (OBSERVE.equals(typeOper)) { | 781 | if (OBSERVE.equals(typeOper)) { |
740 | - lwM2MClient.initValue(this, null); | 782 | + lwM2MClient.initReadValue(this, null); |
741 | } | 783 | } |
742 | } | 784 | } |
743 | } | 785 | } |
@@ -968,7 +1010,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -968,7 +1010,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
968 | // update value in Resources | 1010 | // update value in Resources |
969 | registrationIds.forEach(registrationId -> { | 1011 | registrationIds.forEach(registrationId -> { |
970 | Registration registration = lwM2mClientContext.getRegistration(registrationId); | 1012 | Registration registration = lwM2mClientContext.getRegistration(registrationId); |
971 | - this.readResourceValueObserve(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); | 1013 | + this.readObserveFromProfile(registration, sendAttrToThingsboard.getPathPostParametersAdd(), READ); |
972 | // send attr/telemetry to tingsboard for new path | 1014 | // send attr/telemetry to tingsboard for new path |
973 | this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd()); | 1015 | this.updateAttrTelemetry(registration, sendAttrToThingsboard.getPathPostParametersAdd()); |
974 | }); | 1016 | }); |
@@ -997,12 +1039,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -997,12 +1039,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
997 | registrationIds.forEach(registrationId -> { | 1039 | registrationIds.forEach(registrationId -> { |
998 | Registration registration = lwM2mClientContext.getRegistration(registrationId); | 1040 | Registration registration = lwM2mClientContext.getRegistration(registrationId); |
999 | if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { | 1041 | if (postObserveAnalyzer.getPathPostParametersAdd().size() > 0) { |
1000 | - this.readResourceValueObserve(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); | 1042 | + this.readObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersAdd(), OBSERVE); |
1001 | } | 1043 | } |
1002 | // 5.3 del | 1044 | // 5.3 del |
1003 | // send Request cancel observe to Client | 1045 | // send Request cancel observe to Client |
1004 | if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) { | 1046 | if (postObserveAnalyzer.getPathPostParametersDel().size() > 0) { |
1005 | - this.cancelObserveIsValue(registration, postObserveAnalyzer.getPathPostParametersDel()); | 1047 | + this.cancelObserveFromProfile(registration, postObserveAnalyzer.getPathPostParametersDel()); |
1006 | } | 1048 | } |
1007 | }); | 1049 | }); |
1008 | } | 1050 | } |
@@ -1042,7 +1084,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1042,7 +1084,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1042 | * @param registration - Registration LwM2M Client | 1084 | * @param registration - Registration LwM2M Client |
1043 | * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] | 1085 | * @param targets - path Resources == [ "/2/0/0", "/2/0/1"] |
1044 | */ | 1086 | */ |
1045 | - private void readResourceValueObserve(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) { | 1087 | + private void readObserveFromProfile(Registration registration, Set<String> targets, LwM2mTypeOper typeOper) { |
1046 | targets.forEach(target -> { | 1088 | targets.forEach(target -> { |
1047 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target)); | 1089 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(target)); |
1048 | if (pathIds.isResource()) { | 1090 | if (pathIds.isResource()) { |
@@ -1132,7 +1174,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1132,7 +1174,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1132 | 1174 | ||
1133 | } | 1175 | } |
1134 | 1176 | ||
1135 | - private void cancelObserveIsValue(Registration registration, Set<String> paramAnallyzer) { | 1177 | + private void cancelObserveFromProfile(Registration registration, Set<String> paramAnallyzer) { |
1136 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); | 1178 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(registration, null); |
1137 | paramAnallyzer.forEach(pathIdVer -> { | 1179 | paramAnallyzer.forEach(pathIdVer -> { |
1138 | if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { | 1180 | if (this.getResourceValueFromLwM2MClient(lwM2MClient, pathIdVer) != null) { |
@@ -1152,7 +1194,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1152,7 +1194,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1152 | log.error("Failed update resource [{}] [{}]", path, valueNew); | 1194 | log.error("Failed update resource [{}] [{}]", path, valueNew); |
1153 | String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", | 1195 | String logMsg = String.format("%s: Failed update resource path - %s value - %s. Value is not changed or bad", |
1154 | LOG_LW2M_ERROR, path, valueNew); | 1196 | LOG_LW2M_ERROR, path, valueNew); |
1155 | - this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration()); | 1197 | + this.sendLogsToThingsboard(logMsg, lwM2MClient.getRegistration().getId()); |
1156 | log.info("Failed update resource [{}] [{}]", path, valueNew); | 1198 | log.info("Failed update resource [{}] [{}]", path, valueNew); |
1157 | } | 1199 | } |
1158 | } | 1200 | } |
@@ -1181,8 +1223,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1181,8 +1223,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1181 | } | 1223 | } |
1182 | 1224 | ||
1183 | /** | 1225 | /** |
1184 | - * Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values | ||
1185 | - * #1 Get path resource by result attributesResponse | 1226 | + * 1. FirmwareUpdate: |
1227 | + * - msg.getSharedUpdatedList().forEach(tsKvProto -> {tsKvProto.getKv().getKey().indexOf(FIRMWARE_UPDATE_PREFIX, 0) == 0 | ||
1228 | + * 2. Update resource value on client: if there is a difference in values between the current resource values and the shared attribute values | ||
1229 | + * - Get path resource by result attributesResponse | ||
1186 | * | 1230 | * |
1187 | * @param attributesResponse - | 1231 | * @param attributesResponse - |
1188 | * @param sessionInfo - | 1232 | * @param sessionInfo - |
@@ -1190,6 +1234,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1190,6 +1234,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1190 | public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { | 1234 | public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg attributesResponse, TransportProtos.SessionInfoProto sessionInfo) { |
1191 | try { | 1235 | try { |
1192 | List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList(); | 1236 | List<TransportProtos.TsKvProto> tsKvProtos = attributesResponse.getSharedAttributeListList(); |
1237 | + | ||
1193 | this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo); | 1238 | this.updateAttriuteFromThingsboard(tsKvProtos, sessionInfo); |
1194 | } catch (Exception e) { | 1239 | } catch (Exception e) { |
1195 | log.error(String.valueOf(e)); | 1240 | log.error(String.valueOf(e)); |
@@ -1273,7 +1318,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1273,7 +1318,7 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1273 | */ | 1318 | */ |
1274 | private SessionInfoProto getValidateSessionInfo(String registrationId) { | 1319 | private SessionInfoProto getValidateSessionInfo(String registrationId) { |
1275 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId); | 1320 | LwM2mClient lwM2MClient = lwM2mClientContext.getLwM2mClientWithReg(null, registrationId); |
1276 | - return getNewSessionInfoProto(lwM2MClient); | 1321 | + return lwM2MClient != null ? this.getNewSessionInfoProto(lwM2MClient) : null; |
1277 | } | 1322 | } |
1278 | 1323 | ||
1279 | /** | 1324 | /** |
@@ -1292,28 +1337,88 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1292,28 +1337,88 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1292 | } | 1337 | } |
1293 | 1338 | ||
1294 | /** | 1339 | /** |
1295 | - * !!! sharedAttr === profileAttr !!! | ||
1296 | - * If there is a difference in values between the current resource values and the shared attribute values | ||
1297 | - * when the client connects to the server | ||
1298 | - * #1 get attributes name from profile include name resources in ModelObject if resource isWritable | ||
1299 | - * #2.1 #1 size > 0 => send Request getAttributes to thingsboard | 1340 | + * #1. !!! sharedAttr === profileAttr !!! |
1341 | + * - If there is a difference in values between the current resource values and the shared attribute values | ||
1342 | + * - when the client connects to the server | ||
1343 | + * #1.1 get attributes name from profile include name resources in ModelObject if resource isWritable | ||
1344 | + * #1.2 #1 size > 0 => send Request getAttributes to thingsboard | ||
1345 | + * #2. FirmwareAttribute subscribe: | ||
1300 | * | 1346 | * |
1301 | * @param lwM2MClient - LwM2M Client | 1347 | * @param lwM2MClient - LwM2M Client |
1302 | */ | 1348 | */ |
1303 | public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { | 1349 | public void putDelayedUpdateResourcesThingsboard(LwM2mClient lwM2MClient) { |
1304 | SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); | 1350 | SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); |
1305 | if (sessionInfo != null) { | 1351 | if (sessionInfo != null) { |
1306 | - //#1.1 + #1.2 | ||
1307 | - List<String> attrSharedNames = this.getNamesAttrFromProfileIsWritable(lwM2MClient); | ||
1308 | - if (attrSharedNames.size() > 0) { | ||
1309 | - //#2.1 | 1352 | + //#1.1 |
1353 | + ConcurrentMap<String, String> keyNamesMap = this.getNamesFromProfileForSharedAttributes(lwM2MClient); | ||
1354 | + if (keyNamesMap.values().size() > 0) { | ||
1310 | try { | 1355 | try { |
1311 | - TransportProtos.GetAttributeRequestMsg getAttributeMsg = lwM2mTransportContextServer.getAdaptor().convertToGetAttributes(null, attrSharedNames); | 1356 | + //#1.2 |
1357 | + TransportProtos.GetAttributeRequestMsg getAttributeMsg = lwM2mTransportContextServer.getAdaptor().convertToGetAttributes(null, keyNamesMap.values()); | ||
1312 | transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); | 1358 | transportService.process(sessionInfo, getAttributeMsg, getAckCallback(lwM2MClient, getAttributeMsg.getRequestId(), DEVICE_ATTRIBUTES_REQUEST)); |
1313 | } catch (AdaptorException e) { | 1359 | } catch (AdaptorException e) { |
1314 | log.warn("Failed to decode get attributes request", e); | 1360 | log.warn("Failed to decode get attributes request", e); |
1315 | } | 1361 | } |
1316 | } | 1362 | } |
1363 | + | ||
1364 | + } | ||
1365 | + } | ||
1366 | + | ||
1367 | + public void getInfoFirmwareUpdate(LwM2mClient lwM2MClient) { | ||
1368 | + SessionInfoProto sessionInfo = this.getValidateSessionInfo(lwM2MClient.getRegistration()); | ||
1369 | + if (sessionInfo != null) { | ||
1370 | + TransportProtos.GetFirmwareRequestMsg getFirmwareRequestMsg = TransportProtos.GetFirmwareRequestMsg.newBuilder() | ||
1371 | + .setDeviceIdMSB(sessionInfo.getDeviceIdMSB()) | ||
1372 | + .setDeviceIdLSB(sessionInfo.getDeviceIdLSB()) | ||
1373 | + .setTenantIdMSB(sessionInfo.getTenantIdMSB()) | ||
1374 | + .setTenantIdLSB(sessionInfo.getTenantIdLSB()) | ||
1375 | + .build(); | ||
1376 | + transportService.process(sessionInfo, getFirmwareRequestMsg, | ||
1377 | + new TransportServiceCallback<>() { | ||
1378 | + @Override | ||
1379 | + public void onSuccess(TransportProtos.GetFirmwareResponseMsg response) { | ||
1380 | + if (TransportProtos.ResponseStatus.SUCCESS.equals(response.getResponseStatus())) { | ||
1381 | + lwM2MClient.getFrUpdate().setCurrentFwVersion(response.getVersion()); | ||
1382 | + lwM2MClient.getFrUpdate().setCurrentFwId(new FirmwareId(new UUID(response.getFirmwareIdMSB(), response.getFirmwareIdLSB())).getId()); | ||
1383 | + lwM2MClient.setUpdateFw(true); | ||
1384 | + readRequestToClientFirmwareVer(lwM2MClient.getRegistration()); | ||
1385 | + } else { | ||
1386 | + log.trace("Firmware [{}] [{}]", lwM2MClient.getDeviceName(), response.getResponseStatus().toString()); | ||
1387 | + } | ||
1388 | + } | ||
1389 | + | ||
1390 | + @Override | ||
1391 | + public void onError(Throwable e) { | ||
1392 | + log.trace("Failed to process credentials ", e); | ||
1393 | + } | ||
1394 | + }); | ||
1395 | + } | ||
1396 | + } | ||
1397 | + | ||
1398 | + /** | ||
1399 | + * @param registration | ||
1400 | + */ | ||
1401 | + public void readRequestToClientFirmwareVer(Registration registration) { | ||
1402 | + String pathIdVer = convertPathFromObjectIdToIdVer(FR_PATH_RESOURCE_VER_ID, registration); | ||
1403 | + lwM2mTransportRequest.sendAllRequest(registration, pathIdVer, READ, ContentFormat.TLV.getName(), | ||
1404 | + null, lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | ||
1405 | + } | ||
1406 | + | ||
1407 | + /** | ||
1408 | + * | ||
1409 | + * @param lwM2MClient - | ||
1410 | + */ | ||
1411 | + public void updateFirmwareClient(LwM2mClient lwM2MClient) { | ||
1412 | + if (!lwM2MClient.getFrUpdate().getCurrentFwVersion().equals(lwM2MClient.getFrUpdate().getClientFwVersion())) { | ||
1413 | + int chunkSize = 0; | ||
1414 | + int chunk = 0; | ||
1415 | + byte[] firmwareChunk = firmwareDataCache.get(lwM2MClient.getFrUpdate().getCurrentFwId().toString(), chunkSize, chunk); | ||
1416 | + Integer objectId = 5; | ||
1417 | + String verSupportedObject = lwM2MClient.getRegistration().getSupportedObject().get(objectId); | ||
1418 | + String targetIdVer = LWM2M_SEPARATOR_PATH + objectId + LWM2M_SEPARATOR_KEY + verSupportedObject + LWM2M_SEPARATOR_PATH + 0 + LWM2M_SEPARATOR_PATH + 0; | ||
1419 | + lwM2mTransportRequest.sendAllRequest(lwM2MClient.getRegistration(), targetIdVer, WRITE_REPLACE, ContentFormat.TLV.getName(), | ||
1420 | + firmwareChunk, lwM2mTransportContextServer.getLwM2MTransportConfigServer().getTimeout(), null); | ||
1421 | + log.warn("updateFirmwareClient [{}] [{}]", lwM2MClient.getFrUpdate().getCurrentFwVersion(), lwM2MClient.getFrUpdate().getClientFwVersion()); | ||
1317 | } | 1422 | } |
1318 | } | 1423 | } |
1319 | 1424 | ||
@@ -1325,23 +1430,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1325,23 +1430,12 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1325 | * @param lwM2MClient - | 1430 | * @param lwM2MClient - |
1326 | * @return ArrayList keyNames from profile profileAttr && IsWritable | 1431 | * @return ArrayList keyNames from profile profileAttr && IsWritable |
1327 | */ | 1432 | */ |
1328 | - private List<String> getNamesAttrFromProfileIsWritable(LwM2mClient lwM2MClient) { | 1433 | + private ConcurrentMap<String, String> getNamesFromProfileForSharedAttributes(LwM2mClient lwM2MClient) { |
1434 | + | ||
1329 | LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); | 1435 | LwM2mClientProfile profile = lwM2mClientContext.getProfile(lwM2MClient.getProfileId()); |
1330 | - Set<String> attrSet = new Gson().fromJson(profile.getPostAttributeProfile(), | ||
1331 | - new TypeToken<HashSet<String>>() { | ||
1332 | - }.getType()); | ||
1333 | - ConcurrentMap<String, String> keyNamesMap = new Gson().fromJson(profile.getPostKeyNameProfile().toString(), | 1436 | + return new Gson().fromJson(profile.getPostKeyNameProfile().toString(), |
1334 | new TypeToken<ConcurrentHashMap<String, String>>() { | 1437 | new TypeToken<ConcurrentHashMap<String, String>>() { |
1335 | }.getType()); | 1438 | }.getType()); |
1336 | - | ||
1337 | - ConcurrentMap<String, String> keyNamesIsWritable = keyNamesMap.entrySet() | ||
1338 | - .stream() | ||
1339 | - .filter(e -> (attrSet.contains(e.getKey()) && validateResourceInModel(lwM2MClient, e.getKey(), true))) | ||
1340 | - .collect(Collectors.toConcurrentMap(Map.Entry::getKey, Map.Entry::getValue)); | ||
1341 | - | ||
1342 | - Set<String> namesIsWritable = ConcurrentHashMap.newKeySet(); | ||
1343 | - namesIsWritable.addAll(new HashSet<>(keyNamesIsWritable.values())); | ||
1344 | - return new ArrayList<>(namesIsWritable); | ||
1345 | } | 1439 | } |
1346 | 1440 | ||
1347 | private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { | 1441 | private boolean validateResourceInModel(LwM2mClient lwM2mClient, String pathIdVer, boolean isWritableNotOptional) { |
@@ -1353,4 +1447,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | @@ -1353,4 +1447,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { | ||
1353 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : | 1447 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : |
1354 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); | 1448 | objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); |
1355 | } | 1449 | } |
1450 | + | ||
1451 | + @Override | ||
1452 | + public String getName() { | ||
1453 | + return "LWM2M"; | ||
1454 | + } | ||
1455 | + | ||
1356 | } | 1456 | } |
@@ -24,11 +24,8 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException; | @@ -24,11 +24,8 @@ import org.thingsboard.server.common.transport.adaptor.AdaptorException; | ||
24 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; | 24 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
25 | import org.thingsboard.server.gen.transport.TransportProtos; | 25 | import org.thingsboard.server.gen.transport.TransportProtos; |
26 | 26 | ||
27 | -import java.util.Arrays; | ||
28 | -import java.util.HashSet; | ||
29 | -import java.util.List; | 27 | +import java.util.Collection; |
30 | import java.util.Random; | 28 | import java.util.Random; |
31 | -import java.util.Set; | ||
32 | 29 | ||
33 | @Slf4j | 30 | @Slf4j |
34 | @Component("LwM2MJsonAdaptor") | 31 | @Component("LwM2MJsonAdaptor") |
@@ -54,11 +51,7 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { | @@ -54,11 +51,7 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { | ||
54 | } | 51 | } |
55 | 52 | ||
56 | @Override | 53 | @Override |
57 | - public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException { | ||
58 | - return processGetAttributeRequestMsg(clientKeys, sharedKeys); | ||
59 | - } | ||
60 | - | ||
61 | - protected TransportProtos.GetAttributeRequestMsg processGetAttributeRequestMsg(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException { | 54 | + public TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException { |
62 | try { | 55 | try { |
63 | TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); | 56 | TransportProtos.GetAttributeRequestMsg.Builder result = TransportProtos.GetAttributeRequestMsg.newBuilder(); |
64 | Random random = new Random(); | 57 | Random random = new Random(); |
@@ -75,14 +68,4 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { | @@ -75,14 +68,4 @@ public class LwM2MJsonAdaptor implements LwM2MTransportAdaptor { | ||
75 | throw new AdaptorException(e); | 68 | throw new AdaptorException(e); |
76 | } | 69 | } |
77 | } | 70 | } |
78 | - | ||
79 | - private Set<String> toStringSet(JsonElement requestBody, String name) { | ||
80 | - JsonElement element = requestBody.getAsJsonObject().get(name); | ||
81 | - if (element != null) { | ||
82 | - return new HashSet<>(Arrays.asList(element.getAsString().split(","))); | ||
83 | - } else { | ||
84 | - return null; | ||
85 | - } | ||
86 | - } | ||
87 | - | ||
88 | } | 71 | } |
@@ -19,7 +19,7 @@ import com.google.gson.JsonElement; | @@ -19,7 +19,7 @@ import com.google.gson.JsonElement; | ||
19 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; | 19 | import org.thingsboard.server.common.transport.adaptor.AdaptorException; |
20 | import org.thingsboard.server.gen.transport.TransportProtos; | 20 | import org.thingsboard.server.gen.transport.TransportProtos; |
21 | 21 | ||
22 | -import java.util.List; | 22 | +import java.util.Collection; |
23 | 23 | ||
24 | public interface LwM2MTransportAdaptor { | 24 | public interface LwM2MTransportAdaptor { |
25 | 25 | ||
@@ -27,5 +27,5 @@ public interface LwM2MTransportAdaptor { | @@ -27,5 +27,5 @@ public interface LwM2MTransportAdaptor { | ||
27 | 27 | ||
28 | TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException; | 28 | TransportProtos.PostAttributeMsg convertToPostAttributes(JsonElement jsonElement) throws AdaptorException; |
29 | 29 | ||
30 | - TransportProtos.GetAttributeRequestMsg convertToGetAttributes(List<String> clientKeys, List<String> sharedKeys) throws AdaptorException; | 30 | + TransportProtos.GetAttributeRequestMsg convertToGetAttributes(Collection<String> clientKeys, Collection<String> sharedKeys) throws AdaptorException; |
31 | } | 31 | } |
@@ -57,13 +57,15 @@ public class LwM2mClient implements Cloneable { | @@ -57,13 +57,15 @@ public class LwM2mClient implements Cloneable { | ||
57 | private UUID deviceId; | 57 | private UUID deviceId; |
58 | private UUID sessionId; | 58 | private UUID sessionId; |
59 | private UUID profileId; | 59 | private UUID profileId; |
60 | + private volatile LwM2mFirmwareUpdate frUpdate; | ||
60 | private Registration registration; | 61 | private Registration registration; |
61 | private ValidateDeviceCredentialsResponseMsg credentialsResponse; | 62 | private ValidateDeviceCredentialsResponseMsg credentialsResponse; |
62 | private final Map<String, ResourceValue> resources; | 63 | private final Map<String, ResourceValue> resources; |
63 | private final Map<String, TransportProtos.TsKvProto> delayedRequests; | 64 | private final Map<String, TransportProtos.TsKvProto> delayedRequests; |
64 | - private final List<String> pendingRequests; | 65 | + private final List<String> pendingReadRequests; |
65 | private final Queue<LwM2mQueuedRequest> queuedRequests; | 66 | private final Queue<LwM2mQueuedRequest> queuedRequests; |
66 | private boolean init; | 67 | private boolean init; |
68 | + private volatile boolean updateFw; | ||
67 | 69 | ||
68 | public Object clone() throws CloneNotSupportedException { | 70 | public Object clone() throws CloneNotSupportedException { |
69 | return super.clone(); | 71 | return super.clone(); |
@@ -75,12 +77,14 @@ public class LwM2mClient implements Cloneable { | @@ -75,12 +77,14 @@ public class LwM2mClient implements Cloneable { | ||
75 | this.securityInfo = securityInfo; | 77 | this.securityInfo = securityInfo; |
76 | this.credentialsResponse = credentialsResponse; | 78 | this.credentialsResponse = credentialsResponse; |
77 | this.delayedRequests = new ConcurrentHashMap<>(); | 79 | this.delayedRequests = new ConcurrentHashMap<>(); |
78 | - this.pendingRequests = new CopyOnWriteArrayList<>(); | 80 | + this.pendingReadRequests = new CopyOnWriteArrayList<>(); |
79 | this.resources = new ConcurrentHashMap<>(); | 81 | this.resources = new ConcurrentHashMap<>(); |
80 | this.profileId = profileId; | 82 | this.profileId = profileId; |
81 | this.sessionId = sessionId; | 83 | this.sessionId = sessionId; |
82 | this.init = false; | 84 | this.init = false; |
85 | + this.updateFw = false; | ||
83 | this.queuedRequests = new ConcurrentLinkedQueue<>(); | 86 | this.queuedRequests = new ConcurrentLinkedQueue<>(); |
87 | + this.frUpdate = new LwM2mFirmwareUpdate(); | ||
84 | } | 88 | } |
85 | 89 | ||
86 | public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) { | 90 | public boolean saveResourceValue(String pathRez, LwM2mResource rez, LwM2mModelProvider modelProvider) { |
@@ -103,15 +107,13 @@ public class LwM2mClient implements Cloneable { | @@ -103,15 +107,13 @@ public class LwM2mClient implements Cloneable { | ||
103 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); | 107 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRez)); |
104 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | 108 | String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); |
105 | String verRez = getVerFromPathIdVerOrId(pathRez); | 109 | String verRez = getVerFromPathIdVerOrId(pathRez); |
106 | - return (verRez == null || verSupportedObject.equals(verRez)) ? modelProvider.getObjectModel(registration) | 110 | + return verRez == null || verRez.equals(verSupportedObject) ? modelProvider.getObjectModel(registration) |
107 | .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; | 111 | .getResourceModel(pathIds.getObjectId(), pathIds.getResourceId()) : null; |
108 | } | 112 | } |
109 | 113 | ||
110 | public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, LwM2mModelProvider modelProvider, | 114 | public Collection<LwM2mResource> getNewResourcesForInstance(String pathRezIdVer, LwM2mModelProvider modelProvider, |
111 | LwM2mValueConverterImpl converter) { | 115 | LwM2mValueConverterImpl converter) { |
112 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); | 116 | LwM2mPath pathIds = new LwM2mPath(convertPathFromIdVerToObjectId(pathRezIdVer)); |
113 | - String verSupportedObject = registration.getSupportedObject().get(pathIds.getObjectId()); | ||
114 | - String verRez = getVerFromPathIdVerOrId(pathRezIdVer); | ||
115 | Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); | 117 | Collection<LwM2mResource> resources = ConcurrentHashMap.newKeySet(); |
116 | Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) | 118 | Map<Integer, ResourceModel> resourceModels = modelProvider.getObjectModel(registration) |
117 | .getObjectModel(pathIds.getObjectId()).resources; | 119 | .getObjectModel(pathIds.getObjectId()).resources; |
@@ -170,11 +172,11 @@ public class LwM2mClient implements Cloneable { | @@ -170,11 +172,11 @@ public class LwM2mClient implements Cloneable { | ||
170 | .collect(Collectors.toSet()); | 172 | .collect(Collectors.toSet()); |
171 | } | 173 | } |
172 | 174 | ||
173 | - public void initValue(LwM2mTransportServiceImpl serviceImpl, String path) { | 175 | + public void initReadValue(LwM2mTransportServiceImpl serviceImpl, String path) { |
174 | if (path != null) { | 176 | if (path != null) { |
175 | - this.pendingRequests.remove(path); | 177 | + this.pendingReadRequests.remove(path); |
176 | } | 178 | } |
177 | - if (this.pendingRequests.size() == 0) { | 179 | + if (this.pendingReadRequests.size() == 0) { |
178 | this.init = true; | 180 | this.init = true; |
179 | serviceImpl.putDelayedUpdateResourcesThingsboard(this); | 181 | serviceImpl.putDelayedUpdateResourcesThingsboard(this); |
180 | } | 182 | } |
@@ -82,12 +82,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | @@ -82,12 +82,12 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { | ||
82 | 82 | ||
83 | @Override | 83 | @Override |
84 | public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) { | 84 | public LwM2mClient getLwM2mClientWithReg(Registration registration, String registrationId) { |
85 | - LwM2mClient client = registrationId != null ? | 85 | + LwM2mClient client = registrationId != null && this.lwM2mClients.containsKey(registrationId) ? |
86 | this.lwM2mClients.get(registrationId) : | 86 | this.lwM2mClients.get(registrationId) : |
87 | - this.lwM2mClients.containsKey(registration.getId()) ? | ||
88 | - this.lwM2mClients.get(registration.getId()) : | ||
89 | - this.lwM2mClients.get(registration.getEndpoint()); | ||
90 | - return client != null ? client : updateInSessionsLwM2MClient(registration); | 87 | + registration !=null && this.lwM2mClients.containsKey(registration.getId()) ? |
88 | + this.lwM2mClients.get(registration.getId()) : registration !=null && this.lwM2mClients.containsKey(registration) ? | ||
89 | + this.lwM2mClients.get(registration.getEndpoint()) : null; | ||
90 | + return client != null ? client : registration!= null ? updateInSessionsLwM2MClient(registration) : null; | ||
91 | } | 91 | } |
92 | 92 | ||
93 | @Override | 93 | @Override |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.lwm2m.server.client; | ||
17 | + | ||
18 | +import lombok.Data; | ||
19 | + | ||
20 | +import java.util.UUID; | ||
21 | + | ||
22 | +@Data | ||
23 | +public class LwM2mFirmwareUpdate { | ||
24 | + private volatile String clientFwVersion; | ||
25 | + private volatile String currentFwVersion; | ||
26 | + private volatile UUID currentFwId; | ||
27 | +} |
@@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; | @@ -28,6 +28,7 @@ import org.springframework.beans.factory.annotation.Value; | ||
28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
29 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 29 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
30 | import org.springframework.stereotype.Service; | 30 | import org.springframework.stereotype.Service; |
31 | +import org.thingsboard.server.common.data.TbTransportService; | ||
31 | 32 | ||
32 | import javax.annotation.PostConstruct; | 33 | import javax.annotation.PostConstruct; |
33 | import javax.annotation.PreDestroy; | 34 | import javax.annotation.PreDestroy; |
@@ -38,7 +39,7 @@ import javax.annotation.PreDestroy; | @@ -38,7 +39,7 @@ import javax.annotation.PreDestroy; | ||
38 | @Service("MqttTransportService") | 39 | @Service("MqttTransportService") |
39 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')") | 40 | @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.mqtt.enabled}'=='true')") |
40 | @Slf4j | 41 | @Slf4j |
41 | -public class MqttTransportService { | 42 | +public class MqttTransportService implements TbTransportService { |
42 | 43 | ||
43 | @Value("${transport.mqtt.bind_address}") | 44 | @Value("${transport.mqtt.bind_address}") |
44 | private String host; | 45 | private String host; |
@@ -90,4 +91,9 @@ public class MqttTransportService { | @@ -90,4 +91,9 @@ public class MqttTransportService { | ||
90 | } | 91 | } |
91 | log.info("MQTT transport stopped!"); | 92 | log.info("MQTT transport stopped!"); |
92 | } | 93 | } |
94 | + | ||
95 | + @Override | ||
96 | + public String getName() { | ||
97 | + return "MQTT"; | ||
98 | + } | ||
93 | } | 99 | } |
common/transport/snmp/pom.xml
0 → 100644
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2021 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
20 | + <modelVersion>4.0.0</modelVersion> | ||
21 | + | ||
22 | + <parent> | ||
23 | + <groupId>org.thingsboard.common</groupId> | ||
24 | + <version>3.3.0-SNAPSHOT</version> | ||
25 | + <artifactId>transport</artifactId> | ||
26 | + </parent> | ||
27 | + | ||
28 | + <groupId>org.thingsboard.common.transport</groupId> | ||
29 | + <artifactId>snmp</artifactId> | ||
30 | + <packaging>jar</packaging> | ||
31 | + | ||
32 | + <name>Thingsboard SNMP Transport Common</name> | ||
33 | + <url>https://thingsboard.io</url> | ||
34 | + | ||
35 | + <properties> | ||
36 | + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||
37 | + <main.dir>${basedir}/../../..</main.dir> | ||
38 | + </properties> | ||
39 | + | ||
40 | + <dependencies> | ||
41 | + <dependency> | ||
42 | + <groupId>org.thingsboard.common.transport</groupId> | ||
43 | + <artifactId>transport-api</artifactId> | ||
44 | + </dependency> | ||
45 | + <dependency> | ||
46 | + <groupId>org.springframework</groupId> | ||
47 | + <artifactId>spring-context-support</artifactId> | ||
48 | + </dependency> | ||
49 | + <dependency> | ||
50 | + <groupId>org.springframework</groupId> | ||
51 | + <artifactId>spring-context</artifactId> | ||
52 | + </dependency> | ||
53 | + <dependency> | ||
54 | + <groupId>org.slf4j</groupId> | ||
55 | + <artifactId>slf4j-api</artifactId> | ||
56 | + </dependency> | ||
57 | + <dependency> | ||
58 | + <groupId>org.snmp4j</groupId> | ||
59 | + <artifactId>snmp4j</artifactId> | ||
60 | + </dependency> | ||
61 | + <dependency> | ||
62 | + <groupId>org.snmp4j</groupId> | ||
63 | + <artifactId>snmp4j-agent</artifactId> | ||
64 | + <version>3.3.6</version> | ||
65 | + <scope>test</scope> | ||
66 | + </dependency> | ||
67 | + </dependencies> | ||
68 | +</project> |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp; | ||
17 | + | ||
18 | +import lombok.Getter; | ||
19 | +import lombok.RequiredArgsConstructor; | ||
20 | +import lombok.extern.slf4j.Slf4j; | ||
21 | +import org.springframework.context.event.EventListener; | ||
22 | +import org.springframework.stereotype.Component; | ||
23 | +import org.thingsboard.server.common.data.Device; | ||
24 | +import org.thingsboard.server.common.data.DeviceProfile; | ||
25 | +import org.thingsboard.server.common.data.DeviceTransportType; | ||
26 | +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; | ||
27 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | ||
28 | +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | ||
29 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
30 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | ||
31 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | ||
32 | +import org.thingsboard.server.common.data.security.DeviceCredentialsType; | ||
33 | +import org.thingsboard.server.common.transport.DeviceUpdatedEvent; | ||
34 | +import org.thingsboard.server.common.transport.TransportContext; | ||
35 | +import org.thingsboard.server.common.transport.TransportDeviceProfileCache; | ||
36 | +import org.thingsboard.server.common.transport.TransportService; | ||
37 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
38 | +import org.thingsboard.server.common.transport.auth.SessionInfoCreator; | ||
39 | +import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; | ||
40 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
41 | +import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; | ||
42 | +import org.thingsboard.server.queue.util.AfterStartUp; | ||
43 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
44 | +import org.thingsboard.server.transport.snmp.service.ProtoTransportEntityService; | ||
45 | +import org.thingsboard.server.transport.snmp.service.SnmpAuthService; | ||
46 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; | ||
47 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportService; | ||
48 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | ||
49 | + | ||
50 | +import java.util.Collection; | ||
51 | +import java.util.LinkedList; | ||
52 | +import java.util.List; | ||
53 | +import java.util.Map; | ||
54 | +import java.util.Optional; | ||
55 | +import java.util.UUID; | ||
56 | +import java.util.concurrent.ConcurrentHashMap; | ||
57 | +import java.util.concurrent.ConcurrentLinkedDeque; | ||
58 | + | ||
59 | +@TbSnmpTransportComponent | ||
60 | +@Component | ||
61 | +@Slf4j | ||
62 | +@RequiredArgsConstructor | ||
63 | +public class SnmpTransportContext extends TransportContext { | ||
64 | + @Getter | ||
65 | + private final SnmpTransportService snmpTransportService; | ||
66 | + private final TransportDeviceProfileCache deviceProfileCache; | ||
67 | + private final TransportService transportService; | ||
68 | + private final ProtoTransportEntityService protoEntityService; | ||
69 | + private final SnmpTransportBalancingService balancingService; | ||
70 | + @Getter | ||
71 | + private final SnmpAuthService snmpAuthService; | ||
72 | + | ||
73 | + private final Map<DeviceId, DeviceSessionContext> sessions = new ConcurrentHashMap<>(); | ||
74 | + private final Collection<DeviceId> allSnmpDevicesIds = new ConcurrentLinkedDeque<>(); | ||
75 | + | ||
76 | + @AfterStartUp(order = 2) | ||
77 | + public void fetchDevicesAndEstablishSessions() { | ||
78 | + log.info("Initializing SNMP devices sessions"); | ||
79 | + | ||
80 | + int batchIndex = 0; | ||
81 | + int batchSize = 512; | ||
82 | + boolean nextBatchExists = true; | ||
83 | + | ||
84 | + while (nextBatchExists) { | ||
85 | + TransportProtos.GetSnmpDevicesResponseMsg snmpDevicesResponse = protoEntityService.getSnmpDevicesIds(batchIndex, batchSize); | ||
86 | + snmpDevicesResponse.getIdsList().stream() | ||
87 | + .map(id -> new DeviceId(UUID.fromString(id))) | ||
88 | + .peek(allSnmpDevicesIds::add) | ||
89 | + .filter(deviceId -> balancingService.isManagedByCurrentTransport(deviceId.getId())) | ||
90 | + .map(protoEntityService::getDeviceById) | ||
91 | + .forEach(device -> getExecutor().execute(() -> establishDeviceSession(device))); | ||
92 | + | ||
93 | + nextBatchExists = snmpDevicesResponse.getHasNextPage(); | ||
94 | + batchIndex++; | ||
95 | + } | ||
96 | + | ||
97 | + log.debug("Found all SNMP devices ids: {}", allSnmpDevicesIds); | ||
98 | + } | ||
99 | + | ||
100 | + private void establishDeviceSession(Device device) { | ||
101 | + if (device == null) return; | ||
102 | + log.info("Establishing SNMP session for device {}", device.getId()); | ||
103 | + | ||
104 | + DeviceProfileId deviceProfileId = device.getDeviceProfileId(); | ||
105 | + DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId); | ||
106 | + | ||
107 | + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId()); | ||
108 | + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { | ||
109 | + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType()); | ||
110 | + return; | ||
111 | + } | ||
112 | + | ||
113 | + SnmpDeviceProfileTransportConfiguration profileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); | ||
114 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration(); | ||
115 | + | ||
116 | + DeviceSessionContext deviceSessionContext; | ||
117 | + try { | ||
118 | + deviceSessionContext = new DeviceSessionContext( | ||
119 | + device, deviceProfile, credentials.getCredentialsId(), | ||
120 | + profileTransportConfiguration, deviceTransportConfiguration, this | ||
121 | + ); | ||
122 | + registerSessionMsgListener(deviceSessionContext); | ||
123 | + } catch (Exception e) { | ||
124 | + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString()); | ||
125 | + return; | ||
126 | + } | ||
127 | + sessions.put(device.getId(), deviceSessionContext); | ||
128 | + snmpTransportService.createQueryingTasks(deviceSessionContext); | ||
129 | + log.info("Established SNMP device session for device {}", device.getId()); | ||
130 | + } | ||
131 | + | ||
132 | + private void updateDeviceSession(DeviceSessionContext sessionContext, Device device, DeviceProfile deviceProfile) { | ||
133 | + log.info("Updating SNMP session for device {}", device.getId()); | ||
134 | + | ||
135 | + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId()); | ||
136 | + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) { | ||
137 | + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType()); | ||
138 | + destroyDeviceSession(sessionContext); | ||
139 | + return; | ||
140 | + } | ||
141 | + | ||
142 | + SnmpDeviceProfileTransportConfiguration newProfileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration(); | ||
143 | + SnmpDeviceTransportConfiguration newDeviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration(); | ||
144 | + | ||
145 | + try { | ||
146 | + if (!newProfileTransportConfiguration.equals(sessionContext.getProfileTransportConfiguration())) { | ||
147 | + sessionContext.setProfileTransportConfiguration(newProfileTransportConfiguration); | ||
148 | + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration); | ||
149 | + snmpTransportService.cancelQueryingTasks(sessionContext); | ||
150 | + snmpTransportService.createQueryingTasks(sessionContext); | ||
151 | + } else if (!newDeviceTransportConfiguration.equals(sessionContext.getDeviceTransportConfiguration())) { | ||
152 | + sessionContext.setDeviceTransportConfiguration(newDeviceTransportConfiguration); | ||
153 | + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration); | ||
154 | + } else { | ||
155 | + log.trace("Configuration of the device {} was not updated", device); | ||
156 | + } | ||
157 | + } catch (Exception e) { | ||
158 | + log.error("Failed to update session for SNMP device {}: {}", sessionContext.getDeviceId(), e.getMessage()); | ||
159 | + destroyDeviceSession(sessionContext); | ||
160 | + } | ||
161 | + } | ||
162 | + | ||
163 | + private void destroyDeviceSession(DeviceSessionContext sessionContext) { | ||
164 | + if (sessionContext == null) return; | ||
165 | + log.info("Destroying SNMP device session for device {}", sessionContext.getDevice().getId()); | ||
166 | + sessionContext.close(); | ||
167 | + snmpAuthService.cleanUpSnmpAuthInfo(sessionContext); | ||
168 | + transportService.deregisterSession(sessionContext.getSessionInfo()); | ||
169 | + snmpTransportService.cancelQueryingTasks(sessionContext); | ||
170 | + sessions.remove(sessionContext.getDeviceId()); | ||
171 | + log.trace("Unregistered and removed session"); | ||
172 | + } | ||
173 | + | ||
174 | + private void registerSessionMsgListener(DeviceSessionContext deviceSessionContext) { | ||
175 | + transportService.process(DeviceTransportType.SNMP, | ||
176 | + TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceSessionContext.getToken()).build(), | ||
177 | + new TransportServiceCallback<>() { | ||
178 | + @Override | ||
179 | + public void onSuccess(ValidateDeviceCredentialsResponse msg) { | ||
180 | + if (msg.hasDeviceInfo()) { | ||
181 | + SessionInfoProto sessionInfo = SessionInfoCreator.create( | ||
182 | + msg, SnmpTransportContext.this, UUID.randomUUID() | ||
183 | + ); | ||
184 | + | ||
185 | + transportService.registerAsyncSession(sessionInfo, deviceSessionContext); | ||
186 | + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | ||
187 | + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | ||
188 | + | ||
189 | + deviceSessionContext.setSessionInfo(sessionInfo); | ||
190 | + deviceSessionContext.setDeviceInfo(msg.getDeviceInfo()); | ||
191 | + } else { | ||
192 | + log.warn("[{}] Failed to process device auth", deviceSessionContext.getDeviceId()); | ||
193 | + } | ||
194 | + } | ||
195 | + | ||
196 | + @Override | ||
197 | + public void onError(Throwable e) { | ||
198 | + log.warn("[{}] Failed to process device auth: {}", deviceSessionContext.getDeviceId(), e); | ||
199 | + } | ||
200 | + }); | ||
201 | + } | ||
202 | + | ||
203 | + @EventListener(DeviceUpdatedEvent.class) | ||
204 | + public void onDeviceUpdatedOrCreated(DeviceUpdatedEvent deviceUpdatedEvent) { | ||
205 | + Device device = deviceUpdatedEvent.getDevice(); | ||
206 | + log.trace("Got creating or updating device event for device {}", device); | ||
207 | + DeviceTransportType transportType = Optional.ofNullable(device.getDeviceData().getTransportConfiguration()) | ||
208 | + .map(DeviceTransportConfiguration::getType) | ||
209 | + .orElse(null); | ||
210 | + if (!allSnmpDevicesIds.contains(device.getId())) { | ||
211 | + if (transportType != DeviceTransportType.SNMP) { | ||
212 | + return; | ||
213 | + } | ||
214 | + allSnmpDevicesIds.add(device.getId()); | ||
215 | + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) { | ||
216 | + establishDeviceSession(device); | ||
217 | + } | ||
218 | + } else { | ||
219 | + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) { | ||
220 | + DeviceSessionContext sessionContext = sessions.get(device.getId()); | ||
221 | + if (transportType == DeviceTransportType.SNMP) { | ||
222 | + if (sessionContext != null) { | ||
223 | + updateDeviceSession(sessionContext, device, deviceProfileCache.get(device.getDeviceProfileId())); | ||
224 | + } else { | ||
225 | + establishDeviceSession(device); | ||
226 | + } | ||
227 | + } else { | ||
228 | + log.trace("Transport type was changed to {}", transportType); | ||
229 | + destroyDeviceSession(sessionContext); | ||
230 | + } | ||
231 | + } | ||
232 | + } | ||
233 | + } | ||
234 | + | ||
235 | + public void onDeviceDeleted(DeviceSessionContext sessionContext) { | ||
236 | + destroyDeviceSession(sessionContext); | ||
237 | + } | ||
238 | + | ||
239 | + public void onDeviceProfileUpdated(DeviceProfile deviceProfile, DeviceSessionContext sessionContext) { | ||
240 | + updateDeviceSession(sessionContext, sessionContext.getDevice(), deviceProfile); | ||
241 | + } | ||
242 | + | ||
243 | + public void onSnmpTransportListChanged() { | ||
244 | + log.trace("SNMP transport list changed. Updating sessions"); | ||
245 | + List<DeviceId> deleted = new LinkedList<>(); | ||
246 | + for (DeviceId deviceId : allSnmpDevicesIds) { | ||
247 | + if (balancingService.isManagedByCurrentTransport(deviceId.getId())) { | ||
248 | + if (!sessions.containsKey(deviceId)) { | ||
249 | + Device device = protoEntityService.getDeviceById(deviceId); | ||
250 | + if (device != null) { | ||
251 | + log.info("SNMP device {} is now managed by current transport node", deviceId); | ||
252 | + establishDeviceSession(device); | ||
253 | + } else { | ||
254 | + deleted.add(deviceId); | ||
255 | + } | ||
256 | + } | ||
257 | + } else { | ||
258 | + Optional.ofNullable(sessions.get(deviceId)) | ||
259 | + .ifPresent(sessionContext -> { | ||
260 | + log.info("SNMP session for device {} is not managed by current transport node anymore", deviceId); | ||
261 | + destroyDeviceSession(sessionContext); | ||
262 | + }); | ||
263 | + } | ||
264 | + } | ||
265 | + log.trace("Removing deleted SNMP devices: {}", deleted); | ||
266 | + allSnmpDevicesIds.removeAll(deleted); | ||
267 | + } | ||
268 | + | ||
269 | + | ||
270 | + public Collection<DeviceSessionContext> getSessions() { | ||
271 | + return sessions.values(); | ||
272 | + } | ||
273 | + | ||
274 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.event; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import org.springframework.stereotype.Component; | ||
20 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | ||
21 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | ||
22 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
23 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; | ||
24 | + | ||
25 | +@TbSnmpTransportComponent | ||
26 | +@Component | ||
27 | +@RequiredArgsConstructor | ||
28 | +public class ServiceListChangedEventListener extends TbApplicationEventListener<ServiceListChangedEvent> { | ||
29 | + private final SnmpTransportBalancingService snmpTransportBalancingService; | ||
30 | + | ||
31 | + @Override | ||
32 | + protected void onTbApplicationEvent(ServiceListChangedEvent event) { | ||
33 | + snmpTransportBalancingService.onServiceListChanged(event); | ||
34 | + } | ||
35 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.event; | ||
17 | + | ||
18 | +import org.thingsboard.server.queue.discovery.event.TbApplicationEvent; | ||
19 | + | ||
20 | +public class SnmpTransportListChangedEvent extends TbApplicationEvent { | ||
21 | + public SnmpTransportListChangedEvent() { | ||
22 | + super(new Object()); | ||
23 | + } | ||
24 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.event; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import org.springframework.stereotype.Component; | ||
20 | +import org.thingsboard.server.queue.discovery.TbApplicationEventListener; | ||
21 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
22 | +import org.thingsboard.server.transport.snmp.SnmpTransportContext; | ||
23 | + | ||
24 | +@TbSnmpTransportComponent | ||
25 | +@Component | ||
26 | +@RequiredArgsConstructor | ||
27 | +public class SnmpTransportListChangedEventListener extends TbApplicationEventListener<SnmpTransportListChangedEvent> { | ||
28 | + private final SnmpTransportContext snmpTransportContext; | ||
29 | + | ||
30 | + @Override | ||
31 | + protected void onTbApplicationEvent(SnmpTransportListChangedEvent event) { | ||
32 | + snmpTransportContext.onSnmpTransportListChanged(); | ||
33 | + } | ||
34 | +} |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduService.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.service; | ||
17 | + | ||
18 | +import com.google.gson.JsonObject; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.snmp4j.PDU; | ||
21 | +import org.snmp4j.ScopedPDU; | ||
22 | +import org.snmp4j.smi.Integer32; | ||
23 | +import org.snmp4j.smi.Null; | ||
24 | +import org.snmp4j.smi.OID; | ||
25 | +import org.snmp4j.smi.OctetString; | ||
26 | +import org.snmp4j.smi.Variable; | ||
27 | +import org.snmp4j.smi.VariableBinding; | ||
28 | +import org.springframework.stereotype.Service; | ||
29 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | ||
30 | +import org.thingsboard.server.common.data.kv.DataType; | ||
31 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | ||
32 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | ||
33 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | ||
34 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | ||
35 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
36 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | ||
37 | + | ||
38 | +import java.util.HashMap; | ||
39 | +import java.util.List; | ||
40 | +import java.util.Map; | ||
41 | +import java.util.Objects; | ||
42 | +import java.util.Optional; | ||
43 | +import java.util.stream.Collectors; | ||
44 | +import java.util.stream.IntStream; | ||
45 | + | ||
46 | +@TbSnmpTransportComponent | ||
47 | +@Service | ||
48 | +@Slf4j | ||
49 | +public class PduService { | ||
50 | + public PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | ||
51 | + PDU pdu = setUpPdu(sessionContext); | ||
52 | + | ||
53 | + pdu.setType(communicationConfig.getMethod().getCode()); | ||
54 | + pdu.addAll(communicationConfig.getAllMappings().stream() | ||
55 | + .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) | ||
56 | + .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) | ||
57 | + .map(value -> { | ||
58 | + Variable variable = toSnmpVariable(value, mapping.getDataType()); | ||
59 | + return new VariableBinding(new OID(mapping.getOid()), variable); | ||
60 | + }) | ||
61 | + .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) | ||
62 | + .collect(Collectors.toList())); | ||
63 | + | ||
64 | + return pdu; | ||
65 | + } | ||
66 | + | ||
67 | + public PDU createSingleVariablePdu(DeviceSessionContext sessionContext, SnmpMethod snmpMethod, String oid, String value, DataType dataType) { | ||
68 | + PDU pdu = setUpPdu(sessionContext); | ||
69 | + pdu.setType(snmpMethod.getCode()); | ||
70 | + | ||
71 | + Variable variable = value == null ? Null.instance : toSnmpVariable(value, dataType); | ||
72 | + pdu.add(new VariableBinding(new OID(oid), variable)); | ||
73 | + | ||
74 | + return pdu; | ||
75 | + } | ||
76 | + | ||
77 | + private Variable toSnmpVariable(String value, DataType dataType) { | ||
78 | + dataType = dataType == null ? DataType.STRING : dataType; | ||
79 | + Variable variable; | ||
80 | + switch (dataType) { | ||
81 | + case LONG: | ||
82 | + try { | ||
83 | + variable = new Integer32(Integer.parseInt(value)); | ||
84 | + break; | ||
85 | + } catch (NumberFormatException ignored) { | ||
86 | + } | ||
87 | + case DOUBLE: | ||
88 | + case BOOLEAN: | ||
89 | + case STRING: | ||
90 | + case JSON: | ||
91 | + default: | ||
92 | + variable = new OctetString(value); | ||
93 | + } | ||
94 | + return variable; | ||
95 | + } | ||
96 | + | ||
97 | + private PDU setUpPdu(DeviceSessionContext sessionContext) { | ||
98 | + PDU pdu; | ||
99 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | ||
100 | + SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); | ||
101 | + switch (snmpVersion) { | ||
102 | + case V1: | ||
103 | + case V2C: | ||
104 | + pdu = new PDU(); | ||
105 | + break; | ||
106 | + case V3: | ||
107 | + ScopedPDU scopedPdu = new ScopedPDU(); | ||
108 | + scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); | ||
109 | + scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); | ||
110 | + pdu = scopedPdu; | ||
111 | + break; | ||
112 | + default: | ||
113 | + throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); | ||
114 | + } | ||
115 | + return pdu; | ||
116 | + } | ||
117 | + | ||
118 | + | ||
119 | + public JsonObject processPdu(PDU pdu, List<SnmpMapping> responseMappings) { | ||
120 | + Map<OID, String> values = processPdu(pdu); | ||
121 | + | ||
122 | + Map<OID, SnmpMapping> mappings = new HashMap<>(); | ||
123 | + if (responseMappings != null) { | ||
124 | + for (SnmpMapping mapping : responseMappings) { | ||
125 | + OID oid = new OID(mapping.getOid()); | ||
126 | + mappings.put(oid, mapping); | ||
127 | + } | ||
128 | + } | ||
129 | + | ||
130 | + JsonObject data = new JsonObject(); | ||
131 | + values.forEach((oid, value) -> { | ||
132 | + log.trace("Processing variable binding: {} - {}", oid, value); | ||
133 | + | ||
134 | + SnmpMapping mapping = mappings.get(oid); | ||
135 | + if (mapping == null) { | ||
136 | + log.debug("No SNMP mapping for oid {}", oid); | ||
137 | + return; | ||
138 | + } | ||
139 | + | ||
140 | + processValue(mapping.getKey(), mapping.getDataType(), value, data); | ||
141 | + }); | ||
142 | + | ||
143 | + return data; | ||
144 | + } | ||
145 | + | ||
146 | + public Map<OID, String> processPdu(PDU pdu) { | ||
147 | + return IntStream.range(0, pdu.size()) | ||
148 | + .mapToObj(pdu::get) | ||
149 | + .filter(Objects::nonNull) | ||
150 | + .filter(variableBinding -> !(variableBinding.getVariable() instanceof Null)) | ||
151 | + .collect(Collectors.toMap(VariableBinding::getOid, VariableBinding::toValueString)); | ||
152 | + } | ||
153 | + | ||
154 | + public void processValue(String key, DataType dataType, String value, JsonObject result) { | ||
155 | + switch (dataType) { | ||
156 | + case LONG: | ||
157 | + result.addProperty(key, Long.parseLong(value)); | ||
158 | + break; | ||
159 | + case BOOLEAN: | ||
160 | + result.addProperty(key, Boolean.parseBoolean(value)); | ||
161 | + break; | ||
162 | + case DOUBLE: | ||
163 | + result.addProperty(key, Double.parseDouble(value)); | ||
164 | + break; | ||
165 | + case STRING: | ||
166 | + case JSON: | ||
167 | + default: | ||
168 | + result.addProperty(key, value); | ||
169 | + } | ||
170 | + } | ||
171 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.service; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import org.springframework.stereotype.Service; | ||
20 | +import org.thingsboard.server.common.data.Device; | ||
21 | +import org.thingsboard.server.common.data.device.data.DeviceData; | ||
22 | +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration; | ||
23 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
24 | +import org.thingsboard.server.common.data.id.DeviceProfileId; | ||
25 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | ||
26 | +import org.thingsboard.server.common.transport.TransportService; | ||
27 | +import org.thingsboard.server.common.transport.util.DataDecodingEncodingService; | ||
28 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
29 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
30 | + | ||
31 | +import java.util.ArrayList; | ||
32 | +import java.util.List; | ||
33 | +import java.util.UUID; | ||
34 | +import java.util.stream.Collectors; | ||
35 | + | ||
36 | +@TbSnmpTransportComponent | ||
37 | +@Service | ||
38 | +@RequiredArgsConstructor | ||
39 | +public class ProtoTransportEntityService { | ||
40 | + private final TransportService transportService; | ||
41 | + private final DataDecodingEncodingService dataDecodingEncodingService; | ||
42 | + | ||
43 | + public Device getDeviceById(DeviceId id) { | ||
44 | + TransportProtos.GetDeviceResponseMsg deviceProto = transportService.getDevice(TransportProtos.GetDeviceRequestMsg.newBuilder() | ||
45 | + .setDeviceIdMSB(id.getId().getMostSignificantBits()) | ||
46 | + .setDeviceIdLSB(id.getId().getLeastSignificantBits()) | ||
47 | + .build()); | ||
48 | + | ||
49 | + if (deviceProto == null) { | ||
50 | + return null; | ||
51 | + } | ||
52 | + | ||
53 | + DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID( | ||
54 | + deviceProto.getDeviceProfileIdMSB(), deviceProto.getDeviceProfileIdLSB()) | ||
55 | + ); | ||
56 | + | ||
57 | + Device device = new Device(); | ||
58 | + device.setId(id); | ||
59 | + device.setDeviceProfileId(deviceProfileId); | ||
60 | + | ||
61 | + DeviceTransportConfiguration deviceTransportConfiguration = (DeviceTransportConfiguration) dataDecodingEncodingService.decode( | ||
62 | + deviceProto.getDeviceTransportConfiguration().toByteArray() | ||
63 | + ).orElseThrow(() -> new IllegalStateException("Can't find device transport configuration")); | ||
64 | + | ||
65 | + DeviceData deviceData = new DeviceData(); | ||
66 | + deviceData.setTransportConfiguration(deviceTransportConfiguration); | ||
67 | + device.setDeviceData(deviceData); | ||
68 | + | ||
69 | + return device; | ||
70 | + } | ||
71 | + | ||
72 | + public DeviceCredentials getDeviceCredentialsByDeviceId(DeviceId deviceId) { | ||
73 | + TransportProtos.GetDeviceCredentialsResponseMsg deviceCredentialsResponse = transportService.getDeviceCredentials( | ||
74 | + TransportProtos.GetDeviceCredentialsRequestMsg.newBuilder() | ||
75 | + .setDeviceIdMSB(deviceId.getId().getMostSignificantBits()) | ||
76 | + .setDeviceIdLSB(deviceId.getId().getLeastSignificantBits()) | ||
77 | + .build() | ||
78 | + ); | ||
79 | + | ||
80 | + return (DeviceCredentials) dataDecodingEncodingService.decode(deviceCredentialsResponse.getDeviceCredentialsData().toByteArray()) | ||
81 | + .orElseThrow(() -> new IllegalArgumentException("Device credentials not found")); | ||
82 | + } | ||
83 | + | ||
84 | + public TransportProtos.GetSnmpDevicesResponseMsg getSnmpDevicesIds(int page, int pageSize) { | ||
85 | + TransportProtos.GetSnmpDevicesRequestMsg requestMsg = TransportProtos.GetSnmpDevicesRequestMsg.newBuilder() | ||
86 | + .setPage(page) | ||
87 | + .setPageSize(pageSize) | ||
88 | + .build(); | ||
89 | + return transportService.getSnmpDevicesIds(requestMsg); | ||
90 | + } | ||
91 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.service; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import org.snmp4j.AbstractTarget; | ||
20 | +import org.snmp4j.CommunityTarget; | ||
21 | +import org.snmp4j.Target; | ||
22 | +import org.snmp4j.UserTarget; | ||
23 | +import org.snmp4j.security.SecurityLevel; | ||
24 | +import org.snmp4j.security.SecurityModel; | ||
25 | +import org.snmp4j.security.SecurityProtocols; | ||
26 | +import org.snmp4j.security.USM; | ||
27 | +import org.snmp4j.smi.Address; | ||
28 | +import org.snmp4j.smi.GenericAddress; | ||
29 | +import org.snmp4j.smi.OID; | ||
30 | +import org.snmp4j.smi.OctetString; | ||
31 | +import org.springframework.beans.factory.annotation.Value; | ||
32 | +import org.springframework.stereotype.Service; | ||
33 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | ||
34 | +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; | ||
35 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | ||
36 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
37 | +import org.thingsboard.server.transport.snmp.service.SnmpTransportService; | ||
38 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | ||
39 | + | ||
40 | +import java.util.Optional; | ||
41 | + | ||
42 | +@Service | ||
43 | +@TbSnmpTransportComponent | ||
44 | +@RequiredArgsConstructor | ||
45 | +public class SnmpAuthService { | ||
46 | + private final SnmpTransportService snmpTransportService; | ||
47 | + | ||
48 | + @Value("${transport.snmp.underlying_protocol}") | ||
49 | + private String snmpUnderlyingProtocol; | ||
50 | + | ||
51 | + public Target setUpSnmpTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) { | ||
52 | + AbstractTarget target; | ||
53 | + | ||
54 | + SnmpProtocolVersion protocolVersion = deviceTransportConfig.getProtocolVersion(); | ||
55 | + switch (protocolVersion) { | ||
56 | + case V1: | ||
57 | + CommunityTarget communityTargetV1 = new CommunityTarget(); | ||
58 | + communityTargetV1.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv1); | ||
59 | + communityTargetV1.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV); | ||
60 | + communityTargetV1.setCommunity(new OctetString(deviceTransportConfig.getCommunity())); | ||
61 | + target = communityTargetV1; | ||
62 | + break; | ||
63 | + case V2C: | ||
64 | + CommunityTarget communityTargetV2 = new CommunityTarget(); | ||
65 | + communityTargetV2.setSecurityModel(SecurityModel.SECURITY_MODEL_SNMPv2c); | ||
66 | + communityTargetV2.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV); | ||
67 | + communityTargetV2.setCommunity(new OctetString(deviceTransportConfig.getCommunity())); | ||
68 | + target = communityTargetV2; | ||
69 | + break; | ||
70 | + case V3: | ||
71 | + OctetString username = new OctetString(deviceTransportConfig.getUsername()); | ||
72 | + OctetString securityName = new OctetString(deviceTransportConfig.getSecurityName()); | ||
73 | + OctetString engineId = new OctetString(deviceTransportConfig.getEngineId()); | ||
74 | + | ||
75 | + OID authenticationProtocol = new OID(deviceTransportConfig.getAuthenticationProtocol().getOid()); | ||
76 | + OID privacyProtocol = new OID(deviceTransportConfig.getPrivacyProtocol().getOid()); | ||
77 | + OctetString authenticationPassphrase = new OctetString(deviceTransportConfig.getAuthenticationPassphrase()); | ||
78 | + authenticationPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(authenticationProtocol, authenticationPassphrase, engineId.getValue())); | ||
79 | + OctetString privacyPassphrase = new OctetString(deviceTransportConfig.getPrivacyPassphrase()); | ||
80 | + privacyPassphrase = new OctetString(SecurityProtocols.getInstance().passwordToKey(privacyProtocol, authenticationProtocol, privacyPassphrase, engineId.getValue())); | ||
81 | + | ||
82 | + USM usm = snmpTransportService.getSnmp().getUSM(); | ||
83 | + if (usm.hasUser(engineId, securityName)) { | ||
84 | + usm.removeAllUsers(username, engineId); | ||
85 | + } | ||
86 | + usm.addLocalizedUser( | ||
87 | + engineId.getValue(), username, | ||
88 | + authenticationProtocol, authenticationPassphrase.getValue(), | ||
89 | + privacyProtocol, privacyPassphrase.getValue() | ||
90 | + ); | ||
91 | + | ||
92 | + UserTarget userTarget = new UserTarget(); | ||
93 | + userTarget.setSecurityName(securityName); | ||
94 | + userTarget.setAuthoritativeEngineID(engineId.getValue()); | ||
95 | + userTarget.setSecurityModel(SecurityModel.SECURITY_MODEL_USM); | ||
96 | + userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV); | ||
97 | + target = userTarget; | ||
98 | + break; | ||
99 | + default: | ||
100 | + throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported"); | ||
101 | + } | ||
102 | + | ||
103 | + Address address = GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort()); | ||
104 | + target.setAddress(Optional.ofNullable(address).orElseThrow(() -> new IllegalArgumentException("Address of the SNMP device is invalid"))); | ||
105 | + target.setTimeout(profileTransportConfig.getTimeoutMs()); | ||
106 | + target.setRetries(profileTransportConfig.getRetries()); | ||
107 | + target.setVersion(protocolVersion.getCode()); | ||
108 | + | ||
109 | + return target; | ||
110 | + } | ||
111 | + | ||
112 | + public void cleanUpSnmpAuthInfo(DeviceSessionContext sessionContext) { | ||
113 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | ||
114 | + if (deviceTransportConfiguration.getProtocolVersion() == SnmpProtocolVersion.V3) { | ||
115 | + OctetString username = new OctetString(deviceTransportConfiguration.getUsername()); | ||
116 | + OctetString engineId = new OctetString(deviceTransportConfiguration.getEngineId()); | ||
117 | + snmpTransportService.getSnmp().getUSM().removeAllUsers(username, engineId); | ||
118 | + } | ||
119 | + } | ||
120 | + | ||
121 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.service; | ||
17 | + | ||
18 | +import lombok.RequiredArgsConstructor; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.springframework.context.ApplicationEventPublisher; | ||
21 | +import org.springframework.stereotype.Service; | ||
22 | +import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; | ||
23 | +import org.thingsboard.server.queue.discovery.PartitionService; | ||
24 | +import org.thingsboard.server.queue.discovery.event.ServiceListChangedEvent; | ||
25 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
26 | +import org.thingsboard.server.transport.snmp.event.SnmpTransportListChangedEvent; | ||
27 | + | ||
28 | +import java.util.Comparator; | ||
29 | +import java.util.List; | ||
30 | +import java.util.UUID; | ||
31 | +import java.util.stream.Collectors; | ||
32 | +import java.util.stream.Stream; | ||
33 | + | ||
34 | +@TbSnmpTransportComponent | ||
35 | +@Service | ||
36 | +@RequiredArgsConstructor | ||
37 | +@Slf4j | ||
38 | +public class SnmpTransportBalancingService { | ||
39 | + private final PartitionService partitionService; | ||
40 | + private final ApplicationEventPublisher eventPublisher; | ||
41 | + private final SnmpTransportService snmpTransportService; | ||
42 | + | ||
43 | + private int snmpTransportsCount = 1; | ||
44 | + private Integer currentTransportPartitionIndex = 0; | ||
45 | + | ||
46 | + public void onServiceListChanged(ServiceListChangedEvent event) { | ||
47 | + log.trace("Got service list changed event: {}", event); | ||
48 | + recalculatePartitions(event.getOtherServices(), event.getCurrentService()); | ||
49 | + } | ||
50 | + | ||
51 | + public boolean isManagedByCurrentTransport(UUID entityId) { | ||
52 | + boolean isManaged = resolvePartitionIndexForEntity(entityId) == currentTransportPartitionIndex; | ||
53 | + if (!isManaged) { | ||
54 | + log.trace("Entity {} is not managed by current SNMP transport node", entityId); | ||
55 | + } | ||
56 | + return isManaged; | ||
57 | + } | ||
58 | + | ||
59 | + private int resolvePartitionIndexForEntity(UUID entityId) { | ||
60 | + return partitionService.resolvePartitionIndex(entityId, snmpTransportsCount); | ||
61 | + } | ||
62 | + | ||
63 | + private void recalculatePartitions(List<ServiceInfo> otherServices, ServiceInfo currentService) { | ||
64 | + log.info("Recalculating partitions for SNMP transports"); | ||
65 | + List<ServiceInfo> snmpTransports = Stream.concat(otherServices.stream(), Stream.of(currentService)) | ||
66 | + .filter(service -> service.getTransportsList().contains(snmpTransportService.getName())) | ||
67 | + .sorted(Comparator.comparing(ServiceInfo::getServiceId)) | ||
68 | + .collect(Collectors.toList()); | ||
69 | + log.trace("Found SNMP transports: {}", snmpTransports); | ||
70 | + | ||
71 | + int previousCurrentTransportPartitionIndex = currentTransportPartitionIndex; | ||
72 | + int previousSnmpTransportsCount = snmpTransportsCount; | ||
73 | + | ||
74 | + if (!snmpTransports.isEmpty()) { | ||
75 | + for (int i = 0; i < snmpTransports.size(); i++) { | ||
76 | + if (snmpTransports.get(i).equals(currentService)) { | ||
77 | + currentTransportPartitionIndex = i; | ||
78 | + break; | ||
79 | + } | ||
80 | + } | ||
81 | + snmpTransportsCount = snmpTransports.size(); | ||
82 | + } | ||
83 | + | ||
84 | + if (snmpTransportsCount != previousSnmpTransportsCount || currentTransportPartitionIndex != previousCurrentTransportPartitionIndex) { | ||
85 | + log.info("SNMP transports partitions have changed: transports count = {}, current transport partition index = {}", snmpTransportsCount, currentTransportPartitionIndex); | ||
86 | + eventPublisher.publishEvent(new SnmpTransportListChangedEvent()); | ||
87 | + } else { | ||
88 | + log.info("SNMP transports partitions have not changed"); | ||
89 | + } | ||
90 | + } | ||
91 | + | ||
92 | +} |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.transport.snmp.service; | ||
17 | + | ||
18 | +import com.google.gson.JsonElement; | ||
19 | +import com.google.gson.JsonObject; | ||
20 | +import lombok.Data; | ||
21 | +import lombok.Getter; | ||
22 | +import lombok.RequiredArgsConstructor; | ||
23 | +import lombok.extern.slf4j.Slf4j; | ||
24 | +import org.snmp4j.PDU; | ||
25 | +import org.snmp4j.Snmp; | ||
26 | +import org.snmp4j.TransportMapping; | ||
27 | +import org.snmp4j.event.ResponseEvent; | ||
28 | +import org.snmp4j.mp.MPv3; | ||
29 | +import org.snmp4j.security.SecurityModels; | ||
30 | +import org.snmp4j.security.SecurityProtocols; | ||
31 | +import org.snmp4j.security.USM; | ||
32 | +import org.snmp4j.smi.OctetString; | ||
33 | +import org.snmp4j.transport.DefaultTcpTransportMapping; | ||
34 | +import org.snmp4j.transport.DefaultUdpTransportMapping; | ||
35 | +import org.springframework.beans.factory.annotation.Value; | ||
36 | +import org.springframework.stereotype.Service; | ||
37 | +import org.thingsboard.common.util.ThingsBoardThreadFactory; | ||
38 | +import org.thingsboard.server.common.data.TbTransportService; | ||
39 | +import org.thingsboard.server.common.data.kv.DataType; | ||
40 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | ||
41 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | ||
42 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | ||
43 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | ||
44 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | ||
45 | +import org.thingsboard.server.common.transport.TransportService; | ||
46 | +import org.thingsboard.server.common.transport.TransportServiceCallback; | ||
47 | +import org.thingsboard.server.common.transport.adaptor.JsonConverter; | ||
48 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
49 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | ||
50 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | ||
51 | + | ||
52 | +import javax.annotation.PostConstruct; | ||
53 | +import javax.annotation.PreDestroy; | ||
54 | +import java.io.IOException; | ||
55 | +import java.util.Arrays; | ||
56 | +import java.util.Collections; | ||
57 | +import java.util.EnumMap; | ||
58 | +import java.util.List; | ||
59 | +import java.util.Map; | ||
60 | +import java.util.Optional; | ||
61 | +import java.util.concurrent.ExecutorService; | ||
62 | +import java.util.concurrent.Executors; | ||
63 | +import java.util.concurrent.ScheduledExecutorService; | ||
64 | +import java.util.concurrent.ScheduledFuture; | ||
65 | +import java.util.concurrent.TimeUnit; | ||
66 | +import java.util.stream.Collectors; | ||
67 | + | ||
68 | +@TbSnmpTransportComponent | ||
69 | +@Service | ||
70 | +@Slf4j | ||
71 | +@RequiredArgsConstructor | ||
72 | +public class SnmpTransportService implements TbTransportService { | ||
73 | + private final TransportService transportService; | ||
74 | + private final PduService pduService; | ||
75 | + | ||
76 | + @Getter | ||
77 | + private Snmp snmp; | ||
78 | + private ScheduledExecutorService queryingExecutor; | ||
79 | + private ExecutorService responseProcessingExecutor; | ||
80 | + | ||
81 | + private final Map<SnmpCommunicationSpec, ResponseDataMapper> responseDataMappers = new EnumMap<>(SnmpCommunicationSpec.class); | ||
82 | + private final Map<SnmpCommunicationSpec, ResponseProcessor> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); | ||
83 | + | ||
84 | + @Value("${transport.snmp.response_processing.parallelism_level}") | ||
85 | + private Integer responseProcessingParallelismLevel; | ||
86 | + @Value("${transport.snmp.underlying_protocol}") | ||
87 | + private String snmpUnderlyingProtocol; | ||
88 | + | ||
89 | + @PostConstruct | ||
90 | + private void init() throws IOException { | ||
91 | + queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying")); | ||
92 | + responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel); | ||
93 | + | ||
94 | + initializeSnmp(); | ||
95 | + configureResponseDataMappers(); | ||
96 | + configureResponseProcessors(); | ||
97 | + | ||
98 | + log.info("SNMP transport service initialized"); | ||
99 | + } | ||
100 | + | ||
101 | + private void initializeSnmp() throws IOException { | ||
102 | + TransportMapping<?> transportMapping; | ||
103 | + switch (snmpUnderlyingProtocol) { | ||
104 | + case "udp": | ||
105 | + transportMapping = new DefaultUdpTransportMapping(); | ||
106 | + break; | ||
107 | + case "tcp": | ||
108 | + transportMapping = new DefaultTcpTransportMapping(); | ||
109 | + break; | ||
110 | + default: | ||
111 | + throw new IllegalArgumentException("Underlying protocol " + snmpUnderlyingProtocol + " for SNMP is not supported"); | ||
112 | + } | ||
113 | + snmp = new Snmp(transportMapping); | ||
114 | + snmp.listen(); | ||
115 | + | ||
116 | + USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0); | ||
117 | + SecurityModels.getInstance().addSecurityModel(usm); | ||
118 | + } | ||
119 | + | ||
120 | + public void createQueryingTasks(DeviceSessionContext sessionContext) { | ||
121 | + List<ScheduledFuture<?>> queryingTasks = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() | ||
122 | + .filter(communicationConfig -> communicationConfig instanceof RepeatingQueryingSnmpCommunicationConfig) | ||
123 | + .map(config -> { | ||
124 | + RepeatingQueryingSnmpCommunicationConfig repeatingCommunicationConfig = (RepeatingQueryingSnmpCommunicationConfig) config; | ||
125 | + Long queryingFrequency = repeatingCommunicationConfig.getQueryingFrequencyMs(); | ||
126 | + | ||
127 | + return queryingExecutor.scheduleWithFixedDelay(() -> { | ||
128 | + try { | ||
129 | + if (sessionContext.isActive()) { | ||
130 | + sendRequest(sessionContext, repeatingCommunicationConfig); | ||
131 | + } | ||
132 | + } catch (Exception e) { | ||
133 | + log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); | ||
134 | + } | ||
135 | + }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); | ||
136 | + }) | ||
137 | + .collect(Collectors.toList()); | ||
138 | + sessionContext.getQueryingTasks().addAll(queryingTasks); | ||
139 | + } | ||
140 | + | ||
141 | + public void cancelQueryingTasks(DeviceSessionContext sessionContext) { | ||
142 | + sessionContext.getQueryingTasks().forEach(task -> task.cancel(true)); | ||
143 | + sessionContext.getQueryingTasks().clear(); | ||
144 | + } | ||
145 | + | ||
146 | + | ||
147 | + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { | ||
148 | + sendRequest(sessionContext, communicationConfig, Collections.emptyMap()); | ||
149 | + } | ||
150 | + | ||
151 | + private void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | ||
152 | + PDU request = pduService.createPdu(sessionContext, communicationConfig, values); | ||
153 | + RequestInfo requestInfo = new RequestInfo(communicationConfig.getSpec(), communicationConfig.getAllMappings()); | ||
154 | + sendRequest(sessionContext, request, requestInfo); | ||
155 | + } | ||
156 | + | ||
157 | + private void sendRequest(DeviceSessionContext sessionContext, PDU request, RequestInfo requestInfo) { | ||
158 | + if (request.size() > 0) { | ||
159 | + log.trace("Executing SNMP request for device {}. Variables bindings: {}", sessionContext.getDeviceId(), request.getVariableBindings()); | ||
160 | + try { | ||
161 | + snmp.send(request, sessionContext.getTarget(), requestInfo, sessionContext); | ||
162 | + } catch (IOException e) { | ||
163 | + log.error("Failed to send SNMP request to device {}: {}", sessionContext.getDeviceId(), e.toString()); | ||
164 | + } | ||
165 | + } | ||
166 | + } | ||
167 | + | ||
168 | + public void onAttributeUpdate(DeviceSessionContext sessionContext, TransportProtos.AttributeUpdateNotificationMsg attributeUpdateNotification) { | ||
169 | + sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() | ||
170 | + .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) | ||
171 | + .findFirst() | ||
172 | + .ifPresent(communicationConfig -> { | ||
173 | + Map<String, String> sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream() | ||
174 | + .collect(Collectors.toMap( | ||
175 | + Map.Entry::getKey, | ||
176 | + entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString() | ||
177 | + )); | ||
178 | + sendRequest(sessionContext, communicationConfig, sharedAttributes); | ||
179 | + }); | ||
180 | + } | ||
181 | + | ||
182 | + public void onToDeviceRpcRequest(DeviceSessionContext sessionContext, TransportProtos.ToDeviceRpcRequestMsg toDeviceRpcRequestMsg) { | ||
183 | + SnmpMethod snmpMethod = SnmpMethod.valueOf(toDeviceRpcRequestMsg.getMethodName()); | ||
184 | + JsonObject params = JsonConverter.parse(toDeviceRpcRequestMsg.getParams()).getAsJsonObject(); | ||
185 | + | ||
186 | + String key = Optional.ofNullable(params.get("key")).map(JsonElement::getAsString).orElse(null); | ||
187 | + String value = Optional.ofNullable(params.get("value")).map(JsonElement::getAsString).orElse(null); | ||
188 | + | ||
189 | + if (value == null && snmpMethod == SnmpMethod.SET) { | ||
190 | + throw new IllegalArgumentException("Value must be specified for SNMP method 'SET'"); | ||
191 | + } | ||
192 | + | ||
193 | + SnmpCommunicationConfig communicationConfig = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() | ||
194 | + .filter(config -> config.getSpec() == SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST) | ||
195 | + .findFirst() | ||
196 | + .orElseThrow(() -> new IllegalArgumentException("No communication config found with RPC spec")); | ||
197 | + SnmpMapping snmpMapping = communicationConfig.getAllMappings().stream() | ||
198 | + .filter(mapping -> mapping.getKey().equals(key)) | ||
199 | + .findFirst() | ||
200 | + .orElseThrow(() -> new IllegalArgumentException("No SNMP mapping found in the config for specified key")); | ||
201 | + | ||
202 | + String oid = snmpMapping.getOid(); | ||
203 | + DataType dataType = snmpMapping.getDataType(); | ||
204 | + | ||
205 | + PDU request = pduService.createSingleVariablePdu(sessionContext, snmpMethod, oid, value, dataType); | ||
206 | + RequestInfo requestInfo = new RequestInfo(toDeviceRpcRequestMsg.getRequestId(), communicationConfig.getSpec(), communicationConfig.getAllMappings()); | ||
207 | + sendRequest(sessionContext, request, requestInfo); | ||
208 | + } | ||
209 | + | ||
210 | + | ||
211 | + public void processResponseEvent(DeviceSessionContext sessionContext, ResponseEvent event) { | ||
212 | + ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext); | ||
213 | + | ||
214 | + if (event.getError() != null) { | ||
215 | + log.warn("SNMP response error: {}", event.getError().toString()); | ||
216 | + return; | ||
217 | + } | ||
218 | + | ||
219 | + PDU response = event.getResponse(); | ||
220 | + if (response == null) { | ||
221 | + log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID()); | ||
222 | + return; | ||
223 | + } | ||
224 | + | ||
225 | + RequestInfo requestInfo = (RequestInfo) event.getUserObject(); | ||
226 | + responseProcessingExecutor.execute(() -> { | ||
227 | + processResponse(sessionContext, response, requestInfo); | ||
228 | + }); | ||
229 | + } | ||
230 | + | ||
231 | + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) { | ||
232 | + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationSpec()); | ||
233 | + if (responseProcessor == null) return; | ||
234 | + | ||
235 | + JsonObject responseData = responseDataMappers.get(requestInfo.getCommunicationSpec()).map(response, requestInfo); | ||
236 | + | ||
237 | + if (responseData.entrySet().isEmpty()) { | ||
238 | + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID()); | ||
239 | + return; | ||
240 | + } | ||
241 | + | ||
242 | + responseProcessor.process(responseData, requestInfo, sessionContext); | ||
243 | + reportActivity(sessionContext.getSessionInfo()); | ||
244 | + } | ||
245 | + | ||
246 | + private void configureResponseDataMappers() { | ||
247 | + responseDataMappers.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (pdu, requestInfo) -> { | ||
248 | + JsonObject responseData = new JsonObject(); | ||
249 | + pduService.processPdu(pdu).forEach((oid, value) -> { | ||
250 | + requestInfo.getResponseMappings().stream() | ||
251 | + .filter(snmpMapping -> snmpMapping.getOid().equals(oid.toDottedString())) | ||
252 | + .findFirst() | ||
253 | + .ifPresent(snmpMapping -> { | ||
254 | + pduService.processValue(snmpMapping.getKey(), snmpMapping.getDataType(), value, responseData); | ||
255 | + }); | ||
256 | + }); | ||
257 | + return responseData; | ||
258 | + }); | ||
259 | + | ||
260 | + ResponseDataMapper defaultResponseDataMapper = (pdu, requestInfo) -> { | ||
261 | + return pduService.processPdu(pdu, requestInfo.getResponseMappings()); | ||
262 | + }; | ||
263 | + Arrays.stream(SnmpCommunicationSpec.values()) | ||
264 | + .forEach(communicationSpec -> { | ||
265 | + responseDataMappers.putIfAbsent(communicationSpec, defaultResponseDataMapper); | ||
266 | + }); | ||
267 | + } | ||
268 | + | ||
269 | + private void configureResponseProcessors() { | ||
270 | + responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (responseData, requestInfo, sessionContext) -> { | ||
271 | + TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(responseData); | ||
272 | + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null); | ||
273 | + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), responseData); | ||
274 | + }); | ||
275 | + | ||
276 | + responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (responseData, requestInfo, sessionContext) -> { | ||
277 | + TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(responseData); | ||
278 | + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null); | ||
279 | + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), responseData); | ||
280 | + }); | ||
281 | + | ||
282 | + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (responseData, requestInfo, sessionContext) -> { | ||
283 | + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | ||
284 | + .setRequestId(requestInfo.getRequestId()) | ||
285 | + .setPayload(JsonConverter.toJson(responseData)) | ||
286 | + .build(); | ||
287 | + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null); | ||
288 | + log.debug("Posted RPC response {} for device {}", responseData, sessionContext.getDeviceId()); | ||
289 | + }); | ||
290 | + } | ||
291 | + | ||
292 | + private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { | ||
293 | + transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder() | ||
294 | + .setAttributeSubscription(true) | ||
295 | + .setRpcSubscription(true) | ||
296 | + .setLastActivityTime(System.currentTimeMillis()) | ||
297 | + .build(), TransportServiceCallback.EMPTY); | ||
298 | + } | ||
299 | + | ||
300 | + | ||
301 | + @Override | ||
302 | + public String getName() { | ||
303 | + return "SNMP"; | ||
304 | + } | ||
305 | + | ||
306 | + @PreDestroy | ||
307 | + public void shutdown() { | ||
308 | + log.info("Stopping SNMP transport!"); | ||
309 | + if (queryingExecutor != null) { | ||
310 | + queryingExecutor.shutdownNow(); | ||
311 | + } | ||
312 | + if (responseProcessingExecutor != null) { | ||
313 | + responseProcessingExecutor.shutdownNow(); | ||
314 | + } | ||
315 | + if (snmp != null) { | ||
316 | + try { | ||
317 | + snmp.close(); | ||
318 | + } catch (IOException e) { | ||
319 | + log.error(e.getMessage(), e); | ||
320 | + } | ||
321 | + } | ||
322 | + log.info("SNMP transport stopped!"); | ||
323 | + } | ||
324 | + | ||
325 | + @Data | ||
326 | + private static class RequestInfo { | ||
327 | + private Integer requestId; | ||
328 | + private SnmpCommunicationSpec communicationSpec; | ||
329 | + private List<SnmpMapping> responseMappings; | ||
330 | + | ||
331 | + public RequestInfo(Integer requestId, SnmpCommunicationSpec communicationSpec, List<SnmpMapping> responseMappings) { | ||
332 | + this.requestId = requestId; | ||
333 | + this.communicationSpec = communicationSpec; | ||
334 | + this.responseMappings = responseMappings; | ||
335 | + } | ||
336 | + | ||
337 | + public RequestInfo(SnmpCommunicationSpec communicationSpec, List<SnmpMapping> responseMappings) { | ||
338 | + this.communicationSpec = communicationSpec; | ||
339 | + this.responseMappings = responseMappings; | ||
340 | + } | ||
341 | + } | ||
342 | + | ||
343 | + private interface ResponseDataMapper { | ||
344 | + JsonObject map(PDU pdu, RequestInfo requestInfo); | ||
345 | + } | ||
346 | + | ||
347 | + private interface ResponseProcessor { | ||
348 | + void process(JsonObject responseData, RequestInfo requestInfo, DeviceSessionContext sessionContext); | ||
349 | + } | ||
350 | + | ||
351 | +} |