Commit e3292e89c15e604211fcb33a7ab45229462dd2ff

Authored by Andrew Shvayka
Committed by GitHub
2 parents 5976d517 79eb1183

Merge pull request #4301 from thingsboard/develop/snmp

SNMP Transport
Showing 125 changed files with 4868 additions and 110 deletions
@@ -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>
@@ -25,7 +25,6 @@ import org.springframework.stereotype.Service; @@ -25,7 +25,6 @@ import org.springframework.stereotype.Service;
25 import org.thingsboard.common.util.ThingsBoardThreadFactory; 25 import org.thingsboard.common.util.ThingsBoardThreadFactory;
26 import org.thingsboard.server.actors.ActorSystemContext; 26 import org.thingsboard.server.actors.ActorSystemContext;
27 import org.thingsboard.server.actors.DefaultTbActorSystem; 27 import org.thingsboard.server.actors.DefaultTbActorSystem;
28 -import org.thingsboard.server.actors.TbActorId;  
29 import org.thingsboard.server.actors.TbActorRef; 28 import org.thingsboard.server.actors.TbActorRef;
30 import org.thingsboard.server.actors.TbActorSystem; 29 import org.thingsboard.server.actors.TbActorSystem;
31 import org.thingsboard.server.actors.TbActorSystemSettings; 30 import org.thingsboard.server.actors.TbActorSystemSettings;
@@ -33,14 +32,13 @@ import org.thingsboard.server.actors.app.AppActor; @@ -33,14 +32,13 @@ import org.thingsboard.server.actors.app.AppActor;
33 import org.thingsboard.server.actors.app.AppInitMsg; 32 import org.thingsboard.server.actors.app.AppInitMsg;
34 import org.thingsboard.server.actors.stats.StatsActor; 33 import org.thingsboard.server.actors.stats.StatsActor;
35 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; 34 import org.thingsboard.server.common.msg.queue.PartitionChangeMsg;
36 -import org.thingsboard.server.queue.discovery.PartitionChangeEvent;  
37 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 35 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
  36 +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
38 37
39 import javax.annotation.PostConstruct; 38 import javax.annotation.PostConstruct;
40 import javax.annotation.PreDestroy; 39 import javax.annotation.PreDestroy;
41 import java.util.concurrent.ExecutorService; 40 import java.util.concurrent.ExecutorService;
42 import java.util.concurrent.Executors; 41 import java.util.concurrent.Executors;
43 -import java.util.concurrent.ScheduledExecutorService;  
44 42
45 @Service 43 @Service
46 @Slf4j 44 @Slf4j
@@ -56,7 +56,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; @@ -56,7 +56,7 @@ import org.thingsboard.server.dao.usagerecord.ApiUsageStateService;
56 import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; 56 import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg;
57 import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; 57 import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto;
58 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 58 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
59 -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 59 +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
60 import org.thingsboard.server.queue.discovery.PartitionService; 60 import org.thingsboard.server.queue.discovery.PartitionService;
61 import org.thingsboard.server.queue.discovery.TbApplicationEventListener; 61 import org.thingsboard.server.queue.discovery.TbApplicationEventListener;
62 import org.thingsboard.server.queue.scheduler.SchedulerComponent; 62 import org.thingsboard.server.queue.scheduler.SchedulerComponent;
@@ -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;
@@ -38,7 +38,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; @@ -38,7 +38,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg;
38 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; 38 import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg;
39 import org.thingsboard.server.queue.TbQueueConsumer; 39 import org.thingsboard.server.queue.TbQueueConsumer;
40 import org.thingsboard.server.queue.common.TbProtoQueueMsg; 40 import org.thingsboard.server.queue.common.TbProtoQueueMsg;
41 -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 41 +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
42 import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; 42 import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory;
43 import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings; 43 import org.thingsboard.server.queue.settings.TbQueueRuleEngineSettings;
44 import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration; 44 import org.thingsboard.server.queue.settings.TbRuleEngineQueueConfiguration;
@@ -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;
@@ -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,9 @@ import org.springframework.beans.factory.annotation.Autowired; @@ -20,10 +20,9 @@ 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;  
24 import org.thingsboard.server.gen.transport.TransportProtos; 23 import org.thingsboard.server.gen.transport.TransportProtos;
25 -import org.thingsboard.server.queue.discovery.ClusterTopologyChangeEvent;  
26 -import org.thingsboard.server.queue.discovery.PartitionChangeEvent; 24 +import org.thingsboard.server.queue.discovery.event.ClusterTopologyChangeEvent;
  25 +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent;
27 import org.thingsboard.server.queue.discovery.PartitionService; 26 import org.thingsboard.server.queue.discovery.PartitionService;
28 import org.thingsboard.server.common.msg.queue.ServiceType; 27 import org.thingsboard.server.common.msg.queue.ServiceType;
29 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 28 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
@@ -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.
@@ -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;
@@ -45,6 +46,8 @@ import org.thingsboard.server.common.data.id.DeviceId; @@ -45,6 +46,8 @@ import org.thingsboard.server.common.data.id.DeviceId;
45 import org.thingsboard.server.common.data.id.DeviceProfileId; 46 import org.thingsboard.server.common.data.id.DeviceProfileId;
46 import org.thingsboard.server.common.data.id.FirmwareId; 47 import org.thingsboard.server.common.data.id.FirmwareId;
47 import org.thingsboard.server.common.data.id.TenantId; 48 import org.thingsboard.server.common.data.id.TenantId;
  49 +import org.thingsboard.server.common.data.page.PageData;
  50 +import org.thingsboard.server.common.data.page.PageLink;
48 import org.thingsboard.server.common.data.relation.EntityRelation; 51 import org.thingsboard.server.common.data.relation.EntityRelation;
49 import org.thingsboard.server.common.data.security.DeviceCredentials; 52 import org.thingsboard.server.common.data.security.DeviceCredentials;
50 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 53 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
@@ -64,11 +67,15 @@ import org.thingsboard.server.dao.relation.RelationService; @@ -64,11 +67,15 @@ import org.thingsboard.server.dao.relation.RelationService;
64 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 67 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
65 import org.thingsboard.server.gen.transport.TransportProtos; 68 import org.thingsboard.server.gen.transport.TransportProtos;
66 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 69 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
  70 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsRequestMsg;
  71 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg;
67 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; 72 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
68 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; 73 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
69 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 74 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
70 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; 75 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
71 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; 76 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg;
  77 +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRequestMsg;
  78 +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesResponseMsg;
72 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 79 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
73 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; 80 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
74 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; 81 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg;
@@ -91,6 +98,7 @@ import java.util.concurrent.ConcurrentHashMap; @@ -91,6 +98,7 @@ import java.util.concurrent.ConcurrentHashMap;
91 import java.util.concurrent.ConcurrentMap; 98 import java.util.concurrent.ConcurrentMap;
92 import java.util.concurrent.locks.Lock; 99 import java.util.concurrent.locks.Lock;
93 import java.util.concurrent.locks.ReentrantLock; 100 import java.util.concurrent.locks.ReentrantLock;
  101 +import java.util.stream.Collectors;
94 102
95 /** 103 /**
96 * Created by ashvayka on 05.10.18. 104 * Created by ashvayka on 05.10.18.
@@ -144,43 +152,43 @@ public class DefaultTransportApiService implements TransportApiService { @@ -144,43 +152,43 @@ public class DefaultTransportApiService implements TransportApiService {
144 @Override 152 @Override
145 public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) { 153 public ListenableFuture<TbProtoQueueMsg<TransportApiResponseMsg>> handle(TbProtoQueueMsg<TransportApiRequestMsg> tbProtoQueueMsg) {
146 TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue(); 154 TransportApiRequestMsg transportApiRequestMsg = tbProtoQueueMsg.getValue();
  155 + ListenableFuture<TransportApiResponseMsg> result = null;
  156 +
147 if (transportApiRequestMsg.hasValidateTokenRequestMsg()) { 157 if (transportApiRequestMsg.hasValidateTokenRequestMsg()) {
148 ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg(); 158 ValidateDeviceTokenRequestMsg msg = transportApiRequestMsg.getValidateTokenRequestMsg();
149 - return Futures.transform(validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN),  
150 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 159 + result = validateCredentials(msg.getToken(), DeviceCredentialsType.ACCESS_TOKEN);
151 } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) { 160 } else if (transportApiRequestMsg.hasValidateBasicMqttCredRequestMsg()) {
152 TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg(); 161 TransportProtos.ValidateBasicMqttCredRequestMsg msg = transportApiRequestMsg.getValidateBasicMqttCredRequestMsg();
153 - return Futures.transform(validateCredentials(msg),  
154 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 162 + result = validateCredentials(msg);
155 } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) { 163 } else if (transportApiRequestMsg.hasValidateX509CertRequestMsg()) {
156 ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg(); 164 ValidateDeviceX509CertRequestMsg msg = transportApiRequestMsg.getValidateX509CertRequestMsg();
157 - return Futures.transform(validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE),  
158 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 165 + result = validateCredentials(msg.getHash(), DeviceCredentialsType.X509_CERTIFICATE);
159 } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) { 166 } else if (transportApiRequestMsg.hasGetOrCreateDeviceRequestMsg()) {
160 - return Futures.transform(handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg()),  
161 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 167 + result = handle(transportApiRequestMsg.getGetOrCreateDeviceRequestMsg());
162 } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) { 168 } else if (transportApiRequestMsg.hasEntityProfileRequestMsg()) {
163 - return Futures.transform(handle(transportApiRequestMsg.getEntityProfileRequestMsg()),  
164 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 169 + result = handle(transportApiRequestMsg.getEntityProfileRequestMsg());
165 } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) { 170 } else if (transportApiRequestMsg.hasLwM2MRequestMsg()) {
166 - return Futures.transform(handle(transportApiRequestMsg.getLwM2MRequestMsg()),  
167 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 171 + result = handle(transportApiRequestMsg.getLwM2MRequestMsg());
168 } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) { 172 } else if (transportApiRequestMsg.hasValidateDeviceLwM2MCredentialsRequestMsg()) {
169 ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg(); 173 ValidateDeviceLwM2MCredentialsRequestMsg msg = transportApiRequestMsg.getValidateDeviceLwM2MCredentialsRequestMsg();
170 - return Futures.transform(validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS),  
171 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 174 + result = validateCredentials(msg.getCredentialsId(), DeviceCredentialsType.LWM2M_CREDENTIALS);
172 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { 175 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) {
173 - return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()),  
174 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 176 + result = handle(transportApiRequestMsg.getProvisionDeviceRequestMsg());
175 } else if (transportApiRequestMsg.hasResourceRequestMsg()) { 177 } else if (transportApiRequestMsg.hasResourceRequestMsg()) {
176 - return Futures.transform(handle(transportApiRequestMsg.getResourceRequestMsg()),  
177 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 178 + result = handle(transportApiRequestMsg.getResourceRequestMsg());
  179 + } else if (transportApiRequestMsg.hasSnmpDevicesRequestMsg()) {
  180 + result = handle(transportApiRequestMsg.getSnmpDevicesRequestMsg());
  181 + } else if (transportApiRequestMsg.hasDeviceRequestMsg()) {
  182 + result = handle(transportApiRequestMsg.getDeviceRequestMsg());
  183 + } else if (transportApiRequestMsg.hasDeviceCredentialsRequestMsg()) {
  184 + result = handle(transportApiRequestMsg.getDeviceCredentialsRequestMsg());
178 } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) { 185 } else if (transportApiRequestMsg.hasFirmwareRequestMsg()) {
179 - return Futures.transform(handle(transportApiRequestMsg.getFirmwareRequestMsg()),  
180 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 186 + result = handle(transportApiRequestMsg.getFirmwareRequestMsg());
181 } 187 }
182 - return Futures.transform(getEmptyTransportApiResponseFuture(),  
183 - value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 188 +
  189 + return Futures.transform(Optional.ofNullable(result).orElseGet(this::getEmptyTransportApiResponseFuture),
  190 + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()),
  191 + MoreExecutors.directExecutor());
184 } 192 }
185 193
186 private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) { 194 private ListenableFuture<TransportApiResponseMsg> validateCredentials(String credentialsId, DeviceCredentialsType credentialsType) {
@@ -374,6 +382,39 @@ public class DefaultTransportApiService implements TransportApiService { @@ -374,6 +382,39 @@ public class DefaultTransportApiService implements TransportApiService {
374 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build()); 382 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build());
375 } 383 }
376 384
  385 + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceRequestMsg requestMsg) {
  386 + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB()));
  387 + Device device = deviceService.findDeviceById(TenantId.SYS_TENANT_ID, deviceId);
  388 +
  389 + TransportApiResponseMsg responseMsg;
  390 + if (device != null) {
  391 + UUID deviceProfileId = device.getDeviceProfileId().getId();
  392 + responseMsg = TransportApiResponseMsg.newBuilder()
  393 + .setDeviceResponseMsg(TransportProtos.GetDeviceResponseMsg.newBuilder()
  394 + .setDeviceProfileIdMSB(deviceProfileId.getMostSignificantBits())
  395 + .setDeviceProfileIdLSB(deviceProfileId.getLeastSignificantBits())
  396 + .setDeviceTransportConfiguration(ByteString.copyFrom(
  397 + dataDecodingEncodingService.encode(device.getDeviceData().getTransportConfiguration())
  398 + )))
  399 + .build();
  400 + } else {
  401 + responseMsg = TransportApiResponseMsg.getDefaultInstance();
  402 + }
  403 +
  404 + return Futures.immediateFuture(responseMsg);
  405 + }
  406 +
  407 + private ListenableFuture<TransportApiResponseMsg> handle(GetDeviceCredentialsRequestMsg requestMsg) {
  408 + DeviceId deviceId = new DeviceId(new UUID(requestMsg.getDeviceIdMSB(), requestMsg.getDeviceIdLSB()));
  409 + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(TenantId.SYS_TENANT_ID, deviceId);
  410 +
  411 + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder()
  412 + .setDeviceCredentialsResponseMsg(TransportProtos.GetDeviceCredentialsResponseMsg.newBuilder()
  413 + .setDeviceCredentialsData(ByteString.copyFrom(dataDecodingEncodingService.encode(deviceCredentials))))
  414 + .build());
  415 + }
  416 +
  417 +
377 private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) { 418 private ListenableFuture<TransportApiResponseMsg> handle(GetResourceRequestMsg requestMsg) {
378 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB())); 419 TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
379 ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType()); 420 ResourceType resourceType = ResourceType.valueOf(requestMsg.getResourceType());
@@ -392,6 +433,22 @@ public class DefaultTransportApiService implements TransportApiService { @@ -392,6 +433,22 @@ public class DefaultTransportApiService implements TransportApiService {
392 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourceResponseMsg(builder).build()); 433 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourceResponseMsg(builder).build());
393 } 434 }
394 435
  436 + private ListenableFuture<TransportApiResponseMsg> handle(GetSnmpDevicesRequestMsg requestMsg) {
  437 + PageLink pageLink = new PageLink(requestMsg.getPageSize(), requestMsg.getPage());
  438 + PageData<UUID> result = deviceService.findDevicesIdsByDeviceProfileTransportType(DeviceTransportType.SNMP, pageLink);
  439 +
  440 + GetSnmpDevicesResponseMsg responseMsg = GetSnmpDevicesResponseMsg.newBuilder()
  441 + .addAllIds(result.getData().stream()
  442 + .map(UUID::toString)
  443 + .collect(Collectors.toList()))
  444 + .setHasNextPage(result.hasNext())
  445 + .build();
  446 +
  447 + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder()
  448 + .setSnmpDevicesResponseMsg(responseMsg)
  449 + .build());
  450 + }
  451 +
395 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { 452 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) {
396 return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { 453 return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> {
397 if (device == null) { 454 if (device == null) {
@@ -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" />-->
@@ -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:
@@ -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
@@ -93,6 +95,8 @@ public interface DeviceService { @@ -93,6 +95,8 @@ public interface DeviceService {
93 95
94 Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile); 96 Device saveDevice(ProvisionRequest provisionRequest, DeviceProfile profile);
95 97
  98 + PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink);
  99 +
96 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); 100 Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId);
97 101
98 Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); 102 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>
@@ -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 +}
  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 +}
  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 +}
  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 +}
  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 +
  30 +import java.util.List;
  31 +
  32 +@JsonIgnoreProperties(ignoreUnknown = true)
  33 +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "spec")
  34 +@JsonSubTypes({
  35 + @Type(value = TelemetryQueryingSnmpCommunicationConfig.class, name = "TELEMETRY_QUERYING"),
  36 + @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"),
  37 + @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING")
  38 +})
  39 +public interface SnmpCommunicationConfig {
  40 +
  41 + SnmpCommunicationSpec getSpec();
  42 +
  43 + @JsonIgnore
  44 + default SnmpMethod getMethod() {
  45 + return null;
  46 + }
  47 +
  48 + @JsonIgnore
  49 + List<SnmpMapping> getAllMappings();
  50 +
  51 + @JsonIgnore
  52 + boolean isValid();
  53 +
  54 +}
  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 +}
@@ -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;
  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 +}
  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;
@@ -590,6 +621,9 @@ message TransportApiRequestMsg { @@ -590,6 +621,9 @@ message TransportApiRequestMsg {
590 ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; 621 ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8;
591 GetResourceRequestMsg resourceRequestMsg = 9; 622 GetResourceRequestMsg resourceRequestMsg = 9;
592 GetFirmwareRequestMsg firmwareRequestMsg = 10; 623 GetFirmwareRequestMsg firmwareRequestMsg = 10;
  624 + GetSnmpDevicesRequestMsg snmpDevicesRequestMsg = 11;
  625 + GetDeviceRequestMsg deviceRequestMsg = 12;
  626 + GetDeviceCredentialsRequestMsg deviceCredentialsRequestMsg = 13;
593 } 627 }
594 628
595 /* Response from ThingsBoard Core Service to Transport Service */ 629 /* Response from ThingsBoard Core Service to Transport Service */
@@ -598,9 +632,12 @@ message TransportApiResponseMsg { @@ -598,9 +632,12 @@ message TransportApiResponseMsg {
598 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2; 632 GetOrCreateDeviceFromGatewayResponseMsg getOrCreateDeviceResponseMsg = 2;
599 GetEntityProfileResponseMsg entityProfileResponseMsg = 3; 633 GetEntityProfileResponseMsg entityProfileResponseMsg = 3;
600 ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; 634 ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4;
  635 + GetSnmpDevicesResponseMsg snmpDevicesResponseMsg = 5;
601 LwM2MResponseMsg lwM2MResponseMsg = 6; 636 LwM2MResponseMsg lwM2MResponseMsg = 6;
602 GetResourceResponseMsg resourceResponseMsg = 7; 637 GetResourceResponseMsg resourceResponseMsg = 7;
603 GetFirmwareResponseMsg firmwareResponseMsg = 8; 638 GetFirmwareResponseMsg firmwareResponseMsg = 8;
  639 + GetDeviceResponseMsg deviceResponseMsg = 9;
  640 + GetDeviceCredentialsResponseMsg deviceCredentialsResponseMsg = 10;
604 } 641 }
605 642
606 /* Messages that are handled by ThingsBoard Core Service */ 643 /* Messages that are handled by ThingsBoard Core Service */
@@ -21,6 +21,7 @@ import org.eclipse.californium.core.CoapServer; @@ -21,6 +21,7 @@ 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;
25 import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource; 26 import org.thingsboard.server.transport.coap.efento.CoapEfentoTransportResource;
26 27
@@ -31,7 +32,7 @@ import java.net.UnknownHostException; @@ -31,7 +32,7 @@ import java.net.UnknownHostException;
31 @Service("CoapTransportService") 32 @Service("CoapTransportService")
32 @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')") 33 @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.coap.enabled}'=='true')")
33 @Slf4j 34 @Slf4j
34 -public class CoapTransportService { 35 +public class CoapTransportService implements TbTransportService {
35 36
36 private static final String V1 = "v1"; 37 private static final String V1 = "v1";
37 private static final String API = "api"; 38 private static final String API = "api";
@@ -65,4 +66,9 @@ public class CoapTransportService { @@ -65,4 +66,9 @@ public class CoapTransportService {
65 public void shutdown() { 66 public void shutdown() {
66 log.info("CoAP transport stopped!"); 67 log.info("CoAP transport stopped!");
67 } 68 }
  69 +
  70 + @Override
  71 + public String getName() {
  72 + return "COAP";
  73 + }
68 } 74 }
@@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam; @@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestParam;
34 import org.springframework.web.bind.annotation.RestController; 34 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.TbTransportService;
37 import org.thingsboard.server.common.data.id.DeviceId; 38 import org.thingsboard.server.common.data.id.DeviceId;
38 import org.thingsboard.server.common.transport.SessionMsgListener; 39 import org.thingsboard.server.common.transport.SessionMsgListener;
39 import org.thingsboard.server.common.transport.TransportContext; 40 import org.thingsboard.server.common.transport.TransportContext;
@@ -70,7 +71,7 @@ import java.util.function.Consumer; @@ -70,7 +71,7 @@ import java.util.function.Consumer;
70 @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')") 71 @ConditionalOnExpression("'${service.type:null}'=='tb-transport' || ('${service.type:null}'=='monolith' && '${transport.api_enabled:true}'=='true' && '${transport.http.enabled}'=='true')")
71 @RequestMapping("/api/v1") 72 @RequestMapping("/api/v1")
72 @Slf4j 73 @Slf4j
73 -public class DeviceApiController { 74 +public class DeviceApiController implements TbTransportService {
74 75
75 @Autowired 76 @Autowired
76 private HttpTransportContext transportContext; 77 private HttpTransportContext transportContext;
@@ -407,4 +408,9 @@ public class DeviceApiController { @@ -407,4 +408,9 @@ public class DeviceApiController {
407 } 408 }
408 } 409 }
409 410
  411 + @Override
  412 + public String getName() {
  413 + return "HTTP";
  414 + }
  415 +
410 } 416 }
@@ -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
@@ -40,6 +40,7 @@ import org.springframework.stereotype.Service; @@ -40,6 +40,7 @@ import org.springframework.stereotype.Service;
40 import org.thingsboard.common.util.JacksonUtil; 40 import org.thingsboard.common.util.JacksonUtil;
41 import org.thingsboard.server.common.data.Device; 41 import org.thingsboard.server.common.data.Device;
42 import org.thingsboard.server.common.data.DeviceProfile; 42 import org.thingsboard.server.common.data.DeviceProfile;
  43 +import org.thingsboard.server.common.data.DeviceTransportType;
43 import org.thingsboard.server.common.transport.TransportService; 44 import org.thingsboard.server.common.transport.TransportService;
44 import org.thingsboard.server.common.transport.adaptor.AdaptorException; 45 import org.thingsboard.server.common.transport.adaptor.AdaptorException;
45 import org.thingsboard.server.common.transport.service.DefaultTransportService; 46 import org.thingsboard.server.common.transport.service.DefaultTransportService;
@@ -1353,4 +1354,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService { @@ -1353,4 +1354,10 @@ public class LwM2mTransportServiceImpl implements LwM2mTransportService {
1353 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() : 1354 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)) && resourceModel.operations.isWritable() :
1354 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId))); 1355 objectId != null && objectVer != null && objectVer.equals(lwM2mClient.getRegistration().getSupportedVersion(objectId)));
1355 } 1356 }
  1357 +
  1358 + @Override
  1359 + public String getName() {
  1360 + return "LWM2M";
  1361 + }
  1362 +
