From 783b959577be49cbf020f379e09a0043dfcd95a9 Mon Sep 17 00:00:00 2001 From: Viacheslav Klimov Date: Wed, 14 Apr 2021 15:51:13 +0300 Subject: [PATCH] Refactor --- ...mpDeviceProfileTransportConfiguration.java | 11 +- .../transport/snmp/SnmpCommunicationSpec.java | 21 +- .../data/transport/snmp/SnmpMapping.java | 7 +- ...ltipleMappingsSnmpCommunicationConfig.java | 36 +++ ...eatingQueryingSnmpCommunicationConfig.java | 6 +- .../SnmpCommunicationConfig.java | 24 +- ...ibutesQueryingSnmpCommunicationConfig.java | 5 +- ...ributesSettingSnmpCommunicationConfig.java | 7 +- ...emetryQueryingSnmpCommunicationConfig.java | 5 +- ...CommandSettingSnmpCommunicationConfig.java | 59 +++++ ...sponseQueryingSnmpCommunicationConfig.java | 60 +++++ .../transport/snmp/SnmpTransportContext.java | 7 +- .../transport/snmp/service/PduMapper.java | 150 +++++++++++ .../snmp/{ => service}/SnmpAuthService.java | 8 +- .../snmp/service/SnmpTransportService.java | 244 ++++++------------ .../snmp/session/DeviceSessionContext.java | 38 +-- 16 files changed, 454 insertions(+), 234 deletions(-) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/MultipleMappingsSnmpCommunicationConfig.java rename common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/{configs => config}/RepeatingQueryingSnmpCommunicationConfig.java (88%) rename common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/{configs => config}/SnmpCommunicationConfig.java (75%) rename common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/{configs => config/impl}/ClientAttributesQueryingSnmpCommunicationConfig.java (89%) rename common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/{configs => config/impl}/SharedAttributesSettingSnmpCommunicationConfig.java (87%) rename common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/{configs => config/impl}/TelemetryQueryingSnmpCommunicationConfig.java (90%) create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcCommandSettingSnmpCommunicationConfig.java create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcResponseQueryingSnmpCommunicationConfig.java create mode 100644 common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduMapper.java rename common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/{ => service}/SnmpAuthService.java (94%) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SnmpDeviceProfileTransportConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SnmpDeviceProfileTransportConfiguration.java index 5d6afc7155..bbf074eeda 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SnmpDeviceProfileTransportConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/SnmpDeviceProfileTransportConfiguration.java @@ -17,16 +17,11 @@ package org.thingsboard.server.common.data.device.profile; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; -import org.apache.commons.lang3.ArrayUtils; import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; -import java.util.Collections; import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; @Data public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTransportConfiguration { @@ -51,7 +46,7 @@ public class SnmpDeviceProfileTransportConfiguration implements DeviceProfileTra return timeoutMs != null && timeoutMs >= 0 && retries != null && retries >= 0 && communicationConfigs != null && !communicationConfigs.isEmpty() && communicationConfigs.stream().allMatch(config -> config != null && config.isValid()) - && communicationConfigs.stream().flatMap(config -> config.getMappings().stream()).map(SnmpMapping::getOid) - .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getMappings().size()).sum(); + && communicationConfigs.stream().flatMap(config -> config.getAllMappings().stream()).map(SnmpMapping::getOid) + .distinct().count() == communicationConfigs.stream().mapToInt(config -> config.getAllMappings().size()).sum(); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpCommunicationSpec.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpCommunicationSpec.java index a2edf75968..a6643ecf1e 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpCommunicationSpec.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpCommunicationSpec.java @@ -16,22 +16,11 @@ package org.thingsboard.server.common.data.transport.snmp; public enum SnmpCommunicationSpec { - TELEMETRY_QUERYING(true), - CLIENT_ATTRIBUTES_QUERYING(true), + TELEMETRY_QUERYING, - SHARED_ATTRIBUTES_SETTING; + CLIENT_ATTRIBUTES_QUERYING, + SHARED_ATTRIBUTES_SETTING, - private final boolean isRepeatingQuerying; - - SnmpCommunicationSpec() { - this.isRepeatingQuerying = false; - } - - SnmpCommunicationSpec(boolean isRepeatingQuerying) { - this.isRepeatingQuerying = isRepeatingQuerying; - } - - public boolean isRepeatingQuerying() { - return isRepeatingQuerying; - } + TO_DEVICE_RPC_COMMAND_SETTING, + TO_DEVICE_RPC_RESPONSE_QUERYING } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java index 0269491461..d787f7446f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/SnmpMapping.java @@ -16,13 +16,17 @@ package org.thingsboard.server.common.data.transport.snmp; import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.thingsboard.server.common.data.kv.DataType; import java.util.regex.Pattern; @Data +@AllArgsConstructor +@NoArgsConstructor public class SnmpMapping { private String oid; private String key; @@ -32,7 +36,6 @@ public class SnmpMapping { @JsonIgnore public boolean isValid() { - return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && - StringUtils.isNotBlank(key) && dataType != null; + return StringUtils.isNotEmpty(oid) && OID_PATTERN.matcher(oid).matches() && StringUtils.isNotBlank(key); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/MultipleMappingsSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/MultipleMappingsSnmpCommunicationConfig.java new file mode 100644 index 0000000000..f785c8788d --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/MultipleMappingsSnmpCommunicationConfig.java @@ -0,0 +1,36 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.transport.snmp.config; + +import lombok.Data; +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; + +import java.util.List; + +@Data +public abstract class MultipleMappingsSnmpCommunicationConfig implements SnmpCommunicationConfig { + protected List mappings; + + @Override + public boolean isValid() { + return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid()); + } + + @Override + public List getAllMappings() { + return mappings; + } +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/RepeatingQueryingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/RepeatingQueryingSnmpCommunicationConfig.java similarity index 88% rename from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/RepeatingQueryingSnmpCommunicationConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/RepeatingQueryingSnmpCommunicationConfig.java index 19a009457a..38451d4142 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/RepeatingQueryingSnmpCommunicationConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/RepeatingQueryingSnmpCommunicationConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.transport.snmp.configs; +package org.thingsboard.server.common.data.transport.snmp.config; import lombok.Data; import lombok.EqualsAndHashCode; @@ -21,7 +21,7 @@ import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; @EqualsAndHashCode(callSuper = true) @Data -public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommunicationConfig { +public abstract class RepeatingQueryingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { private Long queryingFrequencyMs; @Override @@ -31,6 +31,6 @@ public abstract class RepeatingQueryingSnmpCommunicationConfig extends SnmpCommu @Override public boolean isValid() { - return super.isValid() && queryingFrequencyMs != null && queryingFrequencyMs > 0; + return queryingFrequencyMs != null && queryingFrequencyMs > 0 && super.isValid(); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/SnmpCommunicationConfig.java similarity index 75% rename from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SnmpCommunicationConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/SnmpCommunicationConfig.java index acc0df0dd7..e2ba29abfa 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SnmpCommunicationConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/SnmpCommunicationConfig.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.transport.snmp.configs; +package org.thingsboard.server.common.data.transport.snmp.config; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -23,6 +23,9 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; +import org.thingsboard.server.common.data.transport.snmp.config.impl.ClientAttributesQueryingSnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.impl.SharedAttributesSettingSnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.impl.TelemetryQueryingSnmpCommunicationConfig; import java.util.List; @@ -33,22 +36,19 @@ import java.util.List; @Type(value = ClientAttributesQueryingSnmpCommunicationConfig.class, name = "CLIENT_ATTRIBUTES_QUERYING"), @Type(value = SharedAttributesSettingSnmpCommunicationConfig.class, name = "SHARED_ATTRIBUTES_SETTING") }) -public abstract class SnmpCommunicationConfig { - protected List mappings; +public interface SnmpCommunicationConfig { - public List getMappings() { - return mappings; - } - - public abstract SnmpCommunicationSpec getSpec(); + SnmpCommunicationSpec getSpec(); @JsonIgnore - public SnmpMethod getMethod() { + default SnmpMethod getMethod() { return null; } @JsonIgnore - public boolean isValid() { - return mappings != null && !mappings.isEmpty() && mappings.stream().allMatch(mapping -> mapping != null && mapping.isValid()); - } + List getAllMappings(); + + @JsonIgnore + boolean isValid(); + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesQueryingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ClientAttributesQueryingSnmpCommunicationConfig.java similarity index 89% rename from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesQueryingSnmpCommunicationConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ClientAttributesQueryingSnmpCommunicationConfig.java index 16198f8ef6..51bd2198e9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/ClientAttributesQueryingSnmpCommunicationConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ClientAttributesQueryingSnmpCommunicationConfig.java @@ -13,13 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.transport.snmp.configs; +package org.thingsboard.server.common.data.transport.snmp.config.impl; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; public class ClientAttributesQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { + @Override public SnmpCommunicationSpec getSpec() { return SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING; } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SharedAttributesSettingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/SharedAttributesSettingSnmpCommunicationConfig.java similarity index 87% rename from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SharedAttributesSettingSnmpCommunicationConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/SharedAttributesSettingSnmpCommunicationConfig.java index 74c67f957a..441395d279 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/SharedAttributesSettingSnmpCommunicationConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/SharedAttributesSettingSnmpCommunicationConfig.java @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.transport.snmp.configs; +package org.thingsboard.server.common.data.transport.snmp.config.impl; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; +import org.thingsboard.server.common.data.transport.snmp.config.MultipleMappingsSnmpCommunicationConfig; + +public class SharedAttributesSettingSnmpCommunicationConfig extends MultipleMappingsSnmpCommunicationConfig { -public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunicationConfig { @Override public SnmpCommunicationSpec getSpec() { return SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING; @@ -28,4 +30,5 @@ public class SharedAttributesSettingSnmpCommunicationConfig extends SnmpCommunic public SnmpMethod getMethod() { return SnmpMethod.SET; } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryQueryingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/TelemetryQueryingSnmpCommunicationConfig.java similarity index 90% rename from common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryQueryingSnmpCommunicationConfig.java rename to common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/TelemetryQueryingSnmpCommunicationConfig.java index 68d3c81ed2..c3f82d64ec 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/configs/TelemetryQueryingSnmpCommunicationConfig.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/TelemetryQueryingSnmpCommunicationConfig.java @@ -13,17 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.common.data.transport.snmp.configs; +package org.thingsboard.server.common.data.transport.snmp.config.impl; import lombok.Data; import lombok.EqualsAndHashCode; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; @EqualsAndHashCode(callSuper = true) @Data public class TelemetryQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { + @Override public SnmpCommunicationSpec getSpec() { return SnmpCommunicationSpec.TELEMETRY_QUERYING; } + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcCommandSettingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcCommandSettingSnmpCommunicationConfig.java new file mode 100644 index 0000000000..97f3de047b --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcCommandSettingSnmpCommunicationConfig.java @@ -0,0 +1,59 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.transport.snmp.config.impl; + +import lombok.Data; +import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@Data +public class ToDeviceRpcCommandSettingSnmpCommunicationConfig implements SnmpCommunicationConfig { + private SnmpMapping mapping; + + @Override + public SnmpCommunicationSpec getSpec() { + return SnmpCommunicationSpec.TO_DEVICE_RPC_COMMAND_SETTING; + } + + @Override + public SnmpMethod getMethod() { + return SnmpMethod.SET; + } + + public void setMapping(SnmpMapping mapping) { + this.mapping = mapping != null ? new SnmpMapping(mapping.getOid(), RPC_COMMAND_KEY_NAME, DataType.STRING) : null; + } + + @Override + public List getAllMappings() { + return Collections.singletonList(mapping); + } + + @Override + public boolean isValid() { + return mapping != null && mapping.isValid(); + } + + public static final String RPC_COMMAND_KEY_NAME = "rpcCommand"; + +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcResponseQueryingSnmpCommunicationConfig.java b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcResponseQueryingSnmpCommunicationConfig.java new file mode 100644 index 0000000000..18bce94980 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/transport/snmp/config/impl/ToDeviceRpcResponseQueryingSnmpCommunicationConfig.java @@ -0,0 +1,60 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.common.data.transport.snmp.config.impl; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; +import org.thingsboard.server.common.data.transport.snmp.SnmpMethod; +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; + +import java.util.Collections; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ToDeviceRpcResponseQueryingSnmpCommunicationConfig extends RepeatingQueryingSnmpCommunicationConfig { + private SnmpMapping mapping; + + @Override + public SnmpCommunicationSpec getSpec() { + return SnmpCommunicationSpec.TO_DEVICE_RPC_RESPONSE_QUERYING; + } + + @Override + public SnmpMethod getMethod() { + return SnmpMethod.GET; + } + + public void setMapping(SnmpMapping mapping) { + this.mapping = mapping != null ? new SnmpMapping(mapping.getOid(), RPC_RESPONSE_KEY_NAME, DataType.STRING) : null; + } + + @Override + public List getAllMappings() { + return Collections.singletonList(mapping); + } + + @Override + public boolean isValid() { + return true; + } + + public static final String RPC_RESPONSE_KEY_NAME = "rpcResponse"; + +} diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java index d7441c7c1d..d66d09ab0b 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpTransportContext.java @@ -42,6 +42,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.queue.util.AfterStartUp; import org.thingsboard.server.queue.util.TbSnmpTransportComponent; import org.thingsboard.server.transport.snmp.service.ProtoTransportEntityService; +import org.thingsboard.server.transport.snmp.service.SnmpAuthService; import org.thingsboard.server.transport.snmp.service.SnmpTransportBalancingService; import org.thingsboard.server.transport.snmp.service.SnmpTransportService; import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; @@ -116,7 +117,7 @@ public class SnmpTransportContext extends TransportContext { ); registerSessionMsgListener(deviceSessionContext); } catch (Exception e) { - log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.getMessage()); + log.error("Failed to establish session for SNMP device {}: {}", device.getId(), e.toString()); return; } sessions.put(device.getId(), deviceSessionContext); @@ -177,7 +178,9 @@ public class SnmpTransportContext extends TransportContext { ); transportService.registerAsyncSession(sessionInfo, deviceSessionContext); - transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), null); + transportService.process(sessionInfo, TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().build(), TransportServiceCallback.EMPTY); + transportService.process(sessionInfo, TransportProtos.SubscribeToRPCMsg.newBuilder().build(), TransportServiceCallback.EMPTY); + deviceSessionContext.setSessionInfo(sessionInfo); deviceSessionContext.setDeviceInfo(msg.getDeviceInfo()); } else { diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduMapper.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduMapper.java new file mode 100644 index 0000000000..a3b5f77dfb --- /dev/null +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/PduMapper.java @@ -0,0 +1,150 @@ +/** + * Copyright © 2016-2021 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.server.transport.snmp.service; + +import com.google.gson.JsonObject; +import lombok.extern.slf4j.Slf4j; +import org.snmp4j.PDU; +import org.snmp4j.ScopedPDU; +import org.snmp4j.smi.Integer32; +import org.snmp4j.smi.Null; +import org.snmp4j.smi.OID; +import org.snmp4j.smi.OctetString; +import org.snmp4j.smi.Variable; +import org.snmp4j.smi.VariableBinding; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; +import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; +import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; +import org.thingsboard.server.queue.util.TbSnmpTransportComponent; +import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +@TbSnmpTransportComponent +@Service +@Slf4j +public class PduMapper { + public PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map values) { + PDU pdu; + SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); + SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); + switch (snmpVersion) { + case V1: + case V2C: + pdu = new PDU(); + break; + case V3: + ScopedPDU scopedPdu = new ScopedPDU(); + scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); + scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); + pdu = scopedPdu; + break; + default: + throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); + } + + pdu.setType(communicationConfig.getMethod().getCode()); + pdu.addAll(communicationConfig.getAllMappings().stream() + .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) + .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) + .map(value -> { + Variable variable = toSnmpVariable(mapping, value); + return new VariableBinding(new OID(mapping.getOid()), variable); + }) + .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) + .collect(Collectors.toList())); + + return pdu; + } + + private Variable toSnmpVariable(SnmpMapping mapping, String value) { + Variable variable; + switch (mapping.getDataType()) { + case LONG: + try { + variable = new Integer32(Integer.parseInt(value)); + break; + } catch (NumberFormatException ignored) { + } + case DOUBLE: + case BOOLEAN: + case STRING: + case JSON: + default: + variable = new OctetString(value); + } + return variable; + } + + + public JsonObject processPdu(PDU pdu, DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { + List variablesBindings = IntStream.range(0, pdu.size()) + .mapToObj(pdu::get) + .filter(Objects::nonNull) + .filter(variableBinding -> !(variableBinding.getVariable() instanceof Null)) + .collect(Collectors.toList()); + JsonObject data = new JsonObject(); + + Map mappings = new HashMap<>(); + for (SnmpMapping mapping : communicationConfig.getAllMappings()) { + OID oid = new OID(mapping.getOid()); + mappings.put(oid, mapping); + } + + variablesBindings.forEach(variableBinding -> { + log.trace("Processing variable binding: {}", variableBinding); + + OID oid = variableBinding.getOid(); + SnmpMapping mapping = mappings.get(oid); + if (mapping == null) { + log.debug("No SNMP mapping for oid {}", oid); + return; + } + + processValue(mapping.getKey(), mapping.getDataType(), variableBinding.toValueString(), data); + }); + + return data; + } + + + private void processValue(String key, DataType dataType, String value, JsonObject result) { + switch (dataType) { + case LONG: + result.addProperty(key, Long.parseLong(value)); + break; + case BOOLEAN: + result.addProperty(key, Boolean.parseBoolean(value)); + break; + case DOUBLE: + result.addProperty(key, Double.parseDouble(value)); + break; + case STRING: + case JSON: + default: + result.addProperty(key, value); + } + } +} diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpAuthService.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpAuthService.java similarity index 94% rename from common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpAuthService.java rename to common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpAuthService.java index 81187fb33e..c3ed188bb0 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/SnmpAuthService.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpAuthService.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.snmp; +package org.thingsboard.server.transport.snmp.service; import lombok.RequiredArgsConstructor; import org.snmp4j.AbstractTarget; @@ -24,6 +24,7 @@ import org.snmp4j.security.SecurityLevel; import org.snmp4j.security.SecurityModel; import org.snmp4j.security.SecurityProtocols; import org.snmp4j.security.USM; +import org.snmp4j.smi.Address; import org.snmp4j.smi.GenericAddress; import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; @@ -36,6 +37,8 @@ import org.thingsboard.server.queue.util.TbSnmpTransportComponent; import org.thingsboard.server.transport.snmp.service.SnmpTransportService; import org.thingsboard.server.transport.snmp.session.DeviceSessionContext; +import java.util.Optional; + @Service @TbSnmpTransportComponent @RequiredArgsConstructor @@ -97,7 +100,8 @@ public class SnmpAuthService { throw new UnsupportedOperationException("SNMP protocol version " + protocolVersion + " is not supported"); } - target.setAddress(GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort())); + Address address = GenericAddress.parse(snmpUnderlyingProtocol + ":" + deviceTransportConfig.getHost() + "/" + deviceTransportConfig.getPort()); + target.setAddress(Optional.ofNullable(address).orElseThrow(() -> new IllegalArgumentException("Address of the SNMP device is invalid"))); target.setTimeout(profileTransportConfig.getTimeoutMs()); target.setRetries(profileTransportConfig.getRetries()); target.setVersion(protocolVersion.getCode()); diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpTransportService.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpTransportService.java index 94a18f3d54..f672e36190 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpTransportService.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/service/SnmpTransportService.java @@ -16,11 +16,11 @@ package org.thingsboard.server.transport.snmp.service; import com.google.gson.JsonObject; +import lombok.Data; import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.snmp4j.PDU; -import org.snmp4j.ScopedPDU; import org.snmp4j.Snmp; import org.snmp4j.TransportMapping; import org.snmp4j.event.ResponseEvent; @@ -28,26 +28,18 @@ import org.snmp4j.mp.MPv3; import org.snmp4j.security.SecurityModels; import org.snmp4j.security.SecurityProtocols; import org.snmp4j.security.USM; -import org.snmp4j.smi.Integer32; -import org.snmp4j.smi.Null; -import org.snmp4j.smi.OID; import org.snmp4j.smi.OctetString; -import org.snmp4j.smi.Variable; -import org.snmp4j.smi.VariableBinding; import org.snmp4j.transport.DefaultTcpTransportMapping; import org.snmp4j.transport.DefaultUdpTransportMapping; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.TbTransportService; -import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceProfileId; -import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; -import org.thingsboard.server.common.data.transport.snmp.SnmpMapping; -import org.thingsboard.server.common.data.transport.snmp.SnmpProtocolVersion; -import org.thingsboard.server.common.data.transport.snmp.configs.RepeatingQueryingSnmpCommunicationConfig; -import org.thingsboard.server.common.data.transport.snmp.configs.SnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.RepeatingQueryingSnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.impl.ToDeviceRpcResponseQueryingSnmpCommunicationConfig; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; import org.thingsboard.server.common.transport.adaptor.JsonConverter; @@ -60,44 +52,37 @@ import javax.annotation.PreDestroy; import java.io.IOException; import java.util.Collections; import java.util.EnumMap; -import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -import java.util.function.BiConsumer; import java.util.stream.Collectors; @TbSnmpTransportComponent @Service @Slf4j +@RequiredArgsConstructor public class SnmpTransportService implements TbTransportService { private final TransportService transportService; + private final PduMapper pduMapper; @Getter private Snmp snmp; private ScheduledExecutorService queryingExecutor; private ExecutorService responseProcessingExecutor; - private final Map> responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); + private final Map responseProcessors = new EnumMap<>(SnmpCommunicationSpec.class); @Value("${transport.snmp.response_processing.parallelism_level}") private Integer responseProcessingParallelismLevel; @Value("${transport.snmp.underlying_protocol}") private String snmpUnderlyingProtocol; - public SnmpTransportService(TransportService transportService) { - this.transportService = transportService; - } - @PostConstruct private void init() throws IOException { - log.info("Initializing SNMP transport service"); - queryingExecutor = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), ThingsBoardThreadFactory.forName("snmp-querying")); responseProcessingExecutor = Executors.newWorkStealingPool(responseProcessingParallelismLevel); @@ -128,26 +113,23 @@ public class SnmpTransportService implements TbTransportService { public void createQueryingTasks(DeviceSessionContext sessionContext) { List> queryingTasks = sessionContext.getProfileTransportConfiguration().getCommunicationConfigs().stream() - .filter(config -> config.getSpec().isRepeatingQuerying()) + .filter(communicationConfig -> communicationConfig instanceof RepeatingQueryingSnmpCommunicationConfig) .map(config -> { RepeatingQueryingSnmpCommunicationConfig repeatingCommunicationConfig = (RepeatingQueryingSnmpCommunicationConfig) config; - return createQueryingTaskForConfig(sessionContext, repeatingCommunicationConfig); + Long queryingFrequency = repeatingCommunicationConfig.getQueryingFrequencyMs(); + + return queryingExecutor.scheduleWithFixedDelay(() -> { + try { + if (sessionContext.isActive()) { + sendRequest(sessionContext, repeatingCommunicationConfig); + } + } catch (Exception e) { + log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); + } + }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); }) .collect(Collectors.toList()); - sessionContext.setQueryingTasks(queryingTasks); - } - - private ScheduledFuture createQueryingTaskForConfig(DeviceSessionContext sessionContext, RepeatingQueryingSnmpCommunicationConfig communicationConfig) { - Long queryingFrequency = communicationConfig.getQueryingFrequencyMs(); - return queryingExecutor.scheduleWithFixedDelay(() -> { - try { - if (sessionContext.isActive()) { - sendRequest(sessionContext, communicationConfig); - } - } catch (Exception e) { - log.error("Failed to send SNMP request for device {}: {}", sessionContext.getDeviceId(), e.toString()); - } - }, queryingFrequency, queryingFrequency, TimeUnit.MILLISECONDS); + sessionContext.getQueryingTasks().addAll(queryingTasks); } public void cancelQueryingTasks(DeviceSessionContext sessionContext) { @@ -155,67 +137,23 @@ public class SnmpTransportService implements TbTransportService { sessionContext.getQueryingTasks().clear(); } - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) throws IOException { + + public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig) { sendRequest(sessionContext, communicationConfig, Collections.emptyMap()); } - public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map values) throws IOException { - PDU request = createPdu(sessionContext, communicationConfig, values); - executeRequest(sessionContext, request); - } + public void sendRequest(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map values) { + PDU request = pduMapper.createPdu(sessionContext, communicationConfig, values); - private void executeRequest(DeviceSessionContext sessionContext, PDU request) throws IOException { if (request.size() > 0) { log.trace("Executing SNMP request for device {}. Variables bindings: {}", sessionContext.getDeviceId(), request.getVariableBindings()); - snmp.send(request, sessionContext.getTarget(), sessionContext.getDeviceProfile().getId(), sessionContext); - } - } - - private PDU createPdu(DeviceSessionContext sessionContext, SnmpCommunicationConfig communicationConfig, Map values) { - PDU pdu; - SnmpDeviceTransportConfiguration deviceTransportConfiguration = sessionContext.getDeviceTransportConfiguration(); - SnmpProtocolVersion snmpVersion = deviceTransportConfiguration.getProtocolVersion(); - switch (snmpVersion) { - case V1: - case V2C: - pdu = new PDU(); - break; - case V3: - ScopedPDU scopedPdu = new ScopedPDU(); - scopedPdu.setContextName(new OctetString(deviceTransportConfiguration.getContextName())); - scopedPdu.setContextEngineID(new OctetString(deviceTransportConfiguration.getEngineId())); - pdu = scopedPdu; - break; - default: - throw new UnsupportedOperationException("SNMP version " + snmpVersion + " is not supported"); + RequestInfo requestInfo = new RequestInfo(sessionContext.getDeviceProfile().getId(), communicationConfig); + try { + snmp.send(request, sessionContext.getTarget(), requestInfo, sessionContext); + } catch (IOException e) { + log.error("Failed to send SNMP request to device {}: {}", sessionContext.getDeviceId(), e.toString()); + } } - - pdu.setType(communicationConfig.getMethod().getCode()); - pdu.addAll(communicationConfig.getMappings().stream() - .filter(mapping -> values.isEmpty() || values.containsKey(mapping.getKey())) - .map(mapping -> Optional.ofNullable(values.get(mapping.getKey())) - .map(value -> { - Variable variable; - switch (mapping.getDataType()) { - case LONG: - try { - variable = new Integer32(Integer.parseInt(value)); - break; - } catch (NumberFormatException ignored) { - } - case DOUBLE: - case BOOLEAN: - case STRING: - case JSON: - default: - variable = new OctetString(value); - } - return new VariableBinding(new OID(mapping.getOid()), variable); - }) - .orElseGet(() -> new VariableBinding(new OID(mapping.getOid())))) - .collect(Collectors.toList())); - - return pdu; } @@ -223,7 +161,7 @@ public class SnmpTransportService implements TbTransportService { ((Snmp) event.getSource()).cancel(event.getRequest(), sessionContext); if (event.getError() != null) { - log.warn("Response error: {}", event.getError().getMessage(), event.getError()); + log.warn("SNMP response error: {}", event.getError().toString()); return; } @@ -232,108 +170,65 @@ public class SnmpTransportService implements TbTransportService { log.debug("No response from SNMP device {}, requestId: {}", sessionContext.getDeviceId(), event.getRequest().getRequestID()); return; } - DeviceProfileId deviceProfileId = (DeviceProfileId) event.getUserObject(); - log.debug("[{}] Processing SNMP response for device {} with device profile {}: {}", - response.getRequestID(), sessionContext.getDeviceId(), deviceProfileId, response); - responseProcessingExecutor.execute(() -> processResponse(sessionContext, response)); + RequestInfo requestInfo = (RequestInfo) event.getUserObject(); + responseProcessingExecutor.execute(() -> { + processResponse(sessionContext, response, requestInfo); + }); } - private void processResponse(DeviceSessionContext sessionContext, PDU responsePdu) { - Map mappings = new HashMap<>(); - Map configs = new HashMap<>(); - Map responses = new EnumMap<>(SnmpCommunicationSpec.class); - - for (SnmpCommunicationConfig config : sessionContext.getProfileTransportConfiguration().getCommunicationConfigs()) { - for (SnmpMapping mapping : config.getMappings()) { - OID oid = new OID(mapping.getOid()); - mappings.put(oid, mapping); - configs.put(oid, config); - } - responses.put(config.getSpec(), new JsonObject()); - } - - for (int i = 0; i < responsePdu.size(); i++) { - VariableBinding variableBinding = responsePdu.get(i); - log.trace("Processing variable binding {}: {}", i, variableBinding); - - if (variableBinding.getVariable() instanceof Null) { - log.debug("Response variable is empty"); - continue; - } - - OID oid = variableBinding.getOid(); - if (!mappings.containsKey(oid)) { - log.debug("No SNMP mapping for oid {}", oid); - continue; - } - - SnmpCommunicationSpec spec = configs.get(oid).getSpec(); - if (!responseProcessors.containsKey(spec)) { - log.debug("No response processor found for spec {}", spec); - continue; - } - - SnmpMapping mapping = mappings.get(oid); - processValue(mapping.getKey(), mapping.getDataType(), variableBinding.toValueString(), responses.get(spec)); + private void processResponse(DeviceSessionContext sessionContext, PDU response, RequestInfo requestInfo) { + ResponseProcessor responseProcessor = responseProcessors.get(requestInfo.getCommunicationConfig().getSpec()); + if (responseProcessor == null) { + return; } - if (responses.values().stream().allMatch(response -> response.entrySet().isEmpty())) { - log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), responsePdu.getRequestID()); + JsonObject responseData = pduMapper.processPdu(response, sessionContext, requestInfo.getCommunicationConfig()); + if (responseData.entrySet().isEmpty()) { + log.debug("No values is the SNMP response for device {}. Request id: {}", sessionContext.getDeviceId(), response.getRequestID()); return; } - responses.forEach((spec, response) -> { - Optional.ofNullable(responseProcessors.get(spec)) - .ifPresent(responseProcessor -> { - if (!response.entrySet().isEmpty()) { - responseProcessor.accept(response, sessionContext); - } - }); - }); - + responseProcessor.process(responseData, sessionContext); reportActivity(sessionContext.getSessionInfo()); } private void configureResponseProcessors() { responseProcessors.put(SnmpCommunicationSpec.TELEMETRY_QUERYING, (response, sessionContext) -> { TransportProtos.PostTelemetryMsg postTelemetryMsg = JsonConverter.convertToTelemetryProto(response); - transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, TransportServiceCallback.EMPTY); - log.debug("Posted telemetry for device {}: {}", sessionContext.getDeviceId(), response); + transportService.process(sessionContext.getSessionInfo(), postTelemetryMsg, null); + log.debug("Posted telemetry for SNMP device {}: {}", sessionContext.getDeviceId(), response); }); responseProcessors.put(SnmpCommunicationSpec.CLIENT_ATTRIBUTES_QUERYING, (response, sessionContext) -> { TransportProtos.PostAttributeMsg postAttributesMsg = JsonConverter.convertToAttributesProto(response); - transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, TransportServiceCallback.EMPTY); - log.debug("Posted attributes for device {}: {}", sessionContext.getDeviceId(), response); + transportService.process(sessionContext.getSessionInfo(), postAttributesMsg, null); + log.debug("Posted attributes for SNMP device {}: {}", sessionContext.getDeviceId(), response); + }); + + responseProcessors.put(SnmpCommunicationSpec.TO_DEVICE_RPC_RESPONSE_QUERYING, (response, sessionContext) -> { + String rpcResponse = response.get(ToDeviceRpcResponseQueryingSnmpCommunicationConfig.RPC_RESPONSE_KEY_NAME).getAsString(); + TransportProtos.ToDeviceRpcResponseMsg rpcResponseMsg = TransportProtos.ToDeviceRpcResponseMsg.newBuilder() + .setPayload(rpcResponse) + .build(); + transportService.process(sessionContext.getSessionInfo(), rpcResponseMsg, null); + log.debug("Processed RPC response from device {}: {}", sessionContext.getDeviceId(), rpcResponse); }); + +// responseProcessors.put(, (response, sessionContext) -> { +// TransportProtos.ClaimDeviceMsg claimDeviceMsg = JsonConverter.convertToClaimDeviceProto(sessionContext.getDeviceId(), response); +// transportService.process(sessionContext.getSessionInfo(), claimDeviceMsg, null); +// }); } private void reportActivity(TransportProtos.SessionInfoProto sessionInfo) { transportService.process(sessionInfo, TransportProtos.SubscriptionInfoProto.newBuilder() - .setAttributeSubscription(false) - .setRpcSubscription(false) + .setAttributeSubscription(true) + .setRpcSubscription(true) .setLastActivityTime(System.currentTimeMillis()) .build(), TransportServiceCallback.EMPTY); } - private void processValue(String key, DataType dataType, String value, JsonObject result) { - if (StringUtils.isEmpty(value)) return; - - switch (dataType) { - case LONG: - result.addProperty(key, Long.parseLong(value)); - break; - case BOOLEAN: - result.addProperty(key, Boolean.parseBoolean(value)); - break; - case DOUBLE: - result.addProperty(key, Double.parseDouble(value)); - break; - default: - result.addProperty(key, value); - } - } @Override public String getName() { @@ -358,4 +253,15 @@ public class SnmpTransportService implements TbTransportService { } log.info("SNMP transport stopped!"); } + + @Data + private static class RequestInfo { + private final DeviceProfileId deviceProfileId; + private final SnmpCommunicationConfig communicationConfig; + } + + private interface ResponseProcessor { + void process(JsonObject responseData, DeviceSessionContext sessionContext); + } + } diff --git a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java index b3a38545a8..82fdc037ad 100644 --- a/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java +++ b/common/transport/snmp/src/main/java/org/thingsboard/server/transport/snmp/session/DeviceSessionContext.java @@ -27,6 +27,8 @@ import org.thingsboard.server.common.data.device.data.SnmpDeviceTransportConfigu import org.thingsboard.server.common.data.device.profile.SnmpDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.transport.snmp.SnmpCommunicationSpec; +import org.thingsboard.server.common.data.transport.snmp.config.SnmpCommunicationConfig; +import org.thingsboard.server.common.data.transport.snmp.config.impl.ToDeviceRpcCommandSettingSnmpCommunicationConfig; import org.thingsboard.server.common.transport.SessionMsgListener; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.common.transport.session.DeviceAwareSessionContext; @@ -36,13 +38,13 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeResponse import org.thingsboard.server.gen.transport.TransportProtos.SessionCloseNotificationProto; import org.thingsboard.server.gen.transport.TransportProtos.ToDeviceRpcRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToServerRpcResponseMsg; -import org.thingsboard.server.transport.snmp.SnmpAuthService; import org.thingsboard.server.transport.snmp.SnmpTransportContext; -import org.thingsboard.server.transport.snmp.service.SnmpTransportService; +import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicInteger; @@ -64,16 +66,12 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S private final SnmpTransportContext snmpTransportContext; - @Getter - @Setter - private long previousRequestExecutedAt = 0; private final AtomicInteger msgIdSeq = new AtomicInteger(0); @Getter private boolean isActive = true; @Getter - @Setter - private List> queryingTasks = new LinkedList<>(); + private final List> queryingTasks = new LinkedList<>(); public DeviceSessionContext(Device device, DeviceProfile deviceProfile, String token, SnmpDeviceProfileTransportConfiguration profileTransportConfiguration, @@ -116,7 +114,7 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S public void initializeTarget(SnmpDeviceProfileTransportConfiguration profileTransportConfig, SnmpDeviceTransportConfiguration deviceTransportConfig) throws Exception { log.trace("Initializing target for SNMP session of device {}", device); this.target = snmpTransportContext.getSnmpAuthService().setUpSnmpTarget(profileTransportConfig, deviceTransportConfig); - log.info("SNMP target initialized: {}", target); + log.debug("SNMP target initialized: {}", target); } public void close() { @@ -138,20 +136,14 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S @Override public void onAttributeUpdate(AttributeUpdateNotificationMsg attributeUpdateNotification) { - profileTransportConfiguration.getCommunicationConfigs().stream() - .filter(config -> config.getSpec() == SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) - .findFirst() + getCommunicationConfigForSpec(SnmpCommunicationSpec.SHARED_ATTRIBUTES_SETTING) .ifPresent(communicationConfig -> { Map sharedAttributes = JsonConverter.toJson(attributeUpdateNotification).entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, entry -> entry.getValue().isJsonPrimitive() ? entry.getValue().getAsString() : entry.getValue().toString() )); - try { - snmpTransportContext.getSnmpTransportService().sendRequest(this, communicationConfig, sharedAttributes); - } catch (Exception e) { - log.error("Failed to send request with shared attributes to SNMP device {}: {}", getDeviceId(), e.getMessage()); - } + snmpTransportContext.getSnmpTransportService().sendRequest(this, communicationConfig, sharedAttributes); }); } @@ -161,9 +153,23 @@ public class DeviceSessionContext extends DeviceAwareSessionContext implements S @Override public void onToDeviceRpcRequest(ToDeviceRpcRequestMsg toDeviceRequest) { + getCommunicationConfigForSpec(SnmpCommunicationSpec.TO_DEVICE_RPC_COMMAND_SETTING) + .ifPresent(communicationConfig -> { + String value = JsonConverter.toJson(toDeviceRequest, true).toString(); + snmpTransportContext.getSnmpTransportService().sendRequest( + this, communicationConfig, + Map.of(ToDeviceRpcCommandSettingSnmpCommunicationConfig.RPC_COMMAND_KEY_NAME, value) + ); + }); } @Override public void onToServerRpcResponse(ToServerRpcResponseMsg toServerResponse) { } + + private Optional getCommunicationConfigForSpec(SnmpCommunicationSpec spec) { + return profileTransportConfiguration.getCommunicationConfigs().stream() + .filter(config -> config.getSpec() == spec) + .findFirst(); + } }