Showing
16 changed files
with
454 additions
and
234 deletions
... | ... | @@ -17,16 +17,11 @@ package org.thingsboard.server.common.data.device.profile; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | 19 | import lombok.Data; |
20 | -import org.apache.commons.lang3.ArrayUtils; | |
21 | 20 | import org.thingsboard.server.common.data.DeviceTransportType; |
22 | 21 | import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; |
23 | -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig; | |
22 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
24 | 23 | |
25 | -import java.util.Collections; | |
26 | 24 | import java.util.List; |
27 | -import java.util.function.Function; | |
28 | -import java.util.stream.Collectors; | |
29 | -import java.util.stream.Stream; | |
30 | 25 | |
31 | 26 | @Data |
32 | 27 | public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { |
... | ... | @@ -51,7 +46,7 @@ public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTra |
51 | 46 | return timeoutMs != null && timeoutMs >= 0 && retries != null && retries >= 0 |
52 | 47 | && communicationConfigs != null && !communicationConfigs.isEmpty() |
53 | 48 | && communicationConfigs.stream().allMatch(config -> config != null && config.isValid()) |
54 | - && communicationConfigs.stream().flatMap(config -> config.getMappings().stream()).map(SnmpMapping::getOid) | |
55 | - .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getMappings().size()).sum(); | |
49 | + && communicationConfigs.stream().flatMap(config -> config.getAllMappings().stream()).map(SnmpMapping::getOid) | |
50 | + .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getAllMappings().size()).sum(); | |
56 | 51 | } |
57 | 52 | } | ... | ... |
... | ... | @@ -16,22 +16,11 @@ |
16 | 16 | package org.thingsboard.server.common.data.transport.snmp; |
17 | 17 | |
18 | 18 | public enum SnmpCommunicationSpec { |
19 | - TELEMETRY_QUERYING(true), | |
20 | - CLIENT_ATTRIBUTES_QUERYING(true), | |
19 | + TELEMETRY_QUERYING, | |
21 | 20 | |
22 | - SHARED_ATTRIBUTES_SETTING; | |
21 | + CLIENT_ATTRIBUTES_QUERYING, | |
22 | + SHARED_ATTRIBUTES_SETTING, | |
23 | 23 | |
24 | - private final boolean isRepeatingQuerying; | |
25 | - | |
26 | - SnmpCommunicationSpec() { | |
27 | - this.isRepeatingQuerying = false; | |
28 | - } | |
29 | - | |
30 | - SnmpCommunicationSpec(boolean isRepeatingQuerying) { | |
31 | - this.isRepeatingQuerying = isRepeatingQuerying; | |
32 | - } | |
33 | - | |
34 | - public boolean isRepeatingQuerying() { | |
35 | - return isRepeatingQuerying; | |
36 | - } | |
24 | + TO_DEVICE_RPC_COMMAND_SETTING, | |
25 | + TO_DEVICE_RPC_RESPONSE_QUERYING | |
37 | 26 | } | ... | ... |
... | ... | @@ -16,13 +16,17 @@ |
16 | 16 | package org.thingsboard.server.common.data.transport.snmp; |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | +import lombok.AllArgsConstructor; | |
19 | 20 | import lombok.Data; |
21 | +import lombok.NoArgsConstructor; | |
20 | 22 | import org.apache.commons.lang3.StringUtils; |
21 | 23 | import org.thingsboard.server.common.data.kv.DataType; |
22 | 24 | |
23 | 25 | import java.util.regex.Pattern; |
24 | 26 | |
25 | 27 | @Data |
28 | +@AllArgsConstructor | |
29 | +@NoArgsConstructor | |
26 | 30 | public class SnmpMapping { |
27 | 31 | private String oid; |
28 | 32 | private String key; |
... | ... | @@ -32,7 +36,6 @@ public class SnmpMapping { |
32 | 36 | |
33 | 37 | @JsonIgnore |
34 | 38 | public boolean isValid() { |
35 | - return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && | |
36 | - StringUtils.isNotBlank(key) && dataType != null; | |
39 | + return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && StringUtils.isNotBlank(key); | |
37 | 40 | } |
38 | 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.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 | +} | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/RepeatingQueryingSnmpCommunicationConfig.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/RepeatingQueryingSnmpCommunicationConfig.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.common.data.transport.snmp.configs; | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.EqualsAndHashCode; |
... | ... | @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; |
21 | 21 | |
22 | 22 | @EqualsAndHashCode(callSuper = true) |
23 | 23 | @Data |
24 | -public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommunicationConfig { | |
24 | +public abstract class RepeatingQueryingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { | |
25 | 25 | private Long queryingFrequencyMs; |
26 | 26 | |
27 | 27 | @Override |
... | ... | @@ -31,6 +31,6 @@ public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommu |
31 | 31 | |
32 | 32 | @Override |
33 | 33 | public boolean isValid() { |
34 | - return super.isValid() && queryingFrequencyMs != null && queryingFrequencyMs > 0; | |
34 | + return queryingFrequencyMs != null && queryingFrequencyMs > 0 && super.isValid(); | |
35 | 35 | } |
36 | 36 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/SnmpCommunicationConfig.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SnmpCommunicationConfig.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.common.data.transport.snmp.configs; | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config; | |
17 | 17 | |
18 | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | 19 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
... | ... | @@ -23,6 +23,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; |
23 | 23 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
24 | 24 | import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; |
25 | 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; | |
26 | 29 | |
27 | 30 | import java.util.List; |
28 | 31 | |
... | ... | @@ -33,22 +36,19 @@ import java.util.List; |
33 | 36 | @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"), |
34 | 37 | @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING") |
35 | 38 | }) |
36 | -public abstract class SnmpCommunicationConfig { | |
37 | - protected List<SnmpMapping> mappings; | |
39 | +public interface SnmpCommunicationConfig { | |
38 | 40 | |
39 | - public List<SnmpMapping> getMappings() { | |
40 | - return mappings; | |
41 | - } | |
42 | - | |
43 | - public abstract SnmpCommunicationSpec getSpec(); | |
41 | + SnmpCommunicationSpec getSpec(); | |
44 | 42 | |
45 | 43 | @JsonIgnore |
46 | - public SnmpMethod getMethod() { | |
44 | + default SnmpMethod getMethod() { | |
47 | 45 | return null; |
48 | 46 | } |
49 | 47 | |
50 | 48 | @JsonIgnore |
51 | - public boolean isValid() { | |
52 | - return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid()); | |
53 | - } | |
49 | + List<SnmpMapping> getAllMappings(); | |
50 | + | |
51 | + @JsonIgnore | |
52 | + boolean isValid(); | |
53 | + | |
54 | 54 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ClientAttributesQueryingSnmpCommunicationConfig.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesQueryingSnmpCommunicationConfig.java
... | ... | @@ -13,13 +13,16 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.common.data.transport.snmp.configs; | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
19 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
19 | 20 | |
20 | 21 | public class ClientAttributesQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { |
22 | + | |
21 | 23 | @Override |
22 | 24 | public SnmpCommunicationSpec getSpec() { |
23 | 25 | return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING; |
24 | 26 | } |
27 | + | |
25 | 28 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/SharedAttributesSettingSnmpCommunicationConfig.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SharedAttributesSettingSnmpCommunicationConfig.java
... | ... | @@ -13,12 +13,14 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.common.data.transport.snmp.configs; | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | 17 | |
18 | 18 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
19 | 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 { | |
20 | 23 | |
21 | -public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunicationConfig { | |
22 | 24 | @Override |
23 | 25 | public SnmpCommunicationSpec getSpec() { |
24 | 26 | return SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING; |
... | ... | @@ -28,4 +30,5 @@ public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunic |
28 | 30 | public SnmpMethod getMethod() { |
29 | 31 | return SnmpMethod.SET; |
30 | 32 | } |
33 | + | |
31 | 34 | } | ... | ... |
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/TelemetryQueryingSnmpCommunicationConfig.java
renamed from
common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryQueryingSnmpCommunicationConfig.java
... | ... | @@ -13,17 +13,20 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.common.data.transport.snmp.configs; | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | 17 | |
18 | 18 | import lombok.Data; |
19 | 19 | import lombok.EqualsAndHashCode; |
20 | 20 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
21 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
21 | 22 | |
22 | 23 | @EqualsAndHashCode(callSuper = true) |
23 | 24 | @Data |
24 | 25 | public class TelemetryQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { |
26 | + | |
25 | 27 | @Override |
26 | 28 | public SnmpCommunicationSpec getSpec() { |
27 | 29 | return SnmpCommunicationSpec.TELEMETRY_QUERYING; |
28 | 30 | } |
31 | + | |
29 | 32 | } | ... | ... |
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.common.data.transport.snmp.config.impl; | |
17 | + | |
18 | +import lombok.Data; | |
19 | +import org.thingsboard.server.common.data.kv.DataType; | |
20 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
21 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
22 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
23 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
24 | + | |
25 | +import java.util.Arrays; | |
26 | +import java.util.Collections; | |
27 | +import java.util.List; | |
28 | + | |
29 | +@Data | |
30 | +public class ToDeviceRpcCommandSettingSnmpCommunicationConfig implements SnmpCommunicationConfig { | |
31 | + private SnmpMapping mapping; | |
32 | + | |
33 | + @Override | |
34 | + public SnmpCommunicationSpec getSpec() { | |
35 | + return SnmpCommunicationSpec.TO_DEVICE_RPC_COMMAND_SETTING; | |
36 | + } | |
37 | + | |
38 | + @Override | |
39 | + public SnmpMethod getMethod() { | |
40 | + return SnmpMethod.SET; | |
41 | + } | |
42 | + | |
43 | + public void setMapping(SnmpMapping mapping) { | |
44 | + this.mapping = mapping != null ? new SnmpMapping(mapping.getOid(), RPC_COMMAND_KEY_NAME, DataType.STRING) : null; | |
45 | + } | |
46 | + | |
47 | + @Override | |
48 | + public List<SnmpMapping> getAllMappings() { | |
49 | + return Collections.singletonList(mapping); | |
50 | + } | |
51 | + | |
52 | + @Override | |
53 | + public boolean isValid() { | |
54 | + return mapping != null && mapping.isValid(); | |
55 | + } | |
56 | + | |
57 | + public static final String RPC_COMMAND_KEY_NAME = "rpcCommand"; | |
58 | + | |
59 | +} | ... | ... |
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.kv.DataType; | |
21 | +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; | |
22 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
23 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; | |
24 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
25 | + | |
26 | +import java.util.Collections; | |
27 | +import java.util.List; | |
28 | + | |
29 | +@EqualsAndHashCode(callSuper = true) | |
30 | +@Data | |
31 | +public class ToDeviceRpcResponseQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { | |
32 | + private SnmpMapping mapping; | |
33 | + | |
34 | + @Override | |
35 | + public SnmpCommunicationSpec getSpec() { | |
36 | + return SnmpCommunicationSpec.TO_DEVICE_RPC_RESPONSE_QUERYING; | |
37 | + } | |
38 | + | |
39 | + @Override | |
40 | + public SnmpMethod getMethod() { | |
41 | + return SnmpMethod.GET; | |
42 | + } | |
43 | + | |
44 | + public void setMapping(SnmpMapping mapping) { | |
45 | + this.mapping = mapping != null ? new SnmpMapping(mapping.getOid(), RPC_RESPONSE_KEY_NAME, DataType.STRING) : null; | |
46 | + } | |
47 | + | |
48 | + @Override | |
49 | + public List<SnmpMapping> getAllMappings() { | |
50 | + return Collections.singletonList(mapping); | |
51 | + } | |
52 | + | |
53 | + @Override | |
54 | + public boolean isValid() { | |
55 | + return true; | |
56 | + } | |
57 | + | |
58 | + public static final String RPC_RESPONSE_KEY_NAME = "rpcResponse"; | |
59 | + | |
60 | +} | ... | ... |
... | ... | @@ -42,6 +42,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; |
42 | 42 | import org.thingsboard.server.queue.util.AfterStartUp; |
43 | 43 | import org.thingsboard.server.queue.util.TbSnmpTransportComponent; |
44 | 44 | import org.thingsboard.server.transport.snmp.service.ProtoTransportEntityService; |
45 | +import org.thingsboard.server.transport.snmp.service.SnmpAuthService; | |
45 | 46 | import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; |
46 | 47 | import org.thingsboard.server.transport.snmp.service.SnmpTransportService; |
47 | 48 | import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; |
... | ... | @@ -116,7 +117,7 @@ public class SnmpTransportContext extends TransportContext { |
116 | 117 | ); |
117 | 118 | registerSessionMsgListener(deviceSessionContext); |
118 | 119 | } catch (Exception e) { |
119 | - log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.getMessage()); | |
120 | + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString()); | |
120 | 121 | return; |
121 | 122 | } |
122 | 123 | sessions.put(device.getId(), deviceSessionContext); |
... | ... | @@ -177,7 +178,9 @@ public class SnmpTransportContext extends TransportContext { |
177 | 178 | ); |
178 | 179 | |
179 | 180 | transportService.registerAsyncSession(sessionInfo, deviceSessionContext); |
180 | - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); | |
181 | + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | |
182 | + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY); | |
183 | + | |
181 | 184 | deviceSessionContext.setSessionInfo(sessionInfo); |
182 | 185 | deviceSessionContext.setDeviceInfo(msg.getDeviceInfo()); |
183 | 186 | } else { | ... | ... |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduMapper.java
0 → 100644
1 | +/** | |
2 | + * Copyright © 2016-2021 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | + | |
18 | +import com.google.gson.JsonObject; | |
19 | +import lombok.extern.slf4j.Slf4j; | |
20 | +import org.snmp4j.PDU; | |
21 | +import org.snmp4j.ScopedPDU; | |
22 | +import org.snmp4j.smi.Integer32; | |
23 | +import org.snmp4j.smi.Null; | |
24 | +import org.snmp4j.smi.OID; | |
25 | +import org.snmp4j.smi.OctetString; | |
26 | +import org.snmp4j.smi.Variable; | |
27 | +import org.snmp4j.smi.VariableBinding; | |
28 | +import org.springframework.stereotype.Service; | |
29 | +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
30 | +import org.thingsboard.server.common.data.kv.DataType; | |
31 | +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
32 | +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | |
33 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
34 | +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; | |
35 | +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; | |
36 | + | |
37 | +import java.util.HashMap; | |
38 | +import java.util.List; | |
39 | +import java.util.Map; | |
40 | +import java.util.Objects; | |
41 | +import java.util.Optional; | |
42 | +import java.util.stream.Collectors; | |
43 | +import java.util.stream.IntStream; | |
44 | + | |
45 | +@TbSnmpTransportComponent | |
46 | +@Service | |
47 | +@Slf4j | |
48 | +public class PduMapper { | |
49 | + public PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | |
50 | + PDU pdu; | |
51 | + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | |
52 | + SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); | |
53 | + switch (snmpVersion) { | |
54 | + case V1: | |
55 | + case V2C: | |
56 | + pdu = new PDU(); | |
57 | + break; | |
58 | + case V3: | |
59 | + ScopedPDU scopedPdu = new ScopedPDU(); | |
60 | + scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); | |
61 | + scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); | |
62 | + pdu = scopedPdu; | |
63 | + break; | |
64 | + default: | |
65 | + throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); | |
66 | + } | |
67 | + | |
68 | + pdu.setType(communicationConfig.getMethod().getCode()); | |
69 | + pdu.addAll(communicationConfig.getAllMappings().stream() | |
70 | + .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) | |
71 | + .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) | |
72 | + .map(value -> { | |
73 | + Variable variable = toSnmpVariable(mapping, value); | |
74 | + return new VariableBinding(new OID(mapping.getOid()), variable); | |
75 | + }) | |
76 | + .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) | |
77 | + .collect(Collectors.toList())); | |
78 | + | |
79 | + return pdu; | |
80 | + } | |
81 | + | |
82 | + private Variable toSnmpVariable(SnmpMapping mapping, String value) { | |
83 | + Variable variable; | |
84 | + switch (mapping.getDataType()) { | |
85 | + case LONG: | |
86 | + try { | |
87 | + variable = new Integer32(Integer.parseInt(value)); | |
88 | + break; | |
89 | + } catch (NumberFormatException ignored) { | |
90 | + } | |
91 | + case DOUBLE: | |
92 | + case BOOLEAN: | |
93 | + case STRING: | |
94 | + case JSON: | |
95 | + default: | |
96 | + variable = new OctetString(value); | |
97 | + } | |
98 | + return variable; | |
99 | + } | |
100 | + | |
101 | + | |
102 | + public JsonObject processPdu(PDU pdu, DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { | |
103 | + List<VariableBinding> variablesBindings = IntStream.range(0, pdu.size()) | |
104 | + .mapToObj(pdu::get) | |
105 | + .filter(Objects::nonNull) | |
106 | + .filter(variableBinding -> !(variableBinding.getVariable() instanceof Null)) | |
107 | + .collect(Collectors.toList()); | |
108 | + JsonObject data = new JsonObject(); | |
109 | + | |
110 | + Map<OID, SnmpMapping> mappings = new HashMap<>(); | |
111 | + for (SnmpMapping mapping : communicationConfig.getAllMappings()) { | |
112 | + OID oid = new OID(mapping.getOid()); | |
113 | + mappings.put(oid, mapping); | |
114 | + } | |
115 | + | |
116 | + variablesBindings.forEach(variableBinding -> { | |
117 | + log.trace("Processing variable binding: {}", variableBinding); | |
118 | + | |
119 | + OID oid = variableBinding.getOid(); | |
120 | + SnmpMapping mapping = mappings.get(oid); | |
121 | + if (mapping == null) { | |
122 | + log.debug("No SNMP mapping for oid {}", oid); | |
123 | + return; | |
124 | + } | |
125 | + | |
126 | + processValue(mapping.getKey(), mapping.getDataType(), variableBinding.toValueString(), data); | |
127 | + }); | |
128 | + | |
129 | + return data; | |
130 | + } | |
131 | + | |
132 | + | |
133 | + private void processValue(String key, DataType dataType, String value, JsonObject result) { | |
134 | + switch (dataType) { | |
135 | + case LONG: | |
136 | + result.addProperty(key, Long.parseLong(value)); | |
137 | + break; | |
138 | + case BOOLEAN: | |
139 | + result.addProperty(key, Boolean.parseBoolean(value)); | |
140 | + break; | |
141 | + case DOUBLE: | |
142 | + result.addProperty(key, Double.parseDouble(value)); | |
143 | + break; | |
144 | + case STRING: | |
145 | + case JSON: | |
146 | + default: | |
147 | + result.addProperty(key, value); | |
148 | + } | |
149 | + } | |
150 | +} | ... | ... |
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpAuthService.java
renamed from
common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpAuthService.java
... | ... | @@ -13,7 +13,7 @@ |
13 | 13 | * See the License for the specific language governing permissions and |
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | -package org.thingsboard.server.transport.snmp; | |
16 | +package org.thingsboard.server.transport.snmp.service; | |
17 | 17 | |
18 | 18 | import lombok.RequiredArgsConstructor; |
19 | 19 | import org.snmp4j.AbstractTarget; |
... | ... | @@ -24,6 +24,7 @@ import org.snmp4j.security.SecurityLevel; |
24 | 24 | import org.snmp4j.security.SecurityModel; |
25 | 25 | import org.snmp4j.security.SecurityProtocols; |
26 | 26 | import org.snmp4j.security.USM; |
27 | +import org.snmp4j.smi.Address; | |
27 | 28 | import org.snmp4j.smi.GenericAddress; |
28 | 29 | import org.snmp4j.smi.OID; |
29 | 30 | import org.snmp4j.smi.OctetString; |
... | ... | @@ -36,6 +37,8 @@ import org.thingsboard.server.queue.util.TbSnmpTransportComponent; |
36 | 37 | import org.thingsboard.server.transport.snmp.service.SnmpTransportService; |
37 | 38 | import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; |
38 | 39 | |
40 | +import java.util.Optional; | |
41 | + | |
39 | 42 | @Service |
40 | 43 | @TbSnmpTransportComponent |
41 | 44 | @RequiredArgsConstructor |
... | ... | @@ -97,7 +100,8 @@ public class SnmpAuthService { |
97 | 100 | throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported"); |
98 | 101 | } |
99 | 102 | |
100 | - target.setAddress(GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort())); | |
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"))); | |
101 | 105 | target.setTimeout(profileTransportConfig.getTimeoutMs()); |
102 | 106 | target.setRetries(profileTransportConfig.getRetries()); |
103 | 107 | target.setVersion(protocolVersion.getCode()); | ... | ... |
... | ... | @@ -16,11 +16,11 @@ |
16 | 16 | package org.thingsboard.server.transport.snmp.service; |
17 | 17 | |
18 | 18 | import com.google.gson.JsonObject; |
19 | +import lombok.Data; | |
19 | 20 | import lombok.Getter; |
21 | +import lombok.RequiredArgsConstructor; | |
20 | 22 | import lombok.extern.slf4j.Slf4j; |
21 | -import org.apache.commons.lang3.StringUtils; | |
22 | 23 | import org.snmp4j.PDU; |
23 | -import org.snmp4j.ScopedPDU; | |
24 | 24 | import org.snmp4j.Snmp; |
25 | 25 | import org.snmp4j.TransportMapping; |
26 | 26 | import org.snmp4j.event.ResponseEvent; |
... | ... | @@ -28,26 +28,18 @@ import org.snmp4j.mp.MPv3; |
28 | 28 | import org.snmp4j.security.SecurityModels; |
29 | 29 | import org.snmp4j.security.SecurityProtocols; |
30 | 30 | import org.snmp4j.security.USM; |
31 | -import org.snmp4j.smi.Integer32; | |
32 | -import org.snmp4j.smi.Null; | |
33 | -import org.snmp4j.smi.OID; | |
34 | 31 | import org.snmp4j.smi.OctetString; |
35 | -import org.snmp4j.smi.Variable; | |
36 | -import org.snmp4j.smi.VariableBinding; | |
37 | 32 | import org.snmp4j.transport.DefaultTcpTransportMapping; |
38 | 33 | import org.snmp4j.transport.DefaultUdpTransportMapping; |
39 | 34 | import org.springframework.beans.factory.annotation.Value; |
40 | 35 | import org.springframework.stereotype.Service; |
41 | 36 | import org.thingsboard.common.util.ThingsBoardThreadFactory; |
42 | 37 | import org.thingsboard.server.common.data.TbTransportService; |
43 | -import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; | |
44 | 38 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
45 | -import org.thingsboard.server.common.data.kv.DataType; | |
46 | 39 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
47 | -import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; | |
48 | -import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; | |
49 | -import org.thingsboard.server.common.data.transport.snmp.configs.RepeatingQueryingSnmpCommunicationConfig; | |
50 | -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig; | |
40 | +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; | |
41 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
42 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.ToDeviceRpcResponseQueryingSnmpCommunicationConfig; | |
51 | 43 | import org.thingsboard.server.common.transport.TransportService; |
52 | 44 | import org.thingsboard.server.common.transport.TransportServiceCallback; |
53 | 45 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
... | ... | @@ -60,44 +52,37 @@ import javax.annotation.PreDestroy; |
60 | 52 | import java.io.IOException; |
61 | 53 | import java.util.Collections; |
62 | 54 | import java.util.EnumMap; |
63 | -import java.util.HashMap; | |
64 | 55 | import java.util.List; |
65 | 56 | import java.util.Map; |
66 | -import java.util.Optional; | |
67 | 57 | import java.util.concurrent.ExecutorService; |
68 | 58 | import java.util.concurrent.Executors; |
69 | 59 | import java.util.concurrent.ScheduledExecutorService; |
70 | 60 | import java.util.concurrent.ScheduledFuture; |
71 | 61 | import java.util.concurrent.TimeUnit; |
72 | -import java.util.function.BiConsumer; | |
73 | 62 | import java.util.stream.Collectors; |
74 | 63 | |
75 | 64 | @TbSnmpTransportComponent |
76 | 65 | @Service |
77 | 66 | @Slf4j |
67 | +@RequiredArgsConstructor | |
78 | 68 | public class SnmpTransportService implements TbTransportService { |
79 | 69 | private final TransportService transportService; |
70 | + private final PduMapper pduMapper; | |
80 | 71 | |
81 | 72 | @Getter |
82 | 73 | private Snmp snmp; |
83 | 74 | private ScheduledExecutorService queryingExecutor; |
84 | 75 | private ExecutorService responseProcessingExecutor; |
85 | 76 | |
86 | - private final Map<SnmpCommunicationSpec, BiConsumer<JsonObject, DeviceSessionContext>> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); | |
77 | + private final Map<SnmpCommunicationSpec, ResponseProcessor> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); | |
87 | 78 | |
88 | 79 | @Value("${transport.snmp.response_processing.parallelism_level}") |
89 | 80 | private Integer responseProcessingParallelismLevel; |
90 | 81 | @Value("${transport.snmp.underlying_protocol}") |
91 | 82 | private String snmpUnderlyingProtocol; |
92 | 83 | |
93 | - public SnmpTransportService(TransportService transportService) { | |
94 | - this.transportService = transportService; | |
95 | - } | |
96 | - | |
97 | 84 | @PostConstruct |
98 | 85 | private void init() throws IOException { |
99 | - log.info("Initializing SNMP transport service"); | |
100 | - | |
101 | 86 | queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying")); |
102 | 87 | responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel); |
103 | 88 | |
... | ... | @@ -128,26 +113,23 @@ public class SnmpTransportService implements TbTransportService { |
128 | 113 | |
129 | 114 | public void createQueryingTasks(DeviceSessionContext sessionContext) { |
130 | 115 | List<ScheduledFuture<?>> queryingTasks = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() |
131 | - .filter(config -> config.getSpec().isRepeatingQuerying()) | |
116 | + .filter(communicationConfig -> communicationConfig instanceof RepeatingQueryingSnmpCommunicationConfig) | |
132 | 117 | .map(config -> { |
133 | 118 | RepeatingQueryingSnmpCommunicationConfig repeatingCommunicationConfig = (RepeatingQueryingSnmpCommunicationConfig) config; |
134 | - return createQueryingTaskForConfig(sessionContext, repeatingCommunicationConfig); | |
119 | + Long queryingFrequency = repeatingCommunicationConfig.getQueryingFrequencyMs(); | |
120 | + | |
121 | + return queryingExecutor.scheduleWithFixedDelay(() -> { | |
122 | + try { | |
123 | + if (sessionContext.isActive()) { | |
124 | + sendRequest(sessionContext, repeatingCommunicationConfig); | |
125 | + } | |
126 | + } catch (Exception e) { | |
127 | + log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); | |
128 | + } | |
129 | + }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); | |
135 | 130 | }) |
136 | 131 | .collect(Collectors.toList()); |
137 | - sessionContext.setQueryingTasks(queryingTasks); | |
138 | - } | |
139 | - | |
140 | - private ScheduledFuture<?> createQueryingTaskForConfig(DeviceSessionContext sessionContext, RepeatingQueryingSnmpCommunicationConfig communicationConfig) { | |
141 | - Long queryingFrequency = communicationConfig.getQueryingFrequencyMs(); | |
142 | - return queryingExecutor.scheduleWithFixedDelay(() -> { | |
143 | - try { | |
144 | - if (sessionContext.isActive()) { | |
145 | - sendRequest(sessionContext, communicationConfig); | |
146 | - } | |
147 | - } catch (Exception e) { | |
148 | - log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); | |
149 | - } | |
150 | - }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); | |
132 | + sessionContext.getQueryingTasks().addAll(queryingTasks); | |
151 | 133 | } |
152 | 134 | |
153 | 135 | public void cancelQueryingTasks(DeviceSessionContext sessionContext) { |
... | ... | @@ -155,67 +137,23 @@ public class SnmpTransportService implements TbTransportService { |
155 | 137 | sessionContext.getQueryingTasks().clear(); |
156 | 138 | } |
157 | 139 | |
158 | - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) throws IOException { | |
140 | + | |
141 | + public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { | |
159 | 142 | sendRequest(sessionContext, communicationConfig, Collections.emptyMap()); |
160 | 143 | } |
161 | 144 | |
162 | - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) throws IOException { | |
163 | - PDU request = createPdu(sessionContext, communicationConfig, values); | |
164 | - executeRequest(sessionContext, request); | |
165 | - } | |
145 | + public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | |
146 | + PDU request = pduMapper.createPdu(sessionContext, communicationConfig, values); | |
166 | 147 | |
167 | - private void executeRequest(DeviceSessionContext sessionContext, PDU request) throws IOException { | |
168 | 148 | if (request.size() > 0) { |
169 | 149 | log.trace("Executing SNMP request for device {}. Variables bindings: {}", sessionContext.getDeviceId(), request.getVariableBindings()); |
170 | - snmp.send(request, sessionContext.getTarget(), sessionContext.getDeviceProfile().getId(), sessionContext); | |
171 | - } | |
172 | - } | |
173 | - | |
174 | - private PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map<String, String> values) { | |
175 | - PDU pdu; | |
176 | - SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); | |
177 | - SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); | |
178 | - switch (snmpVersion) { | |
179 | - case V1: | |
180 | - case V2C: | |
181 | - pdu = new PDU(); | |
182 | - break; | |
183 | - case V3: | |
184 | - ScopedPDU scopedPdu = new ScopedPDU(); | |
185 | - scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); | |
186 | - scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); | |
187 | - pdu = scopedPdu; | |
188 | - break; | |
189 | - default: | |
190 | - throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); | |
150 | + RequestInfo requestInfo = new RequestInfo(sessionContext.getDeviceProfile().getId(), communicationConfig); | |
151 | + try { | |
152 | + snmp.send(request, sessionContext.getTarget(), requestInfo, sessionContext); | |
153 | + } catch (IOException e) { | |
154 | + log.error("Failed to send SNMP request to device {}: {}", sessionContext.getDeviceId(), e.toString()); | |
155 | + } | |
191 | 156 | } |
192 | - | |
193 | - pdu.setType(communicationConfig.getMethod().getCode()); | |
194 | - pdu.addAll(communicationConfig.getMappings().stream() | |
195 | - .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) | |
196 | - .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) | |
197 | - .map(value -> { | |
198 | - Variable variable; | |
199 | - switch (mapping.getDataType()) { | |
200 | - case LONG: | |
201 | - try { | |
202 | - variable = new Integer32(Integer.parseInt(value)); | |
203 | - break; | |
204 | - } catch (NumberFormatException ignored) { | |
205 | - } | |
206 | - case DOUBLE: | |
207 | - case BOOLEAN: | |
208 | - case STRING: | |
209 | - case JSON: | |
210 | - default: | |
211 | - variable = new OctetString(value); | |
212 | - } | |
213 | - return new VariableBinding(new OID(mapping.getOid()), variable); | |
214 | - }) | |
215 | - .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) | |
216 | - .collect(Collectors.toList())); | |
217 | - | |
218 | - return pdu; | |
219 | 157 | } |
220 | 158 | |
221 | 159 | |
... | ... | @@ -223,7 +161,7 @@ public class SnmpTransportService implements TbTransportService { |
223 | 161 | ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext); |
224 | 162 | |
225 | 163 | if (event.getError() != null) { |
226 | - log.warn("Response error: {}", event.getError().getMessage(), event.getError()); | |
164 | + log.warn("SNMP response error: {}", event.getError().toString()); | |
227 | 165 | return; |
228 | 166 | } |
229 | 167 | |
... | ... | @@ -232,108 +170,65 @@ public class SnmpTransportService implements TbTransportService { |
232 | 170 | log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID()); |
233 | 171 | return; |
234 | 172 | } |
235 | - DeviceProfileId deviceProfileId = (DeviceProfileId) event.getUserObject(); | |
236 | - log.debug("[{}] Processing SNMP response for device {} with device profile {}: {}", | |
237 | - response.getRequestID(), sessionContext.getDeviceId(), deviceProfileId, response); | |
238 | 173 | |
239 | - responseProcessingExecutor.execute(() -> processResponse(sessionContext, response)); | |
174 | + RequestInfo requestInfo = (RequestInfo) event.getUserObject(); | |
175 | + responseProcessingExecutor.execute(() -> { | |
176 | + processResponse(sessionContext, response, requestInfo); | |
177 | + }); | |
240 | 178 | } |
241 | 179 | |
242 | - private void processResponse(DeviceSessionContext sessionContext, PDU responsePdu) { | |
243 | - Map<OID, SnmpMapping> mappings = new HashMap<>(); | |
244 | - Map<OID, SnmpCommunicationConfig> configs = new HashMap<>(); | |
245 | - Map<SnmpCommunicationSpec, JsonObject> responses = new EnumMap<>(SnmpCommunicationSpec.class); | |
246 | - | |
247 | - for (SnmpCommunicationConfig config : sessionContext.getProfileTransportConfiguration().getCommunicationConfigs()) { | |
248 | - for (SnmpMapping mapping : config.getMappings()) { | |
249 | - OID oid = new OID(mapping.getOid()); | |
250 | - mappings.put(oid, mapping); | |
251 | - configs.put(oid, config); | |
252 | - } | |
253 | - responses.put(config.getSpec(), new JsonObject()); | |
254 | - } | |
255 | - | |
256 | - for (int i = 0; i < responsePdu.size(); i++) { | |
257 | - VariableBinding variableBinding = responsePdu.get(i); | |
258 | - log.trace("Processing variable binding {}: {}", i, variableBinding); | |
259 | - | |
260 | - if (variableBinding.getVariable() instanceof Null) { | |
261 | - log.debug("Response variable is empty"); | |
262 | - continue; | |
263 | - } | |
264 | - | |
265 | - OID oid = variableBinding.getOid(); | |
266 | - if (!mappings.containsKey(oid)) { | |
267 | - log.debug("No SNMP mapping for oid {}", oid); | |
268 | - continue; | |
269 | - } | |
270 | - | |
271 | - SnmpCommunicationSpec spec = configs.get(oid).getSpec(); | |
272 | - if (!responseProcessors.containsKey(spec)) { | |
273 | - log.debug("No response processor found for spec {}", spec); | |
274 | - continue; | |
275 | - } | |
276 | - | |
277 | - SnmpMapping mapping = mappings.get(oid); | |
278 | - processValue(mapping.getKey(), mapping.getDataType(), variableBinding.toValueString(), responses.get(spec)); | |
180 | + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) { | |
181 | + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationConfig().getSpec()); | |
182 | + if (responseProcessor == null) { | |
183 | + return; | |
279 | 184 | } |
280 | 185 | |
281 | - if (responses.values().stream().allMatch(response -> response.entrySet().isEmpty())) { | |
282 | - log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), responsePdu.getRequestID()); | |
186 | + JsonObject responseData = pduMapper.processPdu(response, sessionContext, requestInfo.getCommunicationConfig()); | |
187 | + if (responseData.entrySet().isEmpty()) { | |
188 | + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID()); | |
283 | 189 | return; |
284 | 190 | } |
285 | 191 | |
286 | - responses.forEach((spec, response) -> { | |
287 | - Optional.ofNullable(responseProcessors.get(spec)) | |
288 | - .ifPresent(responseProcessor -> { | |
289 | - if (!response.entrySet().isEmpty()) { | |
290 | - responseProcessor.accept(response, sessionContext); | |
291 | - } | |
292 | - }); | |
293 | - }); | |
294 | - | |
192 | + responseProcessor.process(responseData, sessionContext); | |
295 | 193 | reportActivity(sessionContext.getSessionInfo()); |
296 | 194 | } |
297 | 195 | |
298 | 196 | private void configureResponseProcessors() { |
299 | 197 | responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (response, sessionContext) -> { |
300 | 198 | TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(response); |
301 | - transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, TransportServiceCallback.EMPTY); | |
302 | - log.debug("Posted telemetry for device {}: {}", sessionContext.getDeviceId(), response); | |
199 | + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null); | |
200 | + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), response); | |
303 | 201 | }); |
304 | 202 | |
305 | 203 | responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (response, sessionContext) -> { |
306 | 204 | TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(response); |
307 | - transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, TransportServiceCallback.EMPTY); | |
308 | - log.debug("Posted attributes for device {}: {}", sessionContext.getDeviceId(), response); | |
205 | + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null); | |
206 | + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), response); | |
207 | + }); | |
208 | + | |
209 | + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_RESPONSE_QUERYING, (response, sessionContext) -> { | |
210 | + String rpcResponse = response.get(ToDeviceRpcResponseQueryingSnmpCommunicationConfig.RPC_RESPONSE_KEY_NAME).getAsString(); | |
211 | + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() | |
212 | + .setPayload(rpcResponse) | |
213 | + .build(); | |
214 | + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null); | |
215 | + log.debug("Processed RPC response from device {}: {}", sessionContext.getDeviceId(), rpcResponse); | |
309 | 216 | }); |
217 | + | |
218 | +// responseProcessors.put(, (response, sessionContext) -> { | |
219 | +// TransportProtos.ClaimDeviceMsg claimDeviceMsg = JsonConverter.convertToClaimDeviceProto(sessionContext.getDeviceId(), response); | |
220 | +// transportService.process(sessionContext.getSessionInfo(), claimDeviceMsg, null); | |
221 | +// }); | |
310 | 222 | } |
311 | 223 | |
312 | 224 | private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { |
313 | 225 | transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder() |
314 | - .setAttributeSubscription(false) | |
315 | - .setRpcSubscription(false) | |
226 | + .setAttributeSubscription(true) | |
227 | + .setRpcSubscription(true) | |
316 | 228 | .setLastActivityTime(System.currentTimeMillis()) |
317 | 229 | .build(), TransportServiceCallback.EMPTY); |
318 | 230 | } |
319 | 231 | |
320 | - private void processValue(String key, DataType dataType, String value, JsonObject result) { | |
321 | - if (StringUtils.isEmpty(value)) return; | |
322 | - | |
323 | - switch (dataType) { | |
324 | - case LONG: | |
325 | - result.addProperty(key, Long.parseLong(value)); | |
326 | - break; | |
327 | - case BOOLEAN: | |
328 | - result.addProperty(key, Boolean.parseBoolean(value)); | |
329 | - break; | |
330 | - case DOUBLE: | |
331 | - result.addProperty(key, Double.parseDouble(value)); | |
332 | - break; | |
333 | - default: | |
334 | - result.addProperty(key, value); | |
335 | - } | |
336 | - } | |
337 | 232 | |
338 | 233 | @Override |
339 | 234 | public String getName() { |
... | ... | @@ -358,4 +253,15 @@ public class SnmpTransportService implements TbTransportService { |
358 | 253 | } |
359 | 254 | log.info("SNMP transport stopped!"); |
360 | 255 | } |
256 | + | |
257 | + @Data | |
258 | + private static class RequestInfo { | |
259 | + private final DeviceProfileId deviceProfileId; | |
260 | + private final SnmpCommunicationConfig communicationConfig; | |
261 | + } | |
262 | + | |
263 | + private interface ResponseProcessor { | |
264 | + void process(JsonObject responseData, DeviceSessionContext sessionContext); | |
265 | + } | |
266 | + | |
361 | 267 | } | ... | ... |
... | ... | @@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfigu |
27 | 27 | import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; |
28 | 28 | import org.thingsboard.server.common.data.id.DeviceId; |
29 | 29 | import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; |
30 | +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; | |
31 | +import org.thingsboard.server.common.data.transport.snmp.config.impl.ToDeviceRpcCommandSettingSnmpCommunicationConfig; | |
30 | 32 | import org.thingsboard.server.common.transport.SessionMsgListener; |
31 | 33 | import org.thingsboard.server.common.transport.adaptor.JsonConverter; |
32 | 34 | import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; |
... | ... | @@ -36,13 +38,13 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse |
36 | 38 | import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; |
37 | 39 | import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; |
38 | 40 | import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; |
39 | -import org.thingsboard.server.transport.snmp.SnmpAuthService; | |
40 | 41 | import org.thingsboard.server.transport.snmp.SnmpTransportContext; |
41 | -import org.thingsboard.server.transport.snmp.service.SnmpTransportService; | |
42 | 42 | |
43 | +import java.io.IOException; | |
43 | 44 | import java.util.LinkedList; |
44 | 45 | import java.util.List; |
45 | 46 | import java.util.Map; |
47 | +import java.util.Optional; | |
46 | 48 | import java.util.UUID; |
47 | 49 | import java.util.concurrent.ScheduledFuture; |
48 | 50 | import java.util.concurrent.atomic.AtomicInteger; |
... | ... | @@ -64,16 +66,12 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S |
64 | 66 | |
65 | 67 | private final SnmpTransportContext snmpTransportContext; |
66 | 68 | |
67 | - @Getter | |
68 | - @Setter | |
69 | - private long previousRequestExecutedAt = 0; | |
70 | 69 | private final AtomicInteger msgIdSeq = new AtomicInteger(0); |
71 | 70 | @Getter |
72 | 71 | private boolean isActive = true; |
73 | 72 | |
74 | 73 | @Getter |
75 | - @Setter | |
76 | - private List<ScheduledFuture<?>> queryingTasks = new LinkedList<>(); | |
74 | + private final List<ScheduledFuture<?>> queryingTasks = new LinkedList<>(); | |
77 | 75 | |
78 | 76 | public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token, |
79 | 77 | SnmpDeviceProfileTransportConfiguration profileTransportConfiguration, |
... | ... | @@ -116,7 +114,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S |
116 | 114 | public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) throws Exception { |
117 | 115 | log.trace("Initializing target for SNMP session of device {}", device); |
118 | 116 | this.target = snmpTransportContext.getSnmpAuthService().setUpSnmpTarget(profileTransportConfig, deviceTransportConfig); |
119 | - log.info("SNMP target initialized: {}", target); | |
117 | + log.debug("SNMP target initialized: {}", target); | |
120 | 118 | } |
121 | 119 | |
122 | 120 | public void close() { |
... | ... | @@ -138,20 +136,14 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S |
138 | 136 | |
139 | 137 | @Override |
140 | 138 | public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) { |
141 | - profileTransportConfiguration.getCommunicationConfigs().stream() | |
142 | - .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) | |
143 | - .findFirst() | |
139 | + getCommunicationConfigForSpec(SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) | |
144 | 140 | .ifPresent(communicationConfig -> { |
145 | 141 | Map<String, String> sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream() |
146 | 142 | .collect(Collectors.toMap( |
147 | 143 | Map.Entry::getKey, |
148 | 144 | entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString() |
149 | 145 | )); |
150 | - try { | |
151 | - snmpTransportContext.getSnmpTransportService().sendRequest(this, communicationConfig, sharedAttributes); | |
152 | - } catch (Exception e) { | |
153 | - log.error("Failed to send request with shared attributes to SNMP device {}: {}", getDeviceId(), e.getMessage()); | |
154 | - } | |
146 | + snmpTransportContext.getSnmpTransportService().sendRequest(this, communicationConfig, sharedAttributes); | |
155 | 147 | }); |
156 | 148 | } |
157 | 149 | |
... | ... | @@ -161,9 +153,23 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S |
161 | 153 | |
162 | 154 | @Override |
163 | 155 | public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { |
156 | + getCommunicationConfigForSpec(SnmpCommunicationSpec.TO_DEVICE_RPC_COMMAND_SETTING) | |
157 | + .ifPresent(communicationConfig -> { | |
158 | + String value = JsonConverter.toJson(toDeviceRequest, true).toString(); | |
159 | + snmpTransportContext.getSnmpTransportService().sendRequest( | |
160 | + this, communicationConfig, | |
161 | + Map.of(ToDeviceRpcCommandSettingSnmpCommunicationConfig.RPC_COMMAND_KEY_NAME, value) | |
162 | + ); | |
163 | + }); | |
164 | 164 | } |
165 | 165 | |
166 | 166 | @Override |
167 | 167 | public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) { |
168 | 168 | } |
169 | + | |
170 | + private Optional<SnmpCommunicationConfig> getCommunicationConfigForSpec(SnmpCommunicationSpec spec) { | |
171 | + return profileTransportConfiguration.getCommunicationConfigs().stream() | |
172 | + .filter(config -> config.getSpec() == spec) | |
173 | + .findFirst(); | |
174 | + } | |
169 | 175 | } | ... | ... |