1356 } 1363 }
@@ -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 }
@@ -40,6 +40,7 @@ @@ -40,6 +40,7 @@
40 <module>http</module> 40 <module>http</module>
41 <module>coap</module> 41 <module>coap</module>
42 <module>lwm2m</module> 42 <module>lwm2m</module>
  43 + <module>snmp</module>
43 </modules> 44 </modules>
44 45
45 </project> 46 </project>
  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>
  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 +import java.util.stream.Collectors;
  59 +
  60 +@TbSnmpTransportComponent
  61 +@Component
  62 +@Slf4j
  63 +@RequiredArgsConstructor
  64 +public class SnmpTransportContext extends TransportContext {
  65 + @Getter
  66 + private final SnmpTransportService snmpTransportService;
  67 + private final TransportDeviceProfileCache deviceProfileCache;
  68 + private final TransportService transportService;
  69 + private final ProtoTransportEntityService protoEntityService;
  70 + private final SnmpTransportBalancingService balancingService;
  71 + @Getter
  72 + private final SnmpAuthService snmpAuthService;
  73 +
  74 + private final Map<DeviceId, DeviceSessionContext> sessions = new ConcurrentHashMap<>();
  75 + private Collection<DeviceId> allSnmpDevicesIds = new ConcurrentLinkedDeque<>();
  76 +
  77 + @AfterStartUp(order = 2)
  78 + public void initDevicesSessions() {
  79 + log.info("Initializing SNMP devices sessions");
  80 + allSnmpDevicesIds = protoEntityService.getAllSnmpDevicesIds().stream()
  81 + .map(DeviceId::new)
  82 + .collect(Collectors.toList());
  83 + log.trace("Found all SNMP devices ids: {}", allSnmpDevicesIds);
  84 +
  85 + List<DeviceId> managedDevicesIds = allSnmpDevicesIds.stream()
  86 + .filter(deviceId -> balancingService.isManagedByCurrentTransport(deviceId.getId()))
  87 + .collect(Collectors.toList());
  88 + log.info("SNMP devices managed by current SNMP transport: {}", managedDevicesIds);
  89 +
  90 + managedDevicesIds.stream()
  91 + .map(protoEntityService::getDeviceById)
  92 + .collect(Collectors.toList())
  93 + .forEach(this::establishDeviceSession);
  94 + }
  95 +
  96 + private void establishDeviceSession(Device device) {
  97 + if (device == null) return;
  98 + log.info("Establishing SNMP session for device {}", device.getId());
  99 +
  100 + DeviceProfileId deviceProfileId = device.getDeviceProfileId();
  101 + DeviceProfile deviceProfile = deviceProfileCache.get(deviceProfileId);
  102 +
  103 + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId());
  104 + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) {
  105 + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType());
  106 + return;
  107 + }
  108 +
  109 + SnmpDeviceProfileTransportConfiguration profileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
  110 + SnmpDeviceTransportConfiguration deviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
  111 +
  112 + DeviceSessionContext deviceSessionContext;
  113 + try {
  114 + deviceSessionContext = new DeviceSessionContext(
  115 + device, deviceProfile, credentials.getCredentialsId(),
  116 + profileTransportConfiguration, deviceTransportConfiguration, this
  117 + );
  118 + registerSessionMsgListener(deviceSessionContext);
  119 + } catch (Exception e) {
  120 + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString());
  121 + return;
  122 + }
  123 + sessions.put(device.getId(), deviceSessionContext);
  124 + snmpTransportService.createQueryingTasks(deviceSessionContext);
  125 + log.info("Established SNMP device session for device {}", device.getId());
  126 + }
  127 +
  128 + private void updateDeviceSession(DeviceSessionContext sessionContext, Device device, DeviceProfile deviceProfile) {
  129 + log.info("Updating SNMP session for device {}", device.getId());
  130 +
  131 + DeviceCredentials credentials = protoEntityService.getDeviceCredentialsByDeviceId(device.getId());
  132 + if (credentials.getCredentialsType() != DeviceCredentialsType.ACCESS_TOKEN) {
  133 + log.warn("[{}] Expected credentials type is {} but found {}", device.getId(), DeviceCredentialsType.ACCESS_TOKEN, credentials.getCredentialsType());
  134 + destroyDeviceSession(sessionContext);
  135 + return;
  136 + }
  137 +
  138 + SnmpDeviceProfileTransportConfiguration newProfileTransportConfiguration = (SnmpDeviceProfileTransportConfiguration) deviceProfile.getProfileData().getTransportConfiguration();
  139 + SnmpDeviceTransportConfiguration newDeviceTransportConfiguration = (SnmpDeviceTransportConfiguration) device.getDeviceData().getTransportConfiguration();
  140 +
  141 + try {
  142 + if (!newProfileTransportConfiguration.equals(sessionContext.getProfileTransportConfiguration())) {
  143 + sessionContext.setProfileTransportConfiguration(newProfileTransportConfiguration);
  144 + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
  145 + snmpTransportService.cancelQueryingTasks(sessionContext);
  146 + snmpTransportService.createQueryingTasks(sessionContext);
  147 + } else if (!newDeviceTransportConfiguration.equals(sessionContext.getDeviceTransportConfiguration())) {
  148 + sessionContext.setDeviceTransportConfiguration(newDeviceTransportConfiguration);
  149 + sessionContext.initializeTarget(newProfileTransportConfiguration, newDeviceTransportConfiguration);
  150 + } else {
  151 + log.trace("Configuration of the device {} was not updated", device);
  152 + }
  153 + } catch (Exception e) {
  154 + log.error("Failed to update session for SNMP device {}: {}", sessionContext.getDeviceId(), e.getMessage());
  155 + destroyDeviceSession(sessionContext);
  156 + }
  157 + }
  158 +
  159 + private void destroyDeviceSession(DeviceSessionContext sessionContext) {
  160 + if (sessionContext == null) return;
  161 + log.info("Destroying SNMP device session for device {}", sessionContext.getDevice().getId());
  162 + sessionContext.close();
  163 + snmpAuthService.cleanUpSnmpAuthInfo(sessionContext);
  164 + transportService.deregisterSession(sessionContext.getSessionInfo());
  165 + snmpTransportService.cancelQueryingTasks(sessionContext);
  166 + sessions.remove(sessionContext.getDeviceId());
  167 + log.trace("Unregistered and removed session");
  168 + }
  169 +
  170 + private void registerSessionMsgListener(DeviceSessionContext deviceSessionContext) {
  171 + transportService.process(DeviceTransportType.SNMP,
  172 + TransportProtos.ValidateDeviceTokenRequestMsg.newBuilder().setToken(deviceSessionContext.getToken()).build(),
  173 + new TransportServiceCallback<>() {
  174 + @Override
  175 + public void onSuccess(ValidateDeviceCredentialsResponse msg) {
  176 + if (msg.hasDeviceInfo()) {
  177 + SessionInfoProto sessionInfo = SessionInfoCreator.create(
  178 + msg, SnmpTransportContext.this, UUID.randomUUID()
  179 + );
  180 +
  181 + transportService.registerAsyncSession(sessionInfo, deviceSessionContext);
  182 + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY);
  183 + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY);
  184 +
  185 + deviceSessionContext.setSessionInfo(sessionInfo);
  186 + deviceSessionContext.setDeviceInfo(msg.getDeviceInfo());
  187 + } else {
  188 + log.warn("[{}] Failed to process device auth", deviceSessionContext.getDeviceId());
  189 + }
  190 + }
  191 +
  192 + @Override
  193 + public void onError(Throwable e) {
  194 + log.warn("[{}] Failed to process device auth: {}", deviceSessionContext.getDeviceId(), e);
  195 + }
  196 + });
  197 + }
  198 +
  199 + @EventListener(DeviceUpdatedEvent.class)
  200 + public void onDeviceUpdatedOrCreated(DeviceUpdatedEvent deviceUpdatedEvent) {
  201 + Device device = deviceUpdatedEvent.getDevice();
  202 + log.trace("Got creating or updating device event for device {}", device);
  203 + DeviceTransportType transportType = Optional.ofNullable(device.getDeviceData().getTransportConfiguration())
  204 + .map(DeviceTransportConfiguration::getType)
  205 + .orElse(null);
  206 + if (!allSnmpDevicesIds.contains(device.getId())) {
  207 + if (transportType != DeviceTransportType.SNMP) {
  208 + return;
  209 + }
  210 + allSnmpDevicesIds.add(device.getId());
  211 + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) {
  212 + establishDeviceSession(device);
  213 + }
  214 + } else {
  215 + if (balancingService.isManagedByCurrentTransport(device.getId().getId())) {
  216 + DeviceSessionContext sessionContext = sessions.get(device.getId());
  217 + if (transportType == DeviceTransportType.SNMP) {
  218 + if (sessionContext != null) {
  219 + updateDeviceSession(sessionContext, device, deviceProfileCache.get(device.getDeviceProfileId()));
  220 + } else {
  221 + establishDeviceSession(device);
  222 + }
  223 + } else {
  224 + log.trace("Transport type was changed to {}", transportType);
  225 + destroyDeviceSession(sessionContext);
  226 + }
  227 + }
  228 + }
  229 + }
  230 +
  231 + public void onDeviceDeleted(DeviceSessionContext sessionContext) {
  232 + destroyDeviceSession(sessionContext);
  233 + }
  234 +
  235 + public void onDeviceProfileUpdated(DeviceProfile deviceProfile, DeviceSessionContext sessionContext) {
  236 + updateDeviceSession(sessionContext, sessionContext.getDevice(), deviceProfile);
  237 + }
  238 +
  239 + public void onSnmpTransportListChanged() {
  240 + log.trace("SNMP transport list changed. Updating sessions");
  241 + List<DeviceId> deleted = new LinkedList<>();
  242 + for (DeviceId deviceId : allSnmpDevicesIds) {
  243 + if (balancingService.isManagedByCurrentTransport(deviceId.getId())) {
  244 + if (!sessions.containsKey(deviceId)) {
  245 + Device device = protoEntityService.getDeviceById(deviceId);
  246 + if (device != null) {
  247 + log.info("SNMP device {} is now managed by current transport node", deviceId);
  248 + establishDeviceSession(device);
  249 + } else {
  250 + deleted.add(deviceId);
  251 + }
  252 + }
  253 + } else {
  254 + Optional.ofNullable(sessions.get(deviceId))
  255 + .ifPresent(sessionContext -> {
  256 + log.info("SNMP session for device {} is not managed by current transport node anymore", deviceId);
  257 + destroyDeviceSession(sessionContext);
  258 + });
  259 + }
  260 + }
  261 + log.trace("Removing deleted SNMP devices: {}", deleted);
  262 + allSnmpDevicesIds.removeAll(deleted);
  263 + }
  264 +
  265 +
  266 + public Collection<DeviceSessionContext> getSessions() {
  267 + return sessions.values();
  268 + }
  269 +
  270 +}
  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 +}
  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 + private 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 List<UUID> getAllSnmpDevicesIds() {
  85 + List<UUID> result = new ArrayList<>();
  86 +
  87 + int page = 0;
  88 + int pageSize = 512;
  89 + boolean hasNextPage = true;
  90 +
  91 + while (hasNextPage) {
  92 + TransportProtos.GetSnmpDevicesResponseMsg responseMsg = requestSnmpDevicesIds(page, pageSize);
  93 + result.addAll(responseMsg.getIdsList().stream()
  94 + .map(UUID::fromString)
  95 + .collect(Collectors.toList()));
  96 + hasNextPage = responseMsg.getHasNextPage();
  97 + page++;
  98 + }
  99 +
  100 + return result;
  101 + }
  102 +
  103 + private TransportProtos.GetSnmpDevicesResponseMsg requestSnmpDevicesIds(int page, int pageSize) {
  104 + TransportProtos.GetSnmpDevicesRequestMsg requestMsg = TransportProtos.GetSnmpDevicesRequestMsg.newBuilder()
  105 + .setPage(page)
  106 + .setPageSize(pageSize)
  107 + .build();
  108 + return transportService.getSnmpDevicesIds(requestMsg);
  109 + }
  110 +}
  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 oid = Optional.ofNullable(params.get("oid")).map(JsonElement::getAsString).orElse(null);
  187 + String value = Optional.ofNullable(params.get("value")).map(JsonElement::getAsString).orElse(null);
  188 + DataType dataType = Optional.ofNullable(params.get("dataType")).map(e -> DataType.valueOf(e.getAsString())).orElse(DataType.STRING);
  189 +
  190 + if (oid == null || oid.isEmpty()) {
  191 + throw new IllegalArgumentException("OID in to-device RPC request is not specified");
  192 + }
  193 + if (value == null && snmpMethod == SnmpMethod.SET) {
  194 + throw new IllegalArgumentException("Value must be specified for SNMP method 'SET'");
  195 + }
  196 +
  197 + PDU request = pduService.createSingleVariablePdu(sessionContext, snmpMethod, oid, value, dataType);
  198 + sendRequest(sessionContext, request, new RequestInfo(toDeviceRpcRequestMsg.getRequestId(), SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST));
  199 + }
  200 +
  201 +
  202 + public void processResponseEvent(DeviceSessionContext sessionContext, ResponseEvent event) {
  203 + ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext);
  204 +
  205 + if (event.getError() != null) {
  206 + log.warn("SNMP response error: {}", event.getError().toString());
  207 + return;
  208 + }
  209 +
  210 + PDU response = event.getResponse();
  211 + if (response == null) {
  212 + log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID());
  213 + return;
  214 + }
  215 +
  216 + RequestInfo requestInfo = (RequestInfo) event.getUserObject();
  217 + responseProcessingExecutor.execute(() -> {
  218 + processResponse(sessionContext, response, requestInfo);
  219 + });
  220 + }
  221 +
  222 + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) {
  223 + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationSpec());
  224 + if (responseProcessor == null) return;
  225 +
  226 + JsonObject responseData = responseDataMappers.get(requestInfo.getCommunicationSpec()).map(response, requestInfo);
  227 +
  228 + if (responseData.entrySet().isEmpty()) {
  229 + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID());
  230 + return;
  231 + }
  232 +
  233 + responseProcessor.process(responseData, requestInfo, sessionContext);
  234 + reportActivity(sessionContext.getSessionInfo());
  235 + }
  236 +
  237 + private void configureResponseDataMappers() {
  238 + responseDataMappers.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (pdu, requestInfo) -> {
  239 + JsonObject responseData = new JsonObject();
  240 + pduService.processPdu(pdu).forEach((oid, value) -> {
  241 + responseData.addProperty(oid.toDottedString(), value);
  242 + });
  243 + return responseData;
  244 + });
  245 +
  246 + ResponseDataMapper defaultResponseDataMapper = (pdu, requestInfo) -> {
  247 + return pduService.processPdu(pdu, requestInfo.getResponseMappings());
  248 + };
  249 + Arrays.stream(SnmpCommunicationSpec.values())
  250 + .forEach(communicationSpec -> {
  251 + responseDataMappers.putIfAbsent(communicationSpec, defaultResponseDataMapper);
  252 + });
  253 + }
  254 +
  255 + private void configureResponseProcessors() {
  256 + responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (responseData, requestInfo, sessionContext) -> {
  257 + TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(responseData);
  258 + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null);
  259 + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), responseData);
  260 + });
  261 +
  262 + responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (responseData, requestInfo, sessionContext) -> {
  263 + TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(responseData);
  264 + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null);
  265 + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), responseData);
  266 + });
  267 +
  268 + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_REQUEST, (responseData, requestInfo, sessionContext) -> {
  269 + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder()
  270 + .setRequestId(requestInfo.getRequestId())
  271 + .setPayload(JsonConverter.toJson(responseData))
  272 + .build();
  273 + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null);
  274 + log.debug("Posted RPC response {} for device {}", responseData, sessionContext.getDeviceId());
  275 + });
  276 + }
  277 +
  278 + private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) {
  279 + transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder()
  280 + .setAttributeSubscription(true)
  281 + .setRpcSubscription(true)
  282 + .setLastActivityTime(System.currentTimeMillis())
  283 + .build(), TransportServiceCallback.EMPTY);
  284 + }
  285 +
  286 +
  287 + @Override
  288 + public String getName() {
  289 + return "SNMP";
  290 + }
  291 +
  292 + @PreDestroy
  293 + public void shutdown() {
  294 + log.info("Stopping SNMP transport!");
  295 + if (queryingExecutor != null) {
  296 + queryingExecutor.shutdownNow();
  297 + }
  298 + if (responseProcessingExecutor != null) {
  299 + responseProcessingExecutor.shutdownNow();
  300 + }
  301 + if (snmp != null) {
  302 + try {
  303 + snmp.close();
  304 + } catch (IOException e) {
  305 + log.error(e.getMessage(), e);
  306 + }
  307 + }
  308 + log.info("SNMP transport stopped!");
  309 + }
  310 +
  311 + @Data
  312 + private static class RequestInfo {
  313 + private Integer requestId;
  314 + private SnmpCommunicationSpec communicationSpec;
  315 + private List<SnmpMapping> responseMappings;
  316 +
  317 + public RequestInfo(Integer requestId, SnmpCommunicationSpec communicationSpec) {
  318 + this.requestId = requestId;
  319 + this.communicationSpec = communicationSpec;
  320 + }
  321 +
  322 + public RequestInfo(SnmpCommunicationSpec communicationSpec) {
  323 + this.communicationSpec = communicationSpec;
  324 + }
  325 +
  326 + public RequestInfo(SnmpCommunicationSpec communicationSpec, List<SnmpMapping> responseMappings) {
  327 + this.communicationSpec = communicationSpec;
  328 + this.responseMappings = responseMappings;
  329 + }
  330 + }
  331 +
  332 + private interface ResponseDataMapper {
  333 + JsonObject map(PDU pdu, RequestInfo requestInfo);
  334 + }
  335 +
  336 + private interface ResponseProcessor {
  337 + void process(JsonObject responseData, RequestInfo requestInfo, DeviceSessionContext sessionContext);
  338 + }
  339 +
  340 +}
  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.session;
  17 +
  18 +import lombok.Getter;
  19 +import lombok.Setter;
  20 +import lombok.extern.slf4j.Slf4j;
  21 +import org.snmp4j.Target;
  22 +import org.snmp4j.event.ResponseEvent;
  23 +import org.snmp4j.event.ResponseListener;
  24 +import org.thingsboard.server.common.data.Device;
  25 +import org.thingsboard.server.common.data.DeviceProfile;
  26 +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
  27 +import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration;
  28 +import org.thingsboard.server.common.data.id.DeviceId;
  29 +import org.thingsboard.server.common.transport.SessionMsgListener;
  30 +import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext;
  31 +import org.thingsboard.server.gen.transport.TransportProtos;
  32 +import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
  33 +import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
  34 +import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto;
  35 +import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg;
  36 +import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg;
  37 +import org.thingsboard.server.transport.snmp.SnmpTransportContext;
  38 +
  39 +import java.util.LinkedList;
  40 +import java.util.List;
  41 +import java.util.UUID;
  42 +import java.util.concurrent.ScheduledFuture;
  43 +import java.util.concurrent.atomic.AtomicInteger;
  44 +
  45 +@Slf4j
  46 +public class DeviceSessionContext extends DeviceAwareSessionContext implements SessionMsgListener, ResponseListener {
  47 + @Getter
  48 + private Target target;
  49 + private final String token;
  50 + @Getter
  51 + @Setter
  52 + private SnmpDeviceProfileTransportConfiguration profileTransportConfiguration;
  53 + @Getter
  54 + @Setter
  55 + private SnmpDeviceTransportConfiguration deviceTransportConfiguration;
  56 + @Getter
  57 + private final Device device;
  58 +
  59 + private final SnmpTransportContext snmpTransportContext;
  60 +
  61 + private final AtomicInteger msgIdSeq = new AtomicInteger(0);
  62 + @Getter
  63 + private boolean isActive = true;
  64 +
  65 + @Getter
  66 + private final List<ScheduledFuture<?>> queryingTasks = new LinkedList<>();
  67 +
  68 + public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token,
  69 + SnmpDeviceProfileTransportConfiguration profileTransportConfiguration,
  70 + SnmpDeviceTransportConfiguration deviceTransportConfiguration,
  71 + SnmpTransportContext snmpTransportContext) throws Exception {
  72 + super(UUID.randomUUID());
  73 + super.setDeviceId(device.getId());
  74 + super.setDeviceProfile(deviceProfile);
  75 + this.device = device;
  76 +
  77 + this.token = token;
  78 + this.snmpTransportContext = snmpTransportContext;
  79 +
  80 + this.profileTransportConfiguration = profileTransportConfiguration;
  81 + this.deviceTransportConfiguration = deviceTransportConfiguration;
  82 +
  83 + initializeTarget(profileTransportConfiguration, deviceTransportConfiguration);
  84 + }
  85 +
  86 + @Override
  87 + public void onDeviceProfileUpdate(TransportProtos.SessionInfoProto newSessionInfo, DeviceProfile deviceProfile) {
  88 + super.onDeviceProfileUpdate(newSessionInfo, deviceProfile);
  89 + if (isActive) {
  90 + snmpTransportContext.onDeviceProfileUpdated(deviceProfile, this);
  91 + }
  92 + }
  93 +
  94 + @Override
  95 + public void onDeviceDeleted(DeviceId deviceId) {
  96 + snmpTransportContext.onDeviceDeleted(this);
  97 + }
  98 +
  99 + @Override
  100 + public void onResponse(ResponseEvent event) {
  101 + if (isActive) {
  102 + snmpTransportContext.getSnmpTransportService().processResponseEvent(this, event);
  103 + }
  104 + }
  105 +
  106 + public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) throws Exception {
  107 + log.trace("Initializing target for SNMP session of device {}", device);
  108 + this.target = snmpTransportContext.getSnmpAuthService().setUpSnmpTarget(profileTransportConfig, deviceTransportConfig);
  109 + log.debug("SNMP target initialized: {}", target);
  110 + }
  111 +
  112 + public void close() {
  113 + isActive = false;
  114 + }
  115 +
  116 + public String getToken() {
  117 + return token;
  118 + }
  119 +
  120 + @Override
  121 + public int nextMsgId() {
  122 + return msgIdSeq.incrementAndGet();
  123 + }
  124 +
  125 + @Override
  126 + public void onGetAttributesResponse(GetAttributeResponseMsg getAttributesResponse) {
  127 + }
  128 +
  129 + @Override
  130 + public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) {
  131 + snmpTransportContext.getSnmpTransportService().onAttributeUpdate(this, attributeUpdateNotification);
  132 + }
  133 +
  134 + @Override
  135 + public void onRemoteSessionCloseCommand(SessionCloseNotificationProto sessionCloseNotification) {
  136 + }
  137 +
  138 + @Override
  139 + public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) {
  140 + snmpTransportContext.getSnmpTransportService().onToDeviceRpcRequest(this, toDeviceRequest);
  141 + }
  142 +
  143 + @Override
  144 + public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) {
  145 + }
  146 +}
  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 org.snmp4j.CommandResponderEvent;
  19 +import org.snmp4j.CommunityTarget;
  20 +import org.snmp4j.PDU;
  21 +import org.snmp4j.Snmp;
  22 +import org.snmp4j.Target;
  23 +import org.snmp4j.TransportMapping;
  24 +import org.snmp4j.agent.BaseAgent;
  25 +import org.snmp4j.agent.CommandProcessor;
  26 +import org.snmp4j.agent.DuplicateRegistrationException;
  27 +import org.snmp4j.agent.MOGroup;
  28 +import org.snmp4j.agent.ManagedObject;
  29 +import org.snmp4j.agent.mo.MOAccessImpl;
  30 +import org.snmp4j.agent.mo.MOScalar;
  31 +import org.snmp4j.agent.mo.snmp.RowStatus;
  32 +import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
  33 +import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
  34 +import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
  35 +import org.snmp4j.agent.mo.snmp.StorageType;
  36 +import org.snmp4j.agent.mo.snmp.VacmMIB;
  37 +import org.snmp4j.agent.security.MutableVACM;
  38 +import org.snmp4j.mp.MPv3;
  39 +import org.snmp4j.mp.SnmpConstants;
  40 +import org.snmp4j.security.SecurityLevel;
  41 +import org.snmp4j.security.SecurityModel;
  42 +import org.snmp4j.security.USM;
  43 +import org.snmp4j.smi.Address;
  44 +import org.snmp4j.smi.GenericAddress;
  45 +import org.snmp4j.smi.Integer32;
  46 +import org.snmp4j.smi.OID;
  47 +import org.snmp4j.smi.OctetString;
  48 +import org.snmp4j.smi.UdpAddress;
  49 +import org.snmp4j.smi.Variable;
  50 +import org.snmp4j.smi.VariableBinding;
  51 +import org.snmp4j.transport.TransportMappings;
  52 +
  53 +import java.io.File;
  54 +import java.io.IOException;
  55 +import java.util.Map;
  56 +import java.util.Scanner;
  57 +import java.util.function.Consumer;
  58 +import java.util.stream.Collectors;
  59 +
  60 +public class SnmpDeviceSimulatorV2 extends BaseAgent {
  61 +
  62 + public static class RequestProcessor extends CommandProcessor {
  63 + private final Consumer<CommandResponderEvent> processor;
  64 +
  65 + public RequestProcessor(Consumer<CommandResponderEvent> processor) {
  66 + super(new OctetString(MPv3.createLocalEngineID()));
  67 + this.processor = processor;
  68 + }
  69 +
  70 + @Override
  71 + public void processPdu(CommandResponderEvent event) {
  72 + processor.accept(event);
  73 + }
  74 + }
  75 +
  76 +
  77 + private final Target target;
  78 + private final Address address;
  79 + private Snmp snmp;
  80 +
  81 + private final String password;
  82 +
  83 + public SnmpDeviceSimulatorV2(int port, String password) throws IOException {
  84 + super(new File("conf.agent"), new File("bootCounter.agent"), new RequestProcessor(event -> {
  85 + System.out.println("aboba");
  86 + ((Snmp) event.getSource()).cancel(event.getPDU(), event1 -> System.out.println("canceled"));
  87 + }));
  88 + CommunityTarget target = new CommunityTarget();
  89 + target.setCommunity(new OctetString(password));
  90 + this.address = GenericAddress.parse("udp:0.0.0.0/" + port);
  91 + target.setAddress(address);
  92 + target.setRetries(2);
  93 + target.setTimeout(1500);
  94 + target.setVersion(SnmpConstants.version2c);
  95 + this.target = target;
  96 + this.password = password;
  97 + }
  98 +
  99 + public void start() throws IOException {
  100 + init();
  101 + addShutdownHook();
  102 + getServer().addContext(new OctetString("public"));
  103 + finishInit();
  104 + run();
  105 + sendColdStartNotification();
  106 + snmp = new Snmp(transportMappings[0]);
  107 + }
  108 +
  109 + public void setUpMappings(Map<String, String> oidToResponseMappings) {
  110 + unregisterManagedObject(getSnmpv2MIB());
  111 + oidToResponseMappings.forEach((oid, response) -> {
  112 + registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response)));
  113 + });
  114 + }
  115 +
  116 + public void sendTrap(String host, int port, Map<String, String> values) throws IOException {
  117 + PDU pdu = new PDU();
  118 + pdu.addAll(values.entrySet().stream()
  119 + .map(entry -> new VariableBinding(new OID(entry.getKey()), new OctetString(entry.getValue())))
  120 + .collect(Collectors.toList()));
  121 + pdu.setType(PDU.TRAP);
  122 +
  123 + CommunityTarget remoteTarget = (CommunityTarget) getTarget().clone();
  124 + remoteTarget.setAddress(new UdpAddress(host + "/" + port));
  125 +
  126 + snmp.send(pdu, remoteTarget);
  127 + }
  128 +
  129 + @Override
  130 + protected void registerManagedObjects() {
  131 + }
  132 +
  133 + protected void registerManagedObject(ManagedObject mo) {
  134 + try {
  135 + server.register(mo, null);
  136 + } catch (DuplicateRegistrationException ex) {
  137 + throw new RuntimeException(ex);
  138 + }
  139 + }
  140 +
  141 + protected void unregisterManagedObject(MOGroup moGroup) {
  142 + moGroup.unregisterMOs(server, getContext(moGroup));
  143 + }
  144 +
  145 + @Override
  146 + protected void addNotificationTargets(SnmpTargetMIB targetMIB,
  147 + SnmpNotificationMIB notificationMIB) {
  148 + }
  149 +
  150 + @Override
  151 + protected void addViews(VacmMIB vacm) {
  152 + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c, new OctetString(
  153 + "cpublic"), new OctetString("v1v2group"),
  154 + StorageType.nonVolatile);
  155 +
  156 + vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"),
  157 + SecurityModel.SECURITY_MODEL_ANY, SecurityLevel.NOAUTH_NOPRIV,
  158 + MutableVACM.VACM_MATCH_EXACT, new OctetString("fullReadView"),
  159 + new OctetString("fullWriteView"), new OctetString(
  160 + "fullNotifyView"), StorageType.nonVolatile);
  161 +
  162 + vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
  163 + new OctetString(), VacmMIB.vacmViewIncluded,
  164 + StorageType.nonVolatile);
  165 + }
  166 +
  167 + protected void addUsmUser(USM usm) {
  168 + }
  169 +
  170 + protected void initTransportMappings() {
  171 + transportMappings = new TransportMapping[]{TransportMappings.getInstance().createTransportMapping(address)};
  172 + }
  173 +
  174 + protected void unregisterManagedObjects() {
  175 + }
  176 +
  177 + protected void addCommunities(SnmpCommunityMIB communityMIB) {
  178 + Variable[] com2sec = new Variable[]{
  179 + new OctetString("public"),
  180 + new OctetString("cpublic"),
  181 + getAgent().getContextEngineID(),
  182 + new OctetString("public"),
  183 + new OctetString(),
  184 + new Integer32(StorageType.nonVolatile),
  185 + new Integer32(RowStatus.active)
  186 + };
  187 + SnmpCommunityMIB.SnmpCommunityEntryRow row = communityMIB.getSnmpCommunityEntry().createRow(
  188 + new OctetString("public2public").toSubIndex(true), com2sec);
  189 + communityMIB.getSnmpCommunityEntry().addRow(row);
  190 + }
  191 +
  192 + public Target getTarget() {
  193 + return target;
  194 + }
  195 +
  196 +}
  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 org.snmp4j.MessageDispatcherImpl;
  19 +import org.snmp4j.TransportMapping;
  20 +import org.snmp4j.agent.BaseAgent;
  21 +import org.snmp4j.agent.CommandProcessor;
  22 +import org.snmp4j.agent.DuplicateRegistrationException;
  23 +import org.snmp4j.agent.MOGroup;
  24 +import org.snmp4j.agent.ManagedObject;
  25 +import org.snmp4j.agent.mo.DefaultMOMutableRow2PC;
  26 +import org.snmp4j.agent.mo.DefaultMOTable;
  27 +import org.snmp4j.agent.mo.MOAccessImpl;
  28 +import org.snmp4j.agent.mo.MOColumn;
  29 +import org.snmp4j.agent.mo.MOMutableColumn;
  30 +import org.snmp4j.agent.mo.MOMutableTableModel;
  31 +import org.snmp4j.agent.mo.MOScalar;
  32 +import org.snmp4j.agent.mo.MOTableIndex;
  33 +import org.snmp4j.agent.mo.MOTableRow;
  34 +import org.snmp4j.agent.mo.MOTableSubIndex;
  35 +import org.snmp4j.agent.mo.ext.AgentppSimulationMib;
  36 +import org.snmp4j.agent.mo.snmp.RowStatus;
  37 +import org.snmp4j.agent.mo.snmp.SnmpCommunityMIB;
  38 +import org.snmp4j.agent.mo.snmp.SnmpNotificationMIB;
  39 +import org.snmp4j.agent.mo.snmp.SnmpTargetMIB;
  40 +import org.snmp4j.agent.mo.snmp.StorageType;
  41 +import org.snmp4j.agent.mo.snmp.TransportDomains;
  42 +import org.snmp4j.agent.mo.snmp.VacmMIB;
  43 +import org.snmp4j.agent.mo.snmp4j.example.Snmp4jHeartbeatMib;
  44 +import org.snmp4j.agent.security.MutableVACM;
  45 +import org.snmp4j.mp.MPv1;
  46 +import org.snmp4j.mp.MPv2c;
  47 +import org.snmp4j.mp.MPv3;
  48 +import org.snmp4j.mp.MessageProcessingModel;
  49 +import org.snmp4j.security.AuthHMAC192SHA256;
  50 +import org.snmp4j.security.AuthMD5;
  51 +import org.snmp4j.security.AuthSHA;
  52 +import org.snmp4j.security.PrivAES128;
  53 +import org.snmp4j.security.PrivAES192;
  54 +import org.snmp4j.security.PrivAES256;
  55 +import org.snmp4j.security.PrivDES;
  56 +import org.snmp4j.security.SecurityLevel;
  57 +import org.snmp4j.security.SecurityModel;
  58 +import org.snmp4j.security.SecurityModels;
  59 +import org.snmp4j.security.SecurityProtocols;
  60 +import org.snmp4j.security.USM;
  61 +import org.snmp4j.security.UsmUser;
  62 +import org.snmp4j.smi.Address;
  63 +import org.snmp4j.smi.Gauge32;
  64 +import org.snmp4j.smi.GenericAddress;
  65 +import org.snmp4j.smi.Integer32;
  66 +import org.snmp4j.smi.OID;
  67 +import org.snmp4j.smi.OctetString;
  68 +import org.snmp4j.smi.SMIConstants;
  69 +import org.snmp4j.smi.TcpAddress;
  70 +import org.snmp4j.smi.TimeTicks;
  71 +import org.snmp4j.smi.UdpAddress;
  72 +import org.snmp4j.smi.Variable;
  73 +import org.snmp4j.transport.DefaultTcpTransportMapping;
  74 +import org.snmp4j.transport.TransportMappings;
  75 +import org.snmp4j.util.ThreadPool;
  76 +
  77 +import java.io.File;
  78 +import java.io.IOException;
  79 +import java.util.Map;
  80 +
  81 +/**
  82 + * The TestAgent is a sample SNMP agent implementation of all
  83 + * features (MIB implementations) provided by the SNMP4J-Agent framework.
  84 + *
  85 + * Note, for snmp4s, this code is mostly a copy from snmp4j.
  86 + * And don't remove snmp users
  87 + *
  88 + */
  89 +public class SnmpDeviceSimulatorV3 extends BaseAgent {
  90 + protected String address;
  91 + private Snmp4jHeartbeatMib heartbeatMIB;
  92 + private AgentppSimulationMib agentppSimulationMIB;
  93 +
  94 + public SnmpDeviceSimulatorV3(CommandProcessor processor) throws IOException {
  95 + super(new File("SNMP4JTestAgentBC.cfg"), new File("SNMP4JTestAgentConfig.cfg"),
  96 + processor);
  97 + agent.setWorkerPool(ThreadPool.create("RequestPool", 4));
  98 + }
  99 +
  100 + public void setUpMappings(Map<String, String> oidToResponseMappings) {
  101 + unregisterManagedObject(getSnmpv2MIB());
  102 + oidToResponseMappings.forEach((oid, response) -> {
  103 + registerManagedObject(new MOScalar<>(new OID(oid), MOAccessImpl.ACCESS_READ_WRITE, new OctetString(response)));
  104 + });
  105 + }
  106 + protected void registerManagedObject(ManagedObject mo) {
  107 + try {
  108 + server.register(mo, null);
  109 + } catch (DuplicateRegistrationException ex) {
  110 + throw new RuntimeException(ex);
  111 + }
  112 + }
  113 +
  114 + protected void unregisterManagedObject(MOGroup moGroup) {
  115 + moGroup.unregisterMOs(server, getContext(moGroup));
  116 + }
  117 +
  118 + protected void registerManagedObjects() {
  119 + try {
  120 + server.register(createStaticIfTable(), null);
  121 + server.register(createStaticIfXTable(), null);
  122 + agentppSimulationMIB.registerMOs(server, null);
  123 + heartbeatMIB.registerMOs(server, null);
  124 + } catch (DuplicateRegistrationException ex) {
  125 + ex.printStackTrace();
  126 + }
  127 + }
  128 +
  129 + protected void addNotificationTargets(SnmpTargetMIB targetMIB,
  130 + SnmpNotificationMIB notificationMIB) {
  131 + targetMIB.addDefaultTDomains();
  132 +
  133 + targetMIB.addTargetAddress(new OctetString("notificationV2c"),
  134 + TransportDomains.transportDomainUdpIpv4,
  135 + new OctetString(new UdpAddress("127.0.0.1/162").getValue()),
  136 + 200, 1,
  137 + new OctetString("notify"),
  138 + new OctetString("v2c"),
  139 + StorageType.permanent);
  140 + targetMIB.addTargetAddress(new OctetString("notificationV3"),
  141 + TransportDomains.transportDomainUdpIpv4,
  142 + new OctetString(new UdpAddress("127.0.0.1/1162").getValue()),
  143 + 200, 1,
  144 + new OctetString("notify"),
  145 + new OctetString("v3notify"),
  146 + StorageType.permanent);
  147 + targetMIB.addTargetParams(new OctetString("v2c"),
  148 + MessageProcessingModel.MPv2c,
  149 + SecurityModel.SECURITY_MODEL_SNMPv2c,
  150 + new OctetString("cpublic"),
  151 + SecurityLevel.AUTH_PRIV,
  152 + StorageType.permanent);
  153 + targetMIB.addTargetParams(new OctetString("v3notify"),
  154 + MessageProcessingModel.MPv3,
  155 + SecurityModel.SECURITY_MODEL_USM,
  156 + new OctetString("v3notify"),
  157 + SecurityLevel.NOAUTH_NOPRIV,
  158 + StorageType.permanent);
  159 + notificationMIB.addNotifyEntry(new OctetString("default"),
  160 + new OctetString("notify"),
  161 + SnmpNotificationMIB.SnmpNotifyTypeEnum.inform,
  162 + StorageType.permanent);
  163 + }
  164 + protected void addViews(VacmMIB vacm) {
  165 + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv1,
  166 + new OctetString("cpublic"),
  167 + new OctetString("v1v2group"),
  168 + StorageType.nonVolatile);
  169 + vacm.addGroup(SecurityModel.SECURITY_MODEL_SNMPv2c,
  170 + new OctetString("cpublic"),
  171 + new OctetString("v1v2group"),
  172 + StorageType.nonVolatile);
  173 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  174 + new OctetString("SHADES"),
  175 + new OctetString("v3group"),
  176 + StorageType.nonVolatile);
  177 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  178 + new OctetString("MD5DES"),
  179 + new OctetString("v3group"),
  180 + StorageType.nonVolatile);
  181 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  182 + new OctetString("TEST"),
  183 + new OctetString("v3test"),
  184 + StorageType.nonVolatile);
  185 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  186 + new OctetString("SHA"),
  187 + new OctetString("v3restricted"),
  188 + StorageType.nonVolatile);
  189 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  190 + new OctetString("SHAAES128"),
  191 + new OctetString("v3group"),
  192 + StorageType.nonVolatile);
  193 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  194 + new OctetString("SHAAES192"),
  195 + new OctetString("v3group"),
  196 + StorageType.nonVolatile);
  197 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  198 + new OctetString("SHAAES256"),
  199 + new OctetString("v3group"),
  200 + StorageType.nonVolatile);
  201 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  202 + new OctetString("MD5AES128"),
  203 + new OctetString("v3group"),
  204 + StorageType.nonVolatile);
  205 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  206 + new OctetString("MD5AES192"),
  207 + new OctetString("v3group"),
  208 + StorageType.nonVolatile);
  209 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  210 + new OctetString("MD5AES256"),
  211 + new OctetString("v3group"),
  212 + StorageType.nonVolatile);
  213 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  214 + new OctetString("aboba"),
  215 + new OctetString("v3group"),
  216 + StorageType.nonVolatile);
  217 + //============================================//
  218 + // agent5-auth-priv
  219 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  220 + new OctetString("agent5"),
  221 + new OctetString("v3group"),
  222 + StorageType.nonVolatile);
  223 + //===========================================//
  224 + // agent002
  225 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  226 + new OctetString("agent002"),
  227 + new OctetString("v3group"),
  228 + StorageType.nonVolatile);
  229 + //===========================================//
  230 + // user001-auth-no-priv
  231 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  232 + new OctetString("user001"),
  233 + new OctetString("group001"),
  234 + StorageType.nonVolatile);
  235 + //===========================================//
  236 +
  237 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  238 + new OctetString("v3notify"),
  239 + new OctetString("v3group"),
  240 + StorageType.nonVolatile);
  241 +
  242 + //===========================================//
  243 + // group auth no priv
  244 + vacm.addGroup(SecurityModel.SECURITY_MODEL_USM,
  245 + new OctetString("v3notify-auth"),
  246 + new OctetString("group001"),
  247 + StorageType.nonVolatile);
  248 + //===========================================//
  249 +
  250 +
  251 +
  252 + // my conf
  253 + vacm.addAccess(new OctetString("group001"), new OctetString("public"),
  254 + SecurityModel.SECURITY_MODEL_USM,
  255 + SecurityLevel.AUTH_NOPRIV,
  256 + MutableVACM.VACM_MATCH_EXACT,
  257 + new OctetString("fullReadView"),
  258 + new OctetString("fullWriteView"),
  259 + new OctetString("fullNotifyView"),
  260 + StorageType.nonVolatile);
  261 +
  262 + vacm.addAccess(new OctetString("v1v2group"), new OctetString("public"),
  263 + SecurityModel.SECURITY_MODEL_ANY,
  264 + SecurityLevel.NOAUTH_NOPRIV,
  265 + MutableVACM.VACM_MATCH_EXACT,
  266 + new OctetString("fullReadView"),
  267 + new OctetString("fullWriteView"),
  268 + new OctetString("fullNotifyView"),
  269 + StorageType.nonVolatile);
  270 + vacm.addAccess(new OctetString("v3group"), new OctetString(),
  271 + SecurityModel.SECURITY_MODEL_USM,
  272 + SecurityLevel.AUTH_PRIV,
  273 + MutableVACM.VACM_MATCH_EXACT,
  274 + new OctetString("fullReadView"),
  275 + new OctetString("fullWriteView"),
  276 + new OctetString("fullNotifyView"),
  277 + StorageType.nonVolatile);
  278 + vacm.addAccess(new OctetString("v3restricted"), new OctetString(),
  279 + SecurityModel.SECURITY_MODEL_USM,
  280 + SecurityLevel.NOAUTH_NOPRIV,
  281 + MutableVACM.VACM_MATCH_EXACT,
  282 + new OctetString("restrictedReadView"),
  283 + new OctetString("restrictedWriteView"),
  284 + new OctetString("restrictedNotifyView"),
  285 + StorageType.nonVolatile);
  286 + vacm.addAccess(new OctetString("v3test"), new OctetString(),
  287 + SecurityModel.SECURITY_MODEL_USM,
  288 + SecurityLevel.AUTH_PRIV,
  289 + MutableVACM.VACM_MATCH_EXACT,
  290 + new OctetString("testReadView"),
  291 + new OctetString("testWriteView"),
  292 + new OctetString("testNotifyView"),
  293 + StorageType.nonVolatile);
  294 +
  295 + vacm.addViewTreeFamily(new OctetString("fullReadView"), new OID("1.3"),
  296 + new OctetString(), VacmMIB.vacmViewIncluded,
  297 + StorageType.nonVolatile);
  298 + vacm.addViewTreeFamily(new OctetString("fullWriteView"), new OID("1.3"),
  299 + new OctetString(), VacmMIB.vacmViewIncluded,
  300 + StorageType.nonVolatile);
  301 + vacm.addViewTreeFamily(new OctetString("fullNotifyView"), new OID("1.3"),
  302 + new OctetString(), VacmMIB.vacmViewIncluded,
  303 + StorageType.nonVolatile);
  304 +
  305 + vacm.addViewTreeFamily(new OctetString("restrictedReadView"),
  306 + new OID("1.3.6.1.2"),
  307 + new OctetString(), VacmMIB.vacmViewIncluded,
  308 + StorageType.nonVolatile);
  309 + vacm.addViewTreeFamily(new OctetString("restrictedWriteView"),
  310 + new OID("1.3.6.1.2.1"),
  311 + new OctetString(),
  312 + VacmMIB.vacmViewIncluded,
  313 + StorageType.nonVolatile);
  314 + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
  315 + new OID("1.3.6.1.2"),
  316 + new OctetString(), VacmMIB.vacmViewIncluded,
  317 + StorageType.nonVolatile);
  318 + vacm.addViewTreeFamily(new OctetString("restrictedNotifyView"),
  319 + new OID("1.3.6.1.6.3.1"),
  320 + new OctetString(), VacmMIB.vacmViewIncluded,
  321 + StorageType.nonVolatile);
  322 +
  323 + vacm.addViewTreeFamily(new OctetString("testReadView"),
  324 + new OID("1.3.6.1.2"),
  325 + new OctetString(), VacmMIB.vacmViewIncluded,
  326 + StorageType.nonVolatile);
  327 + vacm.addViewTreeFamily(new OctetString("testReadView"),
  328 + new OID("1.3.6.1.2.1.1"),
  329 + new OctetString(), VacmMIB.vacmViewExcluded,
  330 + StorageType.nonVolatile);
  331 + vacm.addViewTreeFamily(new OctetString("testWriteView"),
  332 + new OID("1.3.6.1.2.1"),
  333 + new OctetString(),
  334 + VacmMIB.vacmViewIncluded,
  335 + StorageType.nonVolatile);
  336 + vacm.addViewTreeFamily(new OctetString("testNotifyView"),
  337 + new OID("1.3.6.1.2"),
  338 + new OctetString(), VacmMIB.vacmViewIncluded,
  339 + StorageType.nonVolatile);
  340 +
  341 + }
  342 +
  343 + protected void addUsmUser(USM usm) {
  344 + UsmUser user = new UsmUser(new OctetString("SHADES"),
  345 + AuthSHA.ID,
  346 + new OctetString("SHADESAuthPassword"),
  347 + PrivDES.ID,
  348 + new OctetString("SHADESPrivPassword"));
  349 +// usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  350 + usm.addUser(user.getSecurityName(), null, user);
  351 + user = new UsmUser(new OctetString("TEST"),
  352 + AuthSHA.ID,
  353 + new OctetString("maplesyrup"),
  354 + PrivDES.ID,
  355 + new OctetString("maplesyrup"));
  356 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  357 + user = new UsmUser(new OctetString("SHA"),
  358 + AuthSHA.ID,
  359 + new OctetString("SHAAuthPassword"),
  360 + null,
  361 + null);
  362 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  363 + user = new UsmUser(new OctetString("SHADES"),
  364 + AuthSHA.ID,
  365 + new OctetString("SHADESAuthPassword"),
  366 + PrivDES.ID,
  367 + new OctetString("SHADESPrivPassword"));
  368 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  369 + user = new UsmUser(new OctetString("MD5DES"),
  370 + AuthMD5.ID,
  371 + new OctetString("MD5DESAuthPassword"),
  372 + PrivDES.ID,
  373 + new OctetString("MD5DESPrivPassword"));
  374 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  375 + user = new UsmUser(new OctetString("SHAAES128"),
  376 + AuthSHA.ID,
  377 + new OctetString("SHAAES128AuthPassword"),
  378 + PrivAES128.ID,
  379 + new OctetString("SHAAES128PrivPassword"));
  380 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  381 + user = new UsmUser(new OctetString("SHAAES192"),
  382 + AuthSHA.ID,
  383 + new OctetString("SHAAES192AuthPassword"),
  384 + PrivAES192.ID,
  385 + new OctetString("SHAAES192PrivPassword"));
  386 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  387 + user = new UsmUser(new OctetString("SHAAES256"),
  388 + AuthSHA.ID,
  389 + new OctetString("SHAAES256AuthPassword"),
  390 + PrivAES256.ID,
  391 + new OctetString("SHAAES256PrivPassword"));
  392 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  393 +
  394 + user = new UsmUser(new OctetString("MD5AES128"),
  395 + AuthMD5.ID,
  396 + new OctetString("MD5AES128AuthPassword"),
  397 + PrivAES128.ID,
  398 + new OctetString("MD5AES128PrivPassword"));
  399 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  400 + user = new UsmUser(new OctetString("MD5AES192"),
  401 + AuthHMAC192SHA256.ID,
  402 + new OctetString("MD5AES192AuthPassword"),
  403 + PrivAES192.ID,
  404 + new OctetString("MD5AES192PrivPassword"));
  405 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  406 + //==============================================================
  407 + user = new UsmUser(new OctetString("MD5AES256"),
  408 + AuthMD5.ID,
  409 + new OctetString("MD5AES256AuthPassword"),
  410 + PrivAES256.ID,
  411 + new OctetString("MD5AES256PrivPassword"));
  412 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  413 + user = new UsmUser(new OctetString("MD5AES256"),
  414 + AuthMD5.ID,
  415 + new OctetString("MD5AES256AuthPassword"),
  416 + PrivAES256.ID,
  417 + new OctetString("MD5AES256PrivPassword"));
  418 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  419 +
  420 + OctetString securityName = new OctetString("aboba");
  421 + OctetString authenticationPassphrase = new OctetString("abobaaboba");
  422 + OctetString privacyPassphrase = new OctetString("abobaaboba");
  423 + OID authenticationProtocol = AuthSHA.ID;
  424 + OID privacyProtocol = PrivDES.ID; // FIXME: to config
  425 + user = new UsmUser(securityName, authenticationProtocol, authenticationPassphrase, privacyProtocol, privacyPassphrase);
  426 + usm.addUser(user);
  427 +
  428 + //===============================================================//
  429 + user = new UsmUser(new OctetString("agent5"),
  430 + AuthSHA.ID,
  431 + new OctetString("authpass"),
  432 + PrivDES.ID,
  433 + new OctetString("privpass"));
  434 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  435 + //===============================================================//
  436 + // user001
  437 + user = new UsmUser(new OctetString("user001"),
  438 + AuthSHA.ID,
  439 + new OctetString("authpass"),
  440 + null, null);
  441 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  442 + //===============================================================//
  443 + // user002
  444 + user = new UsmUser(new OctetString("user001"),
  445 + null,
  446 + null,
  447 + null, null);
  448 + usm.addUser(user.getSecurityName(), usm.getLocalEngineID(), user);
  449 + //===============================================================//
  450 +
  451 + user = new UsmUser(new OctetString("v3notify"),
  452 + null,
  453 + null,
  454 + null,
  455 + null);
  456 + usm.addUser(user.getSecurityName(), null, user);
  457 +
  458 + this.usm = usm;
  459 + }
  460 +
  461 + private static DefaultMOTable createStaticIfXTable() {
  462 + MOTableSubIndex[] subIndexes =
  463 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  464 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  465 + MOColumn[] columns = new MOColumn[19];
  466 + int c = 0;
  467 + columns[c++] =
  468 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  469 + MOAccessImpl.ACCESS_READ_ONLY); // ifName
  470 + columns[c++] =
  471 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  472 + MOAccessImpl.ACCESS_READ_ONLY); // ifInMulticastPkts
  473 + columns[c++] =
  474 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  475 + MOAccessImpl.ACCESS_READ_ONLY); // ifInBroadcastPkts
  476 + columns[c++] =
  477 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  478 + MOAccessImpl.ACCESS_READ_ONLY); // ifOutMulticastPkts
  479 + columns[c++] =
  480 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  481 + MOAccessImpl.ACCESS_READ_ONLY); // ifOutBroadcastPkts
  482 + columns[c++] =
  483 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  484 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInOctets
  485 + columns[c++] =
  486 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  487 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInUcastPkts
  488 + columns[c++] =
  489 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  490 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInMulticastPkts
  491 + columns[c++] =
  492 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  493 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCInBroadcastPkts
  494 + columns[c++] =
  495 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  496 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutOctets
  497 + columns[c++] =
  498 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  499 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutUcastPkts
  500 + columns[c++] =
  501 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  502 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutMulticastPkts
  503 + columns[c++] =
  504 + new MOColumn(c, SMIConstants.SYNTAX_COUNTER32,
  505 + MOAccessImpl.ACCESS_READ_ONLY); // ifHCOutBroadcastPkts
  506 + columns[c++] =
  507 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  508 + MOAccessImpl.ACCESS_READ_WRITE); // ifLinkUpDownTrapEnable
  509 + columns[c++] =
  510 + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
  511 + MOAccessImpl.ACCESS_READ_ONLY); // ifHighSpeed
  512 + columns[c++] =
  513 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  514 + MOAccessImpl.ACCESS_READ_WRITE); // ifPromiscuousMode
  515 + columns[c++] =
  516 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  517 + MOAccessImpl.ACCESS_READ_ONLY); // ifConnectorPresent
  518 + columns[c++] =
  519 + new MOMutableColumn(c, SMIConstants.SYNTAX_OCTET_STRING, // ifAlias
  520 + MOAccessImpl.ACCESS_READ_WRITE, null);
  521 + columns[c++] =
  522 + new MOColumn(c, SMIConstants.SYNTAX_TIMETICKS,
  523 + MOAccessImpl.ACCESS_READ_ONLY); // ifCounterDiscontinuityTime
  524 +
  525 + DefaultMOTable ifXTable =
  526 + new DefaultMOTable(new OID("1.3.6.1.2.1.31.1.1.1"), indexDef, columns);
  527 + MOMutableTableModel model = (MOMutableTableModel) ifXTable.getModel();
  528 + Variable[] rowValues1 = new Variable[] {
  529 + new OctetString("Ethernet-0"),
  530 + new Integer32(1),
  531 + new Integer32(2),
  532 + new Integer32(3),
  533 + new Integer32(4),
  534 + new Integer32(5),
  535 + new Integer32(6),
  536 + new Integer32(7),
  537 + new Integer32(8),
  538 + new Integer32(9),
  539 + new Integer32(10),
  540 + new Integer32(11),
  541 + new Integer32(12),
  542 + new Integer32(13),
  543 + new Integer32(14),
  544 + new Integer32(15),
  545 + new Integer32(16),
  546 + new OctetString("My eth"),
  547 + new TimeTicks(1000)
  548 + };
  549 + Variable[] rowValues2 = new Variable[] {
  550 + new OctetString("Loopback"),
  551 + new Integer32(21),
  552 + new Integer32(22),
  553 + new Integer32(23),
  554 + new Integer32(24),
  555 + new Integer32(25),
  556 + new Integer32(26),
  557 + new Integer32(27),
  558 + new Integer32(28),
  559 + new Integer32(29),
  560 + new Integer32(30),
  561 + new Integer32(31),
  562 + new Integer32(32),
  563 + new Integer32(33),
  564 + new Integer32(34),
  565 + new Integer32(35),
  566 + new Integer32(36),
  567 + new OctetString("My loop"),
  568 + new TimeTicks(2000)
  569 + };
  570 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  571 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  572 + ifXTable.setVolatile(true);
  573 + return ifXTable;
  574 + }
  575 +
  576 + private static DefaultMOTable createStaticIfTable() {
  577 + MOTableSubIndex[] subIndexes =
  578 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  579 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  580 + MOColumn[] columns = new MOColumn[8];
  581 + int c = 0;
  582 + columns[c++] =
  583 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  584 + MOAccessImpl.ACCESS_READ_ONLY); // ifIndex
  585 + columns[c++] =
  586 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  587 + MOAccessImpl.ACCESS_READ_ONLY); // ifDescr
  588 + columns[c++] =
  589 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  590 + MOAccessImpl.ACCESS_READ_ONLY); // ifType
  591 + columns[c++] =
  592 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  593 + MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
  594 + columns[c++] =
  595 + new MOColumn(c, SMIConstants.SYNTAX_GAUGE32,
  596 + MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
  597 + columns[c++] =
  598 + new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING,
  599 + MOAccessImpl.ACCESS_READ_ONLY); // ifPhysAddress
  600 + columns[c++] =
  601 + new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, // ifAdminStatus
  602 + MOAccessImpl.ACCESS_READ_WRITE, null);
  603 + columns[c++] =
  604 + new MOColumn(c, SMIConstants.SYNTAX_INTEGER,
  605 + MOAccessImpl.ACCESS_READ_ONLY); // ifOperStatus
  606 +
  607 + DefaultMOTable ifTable =
  608 + new DefaultMOTable(new OID("1.3.6.1.2.1.2.2.1"), indexDef, columns);
  609 + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
  610 + Variable[] rowValues1 = new Variable[] {
  611 + new Integer32(1),
  612 + new OctetString("eth0"),
  613 + new Integer32(6),
  614 + new Integer32(1500),
  615 + new Gauge32(100000000),
  616 + new OctetString("00:00:00:00:01"),
  617 + new Integer32(1),
  618 + new Integer32(1)
  619 + };
  620 + Variable[] rowValues2 = new Variable[] {
  621 + new Integer32(2),
  622 + new OctetString("loopback"),
  623 + new Integer32(24),
  624 + new Integer32(1500),
  625 + new Gauge32(10000000),
  626 + new OctetString("00:00:00:00:02"),
  627 + new Integer32(1),
  628 + new Integer32(1)
  629 + };
  630 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  631 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  632 + ifTable.setVolatile(true);
  633 + return ifTable;
  634 + }
  635 +
  636 + private static DefaultMOTable createStaticSnmp4sTable() {
  637 + MOTableSubIndex[] subIndexes =
  638 + new MOTableSubIndex[] { new MOTableSubIndex(SMIConstants.SYNTAX_INTEGER) };
  639 + MOTableIndex indexDef = new MOTableIndex(subIndexes, false);
  640 + MOColumn[] columns = new MOColumn[8];
  641 + int c = 0;
  642 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_NULL, MOAccessImpl.ACCESS_READ_ONLY); // testNull
  643 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // testBoolean
  644 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifType
  645 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY); // ifMtu
  646 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_GAUGE32, MOAccessImpl.ACCESS_READ_ONLY); // ifSpeed
  647 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_OCTET_STRING, MOAccessImpl.ACCESS_READ_ONLY); //ifPhysAddress
  648 + columns[c++] = new MOMutableColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_WRITE,
  649 + null);
  650 + // ifAdminStatus
  651 + columns[c++] = new MOColumn(c, SMIConstants.SYNTAX_INTEGER, MOAccessImpl.ACCESS_READ_ONLY);
  652 + // ifOperStatus
  653 +
  654 + DefaultMOTable ifTable =
  655 + new DefaultMOTable(new OID("1.3.6.1.4.1.50000.1.1"), indexDef, columns);
  656 + MOMutableTableModel model = (MOMutableTableModel) ifTable.getModel();
  657 + Variable[] rowValues1 = new Variable[] {
  658 + new Integer32(1),
  659 + new OctetString("eth0"),
  660 + new Integer32(6),
  661 + new Integer32(1500),
  662 + new Gauge32(100000000),
  663 + new OctetString("00:00:00:00:01"),
  664 + new Integer32(1),
  665 + new Integer32(1)
  666 + };
  667 + Variable[] rowValues2 = new Variable[] {
  668 + new Integer32(2),
  669 + new OctetString("loopback"),
  670 + new Integer32(24),
  671 + new Integer32(1500),
  672 + new Gauge32(10000000),
  673 + new OctetString("00:00:00:00:02"),
  674 + new Integer32(1),
  675 + new Integer32(1)
  676 + };
  677 + model.addRow(new DefaultMOMutableRow2PC(new OID("1"), rowValues1));
  678 + model.addRow(new DefaultMOMutableRow2PC(new OID("2"), rowValues2));
  679 + ifTable.setVolatile(true);
  680 + return ifTable;
  681 + }
  682 +
  683 + protected void initTransportMappings() throws IOException {
  684 + transportMappings = new TransportMapping[2];
  685 + Address addr = GenericAddress.parse(address);
  686 + TransportMapping tm =
  687 + TransportMappings.getInstance().createTransportMapping(addr);
  688 + transportMappings[0] = tm;
  689 + transportMappings[1] = new DefaultTcpTransportMapping(new TcpAddress(address));
  690 + }
  691 +
  692 + public void start(String ip, String port) throws IOException {
  693 + address = ip + "/" + port;
  694 + //BasicConfigurator.configure();
  695 + init();
  696 + addShutdownHook();
  697 +// loadConfig(ImportModes.REPLACE_CREATE);
  698 + getServer().addContext(new OctetString("public"));
  699 + finishInit();
  700 + run();
  701 + sendColdStartNotification();
  702 + }
  703 +
  704 + protected void unregisterManagedObjects() {
  705 + // here we should unregister those objects previously registered...
  706 + }
  707 +
  708 + protected void addCommunities(SnmpCommunityMIB communityMIB) {
  709 + Variable[] com2sec = new Variable[] {
  710 + new OctetString("public"), // community name
  711 + new OctetString("cpublic"), // security name
  712 + getAgent().getContextEngineID(), // local engine ID
  713 + new OctetString("public"), // default context name
  714 + new OctetString(), // transport tag
  715 + new Integer32(StorageType.nonVolatile), // storage type
  716 + new Integer32(RowStatus.active) // row status
  717 + };
  718 + MOTableRow row =
  719 + communityMIB.getSnmpCommunityEntry().createRow(
  720 + new OctetString("public2public").toSubIndex(true), com2sec);
  721 + communityMIB.getSnmpCommunityEntry().addRow((SnmpCommunityMIB.SnmpCommunityEntryRow) row);
  722 +// snmpCommunityMIB.setSourceAddressFiltering(true);
  723 + }
  724 +
  725 + protected void registerSnmpMIBs() {
  726 + heartbeatMIB = new Snmp4jHeartbeatMib(super.getNotificationOriginator(),
  727 + new OctetString(),
  728 + super.snmpv2MIB.getSysUpTime());
  729 + agentppSimulationMIB = new AgentppSimulationMib();
  730 + super.registerSnmpMIBs();
  731 + }
  732 +
  733 + protected void initMessageDispatcher() {
  734 + this.dispatcher = new MessageDispatcherImpl();
  735 + this.mpv3 = new MPv3(this.agent.getContextEngineID().getValue());
  736 + this.usm = new USM(SecurityProtocols.getInstance(), this.agent.getContextEngineID(), this.updateEngineBoots());
  737 + SecurityModels.getInstance().addSecurityModel(this.usm);
  738 + SecurityProtocols.getInstance().addDefaultProtocols();
  739 + this.dispatcher.addMessageProcessingModel(new MPv1());
  740 + this.dispatcher.addMessageProcessingModel(new MPv2c());
  741 + this.dispatcher.addMessageProcessingModel(this.mpv3);
  742 + this.initSnmpSession();
  743 + }
  744 +
  745 +}
  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 java.io.IOException;
  19 +import java.util.Map;
  20 +import java.util.Scanner;
  21 +
  22 +public class SnmpTestV2 {
  23 + public static void main(String[] args) throws IOException {
  24 + SnmpDeviceSimulatorV2 device = new SnmpDeviceSimulatorV2(1610, "public");
  25 +
  26 + device.start();
  27 + device.setUpMappings(Map.of(
  28 + ".1.3.6.1.2.1.1.1.50", "12",
  29 + ".1.3.6.1.2.1.2.1.52", "56",
  30 + ".1.3.6.1.2.1.3.1.54", "yes",
  31 + ".1.3.6.1.2.1.7.1.58", ""
  32 + ));
  33 +
  34 +
  35 +// while (true) {
  36 +// new Scanner(System.in).nextLine();
  37 +// device.sendTrap("127.0.0.1", 1062, Map.of(".1.3.6.1.2.87.1.56", "12"));
  38 +// System.out.println("sent");
  39 +// }
  40 +
  41 +// Snmp snmp = new Snmp(device.transportMappings[0]);
  42 +// device.snmp.addCommandResponder(event -> {
  43 +// System.out.println(event);
  44 +// });
  45 +
  46 + new Scanner(System.in).nextLine();
  47 + }
  48 +
  49 +}
  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 org.snmp4j.CommandResponderEvent;
  19 +import org.snmp4j.agent.CommandProcessor;
  20 +import org.snmp4j.mp.MPv3;
  21 +import org.snmp4j.smi.OctetString;
  22 +
  23 +import java.io.IOException;
  24 +import java.util.Map;
  25 +import java.util.Scanner;
  26 +
  27 +public class SnmpTestV3 {
  28 + public static void main(String[] args) throws IOException {
  29 + SnmpDeviceSimulatorV3 device = new SnmpDeviceSimulatorV3(new CommandProcessor(new OctetString(MPv3.createLocalEngineID())) {
  30 + @Override
  31 + public void processPdu(CommandResponderEvent event) {
  32 + System.out.println("event: " + event);
  33 + }
  34 + });
  35 + device.start("0.0.0.0", "1610");
  36 +
  37 + device.setUpMappings(Map.of(
  38 + ".1.3.6.1.2.1.1.1.50", "12",
  39 + ".1.3.6.1.2.1.2.1.52", "56",
  40 + ".1.3.6.1.2.1.3.1.54", "yes",
  41 + ".1.3.6.1.2.1.7.1.58", ""
  42 + ));
  43 +
  44 + new Scanner(System.in).nextLine();
  45 + }
  46 +}
  1 +{
  2 + "timeoutMs": 500,
  3 + "retries": 0,
  4 + "communicationConfigs": [
  5 + {
  6 + "spec": "TELEMETRY_QUERYING",
  7 + "queryingFrequencyMs": 3000,
  8 + "mappings": [
  9 + {
  10 + "oid": ".1.3.6.1.2.1.1.1.50",
  11 + "key": "temperature",
  12 + "dataType": "LONG"
  13 + },
  14 + {
  15 + "oid": ".1.3.6.1.2.1.2.1.52",
  16 + "key": "humidity",
  17 + "dataType": "DOUBLE"
  18 + }
  19 + ]
  20 + },
  21 + {
  22 + "spec": "CLIENT_ATTRIBUTES_QUERYING",
  23 + "queryingFrequencyMs": 5000,
  24 + "mappings": [
  25 + {
  26 + "oid": ".1.3.6.1.2.1.3.1.54",
  27 + "key": "isCool",
  28 + "dataType": "STRING"
  29 + }
  30 + ]
  31 + },
  32 + {
  33 + "spec": "SHARED_ATTRIBUTES_SETTING",
  34 + "mappings": [
  35 + {
  36 + "oid": ".1.3.6.1.2.1.7.1.58",
  37 + "key": "shared",
  38 + "dataType": "STRING"
  39 + }
  40 + ]
  41 + }
  42 + ]
  43 +}
  1 +{
  2 + "address": "192.168.3.23",
  3 + "port": 1610,
  4 + "protocolVersion": "V3",
  5 +
  6 + "username": "tb-user",
  7 + "engineId": "qwertyuioa",
  8 + "securityName": "tb-user",
  9 + "authenticationProtocol": "SHA_512",
  10 + "authenticationPassphrase": "sdfghjkloifgh",
  11 + "privacyProtocol": "DES",
  12 + "privacyPassphrase": "rtytguijokod"
  13 +}
  1 +{
  2 + "address": "127.0.0.1",
  3 + "port": 1610,
  4 + "community": "public",
  5 + "protocolVersion": "V2C"
  6 +}
  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.transport;
  17 +
  18 +import lombok.Getter;
  19 +import org.thingsboard.server.common.data.Device;
  20 +
  21 +@Getter
  22 +public class DeviceUpdatedEvent {
  23 + private final Device device;
  24 +
  25 + public DeviceUpdatedEvent(Device device) {
  26 + this.device = device;
  27 + }
  28 +}
@@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport; @@ -17,6 +17,7 @@ package org.thingsboard.server.common.transport;
17 17
18 import org.thingsboard.server.common.data.Device; 18 import org.thingsboard.server.common.data.Device;
19 import org.thingsboard.server.common.data.DeviceProfile; 19 import org.thingsboard.server.common.data.DeviceProfile;
  20 +import org.thingsboard.server.common.data.id.DeviceId;
20 import org.thingsboard.server.gen.transport.TransportProtos; 21 import org.thingsboard.server.gen.transport.TransportProtos;
21 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; 22 import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg;
22 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg; 23 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponseMsg;
@@ -49,6 +50,8 @@ public interface SessionMsgListener { @@ -49,6 +50,8 @@ public interface SessionMsgListener {
49 default void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device, 50 default void onDeviceUpdate(TransportProtos.SessionInfoProto sessionInfo, Device device,
50 Optional<DeviceProfile> deviceProfileOpt) {} 51 Optional<DeviceProfile> deviceProfileOpt) {}
51 52
  53 + default void onDeviceDeleted(DeviceId deviceId) {}
  54 +
52 default void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {} 55 default void onResourceUpdate(Optional<TransportProtos.ResourceUpdateMsg> resourceUpdateMsgOpt) {}
53 56
54 default void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceUpdateMsgOpt) {} 57 default void onResourceDelete(Optional<TransportProtos.ResourceDeleteMsg> resourceUpdateMsgOpt) {}
@@ -22,6 +22,10 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes @@ -22,6 +22,10 @@ import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsRes
22 import org.thingsboard.server.common.transport.service.SessionMetaData; 22 import org.thingsboard.server.common.transport.service.SessionMetaData;
23 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; 23 import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg;
24 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; 24 import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg;
  25 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsRequestMsg;
  26 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceCredentialsResponseMsg;
  27 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceRequestMsg;
  28 +import org.thingsboard.server.gen.transport.TransportProtos.GetDeviceResponseMsg;
25 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; 29 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
26 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; 30 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
27 import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareRequestMsg; 31 import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareRequestMsg;
@@ -29,6 +33,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareResponseM @@ -29,6 +33,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetFirmwareResponseM
29 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 33 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
30 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg; 34 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceRequestMsg;
31 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg; 35 import org.thingsboard.server.gen.transport.TransportProtos.GetResourceResponseMsg;
  36 +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesRequestMsg;
  37 +import org.thingsboard.server.gen.transport.TransportProtos.GetSnmpDevicesResponseMsg;
32 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg; 38 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg;
33 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg; 39 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg;
34 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 40 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
@@ -57,6 +63,12 @@ public interface TransportService { @@ -57,6 +63,12 @@ public interface TransportService {
57 63
58 GetResourceResponseMsg getResource(GetResourceRequestMsg msg); 64 GetResourceResponseMsg getResource(GetResourceRequestMsg msg);
59 65
  66 + GetSnmpDevicesResponseMsg getSnmpDevicesIds(GetSnmpDevicesRequestMsg requestMsg);
  67 +
  68 + GetDeviceResponseMsg getDevice(GetDeviceRequestMsg requestMsg);
  69 +
  70 + GetDeviceCredentialsResponseMsg getDeviceCredentials(GetDeviceCredentialsRequestMsg requestMsg);
  71 +
60 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg, 72 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg,
61 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); 73 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
62 74
@@ -289,7 +289,7 @@ public class JsonConverter { @@ -289,7 +289,7 @@ public class JsonConverter {
289 return result; 289 return result;
290 } 290 }
291 291
292 - public static JsonElement toJson(AttributeUpdateNotificationMsg payload) { 292 + public static JsonObject toJson(AttributeUpdateNotificationMsg payload) {
293 JsonObject result = new JsonObject(); 293 JsonObject result = new JsonObject();
294 if (payload.getSharedUpdatedCount() > 0) { 294 if (payload.getSharedUpdatedCount() > 0) {
295 payload.getSharedUpdatedList().forEach(addToObjectFromProto(result)); 295 payload.getSharedUpdatedList().forEach(addToObjectFromProto(result));
@@ -558,6 +558,14 @@ public class JsonConverter { @@ -558,6 +558,14 @@ public class JsonConverter {
558 } 558 }
559 } 559 }
560 560
  561 + public static JsonElement parse(String json) {
  562 + return JSON_PARSER.parse(json);
  563 + }
  564 +
  565 + public static String toJson(JsonElement element) {
  566 + return GSON.toJson(element);
  567 + }
  568 +
561 public static void setTypeCastEnabled(boolean enabled) { 569 public static void setTypeCastEnabled(boolean enabled) {
562 isTypeCastEnabled = enabled; 570 isTypeCastEnabled = enabled;
563 } 571 }
@@ -599,8 +607,7 @@ public class JsonConverter { @@ -599,8 +607,7 @@ public class JsonConverter {
599 .build(); 607 .build();
600 } 608 }
601 609
602 - private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String  
603 - provisionKey, String provisionSecret) { 610 + private static TransportProtos.ProvisionDeviceCredentialsMsg buildProvisionDeviceCredentialsMsg(String provisionKey, String provisionSecret) {
604 return TransportProtos.ProvisionDeviceCredentialsMsg.newBuilder() 611 return TransportProtos.ProvisionDeviceCredentialsMsg.newBuilder()
605 .setProvisionDeviceKey(provisionKey) 612 .setProvisionDeviceKey(provisionKey)
606 .setProvisionDeviceSecret(provisionSecret) 613 .setProvisionDeviceSecret(provisionSecret)
@@ -112,8 +112,8 @@ public class DefaultTransportDeviceProfileCache implements TransportDeviceProfil @@ -112,8 +112,8 @@ public class DefaultTransportDeviceProfileCache implements TransportDeviceProfil
112 profile = profileOpt.get(); 112 profile = profileOpt.get();
113 this.put(profile); 113 this.put(profile);
114 } else { 114 } else {
115 - log.warn("[{}] Can't device profile: {}", id, entityProfileMsg.getData());  
116 - throw new RuntimeException("Can't device profile!"); 115 + log.warn("[{}] Can't find device profile: {}", id, entityProfileMsg.getData());
  116 + throw new RuntimeException("Can't find device profile!");
117 } 117 }
118 } finally { 118 } finally {
119 deviceProfileFetchLock.unlock(); 119 deviceProfileFetchLock.unlock();
@@ -23,6 +23,7 @@ import com.google.gson.JsonObject; @@ -23,6 +23,7 @@ import com.google.gson.JsonObject;
23 import com.google.protobuf.ByteString; 23 import com.google.protobuf.ByteString;
24 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
25 import org.springframework.beans.factory.annotation.Value; 25 import org.springframework.beans.factory.annotation.Value;
  26 +import org.springframework.context.ApplicationEventPublisher;
26 import org.springframework.stereotype.Service; 27 import org.springframework.stereotype.Service;
27 import org.thingsboard.common.util.ThingsBoardThreadFactory; 28 import org.thingsboard.common.util.ThingsBoardThreadFactory;
28 import org.thingsboard.server.common.data.ApiUsageRecordKey; 29 import org.thingsboard.server.common.data.ApiUsageRecordKey;
@@ -50,6 +51,7 @@ import org.thingsboard.server.common.msg.tools.TbRateLimitsException; @@ -50,6 +51,7 @@ import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
50 import org.thingsboard.server.common.stats.MessagesStats; 51 import org.thingsboard.server.common.stats.MessagesStats;
51 import org.thingsboard.server.common.stats.StatsFactory; 52 import org.thingsboard.server.common.stats.StatsFactory;
52 import org.thingsboard.server.common.stats.StatsType; 53 import org.thingsboard.server.common.stats.StatsType;
  54 +import org.thingsboard.server.common.transport.DeviceUpdatedEvent;
53 import org.thingsboard.server.common.transport.SessionMsgListener; 55 import org.thingsboard.server.common.transport.SessionMsgListener;
54 import org.thingsboard.server.common.transport.TransportDeviceProfileCache; 56 import org.thingsboard.server.common.transport.TransportDeviceProfileCache;
55 import org.thingsboard.server.common.transport.TransportResourceCache; 57 import org.thingsboard.server.common.transport.TransportResourceCache;
@@ -134,6 +136,7 @@ public class DefaultTransportService implements TransportService { @@ -134,6 +136,7 @@ public class DefaultTransportService implements TransportService {
134 private final TransportRateLimitService rateLimitService; 136 private final TransportRateLimitService rateLimitService;
135 private final DataDecodingEncodingService dataDecodingEncodingService; 137 private final DataDecodingEncodingService dataDecodingEncodingService;
136 private final SchedulerComponent scheduler; 138 private final SchedulerComponent scheduler;
  139 + private final ApplicationEventPublisher eventPublisher;
137 private final TransportResourceCache transportResourceCache; 140 private final TransportResourceCache transportResourceCache;
138 141
139 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate; 142 protected TbQueueRequestTemplate<TbProtoQueueMsg<TransportApiRequestMsg>, TbProtoQueueMsg<TransportApiResponseMsg>> transportApiRequestTemplate;
@@ -161,7 +164,8 @@ public class DefaultTransportService implements TransportService { @@ -161,7 +164,8 @@ public class DefaultTransportService implements TransportService {
161 TransportDeviceProfileCache deviceProfileCache, 164 TransportDeviceProfileCache deviceProfileCache,
162 TransportTenantProfileCache tenantProfileCache, 165 TransportTenantProfileCache tenantProfileCache,
163 TbApiUsageClient apiUsageClient, TransportRateLimitService rateLimitService, 166 TbApiUsageClient apiUsageClient, TransportRateLimitService rateLimitService,
164 - DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache) { 167 + DataDecodingEncodingService dataDecodingEncodingService, SchedulerComponent scheduler, TransportResourceCache transportResourceCache,
  168 + ApplicationEventPublisher eventPublisher) {
165 this.serviceInfoProvider = serviceInfoProvider; 169 this.serviceInfoProvider = serviceInfoProvider;
166 this.queueProvider = queueProvider; 170 this.queueProvider = queueProvider;
167 this.producerProvider = producerProvider; 171 this.producerProvider = producerProvider;
@@ -174,6 +178,7 @@ public class DefaultTransportService implements TransportService { @@ -174,6 +178,7 @@ public class DefaultTransportService implements TransportService {
174 this.dataDecodingEncodingService = dataDecodingEncodingService; 178 this.dataDecodingEncodingService = dataDecodingEncodingService;
175 this.scheduler = scheduler; 179 this.scheduler = scheduler;
176 this.transportResourceCache = transportResourceCache; 180 this.transportResourceCache = transportResourceCache;
  181 + this.eventPublisher = eventPublisher;
177 } 182 }
178 183
179 @PostConstruct 184 @PostConstruct
@@ -272,6 +277,58 @@ public class DefaultTransportService implements TransportService { @@ -272,6 +277,58 @@ public class DefaultTransportService implements TransportService {
272 } 277 }
273 278
274 @Override 279 @Override
  280 + public TransportProtos.GetSnmpDevicesResponseMsg getSnmpDevicesIds(TransportProtos.GetSnmpDevicesRequestMsg requestMsg) {
  281 + TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(
  282 + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder()
  283 + .setSnmpDevicesRequestMsg(requestMsg)
  284 + .build()
  285 + );
  286 +
  287 + try {
  288 + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get();
  289 + return response.getValue().getSnmpDevicesResponseMsg();
  290 + } catch (InterruptedException | ExecutionException e) {
  291 + throw new RuntimeException(e);
  292 + }
  293 + }
  294 +
  295 + @Override
  296 + public TransportProtos.GetDeviceResponseMsg getDevice(TransportProtos.GetDeviceRequestMsg requestMsg) {
  297 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(
  298 + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder()
  299 + .setDeviceRequestMsg(requestMsg)
  300 + .build()
  301 + );
  302 +
  303 + try {
  304 + TransportApiResponseMsg response = transportApiRequestTemplate.send(protoMsg).get().getValue();
  305 + if (response.hasDeviceResponseMsg()) {
  306 + return response.getDeviceResponseMsg();
  307 + } else {
  308 + return null;
  309 + }
  310 + } catch (InterruptedException | ExecutionException e) {
  311 + throw new RuntimeException(e);
  312 + }
  313 + }
  314 +
  315 + @Override
  316 + public TransportProtos.GetDeviceCredentialsResponseMsg getDeviceCredentials(TransportProtos.GetDeviceCredentialsRequestMsg requestMsg) {
  317 + TbProtoQueueMsg<TransportApiRequestMsg> protoMsg = new TbProtoQueueMsg<>(
  318 + UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder()
  319 + .setDeviceCredentialsRequestMsg(requestMsg)
  320 + .build()
  321 + );
  322 +
  323 + try {
  324 + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get();
  325 + return response.getValue().getDeviceCredentialsResponseMsg();
  326 + } catch (InterruptedException | ExecutionException e) {
  327 + throw new RuntimeException(e);
  328 + }
  329 + }
  330 +
  331 + @Override
275 public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg, 332 public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg,
276 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) { 333 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
277 log.trace("Processing msg: {}", msg); 334 log.trace("Processing msg: {}", msg);
@@ -704,7 +761,10 @@ public class DefaultTransportService implements TransportService { @@ -704,7 +761,10 @@ public class DefaultTransportService implements TransportService {
704 } 761 }
705 } else if (EntityType.DEVICE.equals(entityType)) { 762 } else if (EntityType.DEVICE.equals(entityType)) {
706 Optional<Device> deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray()); 763 Optional<Device> deviceOpt = dataDecodingEncodingService.decode(msg.getData().toByteArray());
707 - deviceOpt.ifPresent(this::onDeviceUpdate); 764 + deviceOpt.ifPresent(device -> {
  765 + onDeviceUpdate(device);
  766 + eventPublisher.publishEvent(new DeviceUpdatedEvent(device));
  767 + });
708 } 768 }
709 } else if (toSessionMsg.hasEntityDeleteMsg()) { 769 } else if (toSessionMsg.hasEntityDeleteMsg()) {
710 TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg(); 770 TransportProtos.EntityDeleteMsg msg = toSessionMsg.getEntityDeleteMsg();
@@ -718,6 +778,7 @@ public class DefaultTransportService implements TransportService { @@ -718,6 +778,7 @@ public class DefaultTransportService implements TransportService {
718 rateLimitService.remove(new TenantId(entityUuid)); 778 rateLimitService.remove(new TenantId(entityUuid));
719 } else if (EntityType.DEVICE.equals(entityType)) { 779 } else if (EntityType.DEVICE.equals(entityType)) {
720 rateLimitService.remove(new DeviceId(entityUuid)); 780 rateLimitService.remove(new DeviceId(entityUuid));
  781 + onDeviceDeleted(new DeviceId(entityUuid));
721 } 782 }
722 } else if (toSessionMsg.hasResourceUpdateMsg()) { 783 } else if (toSessionMsg.hasResourceUpdateMsg()) {
723 TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg(); 784 TransportProtos.ResourceUpdateMsg msg = toSessionMsg.getResourceUpdateMsg();
@@ -800,6 +861,17 @@ public class DefaultTransportService implements TransportService { @@ -800,6 +861,17 @@ public class DefaultTransportService implements TransportService {
800 }); 861 });
801 } 862 }
802 863
  864 + private void onDeviceDeleted(DeviceId deviceId) {
  865 + sessions.forEach((id, md) -> {
  866 + DeviceId sessionDeviceId = new DeviceId(new UUID(md.getSessionInfo().getDeviceIdMSB(), md.getSessionInfo().getDeviceIdLSB()));
  867 + if (sessionDeviceId.equals(deviceId)) {
  868 + transportCallbackExecutor.submit(() -> {
  869 + md.getListener().onDeviceDeleted(deviceId);
  870 + });
  871 + }
  872 + });
  873 + }
  874 +
803 protected UUID toSessionId(TransportProtos.SessionInfoProto sessionInfo) { 875 protected UUID toSessionId(TransportProtos.SessionInfoProto sessionInfo) {
804 return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB()); 876 return new UUID(sessionInfo.getSessionIdMSB(), sessionInfo.getSessionIdLSB());
805 } 877 }
@@ -18,11 +18,11 @@ package org.thingsboard.server.dao.device; @@ -18,11 +18,11 @@ package org.thingsboard.server.dao.device;
18 import com.google.common.util.concurrent.ListenableFuture; 18 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.DeviceTransportType;
21 import org.thingsboard.server.common.data.EntitySubtype; 22 import org.thingsboard.server.common.data.EntitySubtype;
22 import org.thingsboard.server.common.data.id.TenantId; 23 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.common.data.page.PageData; 24 import org.thingsboard.server.common.data.page.PageData;
24 import org.thingsboard.server.common.data.page.PageLink; 25 import org.thingsboard.server.common.data.page.PageLink;
25 -import org.thingsboard.server.common.data.page.TimePageLink;  
26 import org.thingsboard.server.dao.Dao; 26 import org.thingsboard.server.dao.Dao;
27 import org.thingsboard.server.dao.TenantEntityDao; 27 import org.thingsboard.server.dao.TenantEntityDao;
28 28
@@ -219,6 +219,7 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao { @@ -219,6 +219,7 @@ public interface DeviceDao extends Dao<Device>, TenantEntityDao {
219 */ 219 */
220 PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink); 220 PageData<Device> findDevicesByTenantIdAndProfileId(UUID tenantId, UUID profileId, PageLink pageLink);
221 221
  222 + PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink);
222 223
223 /** 224 /**
224 * Find devices by tenantId, edgeId and page link. 225 * Find devices by tenantId, edgeId and page link.
@@ -363,6 +363,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D @@ -363,6 +363,7 @@ public class DeviceProfileServiceImpl extends AbstractEntityService implements D
363 } 363 }
364 364
365 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration(); 365 DeviceProfileTransportConfiguration transportConfiguration = deviceProfile.getProfileData().getTransportConfiguration();
  366 + transportConfiguration.validate();
366 if (transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) { 367 if (transportConfiguration instanceof MqttDeviceProfileTransportConfiguration) {
367 MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration; 368 MqttDeviceProfileTransportConfiguration mqttTransportConfiguration = (MqttDeviceProfileTransportConfiguration) transportConfiguration;
368 if (mqttTransportConfiguration.getTransportPayloadTypeConfiguration() instanceof ProtoTransportPayloadConfiguration) { 369 if (mqttTransportConfiguration.getTransportPayloadTypeConfiguration() instanceof ProtoTransportPayloadConfiguration) {
@@ -36,20 +36,22 @@ import org.thingsboard.server.common.data.Customer; @@ -36,20 +36,22 @@ import org.thingsboard.server.common.data.Customer;
36 import org.thingsboard.server.common.data.Device; 36 import org.thingsboard.server.common.data.Device;
37 import org.thingsboard.server.common.data.DeviceInfo; 37 import org.thingsboard.server.common.data.DeviceInfo;
38 import org.thingsboard.server.common.data.DeviceProfile; 38 import org.thingsboard.server.common.data.DeviceProfile;
  39 +import org.thingsboard.server.common.data.DeviceTransportType;
39 import org.thingsboard.server.common.data.EntitySubtype; 40 import org.thingsboard.server.common.data.EntitySubtype;
40 import org.thingsboard.server.common.data.EntityType; 41 import org.thingsboard.server.common.data.EntityType;
41 import org.thingsboard.server.common.data.EntityView; 42 import org.thingsboard.server.common.data.EntityView;
42 import org.thingsboard.server.common.data.Firmware; 43 import org.thingsboard.server.common.data.Firmware;
43 import org.thingsboard.server.common.data.Tenant; 44 import org.thingsboard.server.common.data.Tenant;
44 -import org.thingsboard.server.common.data.asset.Asset;  
45 import org.thingsboard.server.common.data.device.DeviceSearchQuery; 45 import org.thingsboard.server.common.data.device.DeviceSearchQuery;
46 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials; 46 import org.thingsboard.server.common.data.device.credentials.BasicMqttCredentials;
47 import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration; 47 import org.thingsboard.server.common.data.device.data.CoapDeviceTransportConfiguration;
48 import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; 48 import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration;
49 import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration; 49 import org.thingsboard.server.common.data.device.data.DefaultDeviceTransportConfiguration;
50 import org.thingsboard.server.common.data.device.data.DeviceData; 50 import org.thingsboard.server.common.data.device.data.DeviceData;
  51 +import org.thingsboard.server.common.data.device.data.DeviceTransportConfiguration;
51 import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration; 52 import org.thingsboard.server.common.data.device.data.Lwm2mDeviceTransportConfiguration;
52 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; 53 import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration;
  54 +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration;
53 import org.thingsboard.server.common.data.edge.Edge; 55 import org.thingsboard.server.common.data.edge.Edge;
54 import org.thingsboard.server.common.data.id.CustomerId; 56 import org.thingsboard.server.common.data.id.CustomerId;
55 import org.thingsboard.server.common.data.id.DeviceId; 57 import org.thingsboard.server.common.data.id.DeviceId;
@@ -59,7 +61,6 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -59,7 +61,6 @@ import org.thingsboard.server.common.data.id.EntityId;
59 import org.thingsboard.server.common.data.id.TenantId; 61 import org.thingsboard.server.common.data.id.TenantId;
60 import org.thingsboard.server.common.data.page.PageData; 62 import org.thingsboard.server.common.data.page.PageData;
61 import org.thingsboard.server.common.data.page.PageLink; 63 import org.thingsboard.server.common.data.page.PageLink;
62 -import org.thingsboard.server.common.data.page.TimePageLink;  
63 import org.thingsboard.server.common.data.relation.EntityRelation; 64 import org.thingsboard.server.common.data.relation.EntityRelation;
64 import org.thingsboard.server.common.data.relation.EntitySearchDirection; 65 import org.thingsboard.server.common.data.relation.EntitySearchDirection;
65 import org.thingsboard.server.common.data.relation.RelationTypeGroup; 66 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
@@ -86,6 +87,7 @@ import java.util.Collections; @@ -86,6 +87,7 @@ import java.util.Collections;
86 import java.util.Comparator; 87 import java.util.Comparator;
87 import java.util.List; 88 import java.util.List;
88 import java.util.Optional; 89 import java.util.Optional;
  90 +import java.util.UUID;
89 import java.util.concurrent.ExecutionException; 91 import java.util.concurrent.ExecutionException;
90 import java.util.stream.Collectors; 92 import java.util.stream.Collectors;
91 93
@@ -269,11 +271,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -269,11 +271,14 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
269 case MQTT: 271 case MQTT:
270 deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration()); 272 deviceData.setTransportConfiguration(new MqttDeviceTransportConfiguration());
271 break; 273 break;
  274 + case COAP:
  275 + deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration());
  276 + break;
272 case LWM2M: 277 case LWM2M:
273 deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration()); 278 deviceData.setTransportConfiguration(new Lwm2mDeviceTransportConfiguration());
274 break; 279 break;
275 - case COAP:  
276 - deviceData.setTransportConfiguration(new CoapDeviceTransportConfiguration()); 280 + case SNMP:
  281 + deviceData.setTransportConfiguration(new SnmpDeviceTransportConfiguration());
277 break; 282 break;
278 } 283 }
279 } 284 }
@@ -573,6 +578,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -573,6 +578,11 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
573 } 578 }
574 579
575 @Override 580 @Override
  581 + public PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink) {
  582 + return deviceDao.findDevicesIdsByDeviceProfileTransportType(transportType, pageLink);
  583 + }
  584 +
  585 + @Override
576 public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) { 586 public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId) {
577 Device device = findDeviceById(tenantId, deviceId); 587 Device device = findDeviceById(tenantId, deviceId);
578 Edge edge = edgeService.findEdgeById(tenantId, edgeId); 588 Edge edge = edgeService.findEdgeById(tenantId, edgeId);
@@ -677,6 +687,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe @@ -677,6 +687,9 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe
677 throw new DataValidationException("Can't assign device to customer from different tenant!"); 687 throw new DataValidationException("Can't assign device to customer from different tenant!");
678 } 688 }
679 } 689 }
  690 + Optional.ofNullable(device.getDeviceData())
  691 + .flatMap(deviceData -> Optional.ofNullable(deviceData.getTransportConfiguration()))
  692 + .ifPresent(DeviceTransportConfiguration::validate);
680 693
681 if (device.getFirmwareId() != null) { 694 if (device.getFirmwareId() != null) {
682 Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId()); 695 Firmware firmware = firmwareService.findFirmwareById(tenantId, device.getFirmwareId());
@@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable; @@ -20,6 +20,7 @@ import org.springframework.data.domain.Pageable;
20 import org.springframework.data.jpa.repository.Query; 20 import org.springframework.data.jpa.repository.Query;
21 import org.springframework.data.repository.PagingAndSortingRepository; 21 import org.springframework.data.repository.PagingAndSortingRepository;
22 import org.springframework.data.repository.query.Param; 22 import org.springframework.data.repository.query.Param;
  23 +import org.thingsboard.server.common.data.DeviceTransportType;
23 import org.thingsboard.server.dao.model.sql.DeviceEntity; 24 import org.thingsboard.server.dao.model.sql.DeviceEntity;
24 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity; 25 import org.thingsboard.server.dao.model.sql.DeviceInfoEntity;
25 26
@@ -210,4 +211,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit @@ -210,4 +211,9 @@ public interface DeviceRepository extends PagingAndSortingRepository<DeviceEntit
210 * */ 211 * */
211 @Query("SELECT count(*) FROM DeviceEntity d WHERE d.tenantId = :tenantId") 212 @Query("SELECT count(*) FROM DeviceEntity d WHERE d.tenantId = :tenantId")
212 Long countByTenantId(@Param("tenantId") UUID tenantId); 213 Long countByTenantId(@Param("tenantId") UUID tenantId);
  214 +
  215 + @Query("SELECT d.id FROM DeviceEntity d " +
  216 + "INNER JOIN DeviceProfileEntity p ON d.deviceProfileId = p.id " +
  217 + "WHERE p.transportType = :transportType")
  218 + Page<UUID> findIdsByDeviceProfileTransportType(@Param("transportType") DeviceTransportType transportType, Pageable pageable);
213 } 219 }
@@ -23,12 +23,12 @@ import org.springframework.stereotype.Component; @@ -23,12 +23,12 @@ import org.springframework.stereotype.Component;
23 import org.springframework.util.StringUtils; 23 import org.springframework.util.StringUtils;
24 import org.thingsboard.server.common.data.Device; 24 import org.thingsboard.server.common.data.Device;
25 import org.thingsboard.server.common.data.DeviceInfo; 25 import org.thingsboard.server.common.data.DeviceInfo;
  26 +import org.thingsboard.server.common.data.DeviceTransportType;
26 import org.thingsboard.server.common.data.EntitySubtype; 27 import org.thingsboard.server.common.data.EntitySubtype;
27 import org.thingsboard.server.common.data.EntityType; 28 import org.thingsboard.server.common.data.EntityType;
28 import org.thingsboard.server.common.data.id.TenantId; 29 import org.thingsboard.server.common.data.id.TenantId;
29 import org.thingsboard.server.common.data.page.PageData; 30 import org.thingsboard.server.common.data.page.PageData;
30 import org.thingsboard.server.common.data.page.PageLink; 31 import org.thingsboard.server.common.data.page.PageLink;
31 -import org.thingsboard.server.common.data.page.TimePageLink;  
32 import org.thingsboard.server.dao.DaoUtil; 32 import org.thingsboard.server.dao.DaoUtil;
33 import org.thingsboard.server.dao.device.DeviceDao; 33 import org.thingsboard.server.dao.device.DeviceDao;
34 import org.thingsboard.server.dao.model.sql.DeviceEntity; 34 import org.thingsboard.server.dao.model.sql.DeviceEntity;
@@ -118,6 +118,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> @@ -118,6 +118,11 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
118 } 118 }
119 119
120 @Override 120 @Override
  121 + public PageData<UUID> findDevicesIdsByDeviceProfileTransportType(DeviceTransportType transportType, PageLink pageLink) {
  122 + return DaoUtil.pageToPageData(deviceRepository.findIdsByDeviceProfileTransportType(transportType, DaoUtil.toPageable(pageLink)));
  123 + }
  124 +
  125 + @Override
121 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) { 126 public PageData<DeviceInfo> findDeviceInfosByTenantIdAndCustomerId(UUID tenantId, UUID customerId, PageLink pageLink) {
122 return DaoUtil.toPageData( 127 return DaoUtil.toPageData(
123 deviceRepository.findDeviceInfosByTenantIdAndCustomerId( 128 deviceRepository.findDeviceInfosByTenantIdAndCustomerId(
@@ -9,6 +9,7 @@ MQTT_TRANSPORT_DOCKER_NAME=tb-mqtt-transport @@ -9,6 +9,7 @@ MQTT_TRANSPORT_DOCKER_NAME=tb-mqtt-transport
9 HTTP_TRANSPORT_DOCKER_NAME=tb-http-transport 9 HTTP_TRANSPORT_DOCKER_NAME=tb-http-transport
10 COAP_TRANSPORT_DOCKER_NAME=tb-coap-transport 10 COAP_TRANSPORT_DOCKER_NAME=tb-coap-transport
11 LWM2M_TRANSPORT_DOCKER_NAME=tb-lwm2m-transport 11 LWM2M_TRANSPORT_DOCKER_NAME=tb-lwm2m-transport
  12 +SNMP_TRANSPORT_DOCKER_NAME=tb-snmp-transport
12 13
13 TB_VERSION=latest 14 TB_VERSION=latest
14 15
@@ -74,3 +74,8 @@ services: @@ -74,3 +74,8 @@ services:
74 - queue-aws-sqs.env 74 - queue-aws-sqs.env
75 depends_on: 75 depends_on:
76 - zookeeper 76 - zookeeper
  77 + tb-snmp-transport:
  78 + env_file:
  79 + - queue-aws-sqs.env
  80 + depends_on:
  81 + - zookeeper
@@ -58,3 +58,6 @@ services: @@ -58,3 +58,6 @@ services:
58 tb-lwm2m-transport: 58 tb-lwm2m-transport:
59 env_file: 59 env_file:
60 - queue-confluent.env 60 - queue-confluent.env
  61 + tb-snmp-transport:
  62 + env_file:
  63 + - queue-confluent.env
@@ -85,3 +85,8 @@ services: @@ -85,3 +85,8 @@ services:
85 - queue-kafka.env 85 - queue-kafka.env
86 depends_on: 86 depends_on:
87 - kafka 87 - kafka
  88 + tb-snmp-transport:
  89 + env_file:
  90 + - queue-kafka.env
  91 + depends_on:
  92 + - kafka
@@ -50,6 +50,9 @@ services: @@ -50,6 +50,9 @@ services:
50 tb-mqtt-transport2: 50 tb-mqtt-transport2:
51 volumes: 51 volumes:
52 - tb-mqtt-transport-log-volume:/var/log/tb-mqtt-transport 52 - tb-mqtt-transport-log-volume:/var/log/tb-mqtt-transport
  53 + tb-snmp-transport:
  54 + volumes:
  55 + - tb-snmp-transport-log-volume:/var/log/tb-snmp-transport
53 56
54 volumes: 57 volumes:
55 postgres-db-volume: 58 postgres-db-volume:
@@ -70,3 +73,6 @@ volumes: @@ -70,3 +73,6 @@ volumes:
70 tb-mqtt-transport-log-volume: 73 tb-mqtt-transport-log-volume:
71 external: true 74 external: true
72 name: ${TB_MQTT_TRANSPORT_LOG_VOLUME} 75 name: ${TB_MQTT_TRANSPORT_LOG_VOLUME}
  76 + tb-snmp-transport-log-volume:
  77 + external: true
  78 + name: ${TB_SNMP_TRANSPORT_LOG_VOLUME}
@@ -74,3 +74,8 @@ services: @@ -74,3 +74,8 @@ services:
74 - queue-pubsub.env 74 - queue-pubsub.env
75 depends_on: 75 depends_on:
76 - zookeeper 76 - zookeeper
  77 + tb-snmp-transport:
  78 + env_file:
  79 + - queue-pubsub.env
  80 + depends_on:
  81 + - zookeeper
@@ -74,3 +74,8 @@ services: @@ -74,3 +74,8 @@ services:
74 - queue-rabbitmq.env 74 - queue-rabbitmq.env
75 depends_on: 75 depends_on:
76 - zookeeper 76 - zookeeper
  77 + tb-snmp-transport:
  78 + env_file:
  79 + - queue-rabbitmq.env
  80 + depends_on:
  81 + - zookeeper
@@ -72,3 +72,8 @@ services: @@ -72,3 +72,8 @@ services:
72 - queue-service-bus.env 72 - queue-service-bus.env
73 depends_on: 73 depends_on:
74 - zookeeper 74 - zookeeper
  75 + tb-snmp-transport:
  76 + env_file:
  77 + - queue-service-bus.env
  78 + depends_on:
  79 + - zookeeper
@@ -217,6 +217,18 @@ services: @@ -217,6 +217,18 @@ services:
217 - ./tb-transports/lwm2m/log:/var/log/tb-lwm2m-transport 217 - ./tb-transports/lwm2m/log:/var/log/tb-lwm2m-transport
218 depends_on: 218 depends_on:
219 - zookeeper 219 - zookeeper
  220 + tb-snmp-transport:
  221 + restart: always
  222 + image: "${DOCKER_REPO}/${SNMP_TRANSPORT_DOCKER_NAME}:${TB_VERSION}"
  223 + environment:
  224 + TB_SERVICE_ID: tb-snmp-transport
  225 + env_file:
  226 + - tb-snmp-transport.env
  227 + volumes:
  228 + - ./tb-transports/snmp/conf:/config
  229 + - ./tb-transports/snmp/log:/var/log/tb-snmp-transport
  230 + depends_on:
  231 + - zookeeper
220 tb-web-ui1: 232 tb-web-ui1:
221 restart: always 233 restart: always
222 image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}" 234 image: "${DOCKER_REPO}/${WEB_UI_DOCKER_NAME}:${TB_VERSION}"
@@ -24,3 +24,5 @@ mkdir -p tb-transports/lwm2m/log && sudo chown -R 799:799 tb-transports/lwm2m/lo @@ -24,3 +24,5 @@ mkdir -p tb-transports/lwm2m/log && sudo chown -R 799:799 tb-transports/lwm2m/lo
24 mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log 24 mkdir -p tb-transports/http/log && sudo chown -R 799:799 tb-transports/http/log
25 25
26 mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log 26 mkdir -p tb-transports/mqtt/log && sudo chown -R 799:799 tb-transports/mqtt/log
  27 +
  28 +mkdir -p tb-transports/snmp/log && sudo chown -R 799:799 tb-transports/snmp/log
  1 +ZOOKEEPER_ENABLED=true
  2 +ZOOKEEPER_URL=zookeeper:2181
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2021 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<!DOCTYPE configuration>
  20 +<configuration scan="true" scanPeriod="10 seconds">
  21 +
  22 + <appender name="fileLogAppender"
  23 + class="ch.qos.logback.core.rolling.RollingFileAppender">
  24 + <file>/var/log/tb-snmp-transport/${TB_SERVICE_ID}/tb-snmp-transport.log</file>
  25 + <rollingPolicy
  26 + class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  27 + <fileNamePattern>/var/log/tb-snmp-transport/${TB_SERVICE_ID}/tb-snmp-transport.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  28 + <maxFileSize>100MB</maxFileSize>
  29 + <maxHistory>30</maxHistory>
  30 + <totalSizeCap>3GB</totalSizeCap>
  31 + </rollingPolicy>
  32 + <encoder>
  33 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  34 + </encoder>
  35 + </appender>
  36 +
  37 + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  38 + <encoder>
  39 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  40 + </encoder>
  41 + </appender>
  42 +
  43 + <logger name="org.thingsboard.server" level="INFO" />
  44 +
  45 + <root level="INFO">
  46 + <appender-ref ref="fileLogAppender"/>
  47 + <appender-ref ref="STDOUT"/>
  48 + </root>
  49 +
  50 +</configuration>
  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 +
  17 +export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=/var/log/tb-snmp-transport/${TB_SERVICE_ID}-gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
  18 +export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/tb-snmp-transport/${TB_SERVICE_ID}-heapdump.bin"
  19 +export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
  20 +export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
  21 +export JAVA_OPTS="$JAVA_OPTS -XX:+ExitOnOutOfMemoryError"
  22 +export LOG_FILENAME=tb-snmp-transport.out
  23 +export LOADER_PATH=/usr/share/tb-snmp-transport/conf
@@ -32,6 +32,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -32,6 +32,7 @@ public class ThingsBoardDbInstaller extends ExternalResource {
32 private final static String TB_LWM2M_TRANSPORT_LOG_VOLUME = "tb-lwm2m-transport-log-test-volume"; 32 private final static String TB_LWM2M_TRANSPORT_LOG_VOLUME = "tb-lwm2m-transport-log-test-volume";
33 private final static String TB_HTTP_TRANSPORT_LOG_VOLUME = "tb-http-transport-log-test-volume"; 33 private final static String TB_HTTP_TRANSPORT_LOG_VOLUME = "tb-http-transport-log-test-volume";
34 private final static String TB_MQTT_TRANSPORT_LOG_VOLUME = "tb-mqtt-transport-log-test-volume"; 34 private final static String TB_MQTT_TRANSPORT_LOG_VOLUME = "tb-mqtt-transport-log-test-volume";
  35 + private final static String TB_SNMP_TRANSPORT_LOG_VOLUME = "tb-snmp-transport-log-test-volume";
35 36
36 private final DockerComposeExecutor dockerCompose; 37 private final DockerComposeExecutor dockerCompose;
37 38
@@ -41,6 +42,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -41,6 +42,7 @@ public class ThingsBoardDbInstaller extends ExternalResource {
41 private final String tbLwm2mTransportLogVolume; 42 private final String tbLwm2mTransportLogVolume;
42 private final String tbHttpTransportLogVolume; 43 private final String tbHttpTransportLogVolume;
43 private final String tbMqttTransportLogVolume; 44 private final String tbMqttTransportLogVolume;
  45 + private final String tbSnmpTransportLogVolume;
44 private final Map<String, String> env; 46 private final Map<String, String> env;
45 47
46 public ThingsBoardDbInstaller() { 48 public ThingsBoardDbInstaller() {
@@ -57,6 +59,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -57,6 +59,7 @@ public class ThingsBoardDbInstaller extends ExternalResource {
57 tbLwm2mTransportLogVolume = project + "_" + TB_LWM2M_TRANSPORT_LOG_VOLUME; 59 tbLwm2mTransportLogVolume = project + "_" + TB_LWM2M_TRANSPORT_LOG_VOLUME;
58 tbHttpTransportLogVolume = project + "_" + TB_HTTP_TRANSPORT_LOG_VOLUME; 60 tbHttpTransportLogVolume = project + "_" + TB_HTTP_TRANSPORT_LOG_VOLUME;
59 tbMqttTransportLogVolume = project + "_" + TB_MQTT_TRANSPORT_LOG_VOLUME; 61 tbMqttTransportLogVolume = project + "_" + TB_MQTT_TRANSPORT_LOG_VOLUME;
  62 + tbSnmpTransportLogVolume = project + "_" + TB_SNMP_TRANSPORT_LOG_VOLUME;
60 63
61 dockerCompose = new DockerComposeExecutor(composeFiles, project); 64 dockerCompose = new DockerComposeExecutor(composeFiles, project);
62 65
@@ -67,6 +70,7 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -67,6 +70,7 @@ public class ThingsBoardDbInstaller extends ExternalResource {
67 env.put("TB_LWM2M_TRANSPORT_LOG_VOLUME", tbLwm2mTransportLogVolume); 70 env.put("TB_LWM2M_TRANSPORT_LOG_VOLUME", tbLwm2mTransportLogVolume);
68 env.put("TB_HTTP_TRANSPORT_LOG_VOLUME", tbHttpTransportLogVolume); 71 env.put("TB_HTTP_TRANSPORT_LOG_VOLUME", tbHttpTransportLogVolume);
69 env.put("TB_MQTT_TRANSPORT_LOG_VOLUME", tbMqttTransportLogVolume); 72 env.put("TB_MQTT_TRANSPORT_LOG_VOLUME", tbMqttTransportLogVolume);
  73 + env.put("TB_SNMP_TRANSPORT_LOG_VOLUME", tbSnmpTransportLogVolume);
70 dockerCompose.withEnv(env); 74 dockerCompose.withEnv(env);
71 } 75 }
72 76
@@ -96,6 +100,9 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -96,6 +100,9 @@ public class ThingsBoardDbInstaller extends ExternalResource {
96 dockerCompose.withCommand("volume create " + tbMqttTransportLogVolume); 100 dockerCompose.withCommand("volume create " + tbMqttTransportLogVolume);
97 dockerCompose.invokeDocker(); 101 dockerCompose.invokeDocker();
98 102
  103 + dockerCompose.withCommand("volume create " + tbSnmpTransportLogVolume);
  104 + dockerCompose.invokeDocker();
  105 +
99 dockerCompose.withCommand("up -d redis postgres"); 106 dockerCompose.withCommand("up -d redis postgres");
100 dockerCompose.invokeCompose(); 107 dockerCompose.invokeCompose();
101 108
@@ -117,9 +124,11 @@ public class ThingsBoardDbInstaller extends ExternalResource { @@ -117,9 +124,11 @@ public class ThingsBoardDbInstaller extends ExternalResource {
117 copyLogs(tbLwm2mTransportLogVolume, "./target/tb-lwm2m-transport-logs/"); 124 copyLogs(tbLwm2mTransportLogVolume, "./target/tb-lwm2m-transport-logs/");
118 copyLogs(tbHttpTransportLogVolume, "./target/tb-http-transport-logs/"); 125 copyLogs(tbHttpTransportLogVolume, "./target/tb-http-transport-logs/");
119 copyLogs(tbMqttTransportLogVolume, "./target/tb-mqtt-transport-logs/"); 126 copyLogs(tbMqttTransportLogVolume, "./target/tb-mqtt-transport-logs/");
  127 + copyLogs(tbSnmpTransportLogVolume, "./target/tb-snmp-transport-logs/");
120 128
121 dockerCompose.withCommand("volume rm -f " + postgresDataVolume + " " + tbLogVolume + 129 dockerCompose.withCommand("volume rm -f " + postgresDataVolume + " " + tbLogVolume +
122 - " " + tbCoapTransportLogVolume + " " + tbLwm2mTransportLogVolume + " " + tbHttpTransportLogVolume + " " + tbMqttTransportLogVolume); 130 + " " + tbCoapTransportLogVolume + " " + tbLwm2mTransportLogVolume + " " + tbHttpTransportLogVolume +
  131 + " " + tbMqttTransportLogVolume + " " + tbSnmpTransportLogVolume);
123 dockerCompose.invokeDocker(); 132 dockerCompose.invokeDocker();
124 } 133 }
125 134
@@ -39,5 +39,6 @@ @@ -39,5 +39,6 @@
39 <module>http</module> 39 <module>http</module>
40 <module>coap</module> 40 <module>coap</module>
41 <module>lwm2m</module> 41 <module>lwm2m</module>
  42 + <module>snmp</module>
42 </modules> 43 </modules>
43 </project> 44 </project>
  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 +
  17 +FROM thingsboard/openjdk11
  18 +
  19 +COPY start-tb-snmp-transport.sh ${pkg.name}.deb /tmp/
  20 +
  21 +RUN chmod a+x /tmp/*.sh \
  22 + && mv /tmp/start-tb-snmp-transport.sh /usr/bin
  23 +
  24 +RUN yes | dpkg -i /tmp/${pkg.name}.deb
  25 +RUN rm /tmp/${pkg.name}.deb
  26 +
  27 +RUN systemctl --no-reload disable --now ${pkg.name}.service > /dev/null 2>&1 || :
  28 +
  29 +RUN chmod 555 ${pkg.installFolder}/bin/${pkg.name}.jar
  30 +
  31 +USER ${pkg.user}
  32 +
  33 +CMD ["start-tb-snmp-transport.sh"]
  1 +#!/bin/bash
  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 +CONF_FOLDER="/config"
  19 +jarfile=${pkg.installFolder}/bin/${pkg.name}.jar
  20 +configfile=${pkg.name}.conf
  21 +
  22 +source "${CONF_FOLDER}/${configfile}"
  23 +
  24 +export LOADER_PATH=/config,${LOADER_PATH}
  25 +
  26 +echo "Starting '${project.name}' ..."
  27 +
  28 +cd ${pkg.installFolder}/bin
  29 +
  30 +exec java -cp ${jarfile} $JAVA_OPTS -Dloader.main=org.thingsboard.server.snmp.ThingsboardSnmpTransportApplication \
  31 + -Dspring.jpa.hibernate.ddl-auto=none \
  32 + -Dlogging.config=/config/logback.xml \
  33 + org.springframework.boot.loader.PropertiesLauncher
  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 + <parent>
  22 + <groupId>org.thingsboard.msa</groupId>
  23 + <artifactId>transport</artifactId>
  24 + <version>3.3.0-SNAPSHOT</version>
  25 + </parent>
  26 +
  27 + <groupId>org.thingsboard.msa.transport</groupId>
  28 + <artifactId>snmp</artifactId>
  29 + <packaging>pom</packaging>
  30 +
  31 + <name>ThingsBoard SNMP Transport Microservice</name>
  32 + <url>https://thingsboard.io</url>
  33 + <description>ThingsBoard SNMP Transport Microservice</description>
  34 +
  35 + <properties>
  36 + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  37 + <main.dir>${basedir}/../../..</main.dir>
  38 + <pkg.name>tb-snmp-transport</pkg.name>
  39 + <docker.name>tb-snmp-transport</docker.name>
  40 + <pkg.logFolder>/var/log/${pkg.name}</pkg.logFolder>
  41 + <pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder>
  42 + </properties>
  43 +
  44 + <dependencies>
  45 + <dependency>
  46 + <groupId>org.thingsboard.transport</groupId>
  47 + <artifactId>snmp</artifactId>
  48 + <version>${project.version}</version>
  49 + <classifier>deb</classifier>
  50 + <type>deb</type>
  51 + <scope>provided</scope>
  52 + </dependency>
  53 + </dependencies>
  54 +
  55 + <build>
  56 + <plugins>
  57 + <plugin>
  58 + <groupId>org.apache.maven.plugins</groupId>
  59 + <artifactId>maven-dependency-plugin</artifactId>
  60 + <executions>
  61 + <execution>
  62 + <id>copy-tb-snmp-transport-deb</id>
  63 + <phase>package</phase>
  64 + <goals>
  65 + <goal>copy</goal>
  66 + </goals>
  67 + <configuration>
  68 + <artifactItems>
  69 + <artifactItem>
  70 + <groupId>org.thingsboard.transport</groupId>
  71 + <artifactId>snmp</artifactId>
  72 + <classifier>deb</classifier>
  73 + <type>deb</type>
  74 + <destFileName>${pkg.name}.deb</destFileName>
  75 + <outputDirectory>${project.build.directory}</outputDirectory>
  76 + </artifactItem>
  77 + </artifactItems>
  78 + </configuration>
  79 + </execution>
  80 + </executions>
  81 + </plugin>
  82 + <plugin>
  83 + <groupId>org.apache.maven.plugins</groupId>
  84 + <artifactId>maven-resources-plugin</artifactId>
  85 + <executions>
  86 + <execution>
  87 + <id>copy-docker-config</id>
  88 + <phase>process-resources</phase>
  89 + <goals>
  90 + <goal>copy-resources</goal>
  91 + </goals>
  92 + <configuration>
  93 + <outputDirectory>${project.build.directory}</outputDirectory>
  94 + <resources>
  95 + <resource>
  96 + <directory>docker</directory>
  97 + <filtering>true</filtering>
  98 + </resource>
  99 + </resources>
  100 + </configuration>
  101 + </execution>
  102 + </executions>
  103 + </plugin>
  104 + <plugin>
  105 + <groupId>com.spotify</groupId>
  106 + <artifactId>dockerfile-maven-plugin</artifactId>
  107 + <executions>
  108 + <execution>
  109 + <id>build-docker-image</id>
  110 + <phase>pre-integration-test</phase>
  111 + <goals>
  112 + <goal>build</goal>
  113 + </goals>
  114 + <configuration>
  115 + <skip>${dockerfile.skip}</skip>
  116 + <repository>${docker.repo}/${docker.name}</repository>
  117 + <verbose>true</verbose>
  118 + <googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
  119 + <contextDirectory>${project.build.directory}</contextDirectory>
  120 + </configuration>
  121 + </execution>
  122 + <execution>
  123 + <id>tag-docker-image</id>
  124 + <phase>pre-integration-test</phase>
  125 + <goals>
  126 + <goal>tag</goal>
  127 + </goals>
  128 + <configuration>
  129 + <skip>${dockerfile.skip}</skip>
  130 + <repository>${docker.repo}/${docker.name}</repository>
  131 + <tag>${project.version}</tag>
  132 + </configuration>
  133 + </execution>
  134 + </executions>
  135 + </plugin>
  136 + </plugins>
  137 + </build>
  138 + <profiles>
  139 + <profile>
  140 + <id>push-docker-image</id>
  141 + <activation>
  142 + <property>
  143 + <name>push-docker-image</name>
  144 + </property>
  145 + </activation>
  146 + <build>
  147 + <plugins>
  148 + <plugin>
  149 + <groupId>com.spotify</groupId>
  150 + <artifactId>dockerfile-maven-plugin</artifactId>
  151 + <executions>
  152 + <execution>
  153 + <id>push-latest-docker-image</id>
  154 + <phase>pre-integration-test</phase>
  155 + <goals>
  156 + <goal>push</goal>
  157 + </goals>
  158 + <configuration>
  159 + <tag>latest</tag>
  160 + <repository>${docker.repo}/${docker.name}</repository>
  161 + </configuration>
  162 + </execution>
  163 + <execution>
  164 + <id>push-version-docker-image</id>
  165 + <phase>pre-integration-test</phase>
  166 + <goals>
  167 + <goal>push</goal>
  168 + </goals>
  169 + <configuration>
  170 + <tag>${project.version}</tag>
  171 + <repository>${docker.repo}/${docker.name}</repository>
  172 + </configuration>
  173 + </execution>
  174 + </executions>
  175 + </plugin>
  176 + </plugins>
  177 + </build>
  178 + </profile>
  179 + </profiles>
  180 + <repositories>
  181 + <repository>
  182 + <id>jenkins</id>
  183 + <name>Jenkins Repository</name>
  184 + <url>https://repo.jenkins-ci.org/releases</url>
  185 + <snapshots>
  186 + <enabled>false</enabled>
  187 + </snapshots>
  188 + </repository>
  189 + </repositories>
  190 +</project>
@@ -121,6 +121,7 @@ @@ -121,6 +121,7 @@
121 <javax.el.version>3.0.0</javax.el.version> 121 <javax.el.version>3.0.0</javax.el.version>
122 <javax.validation-api.version>2.0.1.Final</javax.validation-api.version> 122 <javax.validation-api.version>2.0.1.Final</javax.validation-api.version>
123 <antisamy.version>1.6.2</antisamy.version> 123 <antisamy.version>1.6.2</antisamy.version>
  124 + <snmp4j.version>2.8.5</snmp4j.version>
124 </properties> 125 </properties>
125 126
126 <modules> 127 <modules>
@@ -915,6 +916,11 @@ @@ -915,6 +916,11 @@
915 </dependency> 916 </dependency>
916 <dependency> 917 <dependency>
917 <groupId>org.thingsboard.common.transport</groupId> 918 <groupId>org.thingsboard.common.transport</groupId>
  919 + <artifactId>snmp</artifactId>
  920 + <version>${project.version}</version>
  921 + </dependency>
  922 + <dependency>
  923 + <groupId>org.thingsboard.common.transport</groupId>
918 <artifactId>lwm2m</artifactId> 924 <artifactId>lwm2m</artifactId>
919 <version>${project.version}</version> 925 <version>${project.version}</version>
920 </dependency> 926 </dependency>
@@ -1598,6 +1604,11 @@ @@ -1598,6 +1604,11 @@
1598 </exclusion> 1604 </exclusion>
1599 </exclusions> 1605 </exclusions>
1600 </dependency> 1606 </dependency>
  1607 + <dependency>
  1608 + <groupId>org.snmp4j</groupId>
  1609 + <artifactId>snmp4j</artifactId>
  1610 + <version>${snmp4j.version}</version>
  1611 + </dependency>
1601 </dependencies> 1612 </dependencies>
1602 </dependencyManagement> 1613 </dependencyManagement>
1603 1614
@@ -38,6 +38,7 @@ @@ -38,6 +38,7 @@
38 <module>mqtt</module> 38 <module>mqtt</module>
39 <module>coap</module> 39 <module>coap</module>
40 <module>lwm2m</module> 40 <module>lwm2m</module>
  41 + <module>snmp</module>
41 </modules> 42 </modules>
42 43
43 </project> 44 </project>
  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</groupId>
  24 + <version>3.3.0-SNAPSHOT</version>
  25 + <artifactId>transport</artifactId>
  26 + </parent>
  27 +
  28 + <groupId>org.thingsboard.transport</groupId>
  29 + <artifactId>snmp</artifactId>
  30 + <packaging>jar</packaging>
  31 +
  32 + <name>Thingsboard SNMP Transport Service</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 + <pkg.type>java</pkg.type>
  39 + <pkg.disabled>false</pkg.disabled>
  40 + <pkg.process-resources.phase>process-resources</pkg.process-resources.phase>
  41 + <pkg.package.phase>package</pkg.package.phase>
  42 + <pkg.name>tb-snmp-transport</pkg.name>
  43 + <pkg.copyInstallScripts>false</pkg.copyInstallScripts>
  44 + <pkg.win.dist>${project.build.directory}/windows</pkg.win.dist>
  45 + <pkg.implementationTitle>ThingsBoard SNMP Transport Service</pkg.implementationTitle>
  46 + <pkg.mainClass>org.thingsboard.server.snmp.ThingsboardSnmpTransportApplication</pkg.mainClass>
  47 + </properties>
  48 +
  49 + <dependencies>
  50 + <dependency>
  51 + <groupId>org.thingsboard.common.transport</groupId>
  52 + <artifactId>snmp</artifactId>
  53 + </dependency>
  54 + <dependency>
  55 + <groupId>org.thingsboard.common</groupId>
  56 + <artifactId>queue</artifactId>
  57 + </dependency>
  58 + <dependency>
  59 + <groupId>org.springframework.boot</groupId>
  60 + <artifactId>spring-boot-starter-web</artifactId>
  61 + </dependency>
  62 + </dependencies>
  63 +
  64 + <build>
  65 + <finalName>${pkg.name}-${project.version}</finalName>
  66 + <resources>
  67 + <resource>
  68 + <directory>${project.basedir}/src/main/resources</directory>
  69 + </resource>
  70 + </resources>
  71 + <plugins>
  72 + <plugin>
  73 + <groupId>org.apache.maven.plugins</groupId>
  74 + <artifactId>maven-resources-plugin</artifactId>
  75 + </plugin>
  76 + <plugin>
  77 + <groupId>org.apache.maven.plugins</groupId>
  78 + <artifactId>maven-dependency-plugin</artifactId>
  79 + </plugin>
  80 + <plugin>
  81 + <groupId>org.apache.maven.plugins</groupId>
  82 + <artifactId>maven-jar-plugin</artifactId>
  83 + </plugin>
  84 + <plugin>
  85 + <groupId>org.springframework.boot</groupId>
  86 + <artifactId>spring-boot-maven-plugin</artifactId>
  87 + </plugin>
  88 + <plugin>
  89 + <groupId>org.thingsboard</groupId>
  90 + <artifactId>gradle-maven-plugin</artifactId>
  91 + </plugin>
  92 + <plugin>
  93 + <groupId>org.apache.maven.plugins</groupId>
  94 + <artifactId>maven-assembly-plugin</artifactId>
  95 + </plugin>
  96 + <plugin>
  97 + <groupId>org.apache.maven.plugins</groupId>
  98 + <artifactId>maven-install-plugin</artifactId>
  99 + </plugin>
  100 + </plugins>
  101 + </build>
  102 + <repositories>
  103 + <repository>
  104 + <id>jenkins</id>
  105 + <name>Jenkins Repository</name>
  106 + <url>https://repo.jenkins-ci.org/releases</url>
  107 + <snapshots>
  108 + <enabled>false</enabled>
  109 + </snapshots>
  110 + </repository>
  111 + </repositories>
  112 +</project>
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2021 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<!DOCTYPE configuration>
  20 +<configuration>
  21 +
  22 + <appender name="fileLogAppender"
  23 + class="ch.qos.logback.core.rolling.RollingFileAppender">
  24 + <file>${pkg.logFolder}/${pkg.name}.log</file>
  25 + <rollingPolicy
  26 + class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
  27 + <fileNamePattern>${pkg.logFolder}/${pkg.name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
  28 + <maxFileSize>100MB</maxFileSize>
  29 + <maxHistory>30</maxHistory>
  30 + <totalSizeCap>3GB</totalSizeCap>
  31 + </rollingPolicy>
  32 + <encoder>
  33 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  34 + </encoder>
  35 + </appender>
  36 +
  37 + <logger name="org.thingsboard.server" level="INFO" />
  38 +
  39 + <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
  40 +
  41 + <root level="INFO">
  42 + <appender-ref ref="fileLogAppender"/>
  43 + </root>
  44 +
  45 +</configuration>
  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 +
  17 +export JAVA_OPTS="$JAVA_OPTS -Xlog:gc*,heap*,age*,safepoint=debug:file=@pkg.logFolder@/gc.log:time,uptime,level,tags:filecount=10,filesize=10M"
  18 +export JAVA_OPTS="$JAVA_OPTS -XX:+IgnoreUnrecognizedVMOptions -XX:+HeapDumpOnOutOfMemoryError"
  19 +export JAVA_OPTS="$JAVA_OPTS -XX:-UseBiasedLocking -XX:+UseTLAB -XX:+ResizeTLAB -XX:+PerfDisableSharedMem -XX:+UseCondCardMark"
  20 +export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC -XX:MaxGCPauseMillis=500 -XX:+UseStringDeduplication -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=10"
  21 +export LOG_FILENAME=${pkg.name}.out
  22 +export LOADER_PATH=${pkg.installFolder}/conf
  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.snmp;
  17 +
  18 +import org.springframework.boot.SpringApplication;
  19 +import org.springframework.boot.SpringBootConfiguration;
  20 +import org.springframework.context.annotation.ComponentScan;
  21 +import org.springframework.scheduling.annotation.EnableAsync;
  22 +import org.springframework.scheduling.annotation.EnableScheduling;
  23 +
  24 +import java.util.Arrays;
  25 +
  26 +@SpringBootConfiguration
  27 +@EnableAsync
  28 +@EnableScheduling
  29 +@ComponentScan({"org.thingsboard.server.snmp", "org.thingsboard.server.common", "org.thingsboard.server.transport.snmp", "org.thingsboard.server.queue"})
  30 +public class ThingsboardSnmpTransportApplication {
  31 +
  32 + private static final String SPRING_CONFIG_NAME_KEY = "--spring.config.name";
  33 + private static final String DEFAULT_SPRING_CONFIG_PARAM = SPRING_CONFIG_NAME_KEY + "=" + "tb-snmp-transport";
  34 +
  35 + public static void main(String[] args) {
  36 + SpringApplication.run(ThingsboardSnmpTransportApplication.class, updateArguments(args));
  37 + }
  38 +
  39 + private static String[] updateArguments(String[] args) {
  40 + if (Arrays.stream(args).noneMatch(arg -> arg.startsWith(SPRING_CONFIG_NAME_KEY))) {
  41 + String[] modifiedArgs = new String[args.length + 1];
  42 + System.arraycopy(args, 0, modifiedArgs, 0, args.length);
  43 + modifiedArgs[args.length] = DEFAULT_SPRING_CONFIG_PARAM;
  44 + return modifiedArgs;
  45 + }
  46 + return args;
  47 + }
  48 +}
  1 +<?xml version="1.0" encoding="UTF-8" ?>
  2 +<!--
  3 +
  4 + Copyright © 2016-2021 The Thingsboard Authors
  5 +
  6 + Licensed under the Apache License, Version 2.0 (the "License");
  7 + you may not use this file except in compliance with the License.
  8 + You may obtain a copy of the License at
  9 +
  10 + http://www.apache.org/licenses/LICENSE-2.0
  11 +
  12 + Unless required by applicable law or agreed to in writing, software
  13 + distributed under the License is distributed on an "AS IS" BASIS,
  14 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 + See the License for the specific language governing permissions and
  16 + limitations under the License.
  17 +
  18 +-->
  19 +<!DOCTYPE configuration>
  20 +<configuration scan="true" scanPeriod="10 seconds">
  21 +
  22 + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
  23 + <encoder>
  24 + <pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern>
  25 + </encoder>
  26 + </appender>
  27 +
  28 + <logger name="org.thingsboard.server" level="TRACE" />
  29 +
  30 + <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" />
  31 +
  32 + <root level="INFO">
  33 + <appender-ref ref="STDOUT"/>
  34 + </root>
  35 +
  36 +</configuration>
  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 +
  17 +# Zookeeper connection parameters. Used for service discovery.
  18 +zk:
  19 + # Enable/disable zookeeper discovery service.
  20 + enabled: "${ZOOKEEPER_ENABLED:false}"
  21 + # Zookeeper connect string
  22 + url: "${ZOOKEEPER_URL:localhost:2181}"
  23 + # Zookeeper retry interval in milliseconds
  24 + retry_interval_ms: "${ZOOKEEPER_RETRY_INTERVAL_MS:3000}"
  25 + # Zookeeper connection timeout in milliseconds
  26 + connection_timeout_ms: "${ZOOKEEPER_CONNECTION_TIMEOUT_MS:3000}"
  27 + # Zookeeper session timeout in milliseconds
  28 + session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}"
  29 + # Name of the directory in zookeeper 'filesystem'
  30 + zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}"
  31 +
  32 +transport:
  33 + snmp:
  34 + enabled: "${SNMP_ENABLED:true}"
  35 + response_processing:
  36 + # parallelism level for executor (workStealingPool) that is responsible for handling responses from SNMP devices
  37 + parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}"
  38 + # to configure SNMP to work over UDP or TCP
  39 + underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}"
  40 + sessions:
  41 + inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}"
  42 + report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:30000}"
  43 + json:
  44 + # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON
  45 + type_cast_enabled: "${JSON_TYPE_CAST_ENABLED:true}"
  46 + # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check)
  47 + max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}"
  48 +
  49 +queue:
  50 + type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ)
  51 + kafka:
  52 + bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}"
  53 + acks: "${TB_KAFKA_ACKS:all}"
  54 + retries: "${TB_KAFKA_RETRIES:1}"
  55 + batch.size: "${TB_KAFKA_BATCH_SIZE:16384}"
  56 + linger.ms: "${TB_KAFKA_LINGER_MS:1}"
  57 + buffer.memory: "${TB_BUFFER_MEMORY:33554432}"
  58 + replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}"
  59 + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}"
  60 + confluent:
  61 + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}"
  62 + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}"
  63 + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}"
  64 + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}"
  65 + other:
  66 + topic-properties:
  67 + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
  68 + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
  69 + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
  70 + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}"
  71 + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}"
  72 + consumer-stats:
  73 + enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}"
  74 + print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}"
  75 + kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}"
  76 + aws_sqs:
  77 + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}"
  78 + access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}"
  79 + secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}"
  80 + region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}"
  81 + threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}"
  82 + queue-properties:
  83 + rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
  84 + core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
  85 + transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
  86 + notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
  87 + js-executor: "${TB_QUEUE_AWS_SQS_JE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}"
  88 + # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds
  89 + pubsub:
  90 + project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}"
  91 + service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}"
  92 + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes
  93 + max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}"
  94 + queue-properties:
  95 + rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
  96 + core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
  97 + transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
  98 + notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
  99 + js-executor: "${TB_QUEUE_PUBSUB_JE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}"
  100 + service_bus:
  101 + namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}"
  102 + sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}"
  103 + sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}"
  104 + max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}"
  105 + queue-properties:
  106 + rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
  107 + core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
  108 + transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
  109 + notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
  110 + js-executor: "${TB_QUEUE_SERVICE_BUS_JE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}"
  111 + rabbitmq:
  112 + exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}"
  113 + host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}"
  114 + port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}"
  115 + virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}"
  116 + username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}"
  117 + password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}"
  118 + automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}"
  119 + connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}"
  120 + handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}"
  121 + queue-properties:
  122 + rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
  123 + core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
  124 + transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
  125 + notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
  126 + js-executor: "${TB_QUEUE_RABBIT_MQ_JE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}"
  127 + partitions:
  128 + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}"
  129 + virtual_nodes_size: "${TB_QUEUE_PARTITIONS_VIRTUAL_NODES_SIZE:16}"
  130 + transport_api:
  131 + requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}"
  132 + responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}"
  133 + max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}"
  134 + max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}"
  135 + max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}"
  136 + request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}"
  137 + response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}"
  138 + core:
  139 + topic: "${TB_QUEUE_CORE_TOPIC:tb_core}"
  140 + poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}"
  141 + partitions: "${TB_QUEUE_CORE_PARTITIONS:10}"
  142 + pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}"
  143 + usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}"
  144 + stats:
  145 + enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}"
  146 + print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}"
  147 + js:
  148 + # JS Eval request topic
  149 + request_topic: "${REMOTE_JS_EVAL_REQUEST_TOPIC:js_eval.requests}"
  150 + # JS Eval responses topic prefix that is combined with node id
  151 + response_topic_prefix: "${REMOTE_JS_EVAL_RESPONSE_TOPIC:js_eval.responses}"
  152 + # JS Eval max pending requests
  153 + max_pending_requests: "${REMOTE_JS_MAX_PENDING_REQUESTS:10000}"
  154 + # JS Eval max request timeout
  155 + max_requests_timeout: "${REMOTE_JS_MAX_REQUEST_TIMEOUT:10000}"
  156 + # JS response poll interval
  157 + response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}"
  158 + rule-engine:
  159 + topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}"
  160 + poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}"
  161 + pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}"
  162 + stats:
  163 + enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}"
  164 + print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}"
  165 + queues:
  166 + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}"
  167 + topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}"
  168 + poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}"
  169 + partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}"
  170 + pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:60000}"
  171 + submit-strategy:
  172 + type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
  173 + # For BATCH only
  174 + batch-size: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_BATCH_SIZE:1000}" # Maximum number of messages in batch
  175 + processing-strategy:
  176 + type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  177 + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  178 + retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited
  179 + failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
  180 + pause-between-retries: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_RETRY_PAUSE:3}"# Time in seconds to wait in consumer thread before retries;
  181 + - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}"
  182 + topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}"
  183 + poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}"
  184 + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}"
  185 + pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:60000}"
  186 + submit-strategy:
  187 + type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
  188 + # For BATCH only
  189 + batch-size: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch
  190 + processing-strategy:
  191 + type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  192 + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  193 + retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRIES:0}" # Number of retries, 0 is unlimited
  194 + failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
  195 + pause-between-retries: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries;
  196 + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}"
  197 + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}"
  198 + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}"
  199 + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}"
  200 + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:60000}"
  201 + submit-strategy:
  202 + type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL
  203 + # For BATCH only
  204 + batch-size: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_BATCH_SIZE:100}" # Maximum number of messages in batch
  205 + processing-strategy:
  206 + type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  207 + # For RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT
  208 + retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRIES:3}" # Number of retries, 0 is unlimited
  209 + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less then X percentage of messages;
  210 + pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_RETRY_PAUSE:5}"# Time in seconds to wait in consumer thread before retries;
  211 + transport:
  212 + # For high priority notifications that require minimum latency and processing time
  213 + notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}"
  214 + poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}"
  215 +
  216 +service:
  217 + type: "${TB_SERVICE_TYPE:tb-transport}"
  218 + # Unique id for this service (autogenerated if empty)
  219 + id: "${TB_SERVICE_ID:}"
  220 + tenant_id: "${TB_SERVICE_TENANT_ID:}" # empty or specific tenant id.
  221 +
  222 +metrics:
  223 + # Enable/disable actuator metrics.
  224 + enabled: "${METRICS_ENABLED:false}"
  225 +
  226 +management:
  227 + endpoints:
  228 + web:
  229 + exposure:
  230 + # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics).
  231 + include: '${METRICS_ENDPOINTS_EXPOSE:info}'
@@ -98,6 +98,7 @@ import { DeviceProfileDialogComponent } from '@home/components/profile/device-pr @@ -98,6 +98,7 @@ import { DeviceProfileDialogComponent } from '@home/components/profile/device-pr
98 import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component'; 98 import { DeviceProfileAutocompleteComponent } from '@home/components/profile/device-profile-autocomplete.component';
99 import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component'; 99 import { MqttDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/mqtt-device-profile-transport-configuration.component';
100 import { CoapDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/coap-device-profile-transport-configuration.component'; 100 import { CoapDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/coap-device-profile-transport-configuration.component';
  101 +import { SnmpDeviceProfileTransportConfigurationComponent } from '@home/components/profile/device/snmp-device-profile-transport-configuration.component';
101 import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component'; 102 import { DeviceProfileAlarmsComponent } from '@home/components/profile/alarm/device-profile-alarms.component';
102 import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component'; 103 import { DeviceProfileAlarmComponent } from '@home/components/profile/alarm/device-profile-alarm.component';
103 import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component'; 104 import { CreateAlarmRulesComponent } from '@home/components/profile/alarm/create-alarm-rules.component';
@@ -220,6 +221,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag @@ -220,6 +221,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag
220 DefaultDeviceProfileTransportConfigurationComponent, 221 DefaultDeviceProfileTransportConfigurationComponent,
221 MqttDeviceProfileTransportConfigurationComponent, 222 MqttDeviceProfileTransportConfigurationComponent,
222 CoapDeviceProfileTransportConfigurationComponent, 223 CoapDeviceProfileTransportConfigurationComponent,
  224 + SnmpDeviceProfileTransportConfigurationComponent,
223 DeviceProfileTransportConfigurationComponent, 225 DeviceProfileTransportConfigurationComponent,
224 CreateAlarmRulesComponent, 226 CreateAlarmRulesComponent,
225 AlarmRuleComponent, 227 AlarmRuleComponent,
@@ -325,6 +327,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag @@ -325,6 +327,7 @@ import { DisplayWidgetTypesPanelComponent } from '@home/components/dashboard-pag
325 DefaultDeviceProfileTransportConfigurationComponent, 327 DefaultDeviceProfileTransportConfigurationComponent,
326 MqttDeviceProfileTransportConfigurationComponent, 328 MqttDeviceProfileTransportConfigurationComponent,
327 CoapDeviceProfileTransportConfigurationComponent, 329 CoapDeviceProfileTransportConfigurationComponent,
  330 + SnmpDeviceProfileTransportConfigurationComponent,
328 DeviceProfileTransportConfigurationComponent, 331 DeviceProfileTransportConfigurationComponent,
329 CreateAlarmRulesComponent, 332 CreateAlarmRulesComponent,
330 AlarmRuleComponent, 333 AlarmRuleComponent,
@@ -41,5 +41,11 @@ @@ -41,5 +41,11 @@
41 formControlName="configuration"> 41 formControlName="configuration">
42 </tb-profile-lwm2m-device-transport-configuration> 42 </tb-profile-lwm2m-device-transport-configuration>
43 </ng-template> 43 </ng-template>
  44 + <ng-template [ngSwitchCase]="deviceTransportType.SNMP">
  45 + <tb-snmp-device-profile-transport-configuration
  46 + [required]="required"
  47 + formControlName="configuration">
  48 + </tb-snmp-device-profile-transport-configuration>
  49 + </ng-template>
44 </div> 50 </div>
45 </div> 51 </div>
  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 +<form [formGroup]="snmpDeviceProfileTransportConfigurationFormGroup" style="padding-bottom: 16px;">
  19 + <tb-json-object-edit
  20 + required
  21 + formControlName="configuration">
  22 + </tb-json-object-edit>
  23 +</form>
  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 +
  17 +import {Component, forwardRef, Input, OnInit} from '@angular/core';
  18 +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms';
  19 +import {Store} from '@ngrx/store';
  20 +import {AppState} from '@app/core/core.state';
  21 +import {coerceBooleanProperty} from '@angular/cdk/coercion';
  22 +import {
  23 + DeviceProfileTransportConfiguration,
  24 + DeviceTransportType,
  25 + SnmpDeviceProfileTransportConfiguration
  26 +} from '@shared/models/device.models';
  27 +import {isDefinedAndNotNull} from "@core/utils";
  28 +
  29 +export interface OidMappingConfiguration {
  30 + isAttribute: boolean;
  31 + key: string;
  32 + type: string;
  33 + method: string;
  34 + oid: string;
  35 +}
  36 +
  37 +@Component({
  38 + selector: 'tb-snmp-device-profile-transport-configuration',
  39 + templateUrl: './snmp-device-profile-transport-configuration.component.html',
  40 + styleUrls: [],
  41 + providers: [{
  42 + provide: NG_VALUE_ACCESSOR,
  43 + useExisting: forwardRef(() => SnmpDeviceProfileTransportConfigurationComponent),
  44 + multi: true
  45 + }]
  46 +})
  47 +export class SnmpDeviceProfileTransportConfigurationComponent implements ControlValueAccessor, OnInit {
  48 + snmpDeviceProfileTransportConfigurationFormGroup: FormGroup;
  49 + private requiredValue: boolean;
  50 + private configuration = [];
  51 +
  52 + get required(): boolean {
  53 + return this.requiredValue;
  54 + }
  55 +
  56 + @Input()
  57 + set required(value: boolean) {
  58 + this.requiredValue = coerceBooleanProperty(value);
  59 + }
  60 +
  61 + @Input()
  62 + disabled: boolean;
  63 +
  64 + private propagateChange = (v: any) => {
  65 + }
  66 +
  67 + constructor(private store: Store<AppState>, private fb: FormBuilder) {
  68 + }
  69 +
  70 + ngOnInit(): void {
  71 + this.snmpDeviceProfileTransportConfigurationFormGroup = this.fb.group({
  72 + configuration: [null, Validators.required]
  73 + });
  74 + this.snmpDeviceProfileTransportConfigurationFormGroup.valueChanges.subscribe(() => {
  75 + this.updateModel();
  76 + });
  77 + }
  78 +
  79 + registerOnChange(fn: any): void {
  80 + this.propagateChange = fn;
  81 + }
  82 +
  83 + registerOnTouched(fn: any): void {
  84 + }
  85 +
  86 + writeValue(value: SnmpDeviceProfileTransportConfiguration | null): void {
  87 + if (isDefinedAndNotNull(value)) {
  88 + this.snmpDeviceProfileTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
  89 + }
  90 + }
  91 +
  92 + private updateModel() {
  93 + let configuration: DeviceProfileTransportConfiguration = null;
  94 + if (this.snmpDeviceProfileTransportConfigurationFormGroup.valid) {
  95 + configuration = this.snmpDeviceProfileTransportConfigurationFormGroup.getRawValue().configuration;
  96 + configuration.type = DeviceTransportType.SNMP;
  97 + }
  98 + this.propagateChange(configuration);
  99 + }
  100 +}
@@ -41,5 +41,11 @@ @@ -41,5 +41,11 @@
41 formControlName="configuration"> 41 formControlName="configuration">
42 </tb-coap-device-transport-configuration> 42 </tb-coap-device-transport-configuration>
43 </ng-template> 43 </ng-template>
  44 + <ng-template [ngSwitchCase]="deviceTransportType.SNMP">
  45 + <tb-snmp-device-transport-configuration
  46 + [required]="required"
  47 + formControlName="configuration">
  48 + </tb-snmp-device-transport-configuration>
  49 + </ng-template>
44 </div> 50 </div>
45 </div> 51 </div>
  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 +<form [formGroup]="snmpDeviceTransportConfigurationFormGroup" style="padding-bottom: 16px;">
  19 + <tb-json-object-edit
  20 + [required]="required"
  21 + label="{{ 'device-profile.transport-type-snmp-hint' | translate }}"
  22 + formControlName="configuration">
  23 + </tb-json-object-edit>
  24 +</form>
  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 +
  17 +import {Component, forwardRef, Input, OnInit} from '@angular/core';
  18 +import {ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators} from '@angular/forms';
  19 +import {Store} from '@ngrx/store';
  20 +import {AppState} from '@app/core/core.state';
  21 +import {coerceBooleanProperty} from '@angular/cdk/coercion';
  22 +import {
  23 + DeviceTransportConfiguration,
  24 + DeviceTransportType,
  25 + SnmpDeviceTransportConfiguration
  26 +} from '@shared/models/device.models';
  27 +
  28 +@Component({
  29 + selector: 'tb-snmp-device-transport-configuration',
  30 + templateUrl: './snmp-device-transport-configuration.component.html',
  31 + styleUrls: [],
  32 + providers: [{
  33 + provide: NG_VALUE_ACCESSOR,
  34 + useExisting: forwardRef(() => SnmpDeviceTransportConfigurationComponent),
  35 + multi: true
  36 + }]
  37 +})
  38 +export class SnmpDeviceTransportConfigurationComponent implements ControlValueAccessor, OnInit {
  39 +
  40 + snmpDeviceTransportConfigurationFormGroup: FormGroup;
  41 +
  42 + private requiredValue: boolean;
  43 +
  44 + get required(): boolean {
  45 + return this.requiredValue;
  46 + }
  47 +
  48 + @Input()
  49 + set required(value: boolean) {
  50 + this.requiredValue = coerceBooleanProperty(value);
  51 + }
  52 +
  53 + @Input()
  54 + disabled: boolean;
  55 +
  56 + private propagateChange = (v: any) => {
  57 + };
  58 +
  59 + constructor(private store: Store<AppState>,
  60 + private fb: FormBuilder) {
  61 + }
  62 +
  63 + registerOnChange(fn: any): void {
  64 + this.propagateChange = fn;
  65 + }
  66 +
  67 + registerOnTouched(fn: any): void {
  68 + }
  69 +
  70 + ngOnInit() {
  71 + this.snmpDeviceTransportConfigurationFormGroup = this.fb.group({
  72 + configuration: [null, Validators.required]
  73 + });
  74 + this.snmpDeviceTransportConfigurationFormGroup.valueChanges.subscribe(() => {
  75 + this.updateModel();
  76 + });
  77 + }
  78 +
  79 + setDisabledState(isDisabled: boolean): void {
  80 + this.disabled = isDisabled;
  81 + if (this.disabled) {
  82 + this.snmpDeviceTransportConfigurationFormGroup.disable({emitEvent: false});
  83 + } else {
  84 + this.snmpDeviceTransportConfigurationFormGroup.enable({emitEvent: false});
  85 + }
  86 + }
  87 +
  88 + writeValue(value: SnmpDeviceTransportConfiguration | null): void {
  89 + this.snmpDeviceTransportConfigurationFormGroup.patchValue({configuration: value}, {emitEvent: false});
  90 + }
  91 +
  92 + private updateModel() {
  93 + let configuration: DeviceTransportConfiguration = null;
  94 + if (this.snmpDeviceTransportConfigurationFormGroup.valid) {
  95 + configuration = this.snmpDeviceTransportConfigurationFormGroup.getRawValue().configuration;
  96 + configuration.type = DeviceTransportType.SNMP;
  97 + }
  98 + this.propagateChange(configuration);
  99 + }
  100 +}
@@ -32,8 +32,9 @@ import { DeviceDataComponent } from './data/device-data.component'; @@ -32,8 +32,9 @@ import { DeviceDataComponent } from './data/device-data.component';
32 import { DefaultDeviceTransportConfigurationComponent } from './data/default-device-transport-configuration.component'; 32 import { DefaultDeviceTransportConfigurationComponent } from './data/default-device-transport-configuration.component';
33 import { DeviceTransportConfigurationComponent } from './data/device-transport-configuration.component'; 33 import { DeviceTransportConfigurationComponent } from './data/device-transport-configuration.component';
34 import { MqttDeviceTransportConfigurationComponent } from './data/mqtt-device-transport-configuration.component'; 34 import { MqttDeviceTransportConfigurationComponent } from './data/mqtt-device-transport-configuration.component';
35 -import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component';  
36 import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-transport-configuration.component'; 35 import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-transport-configuration.component';
  36 +import { Lwm2mDeviceTransportConfigurationComponent } from './data/lwm2m-device-transport-configuration.component';
  37 +import { SnmpDeviceTransportConfigurationComponent } from './data/snmp-device-transport-configuration.component';
37 38
38 @NgModule({ 39 @NgModule({
39 declarations: [ 40 declarations: [
@@ -41,8 +42,9 @@ import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-tr @@ -41,8 +42,9 @@ import { CoapDeviceTransportConfigurationComponent } from './data/coap-device-tr
41 DeviceConfigurationComponent, 42 DeviceConfigurationComponent,
42 DefaultDeviceTransportConfigurationComponent, 43 DefaultDeviceTransportConfigurationComponent,
43 MqttDeviceTransportConfigurationComponent, 44 MqttDeviceTransportConfigurationComponent,
44 - Lwm2mDeviceTransportConfigurationComponent,  
45 CoapDeviceTransportConfigurationComponent, 45 CoapDeviceTransportConfigurationComponent,
  46 + Lwm2mDeviceTransportConfigurationComponent,
  47 + SnmpDeviceTransportConfigurationComponent,
46 DeviceTransportConfigurationComponent, 48 DeviceTransportConfigurationComponent,
47 DeviceDataComponent, 49 DeviceDataComponent,
48 DeviceComponent, 50 DeviceComponent,
@@ -30,14 +30,16 @@ import { AbstractControl, ValidationErrors } from '@angular/forms'; @@ -30,14 +30,16 @@ import { AbstractControl, ValidationErrors } from '@angular/forms';
30 import { FirmwareId } from '@shared/models/id/firmware-id'; 30 import { FirmwareId } from '@shared/models/id/firmware-id';
31 31
32 export enum DeviceProfileType { 32 export enum DeviceProfileType {
33 - DEFAULT = 'DEFAULT' 33 + DEFAULT = 'DEFAULT',
  34 + SNMP = 'SNMP'
34 } 35 }
35 36
36 export enum DeviceTransportType { 37 export enum DeviceTransportType {
37 DEFAULT = 'DEFAULT', 38 DEFAULT = 'DEFAULT',
38 MQTT = 'MQTT', 39 MQTT = 'MQTT',
39 COAP = 'COAP', 40 COAP = 'COAP',
40 - LWM2M = 'LWM2M' 41 + LWM2M = 'LWM2M',
  42 + SNMP = 'SNMP'
41 } 43 }
42 44
43 export enum TransportPayloadType { 45 export enum TransportPayloadType {
@@ -75,6 +77,13 @@ export const deviceProfileTypeConfigurationInfoMap = new Map<DeviceProfileType, @@ -75,6 +77,13 @@ export const deviceProfileTypeConfigurationInfoMap = new Map<DeviceProfileType,
75 hasProfileConfiguration: false, 77 hasProfileConfiguration: false,
76 hasDeviceConfiguration: false, 78 hasDeviceConfiguration: false,
77 } 79 }
  80 + ],
  81 + [
  82 + DeviceProfileType.SNMP,
  83 + {
  84 + hasProfileConfiguration: true,
  85 + hasDeviceConfiguration: true,
  86 + }
78 ] 87 ]
79 ] 88 ]
80 ); 89 );
@@ -84,7 +93,8 @@ export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, st @@ -84,7 +93,8 @@ export const deviceTransportTypeTranslationMap = new Map<DeviceTransportType, st
84 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'], 93 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default'],
85 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'], 94 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt'],
86 [DeviceTransportType.COAP, 'device-profile.transport-type-coap'], 95 [DeviceTransportType.COAP, 'device-profile.transport-type-coap'],
87 - [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m'] 96 + [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m'],
  97 + [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp']
88 ] 98 ]
89 ); 99 );
90 100
@@ -102,7 +112,8 @@ export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>( @@ -102,7 +112,8 @@ export const deviceTransportTypeHintMap = new Map<DeviceTransportType, string>(
102 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'], 112 [DeviceTransportType.DEFAULT, 'device-profile.transport-type-default-hint'],
103 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'], 113 [DeviceTransportType.MQTT, 'device-profile.transport-type-mqtt-hint'],
104 [DeviceTransportType.COAP, 'device-profile.transport-type-coap-hint'], 114 [DeviceTransportType.COAP, 'device-profile.transport-type-coap-hint'],
105 - [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint'] 115 + [DeviceTransportType.LWM2M, 'device-profile.transport-type-lwm2m-hint'],
  116 + [DeviceTransportType.SNMP, 'device-profile.transport-type-snmp-hint']
106 ] 117 ]
107 ); 118 );
108 119
@@ -196,6 +207,13 @@ export const deviceTransportTypeConfigurationInfoMap = new Map<DeviceTransportTy @@ -196,6 +207,13 @@ export const deviceTransportTypeConfigurationInfoMap = new Map<DeviceTransportTy
196 hasProfileConfiguration: true, 207 hasProfileConfiguration: true,
197 hasDeviceConfiguration: false, 208 hasDeviceConfiguration: false,
198 } 209 }
  210 + ],
  211 + [
  212 + DeviceTransportType.SNMP,
  213 + {
  214 + hasProfileConfiguration: true,
  215 + hasDeviceConfiguration: true
  216 + }
199 ] 217 ]
200 ] 218 ]
201 ); 219 );
@@ -237,10 +255,15 @@ export interface Lwm2mDeviceProfileTransportConfiguration { @@ -237,10 +255,15 @@ export interface Lwm2mDeviceProfileTransportConfiguration {
237 [key: string]: any; 255 [key: string]: any;
238 } 256 }
239 257
  258 +export interface SnmpDeviceProfileTransportConfiguration {
  259 + [key: string]: any;
  260 +}
  261 +
240 export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration & 262 export type DeviceProfileTransportConfigurations = DefaultDeviceProfileTransportConfiguration &
241 MqttDeviceProfileTransportConfiguration & 263 MqttDeviceProfileTransportConfiguration &
242 CoapDeviceProfileTransportConfiguration & 264 CoapDeviceProfileTransportConfiguration &
243 - Lwm2mDeviceProfileTransportConfiguration; 265 + Lwm2mDeviceProfileTransportConfiguration &
  266 + SnmpDeviceProfileTransportConfiguration;
244 267
245 export interface DeviceProfileTransportConfiguration extends DeviceProfileTransportConfigurations { 268 export interface DeviceProfileTransportConfiguration extends DeviceProfileTransportConfigurations {
246 type: DeviceTransportType; 269 type: DeviceTransportType;
@@ -307,6 +330,10 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT @@ -307,6 +330,10 @@ export function createDeviceProfileTransportConfiguration(type: DeviceTransportT
307 const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {}; 330 const lwm2mTransportConfiguration: Lwm2mDeviceProfileTransportConfiguration = {};
308 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; 331 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
309 break; 332 break;
  333 + case DeviceTransportType.SNMP:
  334 + const snmpTransportConfiguration: SnmpDeviceProfileTransportConfiguration = {};
  335 + transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP};
  336 + break;
310 } 337 }
311 } 338 }
312 return transportConfiguration; 339 return transportConfiguration;
@@ -332,6 +359,10 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D @@ -332,6 +359,10 @@ export function createDeviceTransportConfiguration(type: DeviceTransportType): D
332 const lwm2mTransportConfiguration: Lwm2mDeviceTransportConfiguration = {}; 359 const lwm2mTransportConfiguration: Lwm2mDeviceTransportConfiguration = {};
333 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M}; 360 transportConfiguration = {...lwm2mTransportConfiguration, type: DeviceTransportType.LWM2M};
334 break; 361 break;
  362 + case DeviceTransportType.SNMP:
  363 + const snmpTransportConfiguration: SnmpDeviceTransportConfiguration = {};
  364 + transportConfiguration = {...snmpTransportConfiguration, type: DeviceTransportType.SNMP};
  365 + break;
335 } 366 }
336 } 367 }
337 return transportConfiguration; 368 return transportConfiguration;
@@ -501,10 +532,15 @@ export interface Lwm2mDeviceTransportConfiguration { @@ -501,10 +532,15 @@ export interface Lwm2mDeviceTransportConfiguration {
501 [key: string]: any; 532 [key: string]: any;
502 } 533 }
503 534
  535 +export interface SnmpDeviceTransportConfiguration {
  536 + [key: string]: any;
  537 +}
  538 +
504 export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration & 539 export type DeviceTransportConfigurations = DefaultDeviceTransportConfiguration &
505 MqttDeviceTransportConfiguration & 540 MqttDeviceTransportConfiguration &
506 CoapDeviceTransportConfiguration & 541 CoapDeviceTransportConfiguration &
507 - Lwm2mDeviceTransportConfiguration; 542 + Lwm2mDeviceTransportConfiguration &
  543 + SnmpDeviceTransportConfiguration;
508 544
509 export interface DeviceTransportConfiguration extends DeviceTransportConfigurations { 545 export interface DeviceTransportConfiguration extends DeviceTransportConfigurations {
510 type: DeviceTransportType; 546 type: DeviceTransportType;
@@ -1025,10 +1025,12 @@ @@ -1025,10 +1025,12 @@
1025 "transport-type-default-hint": "Supports basic MQTT, HTTP and CoAP transport", 1025 "transport-type-default-hint": "Supports basic MQTT, HTTP and CoAP transport",
1026 "transport-type-mqtt": "MQTT", 1026 "transport-type-mqtt": "MQTT",
1027 "transport-type-mqtt-hint": "Enables advanced MQTT transport settings", 1027 "transport-type-mqtt-hint": "Enables advanced MQTT transport settings",
1028 - "transport-type-lwm2m": "LWM2M",  
1029 - "transport-type-lwm2m-hint": "LWM2M transport type",  
1030 "transport-type-coap": "CoAP", 1028 "transport-type-coap": "CoAP",
1031 "transport-type-coap-hint": "Enables advanced CoAP transport settings", 1029 "transport-type-coap-hint": "Enables advanced CoAP transport settings",
  1030 + "transport-type-lwm2m": "LWM2M",
  1031 + "transport-type-lwm2m-hint": "LWM2M transport type",
  1032 + "transport-type-snmp": "SNMP",
  1033 + "transport-type-snmp-hint": "Specify SNMP transport configuration",
1032 "description": "Description", 1034 "description": "Description",
1033 "default": "Default", 1035 "default": "Default",
1034 "profile-configuration": "Profile configuration", 1036 "profile-configuration": "Profile configuration",
@@ -1046,6 +1048,15 @@ @@ -1046,6 +1048,15 @@
1046 "mqtt-device-topic-filters": "MQTT device topic filters", 1048 "mqtt-device-topic-filters": "MQTT device topic filters",
1047 "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.", 1049 "mqtt-device-topic-filters-unique": "MQTT device topic filters need to be unique.",
1048 "mqtt-device-payload-type": "MQTT device payload", 1050 "mqtt-device-payload-type": "MQTT device payload",
  1051 + "mqtt-device-payload-type-json": "JSON",
  1052 + "mqtt-device-payload-type-proto": "Protobuf",
  1053 + "snmp-add-mapping": "Add SNMP mapping",
  1054 + "snmp-mapping-not-configured": "No mapping for OID to timeseries/telemetry configured",
  1055 + "snmp-timseries-or-attribute-name": "Timeseries/attribute name for mapping",
  1056 + "snmp-timseries-or-attribute-type": "Timeseries/attribute type for mapping",
  1057 + "snmp-method-pdu-type-get-request": "GetRequest",
  1058 + "snmp-method-pdu-type-get-next-request": "GetNextRequest",
  1059 + "snmp-oid": "OID",
1049 "transport-device-payload-type-json": "JSON", 1060 "transport-device-payload-type-json": "JSON",
1050 "transport-device-payload-type-proto": "Protobuf", 1061 "transport-device-payload-type-proto": "Protobuf",
1051 "mqtt-payload-type-required": "Payload type is required.", 1062 "mqtt-payload-type-required": "Payload type is required.",