From b53746bda6bf246f5ad9c28f31b746de739f068a Mon Sep 17 00:00:00 2001 From: desoliture Date: Tue, 28 Dec 2021 16:38:05 +0200 Subject: [PATCH 01/20] MQTT Gateway API attributes request fix --- .../transport/mqtt/adaptors/JsonMqttAdaptor.java | 12 +++++++++--- .../mqtt/session/GatewayDeviceSessionCtx.java | 6 ++++++ .../mqtt/session/GatewaySessionHandler.java | 6 ++++++ .../common/transport/adaptor/JsonConverter.java | 15 +++++++++------ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index dc2b74a8ea..0548fa08fb 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.transport.mqtt.session.GatewayDeviceSessionCtx; import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; import java.nio.charset.Charset; @@ -123,7 +124,12 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { - return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); + JsonObject request = ((GatewayDeviceSessionCtx) ctx) + .getPendingAttributesRequests() + .getOrDefault(responseMsg.getRequestId(), new JsonObject()); + boolean multipleAttrKeysRequested = + request.has("keys") && request.get("keys").getAsJsonArray().size() > 1; + return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg, multipleAttrKeysRequested); } @Override @@ -232,11 +238,11 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } } - private Optional processConvertFromGatewayAttributeResponseMsg(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { + private Optional processConvertFromGatewayAttributeResponseMsg(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttrKeysRequested) throws AdaptorException { if (!StringUtils.isEmpty(responseMsg.getError())) { throw new AdaptorException(responseMsg.getError()); } else { - JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg); + JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg, multipleAttrKeysRequested); return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, result)); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index f41c5668cd..593205b745 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.transport.mqtt.session; +import com.google.gson.JsonObject; import io.netty.channel.ChannelFuture; import io.netty.handler.codec.mqtt.MqttMessage; import lombok.extern.slf4j.Slf4j; @@ -27,6 +28,7 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; +import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; @@ -136,6 +138,10 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple // This feature is not supported in the TB IoT Gateway yet. } + public Map getPendingAttributesRequests() { + return parent.getPendingAttributesRequests(); + } + private boolean isAckExpected(MqttMessage message) { return message.fixedHeader().qosLevel().value() > 0; } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 7b45b5f9d9..4b4e986d5f 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -89,6 +89,7 @@ public class GatewaySessionHandler { private final ConcurrentMap mqttQoSMap; private final ChannelHandlerContext channel; private final DeviceSessionCtx deviceSessionCtx; + private final Map pendingAttributesRequests = new ConcurrentHashMap<>(); public GatewaySessionHandler(DeviceSessionCtx deviceSessionCtx, UUID sessionId) { this.context = deviceSessionCtx.getContext(); @@ -107,6 +108,10 @@ public class GatewaySessionHandler { return new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK); } + public Map getPendingAttributesRequests () { + return pendingAttributesRequests; + } + public void onDeviceConnect(MqttPublishMessage mqttMsg) throws AdaptorException { if (isJsonPayloadType()) { onDeviceConnectJson(mqttMsg); @@ -558,6 +563,7 @@ public class GatewaySessionHandler { if (json.isJsonObject()) { JsonObject jsonObj = json.getAsJsonObject(); int requestId = jsonObj.get("id").getAsInt(); + pendingAttributesRequests.put(requestId, jsonObj); String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString(); boolean clientScope = jsonObj.get("client").getAsBoolean(); Set keys; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java index be4143e388..86f90d786f 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java @@ -313,16 +313,19 @@ public class JsonConverter { return result; } - public static JsonObject getJsonObjectForGateway(String deviceName, TransportProtos.GetAttributeResponseMsg - responseMsg) { + public static JsonObject getJsonObjectForGateway( + String deviceName, + TransportProtos.GetAttributeResponseMsg responseMsg, + boolean multipleAttrKeysRequested + ) { JsonObject result = new JsonObject(); result.addProperty("id", responseMsg.getRequestId()); result.addProperty(DEVICE_PROPERTY, deviceName); if (responseMsg.getClientAttributeListCount() > 0) { - addValues(result, responseMsg.getClientAttributeListList()); + addValues(result, responseMsg.getClientAttributeListList(), multipleAttrKeysRequested); } if (responseMsg.getSharedAttributeListCount() > 0) { - addValues(result, responseMsg.getSharedAttributeListList()); + addValues(result, responseMsg.getSharedAttributeListList(), multipleAttrKeysRequested); } return result; } @@ -335,8 +338,8 @@ public class JsonConverter { return result; } - private static void addValues(JsonObject result, List kvList) { - if (kvList.size() == 1) { + private static void addValues(JsonObject result, List kvList, boolean multipleAttrKeysRequested) { + if (kvList.size() == 1 && !multipleAttrKeysRequested) { addValueToJson(result, "value", kvList.get(0).getKv()); } else { JsonObject values; From 2f5648c400122b02838ea11d650dc55056dc860c Mon Sep 17 00:00:00 2001 From: desoliture Date: Wed, 29 Dec 2021 17:22:32 +0200 Subject: [PATCH 02/20] refactoring --- .../server/transport/mqtt/adaptors/JsonMqttAdaptor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index 0548fa08fb..7aea8f3f91 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -43,6 +43,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Optional; import java.util.Set; +import java.util.Map; import java.util.UUID; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT; @@ -124,11 +125,12 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { - JsonObject request = ((GatewayDeviceSessionCtx) ctx) - .getPendingAttributesRequests() - .getOrDefault(responseMsg.getRequestId(), new JsonObject()); + Map pendingAttributesRequests = ((GatewayDeviceSessionCtx) ctx).getPendingAttributesRequests(); + int requestId = responseMsg.getRequestId(); + JsonObject request = pendingAttributesRequests.getOrDefault(requestId, new JsonObject()); boolean multipleAttrKeysRequested = request.has("keys") && request.get("keys").getAsJsonArray().size() > 1; + pendingAttributesRequests.remove(requestId); return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg, multipleAttrKeysRequested); } From 443bb2280fc62f0fbb4ba023d869e2855b7c233f Mon Sep 17 00:00:00 2001 From: desoliture Date: Fri, 31 Dec 2021 13:27:52 +0200 Subject: [PATCH 03/20] add corresponding test --- .../server/msa/AbstractContainerTest.java | 2 + .../connectivity/MqttGatewayClientTest.java | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java index 412cf3094b..e7dc6f2c44 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableMap; import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import lombok.extern.slf4j.Slf4j; import org.apache.cassandra.cql3.Json; import org.apache.commons.lang3.RandomStringUtils; @@ -69,6 +70,7 @@ public abstract class AbstractContainerTest { protected static String TB_TOKEN; protected static RestClient restClient; protected ObjectMapper mapper = new ObjectMapper(); + protected JsonParser jsonParser = new JsonParser(); @BeforeClass public static void before() throws Exception { diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java index 4e7b7cd05b..dfdc68d9d5 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java @@ -20,6 +20,7 @@ import com.google.common.collect.Sets; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.MoreExecutors; +import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import io.netty.buffer.ByteBuf; @@ -151,6 +152,76 @@ public class MqttGatewayClientTest extends AbstractContainerTest { Assert.assertTrue(verify(actualLatestTelemetry, "attr4", Long.toString(73))); } + @Test + public void responseDataOnAttributesRequestCheck() throws Exception { + Optional createdDeviceCredentials = restClient.getDeviceCredentialsByDeviceId(createdDevice.getId()); + Assert.assertTrue(createdDeviceCredentials.isPresent()); + WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); + JsonObject sharedAttributes = new JsonObject(); + sharedAttributes.addProperty("attr1", "value1"); + sharedAttributes.addProperty("attr2", true); + sharedAttributes.addProperty("attr3", 42.0); + sharedAttributes.addProperty("attr4", 73); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + ResponseEntity sharedAttributesResponse = restClient.getRestTemplate() + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/DEVICE/{deviceId}/SHARED_SCOPE", + mapper.readTree(sharedAttributes.toString()), ResponseEntity.class, + createdDevice.getId()); + Assert.assertTrue(sharedAttributesResponse.getStatusCode().is2xxSuccessful()); + var event = listener.getEvents().poll(10, TimeUnit.SECONDS); + + JsonObject requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + requestData.addProperty("key", "attr1"); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + + JsonObject responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + Assert.assertTrue(responseData.has("value")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("value").getAsString()); + + requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + JsonArray keys = new JsonArray(); + keys.add("attr1"); + keys.add("attr2"); + requestData.add("keys", keys); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + + Assert.assertTrue(responseData.has("values")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("values").getAsJsonObject().get("attr1").getAsString()); + Assert.assertEquals(sharedAttributes.get("attr2").getAsString(), responseData.get("values").getAsJsonObject().get("attr2").getAsString()); + + requestData = new JsonObject(); + requestData.addProperty("id", 1); + requestData.addProperty("device", createdDevice.getName()); + requestData.addProperty("client", false); + keys = new JsonArray(); + keys.add("attr1"); + keys.add("undefined"); + requestData.add("keys", keys); + + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(requestData.toString().getBytes())).get(); + event = listener.getEvents().poll(10, TimeUnit.SECONDS); + responseData = jsonParser.parse(Objects.requireNonNull(event).getMessage()).getAsJsonObject(); + + Assert.assertTrue(responseData.has("values")); + Assert.assertEquals(sharedAttributes.get("attr1").getAsString(), responseData.get("values").getAsJsonObject().get("attr1").getAsString()); + Assert.assertEquals(1, responseData.get("values").getAsJsonObject().entrySet().size()); + } + @Test public void requestAttributeValuesFromServer() throws Exception { WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); From 35c30b7678e90a7d53b94ca39a891903fa9f840b Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 13 Jan 2022 17:48:59 +0200 Subject: [PATCH 04/20] refactor GatewayDeviceSessionCtx and MqttAdaptors refactor GatewayDeviceSessionCtx to determine the value of multipleAttrKeysRequested before calling the JsonMqttAdaptor, add corresponding convertToGatewayPublish method to adaptors interface with multipleAttrKeysRequested parameter, refactor other adaptors to deal with new method --- .../mqtt/adaptors/BackwardCompatibilityAdaptor.java | 5 +++++ .../transport/mqtt/adaptors/JsonMqttAdaptor.java | 13 ++++++------- .../mqtt/adaptors/MqttTransportAdaptor.java | 3 +++ .../transport/mqtt/adaptors/ProtoMqttAdaptor.java | 5 +++++ .../mqtt/session/GatewayDeviceSessionCtx.java | 11 ++++++----- .../mqtt/session/GatewaySessionHandler.java | 7 +++++-- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java index a608d6c52d..0cc65da1b0 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -128,6 +128,11 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { return protoAdaptor.convertToGatewayPublish(ctx, deviceName, rpcRequest); } + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { + return protoAdaptor.convertToGatewayPublish(ctx, deviceName, responseMsg, multipleAttributeKeysRequested); + } + @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException { log.warn("[{}] invoked not implemented adaptor method! ToServerRpcResponseMsg: {} TopicBase: {}", ctx.getSessionId(), rpcResponse, topicBase); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index 7aea8f3f91..d71b87efdc 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -125,13 +125,12 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { - Map pendingAttributesRequests = ((GatewayDeviceSessionCtx) ctx).getPendingAttributesRequests(); - int requestId = responseMsg.getRequestId(); - JsonObject request = pendingAttributesRequests.getOrDefault(requestId, new JsonObject()); - boolean multipleAttrKeysRequested = - request.has("keys") && request.get("keys").getAsJsonArray().size() > 1; - pendingAttributesRequests.remove(requestId); - return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg, multipleAttrKeysRequested); + return convertToGatewayPublish(ctx, deviceName, responseMsg, false); + } + + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { + return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg, multipleAttributeKeysRequested); } @Override diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index 53ef439eda..a980e91b53 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -25,6 +25,7 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.adaptor.AdaptorException; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; @@ -72,6 +73,8 @@ public interface MqttTransportAdaptor { Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; + Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException; + Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index 4fa47b367d..4dc9a95d6b 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -209,6 +209,11 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_RPC_TOPIC, payloadBytes)); } + @Override + public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { + return convertToGatewayPublish(ctx, deviceName, responseMsg); + } + public static byte[] toBytes(ByteBuf inbound) { byte[] bytes = new byte[inbound.readableBytes()]; int readerIndex = inbound.readerIndex(); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index 593205b745..02324fd3e7 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.transport.mqtt.session; -import com.google.gson.JsonObject; import io.netty.channel.ChannelFuture; import io.netty.handler.codec.mqtt.MqttMessage; import lombok.extern.slf4j.Slf4j; @@ -28,7 +27,6 @@ import org.thingsboard.server.common.transport.auth.TransportDeviceInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; -import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentMap; @@ -82,7 +80,10 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @Override public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) { try { - parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), response).ifPresent(parent::writeAndFlush); + boolean multipleAttrKeysReq = isMultipleAttributeKeysRequested(response.getRequestId()); + parent.getPayloadAdaptor() + .convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), response, multipleAttrKeysReq) + .ifPresent(parent::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); } @@ -138,8 +139,8 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple // This feature is not supported in the TB IoT Gateway yet. } - public Map getPendingAttributesRequests() { - return parent.getPendingAttributesRequests(); + public boolean isMultipleAttributeKeysRequested(int requestId) { + return parent.isMultipleAttributeKeysRequested(requestId); } private boolean isAckExpected(MqttMessage message) { diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 4b4e986d5f..12e9f786bf 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -108,8 +108,11 @@ public class GatewaySessionHandler { return new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK); } - public Map getPendingAttributesRequests () { - return pendingAttributesRequests; + public boolean isMultipleAttributeKeysRequested(int requestId) { + JsonObject request = pendingAttributesRequests.getOrDefault(requestId, new JsonObject()); + boolean multipleAttributeKeysRequested = request.has("keys") && request.get("keys").getAsJsonArray().size() > 1; + pendingAttributesRequests.remove(requestId); + return multipleAttributeKeysRequested; } public void onDeviceConnect(MqttPublishMessage mqttMsg) throws AdaptorException { From 7b14fdaf5e0e6901a7a509299df744bb380fd63d Mon Sep 17 00:00:00 2001 From: desoliture Date: Mon, 17 Jan 2022 18:59:39 +0200 Subject: [PATCH 05/20] add isMultipleAttributesRequest field in queue.proto in GetAttributeResponseMsg message --- .../device/DeviceActorMessageProcessor.java | 3 +++ common/cluster-api/src/main/proto/queue.proto | 1 + .../adaptors/BackwardCompatibilityAdaptor.java | 5 ----- .../transport/mqtt/adaptors/JsonMqttAdaptor.java | 15 ++++----------- .../mqtt/adaptors/MqttTransportAdaptor.java | 3 --- .../transport/mqtt/adaptors/ProtoMqttAdaptor.java | 5 ----- .../mqtt/session/GatewayDeviceSessionCtx.java | 9 +-------- .../mqtt/session/GatewaySessionHandler.java | 9 --------- .../common/transport/adaptor/JsonConverter.java | 7 +++---- .../msa/connectivity/MqttGatewayClientTest.java | 1 - 10 files changed, 12 insertions(+), 46 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 20109ad074..bfcb95a71c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -450,6 +450,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { .setRequestId(requestId) .setSharedStateMsg(true) .addAllSharedAttributeList(toTsKvProtos(result)) + .setIsMultipleAttributesRequest(request.getSharedAttributeNamesCount() > 1) .build(); sendToTransport(responseMsg, sessionInfo); } @@ -471,6 +472,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { .setRequestId(requestId) .addAllClientAttributeList(toTsKvProtos(result.get(0))) .addAllSharedAttributeList(toTsKvProtos(result.get(1))) + .setIsMultipleAttributesRequest( + request.getSharedAttributeNamesCount() > 1 || request.getClientAttributeNamesCount() > 1) .build(); sendToTransport(responseMsg, sessionInfo); } diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index dca92c1c7a..6565a45740 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -149,6 +149,7 @@ message GetAttributeResponseMsg { int32 requestId = 1; repeated TsKvProto clientAttributeList = 2; repeated TsKvProto sharedAttributeList = 3; + bool isMultipleAttributesRequest = 4; string error = 5; bool sharedStateMsg = 6; } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java index 0cc65da1b0..a608d6c52d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/BackwardCompatibilityAdaptor.java @@ -128,11 +128,6 @@ public class BackwardCompatibilityAdaptor implements MqttTransportAdaptor { return protoAdaptor.convertToGatewayPublish(ctx, deviceName, rpcRequest); } - @Override - public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { - return protoAdaptor.convertToGatewayPublish(ctx, deviceName, responseMsg, multipleAttributeKeysRequested); - } - @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException { log.warn("[{}] invoked not implemented adaptor method! ToServerRpcResponseMsg: {} TopicBase: {}", ctx.getSessionId(), rpcResponse, topicBase); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java index d71b87efdc..8687b02f56 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/JsonMqttAdaptor.java @@ -34,7 +34,6 @@ import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.adaptor.AdaptorException; import org.thingsboard.server.common.transport.adaptor.JsonConverter; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.mqtt.session.GatewayDeviceSessionCtx; import org.thingsboard.server.transport.mqtt.session.MqttDeviceAwareSessionContext; import java.nio.charset.Charset; @@ -43,7 +42,6 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Optional; import java.util.Set; -import java.util.Map; import java.util.UUID; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_SOFTWARE_FIRMWARE_RESPONSES_TOPIC_FORMAT; @@ -125,14 +123,9 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { @Override public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { - return convertToGatewayPublish(ctx, deviceName, responseMsg, false); + return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg); } - - @Override - public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { - return processConvertFromGatewayAttributeResponseMsg(ctx, deviceName, responseMsg, multipleAttributeKeysRequested); - } - + @Override public Optional convertToPublish(MqttDeviceAwareSessionContext ctx, TransportProtos.AttributeUpdateNotificationMsg notificationMsg, String topic) { return Optional.of(createMqttPublishMsg(ctx, topic, JsonConverter.toJson(notificationMsg))); @@ -239,11 +232,11 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { } } - private Optional processConvertFromGatewayAttributeResponseMsg(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttrKeysRequested) throws AdaptorException { + private Optional processConvertFromGatewayAttributeResponseMsg(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) throws AdaptorException { if (!StringUtils.isEmpty(responseMsg.getError())) { throw new AdaptorException(responseMsg.getError()); } else { - JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg, multipleAttrKeysRequested); + JsonObject result = JsonConverter.getJsonObjectForGateway(deviceName, responseMsg); return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC, result)); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java index a980e91b53..53ef439eda 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/MqttTransportAdaptor.java @@ -25,7 +25,6 @@ import io.netty.handler.codec.mqtt.MqttPublishMessage; import io.netty.handler.codec.mqtt.MqttPublishVariableHeader; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.transport.adaptor.AdaptorException; -import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestMsg; @@ -73,8 +72,6 @@ public interface MqttTransportAdaptor { Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, ToDeviceRpcRequestMsg rpcRequest) throws AdaptorException; - Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException; - Optional convertToPublish(MqttDeviceAwareSessionContext ctx, ToServerRpcResponseMsg rpcResponse, String topicBase) throws AdaptorException; ProvisionDeviceRequestMsg convertToProvisionRequestMsg(MqttDeviceAwareSessionContext ctx, MqttPublishMessage inbound) throws AdaptorException; diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java index 4dc9a95d6b..4fa47b367d 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/adaptors/ProtoMqttAdaptor.java @@ -209,11 +209,6 @@ public class ProtoMqttAdaptor implements MqttTransportAdaptor { return Optional.of(createMqttPublishMsg(ctx, MqttTopics.GATEWAY_RPC_TOPIC, payloadBytes)); } - @Override - public Optional convertToGatewayPublish(MqttDeviceAwareSessionContext ctx, String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg, boolean multipleAttributeKeysRequested) throws AdaptorException { - return convertToGatewayPublish(ctx, deviceName, responseMsg); - } - public static byte[] toBytes(ByteBuf inbound) { byte[] bytes = new byte[inbound.readableBytes()]; int readerIndex = inbound.readerIndex(); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java index 02324fd3e7..f41c5668cd 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewayDeviceSessionCtx.java @@ -80,10 +80,7 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple @Override public void onGetAttributesResponse(TransportProtos.GetAttributeResponseMsg response) { try { - boolean multipleAttrKeysReq = isMultipleAttributeKeysRequested(response.getRequestId()); - parent.getPayloadAdaptor() - .convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), response, multipleAttrKeysReq) - .ifPresent(parent::writeAndFlush); + parent.getPayloadAdaptor().convertToGatewayPublish(this, getDeviceInfo().getDeviceName(), response).ifPresent(parent::writeAndFlush); } catch (Exception e) { log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); } @@ -139,10 +136,6 @@ public class GatewayDeviceSessionCtx extends MqttDeviceAwareSessionContext imple // This feature is not supported in the TB IoT Gateway yet. } - public boolean isMultipleAttributeKeysRequested(int requestId) { - return parent.isMultipleAttributeKeysRequested(requestId); - } - private boolean isAckExpected(MqttMessage message) { return message.fixedHeader().qosLevel().value() > 0; } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java index 12e9f786bf..7b45b5f9d9 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/GatewaySessionHandler.java @@ -89,7 +89,6 @@ public class GatewaySessionHandler { private final ConcurrentMap mqttQoSMap; private final ChannelHandlerContext channel; private final DeviceSessionCtx deviceSessionCtx; - private final Map pendingAttributesRequests = new ConcurrentHashMap<>(); public GatewaySessionHandler(DeviceSessionCtx deviceSessionCtx, UUID sessionId) { this.context = deviceSessionCtx.getContext(); @@ -108,13 +107,6 @@ public class GatewaySessionHandler { return new ConcurrentReferenceHashMap<>(16, ReferenceType.WEAK); } - public boolean isMultipleAttributeKeysRequested(int requestId) { - JsonObject request = pendingAttributesRequests.getOrDefault(requestId, new JsonObject()); - boolean multipleAttributeKeysRequested = request.has("keys") && request.get("keys").getAsJsonArray().size() > 1; - pendingAttributesRequests.remove(requestId); - return multipleAttributeKeysRequested; - } - public void onDeviceConnect(MqttPublishMessage mqttMsg) throws AdaptorException { if (isJsonPayloadType()) { onDeviceConnectJson(mqttMsg); @@ -566,7 +558,6 @@ public class GatewaySessionHandler { if (json.isJsonObject()) { JsonObject jsonObj = json.getAsJsonObject(); int requestId = jsonObj.get("id").getAsInt(); - pendingAttributesRequests.put(requestId, jsonObj); String deviceName = jsonObj.get(DEVICE_PROPERTY).getAsString(); boolean clientScope = jsonObj.get("client").getAsBoolean(); Set keys; diff --git a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java index 86f90d786f..1e6267ca33 100644 --- a/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java +++ b/common/transport/transport-api/src/main/java/org/thingsboard/server/common/transport/adaptor/JsonConverter.java @@ -315,17 +315,16 @@ public class JsonConverter { public static JsonObject getJsonObjectForGateway( String deviceName, - TransportProtos.GetAttributeResponseMsg responseMsg, - boolean multipleAttrKeysRequested + TransportProtos.GetAttributeResponseMsg responseMsg ) { JsonObject result = new JsonObject(); result.addProperty("id", responseMsg.getRequestId()); result.addProperty(DEVICE_PROPERTY, deviceName); if (responseMsg.getClientAttributeListCount() > 0) { - addValues(result, responseMsg.getClientAttributeListList(), multipleAttrKeysRequested); + addValues(result, responseMsg.getClientAttributeListList(), responseMsg.getIsMultipleAttributesRequest()); } if (responseMsg.getSharedAttributeListCount() > 0) { - addValues(result, responseMsg.getSharedAttributeListList(), multipleAttrKeysRequested); + addValues(result, responseMsg.getSharedAttributeListList(), responseMsg.getIsMultipleAttributesRequest()); } return result; } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java index dfdc68d9d5..74dfc2107c 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java @@ -156,7 +156,6 @@ public class MqttGatewayClientTest extends AbstractContainerTest { public void responseDataOnAttributesRequestCheck() throws Exception { Optional createdDeviceCredentials = restClient.getDeviceCredentialsByDeviceId(createdDevice.getId()); Assert.assertTrue(createdDeviceCredentials.isPresent()); - WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); JsonObject sharedAttributes = new JsonObject(); sharedAttributes.addProperty("attr1", "value1"); sharedAttributes.addProperty("attr2", true); From 634bf0ff0fcb47d8cef3d37a657b2dd044c4a475 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 18 Jan 2022 14:28:35 +0200 Subject: [PATCH 06/20] fixed NPE --- .../rule/engine/profile/AlarmRuleState.java | 44 +++++++++++++++++-- .../rule/engine/profile/AlarmState.java | 13 +++++- .../engine/profile/NumericParseException.java | 22 ++++++++++ 3 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 087e2256da..0c0768336d 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -229,7 +229,7 @@ class AlarmRuleState { long repeatingTimes = 0; AlarmConditionSpec alarmConditionSpec = getSpec(); AlarmConditionSpecType specType = alarmConditionSpec.getType(); - if(specType.equals(AlarmConditionSpecType.REPEATING)) { + if (specType.equals(AlarmConditionSpecType.REPEATING)) { RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec; repeatingTimes = repeating.getPredicate().getDefaultValue(); @@ -238,7 +238,13 @@ class AlarmRuleState { repeating.getPredicate().getDynamicValue().getSourceAttribute() != null) { EntityKeyValue repeatingKeyValue = getDynamicPredicateValue(data, repeating.getPredicate().getDynamicValue()); if (repeatingKeyValue != null) { - repeatingTimes = repeatingKeyValue.getLngValue(); + var longValue = getLongValue(repeatingKeyValue); + if (longValue != null) { + repeatingTimes = longValue; + } else { + String sourceAttribute = repeating.getPredicate().getDynamicValue().getSourceAttribute(); + throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(repeatingKeyValue))); + } } } } @@ -249,7 +255,7 @@ class AlarmRuleState { long durationTimeInMs = 0; AlarmConditionSpec alarmConditionSpec = getSpec(); AlarmConditionSpecType specType = alarmConditionSpec.getType(); - if(specType.equals(AlarmConditionSpecType.DURATION)) { + if (specType.equals(AlarmConditionSpecType.DURATION)) { DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec; TimeUnit timeUnit = duration.getUnit(); @@ -259,7 +265,13 @@ class AlarmRuleState { duration.getPredicate().getDynamicValue().getSourceAttribute() != null) { EntityKeyValue durationKeyValue = getDynamicPredicateValue(data, duration.getPredicate().getDynamicValue()); if (durationKeyValue != null) { - durationTimeInMs = timeUnit.toMillis(durationKeyValue.getLngValue()); + var longValue = getLongValue(durationKeyValue); + if (longValue != null) { + durationTimeInMs = timeUnit.toMillis(longValue); + } else { + String sourceAttribute = duration.getPredicate().getDynamicValue().getSourceAttribute(); + throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(durationKeyValue))); + } } } } @@ -545,4 +557,28 @@ class AlarmRuleState { } } + private static Long getLongValue(EntityKeyValue ekv) { + switch (ekv.getDataType()) { + case LONG: + return ekv.getLngValue(); + case DOUBLE: + return ekv.getDblValue() != null ? ekv.getDblValue().longValue() : null; + case BOOLEAN: + return ekv.getBoolValue() != null ? (ekv.getBoolValue() ? 1 : 0L) : null; + case STRING: + try { + return Long.parseLong(ekv.getStrValue()); + } catch (RuntimeException e) { + return null; + } + case JSON: + try { + return Long.parseLong(ekv.getJsonValue()); + } catch (RuntimeException e) { + return null; + } + default: + return null; + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index 4e91dfc68e..3a9628dd56 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -51,6 +51,7 @@ import java.util.function.BiFunction; @Slf4j class AlarmState { + public static final String ERROR_MSG = "Failed to process alarm state for Device [%s]: %s"; private final ProfileState deviceProfile; private final EntityId originator; private DeviceProfileAlarm alarmDefinition; @@ -75,12 +76,20 @@ class AlarmState { lastMsgMetaData = msg.getMetaData(); lastMsgQueueName = msg.getQueueName(); this.dataSnapshot = data; - return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); + try { + return createOrClearAlarms(ctx, msg, data, update, AlarmRuleState::eval); + } catch (NumericParseException e) { + throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage())); + } } public boolean process(TbContext ctx, long ts) throws ExecutionException, InterruptedException { initCurrentAlarm(ctx); - return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot)); + try { + return createOrClearAlarms(ctx, null, ts, null, (alarmState, tsParam) -> alarmState.eval(tsParam, dataSnapshot)); + } catch (NumericParseException e) { + throw new RuntimeException(String.format(ERROR_MSG, originator.getId().toString(), e.getMessage())); + } } public boolean createOrClearAlarms(TbContext ctx, TbMsg msg, T data, SnapshotUpdate update, BiFunction evalFunction) { diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java new file mode 100644 index 0000000000..15d3e6e476 --- /dev/null +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/NumericParseException.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2022 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.rule.engine.profile; + +public class NumericParseException extends RuntimeException { + public NumericParseException(String message) { + super(message); + } +} From 4e1cbf5c1ebd741842e3b1ccd6d5e48837c17cd8 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 19 Jan 2022 12:50:22 +0200 Subject: [PATCH 07/20] Code review minor misc fixes --- .../server/service/ttl/EdgeEventsCleanUpService.java | 5 ++++- .../java/org/thingsboard/server/common/data/id/EdgeId.java | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java index 6ffe4324a0..c4ce4e49b2 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java @@ -28,6 +28,9 @@ import org.thingsboard.server.queue.util.TbCoreComponent; @Service public class EdgeEventsCleanUpService extends AbstractCleanUpService { + public static final String RANDOM_DELAY_INTERVAL_MS_EXPRESSION = + "#{T(org.apache.commons.lang3.RandomUtils).nextLong(0, ${sql.ttl.edge_events.execution_interval_ms})}"; + @Value("${sql.ttl.edge_events.edge_events_ttl}") private long ttl; @@ -41,7 +44,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { this.edgeEventService = edgeEventService; } - @Scheduled(initialDelayString = "${sql.ttl.edge_events.execution_interval_ms}", fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") + @Scheduled(initialDelayString = RANDOM_DELAY_INTERVAL_MS_EXPRESSION, fixedDelayString = "${sql.ttl.edge_events.execution_interval_ms}") public void cleanUp() { if (ttlTaskExecutionEnabled && isSystemTenantPartitionMine()) { edgeEventService.cleanupEvents(ttl); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java index c0fd1e529b..ff975059a1 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EdgeId.java @@ -32,8 +32,8 @@ public class EdgeId extends UUIDBased implements EntityId { super(id); } - public static EdgeId fromString(String integrationId) { - return new EdgeId(UUID.fromString(integrationId)); + public static EdgeId fromString(String edgeId) { + return new EdgeId(UUID.fromString(edgeId)); } @ApiModelProperty(position = 2, required = true, value = "string", example = "EDGE", allowableValues = "EDGE") From 0ba7b962830636525667c4f0d30150ffe0c94a7f Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 19 Jan 2022 13:15:08 +0200 Subject: [PATCH 08/20] Added @EqualsAndHashCode(callSuper = true) to @Data filter classes that exends --- .../thingsboard/server/common/data/query/AlarmDataPageLink.java | 2 ++ .../server/common/data/query/AssetSearchQueryFilter.java | 2 ++ .../server/common/data/query/DeviceSearchQueryFilter.java | 2 ++ .../server/common/data/query/EdgeSearchQueryFilter.java | 2 ++ .../server/common/data/query/EntityViewSearchQueryFilter.java | 2 ++ 5 files changed, 10 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java index ac97ab6d8a..ce20d367e3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.query; import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.Getter; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; @@ -26,6 +27,7 @@ import org.thingsboard.server.common.data.alarm.AlarmStatus; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) @AllArgsConstructor public class AlarmDataPageLink extends EntityDataPageLink { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java index e2db80d9b9..a79066c6c5 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java @@ -16,10 +16,12 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) public class AssetSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java index d6428ae72c..8c2b31a99f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java @@ -16,10 +16,12 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) public class DeviceSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java index 81daff3ef5..6988537d92 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java @@ -16,10 +16,12 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) public class EdgeSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java index 86974d14be..501200db7c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java @@ -16,10 +16,12 @@ package org.thingsboard.server.common.data.query; import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; @Data +@EqualsAndHashCode(callSuper = true) public class EntityViewSearchQueryFilter extends EntitySearchQueryFilter { @Override From f907ac16364cb92d51dafa97c8d93c211d279f7f Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 19 Jan 2022 15:07:25 +0200 Subject: [PATCH 09/20] Added @ToString(callSuper = true) to filter classes for correct log output --- .../thingsboard/server/common/data/query/AlarmDataPageLink.java | 2 ++ .../server/common/data/query/AssetSearchQueryFilter.java | 2 ++ .../server/common/data/query/DeviceSearchQueryFilter.java | 2 ++ .../server/common/data/query/EdgeSearchQueryFilter.java | 2 ++ .../server/common/data/query/EntityViewSearchQueryFilter.java | 2 ++ 5 files changed, 10 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java index ce20d367e3..9f41b1a6bc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AlarmDataPageLink.java @@ -20,6 +20,7 @@ import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.ToString; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; @@ -28,6 +29,7 @@ import java.util.List; @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) @AllArgsConstructor public class AlarmDataPageLink extends EntityDataPageLink { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java index a79066c6c5..951bbac030 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/AssetSearchQueryFilter.java @@ -17,11 +17,13 @@ package org.thingsboard.server.common.data.query; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class AssetSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java index 8c2b31a99f..ff93d31856 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/DeviceSearchQueryFilter.java @@ -17,11 +17,13 @@ package org.thingsboard.server.common.data.query; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class DeviceSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java index 6988537d92..25b87629ee 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EdgeSearchQueryFilter.java @@ -17,11 +17,13 @@ package org.thingsboard.server.common.data.query; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class EdgeSearchQueryFilter extends EntitySearchQueryFilter { @Override diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java index 501200db7c..47ff69c091 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/query/EntityViewSearchQueryFilter.java @@ -17,11 +17,13 @@ package org.thingsboard.server.common.data.query; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.List; @Data @EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) public class EntityViewSearchQueryFilter extends EntitySearchQueryFilter { @Override From 292220cddca44bc1e5c4748d5febf5ec9d4596b7 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 20 Jan 2022 09:41:36 +0200 Subject: [PATCH 10/20] updated Californium and Leshan versions --- .../coap/AbstractCoapIntegrationTest.java | 2 + ...AttributesUpdatesProtoIntegrationTest.java | 6 +-- ...tractCoapServerSideRpcIntegrationTest.java | 5 +- .../lwm2m/AbstractLwM2MIntegrationTest.java | 6 +-- .../transport/lwm2m/Lwm2mTestHelper.java | 8 ++-- .../transport/lwm2m/client/FwLwM2MDevice.java | 8 ++-- .../lwm2m/client/LwM2MTestClient.java | 43 +++-------------- .../client/LwM2mBinaryAppDataContainer.java | 19 ++++---- .../transport/lwm2m/client/LwM2mLocation.java | 13 +++-- .../lwm2m/client/LwM2mTemperatureSensor.java | 6 +-- .../lwm2m/client/SimpleLwM2MDevice.java | 6 +-- .../transport/lwm2m/client/SwLwM2MDevice.java | 12 +++-- .../ota/sql/OtaLwM2MIntegrationTest.java | 4 +- .../sql/RpcLwm2mIntegrationDiscoverTest.java | 4 +- .../server/coapserver/CoapServerService.java | 3 +- .../coapserver/DefaultCoapServerService.java | 37 ++++++++------- .../TbCoapDtlsCertificateVerifier.java | 17 +++---- .../TbCoapDtlsSessionInMemoryStorage.java | 11 +++-- .../server/coapserver/TbCoapDtlsSettings.java | 20 ++++---- .../TbCoapServerMessageDeliverer.java | 3 +- .../transport/coap/CoapTransportResource.java | 19 ++++---- .../transport/coap/TbCoapMessageObserver.java | 12 ++++- .../coap/client/SecureClientNoAuth.java | 6 ++- .../coap/client/SecureClientX509.java | 6 ++- .../LwM2MTransportBootstrapService.java | 11 +++-- ...LwM2MBootstrapConfigStoreTaskProvider.java | 16 +++---- ...{LwM2mVersion.java => TbLwM2mVersion.java} | 24 +++++----- .../TbLwM2MDtlsCertificateVerifier.java | 21 ++++----- .../server/DefaultLwM2mTransportService.java | 16 ++++--- .../lwm2m/server/LwM2MNetworkConfig.java | 47 ++++++++++--------- .../lwm2m/server/LwM2mServerListener.java | 19 ++++++-- .../server/LwM2mTransportCoapResource.java | 2 +- .../lwm2m/server/client/LwM2mClient.java | 6 +-- .../server/client/LwM2mClientContextImpl.java | 4 +- .../DefaultLwM2mDownlinkMsgHandler.java | 13 +++-- .../downlink/LwM2mDownlinkMsgHandler.java | 2 +- .../lwm2m/server/rpc/RpcDiscoverCallback.java | 7 ++- .../store/TbLwM2mRedisRegistrationStore.java | 6 ++- .../lwm2m/utils/LwM2MTransportUtil.java | 5 +- pom.xml | 4 +- 40 files changed, 251 insertions(+), 228 deletions(-) rename common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/{LwM2mVersion.java => TbLwM2mVersion.java} (70%) diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java index f44664c256..cc648d52d5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/AbstractCoapIntegrationTest.java @@ -52,6 +52,8 @@ import static org.junit.Assert.assertNotNull; @Slf4j public abstract class AbstractCoapIntegrationTest extends AbstractTransportIntegrationTest { + protected final byte[] EMPTY_PAYLOAD = new byte[0]; + protected CoapClient client; @Override diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java index d4dea4382a..3cf1884bc5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/attributes/updates/AbstractCoapAttributesUpdatesProtoIntegrationTest.java @@ -25,15 +25,13 @@ import org.thingsboard.server.common.data.CoapDeviceType; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.gen.transport.TransportProtos; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertTrue; @Slf4j @@ -88,7 +86,7 @@ public abstract class AbstractCoapAttributesUpdatesProtoIntegrationTest extends } protected void validateEmptyCurrentStateAttributesResponse(TestCoapCallback callback) throws InvalidProtocolBufferException { - assertNull(callback.getPayloadBytes()); + assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertNotNull(callback.getObserve()); assertEquals(CoAP.ResponseCode.CONTENT, callback.getResponseCode()); assertEquals(0, callback.getObserve().intValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java index 4ba151c857..d598a82ccb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/coap/rpc/AbstractCoapServerSideRpcIntegrationTest.java @@ -31,13 +31,12 @@ import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.msg.session.FeatureType; import org.thingsboard.server.transport.coap.AbstractCoapIntegrationTest; -import java.nio.charset.StandardCharsets; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -186,7 +185,7 @@ public abstract class AbstractCoapServerSideRpcIntegrationTest extends AbstractC } private void validateCurrentStateNotification(TestCoapCallback callback) { - assertNull(callback.getPayloadBytes()); + assertArrayEquals(EMPTY_PAYLOAD, callback.getPayloadBytes()); assertNotNull(callback.getObserve()); assertEquals(callback.getResponseCode(), CoAP.ResponseCode.VALID); assertEquals(0, callback.getObserve().intValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java index 44f9f3d52d..fd4c748f85 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/AbstractLwM2MIntegrationTest.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m; import com.fasterxml.jackson.core.type.TypeReference; import org.apache.commons.io.IOUtils; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.leshan.client.object.Security; import org.junit.After; import org.junit.Assert; @@ -174,7 +174,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest public void basicTestConnectionObserveTelemetry(Security security, LwM2MClientCredential credentials, - NetworkConfig coapConfig, + Configuration coapConfig, String endpoint) throws Exception { createDeviceProfile(TRANSPORT_CONFIGURATION); Device device = createDevice(credentials); @@ -259,7 +259,7 @@ public abstract class AbstractLwM2MIntegrationTest extends AbstractWebsocketTest this.resources = resources; } - public void createNewClient(Security security, NetworkConfig coapConfig, boolean isRpc, String endpoint) throws Exception { + public void createNewClient(Security security, Configuration coapConfig, boolean isRpc, String endpoint) throws Exception { clientDestroy(); client = new LwM2MTestClient(this.executor, endpoint); int clientPort = SocketUtils.findAvailableTcpPort(); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java index 29771e1db8..2d10c50bc4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/Lwm2mTestHelper.java @@ -15,9 +15,11 @@ */ package org.thingsboard.server.transport.lwm2m; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.leshan.client.object.Security; +import static org.eclipse.californium.core.config.CoapConfig.COAP_PORT; +import static org.eclipse.californium.core.config.CoapConfig.COAP_SECURE_PORT; import static org.eclipse.leshan.client.object.Security.noSec; public class Lwm2mTestHelper { @@ -32,10 +34,10 @@ public class Lwm2mTestHelper { public static final int SHORT_SERVER_ID = 123; public static final int SHORT_SERVER_ID_BS = 111; - public static final NetworkConfig SECURE_COAP_CONFIG = new NetworkConfig().setString("COAP_SECURE_PORT", Integer.toString(SECURE_PORT)); + public static final Configuration SECURE_COAP_CONFIG = new Configuration().set(COAP_SECURE_PORT, SECURE_PORT); public static final String SECURE_URI = "coaps://" + HOST + ":" + SECURE_PORT; public static final Security SECURITY = noSec("coap://"+ HOST +":" + PORT, SHORT_SERVER_ID); - public static final NetworkConfig COAP_CONFIG = new NetworkConfig().setString("COAP_PORT", Integer.toString(PORT)); + public static final Configuration COAP_CONFIG = new Configuration().set(COAP_PORT, PORT); // Models public static final String[] resources = new String[]{"0.xml", "1.xml", "2.xml", "3.xml", "5.xml", "6.xml", "9.xml", "19.xml", "3303.xml"}; diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java index 2b9df30df9..81159e6584 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/FwLwM2MDevice.java @@ -131,10 +131,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { try { state.set(1); - fireResourcesChange(3); + fireResourceChange(3); Thread.sleep(100); state.set(2); - fireResourcesChange(3); + fireResourceChange(3); } catch (Exception e) { } }, 100, TimeUnit.MILLISECONDS); @@ -144,10 +144,10 @@ public class FwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { try { state.set(3); - fireResourcesChange(3); + fireResourceChange(3); Thread.sleep(100); updateResult.set(1); - fireResourcesChange(5); + fireResourceChange(5); } catch (Exception e) { } }, 100, TimeUnit.MILLISECONDS); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java index 41248efd56..9180617846 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2MTestClient.java @@ -17,10 +17,7 @@ package org.thingsboard.server.transport.lwm2m.client; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.core.network.config.NetworkConfig; -import org.eclipse.californium.core.observe.ObservationStore; -import org.eclipse.californium.scandium.DTLSConnector; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.client.californium.LeshanClient; import org.eclipse.leshan.client.californium.LeshanClientBuilder; @@ -32,7 +29,6 @@ import org.eclipse.leshan.client.resource.DummyInstanceEnabler; import org.eclipse.leshan.client.resource.ObjectsInitializer; import org.eclipse.leshan.client.servers.ServerIdentity; import org.eclipse.leshan.core.ResponseCode; -import org.eclipse.leshan.core.californium.EndpointFactory; import org.eclipse.leshan.core.model.InvalidDDFFileException; import org.eclipse.leshan.core.model.LwM2mModel; import org.eclipse.leshan.core.model.ObjectLoader; @@ -44,15 +40,15 @@ import org.eclipse.leshan.core.request.BootstrapRequest; import org.eclipse.leshan.core.request.DeregisterRequest; import org.eclipse.leshan.core.request.RegisterRequest; import org.eclipse.leshan.core.request.UpdateRequest; -import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import org.junit.Assert; +import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import java.io.IOException; -import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledExecutorService; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; import static org.eclipse.leshan.core.LwM2mId.ACCESS_CONTROL; import static org.eclipse.leshan.core.LwM2mId.DEVICE; import static org.eclipse.leshan.core.LwM2mId.FIRMWARE; @@ -61,10 +57,10 @@ import static org.eclipse.leshan.core.LwM2mId.SECURITY; import static org.eclipse.leshan.core.LwM2mId.SERVER; import static org.eclipse.leshan.core.LwM2mId.SOFTWARE_MANAGEMENT; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.BINARY_APP_DATA_CONTAINER; -import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_0; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_1; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.OBJECT_INSTANCE_ID_12; +import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.TEMPERATURE_SENSOR; import static org.thingsboard.server.transport.lwm2m.Lwm2mTestHelper.resources; @@ -84,7 +80,7 @@ public class LwM2MTestClient { private LwM2MLocationParams locationParams; private LwM2mTemperatureSensor lwM2MTemperatureSensor; - public void init(Security security, NetworkConfig coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { + public void init(Security security, Configuration coapConfig, int port, boolean isRpc) throws InvalidDDFFileException, IOException { Assert.assertNull("client already initialized", client); List models = new ArrayList<>(); for (String resourceName : resources) { @@ -106,44 +102,19 @@ public class LwM2MTestClient { initializer.setInstancesForObject(LOCATION, new LwM2mLocation(locationParams.getLatitude(), locationParams.getLongitude(), locationParams.getScaleFactor(), executor, OBJECT_INSTANCE_ID_0)); initializer.setInstancesForObject(TEMPERATURE_SENSOR, lwM2MTemperatureSensor = new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_0), new LwM2mTemperatureSensor(executor, OBJECT_INSTANCE_ID_12)); - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedCipherSuitesOnly(true); - dtlsConfig.setClientOnly(); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(coapConfig); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, true); DefaultRegistrationEngineFactory engineFactory = new DefaultRegistrationEngineFactory(); engineFactory.setReconnectOnUpdate(false); engineFactory.setResumeOnConnect(true); - EndpointFactory endpointFactory = new EndpointFactory() { - - @Override - public CoapEndpoint createUnsecuredEndpoint(InetSocketAddress address, NetworkConfig coapConfig, - ObservationStore store) { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - builder.setInetSocketAddress(address); - builder.setNetworkConfig(coapConfig); - return builder.build(); - } - - @Override - public CoapEndpoint createSecuredEndpoint(DtlsConnectorConfig dtlsConfig, NetworkConfig coapConfig, - ObservationStore store) { - CoapEndpoint.Builder builder = new CoapEndpoint.Builder(); - DtlsConnectorConfig.Builder dtlsConfigBuilder = new DtlsConnectorConfig.Builder(dtlsConfig); - builder.setConnector(new DTLSConnector(dtlsConfigBuilder.build())); - builder.setNetworkConfig(coapConfig); - return builder.build(); - } - }; - - LeshanClientBuilder builder = new LeshanClientBuilder(endpoint); builder.setLocalAddress("0.0.0.0", port); builder.setObjects(initializer.createAll()); builder.setCoapConfig(coapConfig); builder.setDtlsConfig(dtlsConfig); builder.setRegistrationEngineFactory(engineFactory); - builder.setEndpointFactory(endpointFactory); builder.setSharedExecutor(executor); builder.setDecoder(new DefaultLwM2mDecoder(false)); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java index d8a54b59bd..a88c795f9c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mBinaryAppDataContainer.java @@ -81,8 +81,11 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements public LwM2mBinaryAppDataContainer(ScheduledExecutorService executorService, Integer id) { try { if (id != null) this.setId(id); - executorService.scheduleWithFixedDelay(() -> - fireResourcesChange(0, 2), 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN + executorService.scheduleWithFixedDelay(() -> { + fireResourceChange(0); + fireResourceChange(2); + } + , 1800000, 1800000, TimeUnit.MILLISECONDS); // 30 MIN } catch (Throwable e) { log.error("[{}]Throwable", e.toString()); e.printStackTrace(); @@ -126,23 +129,23 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements } case 1: setPriority((Integer) (value.getValue() instanceof Long ? ((Long) value.getValue()).intValue() : value.getValue())); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 2: setTimestamp(((Date) value.getValue()).getTime()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 3: setDescription((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 4: setDataFormat((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 5: setAppID((Integer) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); default: return super.write(identity, replace, resourceId, value); @@ -185,7 +188,7 @@ public class LwM2mBinaryAppDataContainer extends BaseInstanceEnabler implements try { if (value instanceof LwM2mMultipleResource) { if (replace || this.data == null) { - this.data = new HashMap<>(); + this.data = new HashMap<>(); } value.getInstances().values().forEach(v -> { this.data.put(v.getId(), (byte[]) v.getValue()); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java index 590f35e7e0..d9fef9eab3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mLocation.java @@ -74,8 +74,10 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { } this.scaleFactor = scaleFactor; timestamp = new Date(); - executorService.scheduleWithFixedDelay(() -> - fireResourcesChange(0, 1), 10000, 10000, TimeUnit.MILLISECONDS); + executorService.scheduleWithFixedDelay(() -> { + fireResourceChange(0); + fireResourceChange(1); + }, 10000, 10000, TimeUnit.MILLISECONDS); } catch (Throwable e) { log.error("[{}]Throwable", e.toString()); e.printStackTrace(); @@ -117,13 +119,16 @@ public class LwM2mLocation extends BaseInstanceEnabler implements Destroyable { private void moveLatitude(float delta) { latitude = latitude + delta * scaleFactor; timestamp = new Date(); - fireResourcesChange(0, 5); + fireResourceChange(0); + fireResourceChange(5); } private void moveLongitude(float delta) { longitude = longitude + delta * scaleFactor; timestamp = new Date(); - fireResourcesChange(1, 5); + fireResourceChange(1); + fireResourceChange(5); + } public float getLatitude() { diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java index 53060096f7..919d69d919 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/LwM2mTemperatureSensor.java @@ -93,10 +93,9 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr float delta = (RANDOM.nextInt(20) - 10) / 10f; currentTemp += delta; Integer changedResource = adjustMinMaxMeasuredValue(currentTemp); + fireResourceChange(5700); if (changedResource != null) { - fireResourcesChange(5700, changedResource); - } else { - fireResourcesChange(5700); + fireResourceChange(changedResource); } } @@ -127,5 +126,4 @@ public class LwM2mTemperatureSensor extends BaseInstanceEnabler implements Destr } - } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java index c14a473d63..37d93279bf 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SimpleLwM2MDevice.java @@ -18,6 +18,7 @@ package org.thingsboard.server.transport.lwm2m.client; import lombok.extern.slf4j.Slf4j; import org.eclipse.leshan.client.resource.BaseInstanceEnabler; import org.eclipse.leshan.client.servers.ServerIdentity; +import org.eclipse.leshan.core.Destroyable; import org.eclipse.leshan.core.model.ObjectModel; import org.eclipse.leshan.core.model.ResourceModel; import org.eclipse.leshan.core.node.LwM2mResource; @@ -25,7 +26,6 @@ import org.eclipse.leshan.core.response.ExecuteResponse; import org.eclipse.leshan.core.response.ReadResponse; import org.eclipse.leshan.core.response.WriteResponse; -import javax.security.auth.Destroyable; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; @@ -103,11 +103,11 @@ public class SimpleLwM2MDevice extends BaseInstanceEnabler implements Destroyabl return WriteResponse.notFound(); case 14: setUtcOffset((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); case 15: setTimezone((String) value.getValue()); - fireResourcesChange(resourceId); + fireResourceChange(resourceId); return WriteResponse.success(); default: return super.write(identity, replace, resourceId, value); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java index 0d3400c959..b623f4fa19 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/client/SwLwM2MDevice.java @@ -128,16 +128,17 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { try { state.set(1); updateResult.set(1); - fireResourcesChange(7, 9); + fireResourceChange(7); + fireResourceChange(9); Thread.sleep(100); state.set(2); - fireResourcesChange(7); + fireResourceChange(7); Thread.sleep(100); state.set(3); - fireResourcesChange(7); + fireResourceChange(7); Thread.sleep(100); updateResult.set(3); - fireResourcesChange(9); + fireResourceChange(9); } catch (Exception e) { } @@ -148,7 +149,8 @@ public class SwLwM2MDevice extends BaseInstanceEnabler implements Destroyable { scheduler.schedule(() -> { state.set(4); updateResult.set(2); - fireResourcesChange(7, 9); + fireResourceChange(7); + fireResourceChange(9); }, 100, TimeUnit.MILLISECONDS); } diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java index f3cb4e5770..3095f28f28 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/ota/sql/OtaLwM2MIntegrationTest.java @@ -201,9 +201,9 @@ public class OtaLwM2MIntegrationTest extends AbstractOtaLwM2MIntegrationTest { @Test public void testSoftwareUpdateByObject9() throws Exception { createDeviceProfile(OTA_TRANSPORT_CONFIGURATION); - NoSecClientCredential credentials = createNoSecClientCredentials(this.CLIENT_ENDPOINT_OTA9); + NoSecClientCredential credentials = createNoSecClientCredentials(CLIENT_ENDPOINT_OTA9); final Device device = createDevice(credentials); - createNewClient(SECURITY, COAP_CONFIG, false, this.CLIENT_ENDPOINT_OTA9); + createNewClient(SECURITY, COAP_CONFIG, false, CLIENT_ENDPOINT_OTA9); Thread.sleep(1000); diff --git a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java index 9cea6a8380..a4870b3486 100644 --- a/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/lwm2m/rpc/sql/RpcLwm2mIntegrationDiscoverTest.java @@ -52,8 +52,8 @@ public class RpcLwm2mIntegrationDiscoverTest extends AbstractRpcLwM2MIntegration Set actualObjects = ConcurrentHashMap.newKeySet(); Set actualInstances = ConcurrentHashMap.newKeySet(); rpcActualValue.forEach(node -> { - if (!node.get("url").asText().equals("/")) { - LwM2mPath path = new LwM2mPath(node.get("url").asText()); + if (!node.get("uriReference").asText().equals("/")) { + LwM2mPath path = new LwM2mPath(node.get("uriReference").asText()); actualObjects.add("/" + path.getObjectId()); if (path.isObjectInstance()) { actualInstances.add("/" + path.getObjectId() + "/" + path.getObjectInstanceId()); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java index 1f312da533..8dbbc5a620 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.coapserver; import org.eclipse.californium.core.CoapServer; +import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.concurrent.ConcurrentMap; @@ -24,7 +25,7 @@ public interface CoapServerService { CoapServer getCoapServer() throws UnknownHostException; - ConcurrentMap getDtlsSessionsMap(); + ConcurrentMap getDtlsSessionsMap(); long getTimeout(); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java index 25dfade5a3..3aa0d0c122 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java @@ -18,8 +18,9 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.CoapServer; import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.core.network.config.NetworkConfig; +import org.eclipse.californium.core.config.CoapConfig; import org.eclipse.californium.core.server.resources.Resource; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.springframework.beans.factory.annotation.Autowired; @@ -37,7 +38,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; +import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS; @Slf4j @Component @@ -78,8 +79,8 @@ public class DefaultCoapServerService implements CoapServerService { } @Override - public ConcurrentMap getDtlsSessionsMap() { - return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionIdsMap() : null; + public ConcurrentMap getDtlsSessionsMap() { + return tbDtlsCertificateVerifier != null ? tbDtlsCertificateVerifier.getTbCoapDtlsSessionsMap() : null; } @Override @@ -88,16 +89,16 @@ public class DefaultCoapServerService implements CoapServerService { } private CoapServer createCoapServer() throws UnknownHostException { - NetworkConfig networkConfig = new NetworkConfig(); - networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); - networkConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); - networkConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); - networkConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); - networkConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); - networkConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); - networkConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); - networkConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 4); - networkConfig.setInt(NetworkConfig.Keys.COAP_PORT, coapServerContext.getPort()); + Configuration networkConfig = new Configuration(); + networkConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); + networkConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); + networkConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS); + networkConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); + networkConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED); + networkConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024); + networkConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024); + networkConfig.set(CoapConfig.MAX_RETRANSMIT, 4); + networkConfig.set(CoapConfig.COAP_PORT, coapServerContext.getPort()); server = new CoapServer(networkConfig); CoapEndpoint.Builder noSecCoapEndpointBuilder = new CoapEndpoint.Builder(); @@ -105,15 +106,15 @@ public class DefaultCoapServerService implements CoapServerService { InetSocketAddress sockAddr = new InetSocketAddress(addr, coapServerContext.getPort()); noSecCoapEndpointBuilder.setInetSocketAddress(sockAddr); - noSecCoapEndpointBuilder.setNetworkConfig(networkConfig); + noSecCoapEndpointBuilder.setConfiguration(networkConfig); CoapEndpoint noSecCoapEndpoint = noSecCoapEndpointBuilder.build(); server.addEndpoint(noSecCoapEndpoint); if (isDtlsEnabled()) { CoapEndpoint.Builder dtlsCoapEndpointBuilder = new CoapEndpoint.Builder(); TbCoapDtlsSettings dtlsSettings = coapServerContext.getDtlsSettings(); - DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(); - networkConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort()); - dtlsCoapEndpointBuilder.setNetworkConfig(networkConfig); + DtlsConnectorConfig dtlsConnectorConfig = dtlsSettings.dtlsConnectorConfig(networkConfig); + networkConfig.set(CoapConfig.COAP_SECURE_PORT, dtlsConnectorConfig.getAddress().getPort()); + dtlsCoapEndpointBuilder.setConfiguration(networkConfig); DTLSConnector connector = new DTLSConnector(dtlsConnectorConfig); dtlsCoapEndpointBuilder.setConnector(connector); CoapEndpoint dtlsCoapEndpoint = dtlsCoapEndpointBuilder.build(); diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java index 1954ae900e..ce8b093b4d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsCertificateVerifier.java @@ -23,7 +23,6 @@ import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.ConnectionId; -import org.eclipse.californium.scandium.dtls.DTLSSession; import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; @@ -34,13 +33,13 @@ import org.thingsboard.server.common.data.DeviceTransportType; import org.thingsboard.server.common.msg.EncryptionUtil; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.TransportServiceCallback; -import org.thingsboard.server.common.transport.auth.SessionInfoCreator; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.common.transport.util.SslUtil; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import javax.security.auth.x500.X500Principal; +import java.net.InetSocketAddress; import java.security.cert.CertPath; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateExpiredException; @@ -48,7 +47,6 @@ import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.List; -import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -71,12 +69,12 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri } @Override - public List getSupportedCertificateType() { + public List getSupportedCertificateTypes() { return Collections.singletonList(CertificateType.X_509); } @Override - public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) { try { CertPath certpath = message.getCertificateChain(); X509Certificate[] chain = certpath.getCertificates().toArray(new X509Certificate[0]); @@ -111,7 +109,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri if (msg != null && strCert.equals(msg.getCredentials())) { DeviceProfile deviceProfile = msg.getDeviceProfile(); if (msg.hasDeviceInfo() && deviceProfile != null) { - tbCoapDtlsSessionInMemoryStorage.put(session.getSessionIdentifier().toString(), new TbCoapDtlsSessionInfo(msg, deviceProfile)); + tbCoapDtlsSessionInMemoryStorage.put(remotePeer, new TbCoapDtlsSessionInfo(msg, deviceProfile)); } break; } @@ -120,8 +118,7 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri CertificateExpiredException | CertificateNotYetValidException e) { log.error(e.getMessage(), e); - AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE, - session.getPeer()); + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.BAD_CERTIFICATE); throw new HandshakeException("Certificate chain could not be validated", alert); } } @@ -141,8 +138,8 @@ public class TbCoapDtlsCertificateVerifier implements NewAdvancedCertificateVeri public void setResultHandler(HandshakeResultHandler resultHandler) { } - public ConcurrentMap getTbCoapDtlsSessionIdsMap() { - return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionIdMap(); + public ConcurrentMap getTbCoapDtlsSessionsMap() { + return tbCoapDtlsSessionInMemoryStorage.getDtlsSessionsMap(); } public void evictTimeoutSessions() { diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java index 085bd035ca..8584246f0d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSessionInMemoryStorage.java @@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import java.net.InetSocketAddress; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -25,7 +26,7 @@ import java.util.concurrent.ConcurrentMap; @Data public class TbCoapDtlsSessionInMemoryStorage { - private final ConcurrentMap dtlsSessionIdMap = new ConcurrentHashMap<>(); + private final ConcurrentMap dtlsSessionsMap = new ConcurrentHashMap<>(); private long dtlsSessionInactivityTimeout; private long dtlsSessionReportTimeout; @@ -35,14 +36,14 @@ public class TbCoapDtlsSessionInMemoryStorage { this.dtlsSessionReportTimeout = dtlsSessionReportTimeout; } - public void put(String dtlsSessionId, TbCoapDtlsSessionInfo dtlsSessionInfo) { - log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", dtlsSessionId, dtlsSessionInfo.getLastActivityTime()); - dtlsSessionIdMap.putIfAbsent(dtlsSessionId, dtlsSessionInfo); + public void put(InetSocketAddress remotePeer, TbCoapDtlsSessionInfo dtlsSessionInfo) { + log.trace("DTLS session added to in-memory store: [{}] timestamp: [{}]", remotePeer, dtlsSessionInfo.getLastActivityTime()); + dtlsSessionsMap.putIfAbsent(remotePeer, dtlsSessionInfo); } public void evictTimeoutSessions() { long expTime = System.currentTimeMillis() - dtlsSessionInactivityTimeout; - dtlsSessionIdMap.entrySet().removeIf(entry -> { + dtlsSessionsMap.entrySet().removeIf(entry -> { if (entry.getValue().getLastActivityTime() < expTime) { log.trace("DTLS session was removed from in-memory store: [{}]", entry.getKey()); return true; diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java index ff778b57ab..7d5c17bf6d 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapDtlsSettings.java @@ -16,9 +16,13 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.elements.config.CertificateAuthenticationMode; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.util.SslContextUtil; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; @@ -26,17 +30,14 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.ResourceUtils; import org.thingsboard.server.common.transport.TransportService; import org.thingsboard.server.common.transport.config.ssl.SslCredentials; import org.thingsboard.server.common.transport.config.ssl.SslCredentialsConfig; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; -import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; -import java.security.GeneralSecurityException; import java.util.Collections; @Slf4j @@ -75,15 +76,14 @@ public class TbCoapDtlsSettings { @Autowired private TbServiceInfoProvider serviceInfoProvider; - public DtlsConnectorConfig dtlsConnectorConfig() throws UnknownHostException { - DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(); + public DtlsConnectorConfig dtlsConnectorConfig(Configuration configuration) throws UnknownHostException { + DtlsConnectorConfig.Builder configBuilder = new DtlsConnectorConfig.Builder(configuration); configBuilder.setAddress(getInetSocketAddress()); SslCredentials sslCredentials = this.coapDtlsCredentialsConfig.getCredentials(); SslContextUtil.Credentials serverCredentials = new SslContextUtil.Credentials(sslCredentials.getPrivateKey(), null, sslCredentials.getCertificateChain()); - configBuilder.setServerOnly(true); - configBuilder.setClientAuthenticationRequired(false); - configBuilder.setClientAuthenticationWanted(true); + configBuilder.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); + configBuilder.set(DtlsConfig.DTLS_CLIENT_AUTHENTICATION_MODE, CertificateAuthenticationMode.WANTED); configBuilder.setAdvancedCertificateVerifier( new TbCoapDtlsCertificateVerifier( transportService, @@ -93,8 +93,8 @@ public class TbCoapDtlsSettings { skipValidityCheckForClientCert ) ); - configBuilder.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), - Collections.singletonList(CertificateType.X_509)); + configBuilder.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), + Collections.singletonList(CertificateType.X_509))); return configBuilder.build(); } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java index b52d08fdd9..1d8e4d45f9 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/TbCoapServerMessageDeliverer.java @@ -18,6 +18,7 @@ package org.thingsboard.server.coapserver; import lombok.extern.slf4j.Slf4j; import org.eclipse.californium.core.coap.OptionSet; import org.eclipse.californium.core.network.Exchange; +import org.eclipse.californium.core.server.DelivererException; import org.eclipse.californium.core.server.ServerMessageDeliverer; import org.eclipse.californium.core.server.resources.Resource; import org.springframework.util.CollectionUtils; @@ -32,7 +33,7 @@ public class TbCoapServerMessageDeliverer extends ServerMessageDeliverer { } @Override - protected Resource findResource(Exchange exchange) { + protected Resource findResource(Exchange exchange) throws DelivererException { validateUriPath(exchange); return findResource(exchange.getRequest().getOptions().getUriPath()); } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 0c3ce2a530..3e291a8177 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -30,7 +30,6 @@ import org.thingsboard.server.coapserver.TbCoapDtlsSessionInfo; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceTransportType; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.security.DeviceTokenCredentials; import org.thingsboard.server.common.msg.session.FeatureType; @@ -48,6 +47,7 @@ import org.thingsboard.server.transport.coap.callback.ToServerRpcSyncSessionCall import org.thingsboard.server.transport.coap.client.CoapClientContext; import org.thingsboard.server.transport.coap.client.TbCoapClientState; +import java.net.InetSocketAddress; import java.util.List; import java.util.Optional; import java.util.Random; @@ -56,6 +56,8 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import static org.eclipse.californium.elements.DtlsEndpointContext.KEY_SESSION_ID; + @Slf4j public class CoapTransportResource extends AbstractCoapTransportResource { private static final int ACCESS_TOKEN_POSITION = 3; @@ -64,9 +66,8 @@ public class CoapTransportResource extends AbstractCoapTransportResource { private static final int FEATURE_TYPE_POSITION_CERTIFICATE_REQUEST = 3; private static final int REQUEST_ID_POSITION_CERTIFICATE_REQUEST = 4; - private static final String DTLS_SESSION_ID_KEY = "DTLS_SESSION_ID"; - private final ConcurrentMap dtlsSessionIdMap; + private final ConcurrentMap dtlsSessionsMap; private final long timeout; private final CoapClientContext clients; @@ -74,7 +75,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { super(ctx, name); this.setObservable(true); // enable observing this.addObserver(new CoapResourceObserver()); - this.dtlsSessionIdMap = coapServerService.getDtlsSessionsMap(); + this.dtlsSessionsMap = coapServerService.getDtlsSessionsMap(); this.timeout = coapServerService.getTimeout(); this.clients = ctx.getClientContext(); long sessionReportTimeout = ctx.getSessionReportTimeout(); @@ -91,7 +92,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { if (relation == null || relation.isCanceled()) { return; // because request did not try to establish a relation } - if (CoAP.ResponseCode.isSuccess(response.getCode())) { + if (response.getCode().isSuccess()) { if (!relation.isEstablished()) { relation.setEstablished(); addObserveRelation(relation); @@ -198,10 +199,10 @@ public class CoapTransportResource extends AbstractCoapTransportResource { Exchange advanced = exchange.advanced(); Request request = advanced.getRequest(); - String dtlsSessionIdStr = request.getSourceContext().get(DTLS_SESSION_ID_KEY); - if (dtlsSessionIdMap != null && StringUtils.isNotEmpty(dtlsSessionIdStr)) { - TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionIdMap - .computeIfPresent(dtlsSessionIdStr, (dtlsSessionId, dtlsSessionInfo) -> { + var dtlsSessionId = request.getSourceContext().get(KEY_SESSION_ID); + if (dtlsSessionsMap != null && dtlsSessionId != null && !dtlsSessionId.isEmpty()) { + TbCoapDtlsSessionInfo tbCoapDtlsSessionInfo = dtlsSessionsMap + .computeIfPresent(request.getSourceContext().getPeerAddress(), (dtlsSessionIdStr, dtlsSessionInfo) -> { dtlsSessionInfo.setLastActivityTime(System.currentTimeMillis()); return dtlsSessionInfo; }); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java index f5ff256fef..0e45c52f62 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/TbCoapMessageObserver.java @@ -29,6 +29,11 @@ public class TbCoapMessageObserver implements MessageObserver { private final Consumer onAcknowledge; private final Consumer onTimeout; + @Override + public boolean isInternal() { + return false; + } + @Override public void onRetransmission() { @@ -86,13 +91,18 @@ public class TbCoapMessageObserver implements MessageObserver { } + @Override + public void onResponseHandlingError(Throwable cause) { + + } + @Override public void onContextEstablished(EndpointContext endpointContext) { } @Override - public void onComplete() { + public void onTransferComplete() { } } diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java index f23ae9deb4..fc0ab5a26c 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientNoAuth.java @@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.EndpointContext; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -118,7 +120,7 @@ public class SecureClientNoAuth { String keyStorePassword = args[6]; - DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration()); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); SecureClientNoAuth client = new SecureClientNoAuth(dtlsConnector, host, port, accessToken, clientKeys, sharedKeys); @@ -134,7 +136,7 @@ public class SecureClientNoAuth { keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); trustBuilder.setTrustedCertificates(trustedCertificates); config.setAdvancedCertificateVerifier(trustBuilder.build()); - config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); + config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509))); } catch (GeneralSecurityException e) { System.err.println("certificates are invalid!"); throw new IllegalArgumentException(e.getMessage()); diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java index e67055f4e5..700dee7ed9 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/client/SecureClientX509.java @@ -21,11 +21,13 @@ import org.eclipse.californium.core.Utils; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.elements.DtlsEndpointContext; import org.eclipse.californium.elements.EndpointContext; +import org.eclipse.californium.elements.config.Configuration; import org.eclipse.californium.elements.exception.ConnectorException; import org.eclipse.californium.elements.util.SslContextUtil; import org.eclipse.californium.scandium.DTLSConnector; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.CertificateType; +import org.eclipse.californium.scandium.dtls.x509.SingleCertificateProvider; import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -117,7 +119,7 @@ public class SecureClientX509 { String keyStorePassword = args[5]; - DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new Configuration()); setupCredentials(builder, keyStoreUriPath, keyStoreAlias, trustedAliasPattern, keyStorePassword); DTLSConnector dtlsConnector = new DTLSConnector(builder.build()); SecureClientX509 client = new SecureClientX509(dtlsConnector, host, port, clientKeys, sharedKeys); @@ -133,7 +135,7 @@ public class SecureClientX509 { keyStoreUriPath, trustedAliasPattern, keyStorePassword.toCharArray()); trustBuilder.setTrustedCertificates(trustedCertificates); config.setAdvancedCertificateVerifier(trustBuilder.build()); - config.setIdentity(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509)); + config.setCertificateIdentityProvider(new SingleCertificateProvider(serverCredentials.getPrivateKey(), serverCredentials.getCertificateChain(), Collections.singletonList(CertificateType.X_509))); } catch (GeneralSecurityException e) { System.err.println("certificates are invalid!"); throw new IllegalArgumentException(e.getMessage()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 8f979c6b58..bbf580fba4 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.leshan.server.bootstrap.BootstrapSessionManager; import org.eclipse.leshan.server.californium.bootstrap.LeshanBootstrapServer; @@ -36,6 +37,8 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; @Slf4j @@ -86,10 +89,10 @@ public class LwM2MTransportBootstrapService { /* Create and Set DTLS Config */ - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); - dtlsConfig.setRecommendedSupportedGroupsOnly(serverConfig.isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(serverConfig.isRecommendedCiphers()); - dtlsConfig.setSupportedCipherSuites(this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); + dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups()); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers()); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); /* Set DTLS Config */ builder.setDtlsConfig(dtlsConfig); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java index f315fbe48d..0582ff5450 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/store/LwM2MBootstrapConfigStoreTaskProvider.java @@ -16,7 +16,7 @@ package org.thingsboard.server.transport.lwm2m.bootstrap.store; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.node.LwM2mObject; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.request.BootstrapDeleteRequest; @@ -134,18 +134,18 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi log.info("Object after discover: [{}]", objectLinks); this.securityInstances = new HashMap<>(); for (Link link : objectLinks) { - if (link.getUrl().startsWith("/0/")) { + if (link.getUriReference().startsWith("/0/")) { try { - LwM2mPath path = new LwM2mPath(link.getUrl()); + LwM2mPath path = new LwM2mPath(link.getUriReference()); if (path.isObjectInstance()) { - if (link.getAttributes().containsKey("ssid")) { - int serverId = Integer.parseInt(link.getAttributes().get("ssid")); + if (link.getLinkParams().containsKey("ssid")) { + int serverId = Integer.parseInt(link.getLinkParams().get("ssid").getUnquoted()); if (!this.securityInstances.containsKey(serverId)) { this.securityInstances.put(serverId, path.getObjectInstanceId()); } else { log.error("Invalid lwm2mSecurityInstance by [{}]", path.getObjectInstanceId()); } - this.securityInstances.put(Integer.valueOf(link.getAttributes().get("ssid")), path.getObjectInstanceId()); + this.securityInstances.put(Integer.valueOf(link.getLinkParams().get("ssid").getUnquoted()), path.getObjectInstanceId()); } else { if (!this.securityInstances.containsKey(0)) { this.securityInstances.put(0, path.getObjectInstanceId()); @@ -188,10 +188,10 @@ public class LwM2MBootstrapConfigStoreTaskProvider implements BootstrapTaskProvi private void initAfterBootstrapDiscover(BootstrapDiscoverResponse response) { Link[] links = response.getObjectLinks(); Arrays.stream(links).forEach(link -> { - LwM2mPath path = new LwM2mPath(link.getUrl()); + LwM2mPath path = new LwM2mPath(link.getUriReference()); if (!path.isRoot() && path.getObjectId() < 3) { if (path.isObject()) { - String ver = link.getAttributes().get("ver") != null ? link.getAttributes().get("ver") : "1.0"; + String ver = link.getLinkParams().get("ver") != null ? link.getLinkParams().get("ver").getUnquoted() : "1.0"; this.supportedObjects.put(path.getObjectId(), ver); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java similarity index 70% rename from common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java rename to common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java index 3c12b8f6be..699f57481f 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/LwM2mVersion.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/config/TbLwM2mVersion.java @@ -16,31 +16,31 @@ package org.thingsboard.server.transport.lwm2m.config; import lombok.Getter; -import org.eclipse.leshan.core.LwM2m.Version; +import org.eclipse.leshan.core.LwM2m.LwM2mVersion; import org.eclipse.leshan.core.request.ContentFormat; -public enum LwM2mVersion { - VERSION_1_0(0, Version.V1_0, ContentFormat.TLV, false), - VERSION_1_1(1, Version.V1_1, ContentFormat.TEXT, true); +public enum TbLwM2mVersion { + VERSION_1_0(0, LwM2mVersion.V1_0, ContentFormat.TLV, false), + VERSION_1_1(1, LwM2mVersion.V1_1, ContentFormat.TEXT, true); @Getter private final int code; @Getter - private final Version version; + private final LwM2mVersion version; @Getter private final ContentFormat contentFormat; @Getter private final boolean composite; - LwM2mVersion(int code, Version version, ContentFormat contentFormat, boolean composite) { + TbLwM2mVersion(int code, LwM2mVersion version, ContentFormat contentFormat, boolean composite) { this.code = code; this.version = version; this.contentFormat = contentFormat; this.composite = composite; } - public static LwM2mVersion fromVersion(Version version) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromVersion(LwM2mVersion version) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.version.equals(version)) { return to; } @@ -48,8 +48,8 @@ public enum LwM2mVersion { throw new IllegalArgumentException(String.format("Unsupported typeLwM2mVersion type : %s", version)); } - public static LwM2mVersion fromVersionStr(String versionStr) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromVersionStr(String versionStr) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.version.toString().equals(versionStr)) { return to; } @@ -57,8 +57,8 @@ public enum LwM2mVersion { throw new IllegalArgumentException(String.format("Unsupported contentFormatLwM2mVersion version : %s", versionStr)); } - public static LwM2mVersion fromCode(int code) { - for (LwM2mVersion to : LwM2mVersion.values()) { + public static TbLwM2mVersion fromCode(int code) { + for (TbLwM2mVersion to : TbLwM2mVersion.values()) { if (to.code == code) { return to; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java index 60872f88f2..8831fe044e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/secure/TbLwM2MDtlsCertificateVerifier.java @@ -17,19 +17,18 @@ package org.thingsboard.server.transport.lwm2m.secure; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.elements.auth.RawPublicKeyIdentity; import org.eclipse.californium.elements.util.CertPathUtil; import org.eclipse.californium.scandium.dtls.AlertMessage; import org.eclipse.californium.scandium.dtls.CertificateMessage; import org.eclipse.californium.scandium.dtls.CertificateType; import org.eclipse.californium.scandium.dtls.CertificateVerificationResult; import org.eclipse.californium.scandium.dtls.ConnectionId; -import org.eclipse.californium.scandium.dtls.DTLSSession; import org.eclipse.californium.scandium.dtls.HandshakeException; import org.eclipse.californium.scandium.dtls.HandshakeResultHandler; import org.eclipse.californium.scandium.dtls.x509.NewAdvancedCertificateVerifier; -import org.eclipse.californium.scandium.dtls.x509.StaticCertificateVerifier; +import org.eclipse.californium.scandium.dtls.x509.StaticNewAdvancedCertificateVerifier; import org.eclipse.californium.scandium.util.ServerNames; -import org.eclipse.leshan.core.util.SecurityUtil; import org.eclipse.leshan.server.security.NonUniqueSecurityInfoException; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -50,6 +49,7 @@ import org.thingsboard.server.transport.lwm2m.server.store.TbMainSecurityStore; import javax.annotation.PostConstruct; import javax.security.auth.x500.X500Principal; +import java.net.InetSocketAddress; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; @@ -81,18 +81,16 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer private final LwM2mCredentialsSecurityInfoValidator securityInfoValidator; private final TbMainSecurityStore securityStore; - @SuppressWarnings("deprecation") - private StaticCertificateVerifier staticCertificateVerifier; + private StaticNewAdvancedCertificateVerifier staticCertificateVerifier; @Value("${transport.lwm2m.server.security.skip_validity_check_for_client_cert:false}") private boolean skipValidityCheckForClientCert; @Override - public List getSupportedCertificateType() { + public List getSupportedCertificateTypes() { return Arrays.asList(CertificateType.X_509, CertificateType.RAW_PUBLIC_KEY); } - @SuppressWarnings("deprecation") @PostConstruct public void init() { try { @@ -101,14 +99,14 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer if (config.getTrustSslCredentials() != null) { trustedCertificates = config.getTrustSslCredentials().getTrustedCertificates(); } - staticCertificateVerifier = new StaticCertificateVerifier(trustedCertificates); + staticCertificateVerifier = new StaticNewAdvancedCertificateVerifier(trustedCertificates, new RawPublicKeyIdentity[]{}, null); } catch (Exception e) { log.info("Failed to initialize the "); } } @Override - public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, Boolean clientUsage, boolean truncateCertificatePath, CertificateMessage message, DTLSSession session) { + public CertificateVerificationResult verifyCertificate(ConnectionId cid, ServerNames serverName, InetSocketAddress remotePeer, boolean clientUsage, boolean verifySubject, boolean truncateCertificatePath, CertificateMessage message) { CertPath certChain = message.getCertificateChain(); if (certChain == null) { //We trust all RPK on this layer, and use TbLwM2MAuthorizer @@ -177,10 +175,9 @@ public class TbLwM2MDtlsCertificateVerifier implements NewAdvancedCertificateVer } if (!x509CredentialsFound) { if (staticCertificateVerifier != null) { - staticCertificateVerifier.verifyCertificate(message, session); + staticCertificateVerifier.verifyCertificate(cid, serverName, remotePeer, clientUsage, verifySubject, truncateCertificatePath, message); } else { - AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR, - session.getPeer()); + AlertMessage alert = new AlertMessage(AlertMessage.AlertLevel.FATAL, AlertMessage.AlertDescription.INTERNAL_ERROR); throw new HandshakeException("x509 verification not enabled!", alert); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java index 1245aeb9ea..23238a07a5 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/DefaultLwM2mTransportService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.californium.scandium.config.DtlsConfig; import org.eclipse.californium.scandium.config.DtlsConnectorConfig; import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.leshan.core.node.codec.DefaultLwM2mDecoder; @@ -40,6 +41,8 @@ import org.thingsboard.server.transport.lwm2m.utils.LwM2mValueConverterImpl; import javax.annotation.PreDestroy; import java.security.cert.X509Certificate; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; +import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8; import static org.eclipse.californium.scandium.dtls.cipher.CipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256; @@ -121,11 +124,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { /* Create DTLS Config */ - DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(); + DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(config.getPort(), config.getSecurePort(), config)); + + dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); + dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, config.isRecommendedSupportedGroups()); + dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, config.isRecommendedCiphers()); - dtlsConfig.setServerOnly(true); - dtlsConfig.setRecommendedSupportedGroupsOnly(config.isRecommendedSupportedGroups()); - dtlsConfig.setRecommendedCipherSuitesOnly(config.isRecommendedCiphers()); /* Create credentials */ this.setServerWithCredentials(builder, dtlsConfig); @@ -144,12 +148,12 @@ public class DefaultLwM2mTransportService implements LwM2MTransportService { builder.setCertificateChain(sslCredentials.getCertificateChain()); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); builder.setAuthorizer(authorizer); - dtlsConfig.setSupportedCipherSuites(RPK_OR_X509_CIPHER_SUITES); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES); } else { /* by default trust all */ builder.setTrustedCertificates(new X509Certificate[0]); log.info("Unable to load X509 files for LWM2MServer"); - dtlsConfig.setSupportedCipherSuites(PSK_CIPHER_SUITES); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java index 31e0ae4de5..b47e548b56 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2MNetworkConfig.java @@ -15,27 +15,30 @@ */ package org.thingsboard.server.transport.lwm2m.server; -import org.eclipse.californium.core.network.config.NetworkConfig; -import org.eclipse.californium.core.network.config.NetworkConfigDefaults; +import org.eclipse.californium.core.config.CoapConfig; +import org.eclipse.californium.elements.config.Configuration; import org.springframework.util.CollectionUtils; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import static org.eclipse.californium.core.network.config.NetworkConfigDefaults.DEFAULT_BLOCKWISE_STATUS_LIFETIME; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +import static org.eclipse.californium.core.config.CoapConfig.DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS; public class LwM2MNetworkConfig { - public static NetworkConfig getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { - NetworkConfig coapConfig = new NetworkConfig(); - coapConfig.setInt(NetworkConfig.Keys.COAP_PORT, serverPortNoSec); - coapConfig.setInt(NetworkConfig.Keys.COAP_SECURE_PORT, serverSecurePort); + public static Configuration getCoapConfig(Integer serverPortNoSec, Integer serverSecurePort, LwM2MTransportServerConfig config) { + Configuration coapConfig = new Configuration(); + coapConfig.set(CoapConfig.COAP_PORT, serverPortNoSec); + coapConfig.set(CoapConfig.COAP_SECURE_PORT, serverSecurePort); /** Example:Property for large packet: #NetworkConfig config = new NetworkConfig(); - #config.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE,32); - #config.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE,32); - #config.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE,2048); - #config.setInt(NetworkConfig.Keys.MAX_RETRANSMIT,3); - #config.setInt(NetworkConfig.Keys.MAX_TRANSMIT_WAIT,120000); + #config.setInt(CoapConfig.MAX_MESSAGE_SIZE,32); + #config.setInt(CoapConfig.PREFERRED_BLOCK_SIZE,32); + #config.setInt(CoapConfig.MAX_RESOURCE_BODY_SIZE,2048); + #config.setInt(CoapConfig.MAX_RETRANSMIT,3); + #config.setInt(CoapConfig.MAX_TRANSMIT_WAIT,120000); */ /** @@ -46,14 +49,14 @@ public class LwM2MNetworkConfig { CoAP client will try to use block mode or adapt the block size when receiving a 4.13 Entity too large response code */ - coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_STRICT_BLOCK2_OPTION, true); + coapConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); /** Property to indicate if the response should always include the Block2 option \ when client request early blockwise negociation but the response can be sent on one packet. - value of false indicate that the server will respond without block2 option if no further blocks are required. - value of true indicate that the server will response with block2 option event if no further blocks are required. */ - coapConfig.setBoolean(NetworkConfig.Keys.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); + coapConfig.set(CoapConfig.BLOCKWISE_ENTITY_TOO_LARGE_AUTO_FAILOVER, true); /** * The maximum amount of time (in milliseconds) allowed between * transfers of individual blocks in a blockwise transfer before the @@ -62,7 +65,7 @@ public class LwM2MNetworkConfig { * The default value of this property is * {@link NetworkConfigDefaults#DEFAULT_BLOCKWISE_STATUS_LIFETIME} = 5 * 60 * 1000; // 5 mins [ms]. */ - coapConfig.setLong(NetworkConfig.Keys.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME); + coapConfig.set(CoapConfig.BLOCKWISE_STATUS_LIFETIME, DEFAULT_BLOCKWISE_STATUS_LIFETIME_IN_SECONDS, TimeUnit.SECONDS); /** !!! REQUEST_ENTITY_TOO_LARGE CODE=4.13 The maximum size of a resource body (in bytes) that will be accepted @@ -77,7 +80,7 @@ public class LwM2MNetworkConfig { The default value of this property is DEFAULT_MAX_RESOURCE_BODY_SIZE = 8192 A value of {@code 0} turns off transparent handling of blockwise transfers altogether. */ - coapConfig.setInt(NetworkConfig.Keys.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); + coapConfig.set(CoapConfig.MAX_RESOURCE_BODY_SIZE, 256 * 1024 * 1024); /** The default DTLS response matcher. Supported values are STRICT, RELAXED, or PRINCIPAL. @@ -88,13 +91,13 @@ public class LwM2MNetworkConfig { – true with address check, (STRICT, UDP) - if port Registration of client is changed - it is bad - false, without */ - coapConfig.setString(NetworkConfig.Keys.RESPONSE_MATCHING, "RELAXED"); + coapConfig.set(CoapConfig.RESPONSE_MATCHING, CoapConfig.MatcherMode.RELAXED); /** https://tools.ietf.org/html/rfc7959#section-2.9.3 The block size (number of bytes) to use when doing a blockwise transfer. \ This value serves as the upper limit for block size in blockwise transfers */ - coapConfig.setInt(NetworkConfig.Keys.PREFERRED_BLOCK_SIZE, 1024); + coapConfig.set(CoapConfig.PREFERRED_BLOCK_SIZE, 1024); /** The maximum payload size (in bytes) that can be transferred in a single message, i.e. without requiring a blockwise transfer. @@ -102,12 +105,14 @@ public class LwM2MNetworkConfig { In particular, this value cannot exceed the network's MTU if UDP is used as the transport protocol DEFAULT_VALUE = 1024 */ - coapConfig.setInt(NetworkConfig.Keys.MAX_MESSAGE_SIZE, 1024); + coapConfig.set(CoapConfig.MAX_MESSAGE_SIZE, 1024); - coapConfig.setInt(NetworkConfig.Keys.MAX_RETRANSMIT, 10); + coapConfig.set(CoapConfig.MAX_RETRANSMIT, 10); if (!CollectionUtils.isEmpty(config.getNetworkConfig())) { - config.getNetworkConfig().forEach(p -> coapConfig.setString(p.getKey(), p.getValue())); + Properties networkProps = new Properties(); + config.getNetworkConfig().forEach(p -> networkProps.put(p.getKey(), p.getValue())); + coapConfig.add(networkProps); } return coapConfig; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java index 7ffcf88e31..5c0e225f8b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mServerListener.java @@ -16,7 +16,10 @@ package org.thingsboard.server.transport.lwm2m.server; import lombok.extern.slf4j.Slf4j; +import org.eclipse.leshan.core.observation.CompositeObservation; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; +import org.eclipse.leshan.core.response.ObserveCompositeResponse; import org.eclipse.leshan.core.response.ObserveResponse; import org.eclipse.leshan.server.observation.ObservationListener; import org.eclipse.leshan.server.queue.PresenceListener; @@ -86,26 +89,34 @@ public class LwM2mServerListener { @Override public void cancelled(Observation observation) { - log.trace("Canceled Observation {}.", observation.getPath()); + //TODO: should be able to use CompositeObservation + log.trace("Canceled Observation {}.", ((SingleObservation)observation).getPath()); } @Override - public void onResponse(Observation observation, Registration registration, ObserveResponse response) { + public void onResponse(SingleObservation observation, Registration registration, ObserveResponse response) { if (registration != null) { service.onUpdateValueAfterReadResponse(registration, convertObjectIdToVersionedId(observation.getPath().toString(), registration), response); } } + @Override + public void onResponse(CompositeObservation observation, Registration registration, ObserveCompositeResponse response) { + throw new RuntimeException("Not implemented yet!"); + } + @Override public void onError(Observation observation, Registration registration, Exception error) { if (error != null) { - log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), observation.getPath(), error.getMessage()); + //TODO: should be able to use CompositeObservation + log.debug("Unable to handle notification of [{}:{}] [{}]", observation.getRegistrationId(), ((SingleObservation)observation).getPath(), error.getMessage()); } } @Override public void newObservation(Observation observation, Registration registration) { - log.trace("Successful start newObservation {}.", observation.getPath()); + //TODO: should be able to use CompositeObservation + log.trace("Successful start newObservation {}.", ((SingleObservation)observation).getPath()); } }; } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java index 53bb650868..fdf5e5f8bc 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/LwM2mTransportCoapResource.java @@ -56,7 +56,7 @@ public class LwM2mTransportCoapResource extends AbstractLwM2mTransportResource { if (relation == null || relation.isCanceled()) { return; // because request did not try to establish a relation } - if (CoAP.ResponseCode.isSuccess(response.getCode())) { + if (response.getCode().isSuccess()) { if (!relation.isEstablished()) { relation.setEstablished(); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java index 6f25e752d0..04b8f858c6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClient.java @@ -39,7 +39,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.transport.auth.ValidateDeviceCredentialsResponse; import org.thingsboard.server.gen.transport.TransportProtos.SessionInfoProto; import org.thingsboard.server.gen.transport.TransportProtos.TsKvProto; -import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; +import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion; import java.io.IOException; import java.io.ObjectInputStream; @@ -423,14 +423,14 @@ public class LwM2mClient implements Serializable { if (registration == null) { return ContentFormat.DEFAULT; } else{ - return LwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); + return TbLwM2mVersion.fromVersion(registration.getLwM2mVersion()).getContentFormat(); } } static private Set clientSupportContentFormat(Registration registration) { Set contentFormats = new HashSet<>(); contentFormats.add(ContentFormat.DEFAULT); - String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUrl().equals("/")).findFirst().get().getAttributes().get("ct"); + String code = Arrays.stream(registration.getObjectLinks()).filter(link -> link.getUriReference().equals("/")).findFirst().get().getLinkParams().get("ct").getUnquoted(); if (code != null) { Set codes = Stream.of(code.replaceAll("\"", "").split(" ", -1)) .map(String::trim) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java index 5fcb532c10..eb675c9461 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/client/LwM2mClientContextImpl.java @@ -393,9 +393,9 @@ public class LwM2mClientContextImpl implements LwM2mClientContext { public Set getSupportedIdVerInClient(LwM2mClient client) { Set clientObjects = ConcurrentHashMap.newKeySet(); Arrays.stream(client.getRegistration().getObjectLinks()).forEach(link -> { - LwM2mPath pathIds = new LwM2mPath(link.getUrl()); + LwM2mPath pathIds = new LwM2mPath(link.getUriReference()); if (!pathIds.isRoot()) { - clientObjects.add(convertObjectIdToVersionedId(link.getUrl(), client.getRegistration())); + clientObjects.add(convertObjectIdToVersionedId(link.getUriReference(), client.getRegistration())); } }); return (clientObjects.size() > 0) ? clientObjects : null; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java index 48292c92d0..89d461c76b 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/DefaultLwM2mDownlinkMsgHandler.java @@ -17,7 +17,7 @@ package org.thingsboard.server.transport.lwm2m.server.downlink; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.LwM2m; import org.eclipse.leshan.core.attributes.Attribute; import org.eclipse.leshan.core.attributes.AttributeSet; @@ -29,6 +29,7 @@ import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; import org.eclipse.leshan.core.request.CompositeDownlinkRequest; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.CreateRequest; @@ -160,7 +161,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im validateVersionedId(client, request); LwM2mPath resultIds = new LwM2mPath(request.getObjectId()); Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); - if (observations.stream().noneMatch(observation -> observation.getPath().equals(resultIds))) { + //TODO: should be able to use CompositeObservation + if (observations.stream().noneMatch(observation -> ((SingleObservation)observation).getPath().equals(resultIds))) { ObserveRequest downlink; ContentFormat contentFormat = getReadRequestContentFormat(client, request, modelProvider); if (resultIds.isResource()) { @@ -183,7 +185,8 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im @Override public void sendObserveAllRequest(LwM2mClient client, TbLwM2MObserveAllRequest request, DownlinkRequestCallback> callback) { Set observations = context.getServer().getObservationService().getObservations(client.getRegistration()); - Set paths = observations.stream().map(observation -> observation.getPath().toString()).collect(Collectors.toUnmodifiableSet()); + //TODO: should be able to use CompositeObservation + Set paths = observations.stream().map(observation -> ((SingleObservation)observation).getPath().toString()).collect(Collectors.toUnmodifiableSet()); callback.onSuccess(request, paths); } @@ -620,9 +623,9 @@ public class DefaultLwM2mDownlinkMsgHandler extends LwM2MExecutorAwareService im } private static ContentFormat getContentFormatForComplex(LwM2mClient client) { - if (LwM2m.Version.V1_0.equals(client.getRegistration().getLwM2mVersion())) { + if (LwM2m.LwM2mVersion.V1_0.equals(client.getRegistration().getLwM2mVersion())) { return ContentFormat.TLV; - } else if (LwM2m.Version.V1_1.equals(client.getRegistration().getLwM2mVersion())) { + } else if (LwM2m.LwM2mVersion.V1_1.equals(client.getRegistration().getLwM2mVersion())) { ContentFormat result = findFirst(client.getClientSupportContentFormats(), null, ContentFormat.SENML_CBOR, ContentFormat.SENML_JSON, ContentFormat.TLV, ContentFormat.JSON); if (result != null) { return result; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java index b6f2c37c1d..9f5bf80cf6 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/downlink/LwM2mDownlinkMsgHandler.java @@ -15,7 +15,7 @@ */ package org.thingsboard.server.transport.lwm2m.server.downlink; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.Link; import org.eclipse.leshan.core.request.ContentFormat; import org.eclipse.leshan.core.request.CreateRequest; import org.eclipse.leshan.core.request.DeleteRequest; diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java index d9c213604c..c221f598a2 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/rpc/RpcDiscoverCallback.java @@ -15,7 +15,8 @@ */ package org.thingsboard.server.transport.lwm2m.server.rpc; -import org.eclipse.leshan.core.Link; +import org.eclipse.leshan.core.link.DefaultLinkSerializer; +import org.eclipse.leshan.core.link.LinkSerializer; import org.eclipse.leshan.core.request.DiscoverRequest; import org.eclipse.leshan.core.response.DiscoverResponse; import org.thingsboard.server.common.transport.TransportService; @@ -27,12 +28,14 @@ import java.util.Optional; public class RpcDiscoverCallback extends RpcLwM2MDownlinkCallback { + private final LinkSerializer serializer = new DefaultLinkSerializer(); + public RpcDiscoverCallback(TransportService transportService, LwM2mClient client, TransportProtos.ToDeviceRpcRequestMsg requestMsg, DownlinkRequestCallback callback) { super(transportService, client, requestMsg, callback); } protected Optional serializeSuccessfulResponse(DiscoverResponse response) { - return Optional.of(Link.serialize(response.getObjectLinks())); + return Optional.of(serializer.serialize(response.getObjectLinks())); } } diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java index afa5eae53a..0b1254115e 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/server/store/TbLwM2mRedisRegistrationStore.java @@ -22,10 +22,11 @@ import org.eclipse.leshan.core.Destroyable; import org.eclipse.leshan.core.Startable; import org.eclipse.leshan.core.Stoppable; import org.eclipse.leshan.core.observation.Observation; +import org.eclipse.leshan.core.observation.SingleObservation; import org.eclipse.leshan.core.request.Identity; import org.eclipse.leshan.core.util.NamedThreadFactory; import org.eclipse.leshan.core.util.Validate; -import org.eclipse.leshan.server.californium.observation.ObserveUtil; +import org.eclipse.leshan.core.californium.ObserveUtil; import org.eclipse.leshan.server.californium.registration.CaliforniumRegistrationStore; import org.eclipse.leshan.server.redis.RedisRegistrationStore; import org.eclipse.leshan.server.redis.serialization.IdentitySerDes; @@ -455,7 +456,8 @@ public class TbLwM2mRedisRegistrationStore implements CaliforniumRegistrationSto // cancel existing observations for the same path and registration id. for (Observation obs : getObservations(connection, registrationId)) { - if (observation.getPath().equals(obs.getPath()) + //TODO: should be able to use CompositeObservation + if (((SingleObservation)observation).getPath().equals(((SingleObservation)obs).getPath()) && !Arrays.equals(observation.getId(), obs.getId())) { removed.add(obs); unsafeRemoveObservation(connection, registrationId, obs.getId()); diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java index b1f6637085..e415858755 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/utils/LwM2MTransportUtil.java @@ -30,7 +30,6 @@ import org.eclipse.leshan.core.node.LwM2mMultipleResource; import org.eclipse.leshan.core.node.LwM2mPath; import org.eclipse.leshan.core.node.LwM2mResource; import org.eclipse.leshan.core.node.LwM2mSingleResource; -import org.eclipse.leshan.core.node.ObjectLink; import org.eclipse.leshan.core.node.codec.CodecException; import org.eclipse.leshan.core.request.SimpleDownlinkRequest; import org.eclipse.leshan.core.request.WriteAttributesRequest; @@ -44,7 +43,7 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileTransportC import org.thingsboard.server.common.data.device.profile.Lwm2mDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.ota.OtaPackageKey; import org.thingsboard.server.common.transport.util.JsonUtils; -import org.thingsboard.server.transport.lwm2m.config.LwM2mVersion; +import org.thingsboard.server.transport.lwm2m.config.TbLwM2mVersion; import org.thingsboard.server.transport.lwm2m.server.LwM2mOtaConvert; import org.thingsboard.server.transport.lwm2m.server.client.LwM2mClient; import org.thingsboard.server.transport.lwm2m.server.client.ResourceValue; @@ -236,7 +235,7 @@ public class LwM2MTransportUtil { public static String convertObjectIdToVersionedId(String path, Registration registration) { String ver = registration.getSupportedObject().get(new LwM2mPath(path).getObjectId()); - ver = ver != null ? ver : LwM2mVersion.VERSION_1_0.getVersion().toString(); + ver = ver != null ? ver : TbLwM2mVersion.VERSION_1_0.getVersion().toString(); try { String[] keyArray = path.split(LWM2M_SEPARATOR_PATH); if (keyArray.length > 1) { diff --git a/pom.xml b/pom.xml index 12e9558612..d583c2df67 100755 --- a/pom.xml +++ b/pom.xml @@ -68,8 +68,8 @@ 2.12.1 1.3.4 2.2.6 - 2.6.1 - 2.0.0-M4 + 3.0.0 + 2.0.0-M5 2.6.2 2.3.30 1.6.2 From f528e3c7600fdd30998d330cc61b1e3ee30fcb56 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 20 Jan 2022 11:10:18 +0200 Subject: [PATCH 11/20] refactored --- .../rule/engine/profile/AlarmRuleState.java | 51 ++++++++----------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 0c0768336d..55ef0a44bc 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -232,21 +232,7 @@ class AlarmRuleState { if (specType.equals(AlarmConditionSpecType.REPEATING)) { RepeatingAlarmConditionSpec repeating = (RepeatingAlarmConditionSpec) spec; - repeatingTimes = repeating.getPredicate().getDefaultValue(); - - if (repeating.getPredicate().getDynamicValue() != null && - repeating.getPredicate().getDynamicValue().getSourceAttribute() != null) { - EntityKeyValue repeatingKeyValue = getDynamicPredicateValue(data, repeating.getPredicate().getDynamicValue()); - if (repeatingKeyValue != null) { - var longValue = getLongValue(repeatingKeyValue); - if (longValue != null) { - repeatingTimes = longValue; - } else { - String sourceAttribute = repeating.getPredicate().getDynamicValue().getSourceAttribute(); - throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(repeatingKeyValue))); - } - } - } + repeatingTimes = resolveDynamicValue(data, repeating.getPredicate()); } return repeatingTimes; } @@ -259,24 +245,29 @@ class AlarmRuleState { DurationAlarmConditionSpec duration = (DurationAlarmConditionSpec) spec; TimeUnit timeUnit = duration.getUnit(); - durationTimeInMs = timeUnit.toMillis(duration.getPredicate().getDefaultValue()); + durationTimeInMs = timeUnit.toMillis(resolveDynamicValue(data, duration.getPredicate())); + } + return durationTimeInMs; + } - if (duration.getPredicate().getDynamicValue() != null && - duration.getPredicate().getDynamicValue().getSourceAttribute() != null) { - EntityKeyValue durationKeyValue = getDynamicPredicateValue(data, duration.getPredicate().getDynamicValue()); - if (durationKeyValue != null) { - var longValue = getLongValue(durationKeyValue); - if (longValue != null) { - durationTimeInMs = timeUnit.toMillis(longValue); - } else { - String sourceAttribute = duration.getPredicate().getDynamicValue().getSourceAttribute(); - throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(durationKeyValue))); - } - } - } + private Long resolveDynamicValue(DataSnapshot data, FilterPredicateValue predicate) { + DynamicValue dynamicValue = predicate.getDynamicValue(); + Long defaultValue = predicate.getDefaultValue().longValue(); + if (dynamicValue == null || dynamicValue.getSourceAttribute() == null) { + return defaultValue; } - return durationTimeInMs; + EntityKeyValue keyValue = getDynamicPredicateValue(data, dynamicValue); + if (keyValue == null) { + return defaultValue; + } + + var longValue = getLongValue(keyValue); + if (longValue != null) { + String sourceAttribute = dynamicValue.getSourceAttribute(); + throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(keyValue))); + } + return longValue; } public AlarmEvalResult eval(long ts, DataSnapshot dataSnapshot) { From f6cb46b06905c47632ecea662cbfc732d909900f Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 20 Jan 2022 12:09:43 +0200 Subject: [PATCH 12/20] minor fix --- .../org/thingsboard/rule/engine/profile/AlarmRuleState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 55ef0a44bc..4b686f5919 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -263,7 +263,7 @@ class AlarmRuleState { } var longValue = getLongValue(keyValue); - if (longValue != null) { + if (longValue == null) { String sourceAttribute = dynamicValue.getSourceAttribute(); throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(keyValue))); } From 8b0a1f5538082676c842611716cd315966e35b4c Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 20 Jan 2022 12:53:24 +0200 Subject: [PATCH 13/20] Fix for #5931 and merge the PR #5915 --- .../stats/DefaultRuleEngineStatisticsService.java | 3 +-- .../server/common/msg/queue/RuleEngineException.java | 12 ++++++++++-- .../rule/engine/profile/AlarmRuleState.java | 2 +- .../thingsboard/rule/engine/profile/AlarmState.java | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java index 17fad5d750..86380ea57a 100644 --- a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java +++ b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java @@ -96,8 +96,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS } }); ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> { - TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry("ruleEngineException", - JacksonUtil.toString(JacksonUtil.newObjectNode().put("message", e.getMessage())))); + TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry("ruleEngineException", e.toJsonString())); try { tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), CALLBACK); } catch (DataValidationException e2) { diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java index a7e36a329e..4c317630f2 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java @@ -25,11 +25,19 @@ public class RuleEngineException extends Exception { protected static final ObjectMapper mapper = new ObjectMapper(); @Getter - private final long ts; + private long ts; public RuleEngineException(String message) { super(message != null ? message : "Unknown"); - this.ts = System.currentTimeMillis(); + ts = System.currentTimeMillis(); } + public String toJsonString() { + try { + return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage())); + } catch (JsonProcessingException e) { + log.warn("Failed to serialize exception ", e); + throw new RuntimeException(e); + } + } } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java index 4b686f5919..62508e5503 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmRuleState.java @@ -265,7 +265,7 @@ class AlarmRuleState { var longValue = getLongValue(keyValue); if (longValue == null) { String sourceAttribute = dynamicValue.getSourceAttribute(); - throw new NumericParseException(String.format("could not parse attribute [%s: %s] from source!", sourceAttribute, getStrValue(keyValue))); + throw new NumericParseException(String.format("Could not convert attribute '%s' with value '%s' to numeric value!", sourceAttribute, getStrValue(keyValue))); } return longValue; } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java index db9d12e7e3..2a46b77791 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/profile/AlarmState.java @@ -51,7 +51,7 @@ import java.util.function.BiFunction; @Slf4j class AlarmState { - public static final String ERROR_MSG = "Failed to process alarm state for Device [%s]: %s"; + public static final String ERROR_MSG = "Failed to process alarm rule for Device [%s]: %s"; private final ProfileState deviceProfile; private final EntityId originator; private DeviceProfileAlarm alarmDefinition; From fc9078a2be2b78ce8ab6bd6b9ba9c2025f147ac3 Mon Sep 17 00:00:00 2001 From: desoliture Date: Thu, 20 Jan 2022 12:58:55 +0200 Subject: [PATCH 14/20] fix case where both shared and client attributes were requested --- .../server/actors/device/DeviceActorMessageProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index bfcb95a71c..baf2e9b03e 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -473,7 +473,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { .addAllClientAttributeList(toTsKvProtos(result.get(0))) .addAllSharedAttributeList(toTsKvProtos(result.get(1))) .setIsMultipleAttributesRequest( - request.getSharedAttributeNamesCount() > 1 || request.getClientAttributeNamesCount() > 1) + request.getSharedAttributeNamesCount() + request.getClientAttributeNamesCount() > 1) .build(); sendToTransport(responseMsg, sessionInfo); } From 8e066f387a5e490085114544825c0eeedd60546d Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 20 Jan 2022 13:23:59 +0200 Subject: [PATCH 15/20] Fix tests according to new feature: startTs and endTs of the alarm are taken from the message. --- .../rule/engine/action/TbAlarmNodeTest.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java index 36e838f57e..78caee289f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/action/TbAlarmNodeTest.java @@ -130,7 +130,7 @@ public class TbAlarmNodeTest { when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); - + long ts = msg.getTs(); node.onMsg(ctx, msg); verify(ctx).enqueue(any(), successCaptor.capture(), failureCaptor.capture()); @@ -152,6 +152,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -192,7 +194,7 @@ public class TbAlarmNodeTest { initWithCreateAlarmScript(); metaData.putValue("key", "value"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); - + long ts = msg.getTs(); Alarm clearedAlarm = Alarm.builder().status(CLEARED_ACK).build(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); @@ -222,6 +224,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -407,7 +411,7 @@ public class TbAlarmNodeTest { String rawJson = "{\"alarmSeverity\": \"WARNING\", \"passed\": 5}"; metaData.putValue("key", "value"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); - + long ts = msg.getTs(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); doAnswer((Answer) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(any(Alarm.class)); @@ -433,6 +437,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) @@ -467,6 +473,7 @@ public class TbAlarmNodeTest { metaData.putValue("alarmSeverity", "WARNING"); TbMsg msg = TbMsg.newMsg("USER", originator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); + long ts = msg.getTs(); when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); when(alarmService.findLatestByOriginatorAndType(tenantId, originator, "SomeType")).thenReturn(Futures.immediateFuture(null)); @@ -492,6 +499,8 @@ public class TbAlarmNodeTest { Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); Alarm expectedAlarm = Alarm.builder() + .startTs(ts) + .endTs(ts) .tenantId(tenantId) .originator(originator) .status(ACTIVE_UNACK) From 7f32c10d77fc9cc6b5e6798ee358df43f4f02ceb Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Thu, 20 Jan 2022 14:40:12 +0200 Subject: [PATCH 16/20] Fix initialization error for LwM2M Bootstrap mode --- .../lwm2m/bootstrap/LwM2MTransportBootstrapService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 23f9b26a20..183febcc79 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -40,6 +40,7 @@ import java.security.cert.X509Certificate; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CIPHER_SUITES_ONLY; import static org.eclipse.californium.scandium.config.DtlsConfig.DTLS_RECOMMENDED_CURVES_ONLY; +import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.PSK_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES; import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.getCoapConfig; @@ -48,7 +49,6 @@ import static org.thingsboard.server.transport.lwm2m.server.LwM2MNetworkConfig.g @TbLwM2mBootstrapTransportComponent @RequiredArgsConstructor public class LwM2MTransportBootstrapService { - private boolean pskMode = false; private final LwM2MTransportServerConfig serverConfig; private final LwM2MTransportBootstrapConfig bootstrapConfig; @@ -86,7 +86,7 @@ public class LwM2MTransportBootstrapService { DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups()); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers()); - dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); + setServerWithCredentials(builder, dtlsConfig); /* Set DTLS Config */ @@ -112,13 +112,13 @@ public class LwM2MTransportBootstrapService { builder.setPublicKey(sslCredentials.getPublicKey()); builder.setPrivateKey(sslCredentials.getPrivateKey()); builder.setCertificateChain(sslCredentials.getCertificateChain()); - dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, this.pskMode ? DefaultLwM2mTransportService.PSK_CIPHER_SUITES : DefaultLwM2mTransportService.RPK_OR_X509_CIPHER_SUITES); dtlsConfig.setAdvancedCertificateVerifier(certificateVerifier); + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, RPK_OR_X509_CIPHER_SUITES); } else { /* by default trust all */ builder.setTrustedCertificates(new X509Certificate[0]); log.info("Unable to load X509 files for BootStrapServer"); - this.pskMode = true; + dtlsConfig.setAsList(DtlsConfig.DTLS_CIPHER_SUITES, PSK_CIPHER_SUITES); } } } From 427f9b191f471e13fcd916cac02df02f32c05651 Mon Sep 17 00:00:00 2001 From: nickAS21 Date: Thu, 20 Jan 2022 15:27:10 +0200 Subject: [PATCH 17/20] lwm2m: add bootstrap DTLS config - SERVER_ONLY --- .../lwm2m/bootstrap/LwM2MTransportBootstrapService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java index 183febcc79..ff40289884 100644 --- a/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java +++ b/common/transport/lwm2m/src/main/java/org/thingsboard/server/transport/lwm2m/bootstrap/LwM2MTransportBootstrapService.java @@ -32,7 +32,6 @@ import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MBootstrapSecu import org.thingsboard.server.transport.lwm2m.bootstrap.store.LwM2MInMemoryBootstrapConfigStore; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportBootstrapConfig; import org.thingsboard.server.transport.lwm2m.config.LwM2MTransportServerConfig; -import org.thingsboard.server.transport.lwm2m.server.DefaultLwM2mTransportService; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -84,6 +83,8 @@ public class LwM2MTransportBootstrapService { /* Create and Set DTLS Config */ DtlsConnectorConfig.Builder dtlsConfig = new DtlsConnectorConfig.Builder(getCoapConfig(bootstrapConfig.getPort(), bootstrapConfig.getSecurePort(), serverConfig)); + + dtlsConfig.set(DtlsConfig.DTLS_ROLE, DtlsConfig.DtlsRole.SERVER_ONLY); dtlsConfig.set(DTLS_RECOMMENDED_CURVES_ONLY, serverConfig.isRecommendedSupportedGroups()); dtlsConfig.set(DTLS_RECOMMENDED_CIPHER_SUITES_ONLY, serverConfig.isRecommendedCiphers()); From d8bb296d3ca837a18232b4174573512d5281d64d Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 20 Jan 2022 18:35:59 +0200 Subject: [PATCH 18/20] UI: Add script to generate types in the project --- ui-ngx/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 7308a86c9e..1ae3b84cb9 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -6,6 +6,7 @@ "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", + "build:type": "rm -rf target/type && ./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir target/type && find target/type -type f -name '*.js*' -delete", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", From e538d4288d421a114d3183cf4b3157f29011de3c Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 21 Jan 2022 15:19:43 +0200 Subject: [PATCH 19/20] UI: Updated build:types script --- ui-ngx/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 1ae3b84cb9..ea004ccfa2 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -6,7 +6,7 @@ "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", - "build:type": "rm -rf target/type && ./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir target/type && find target/type -type f -name '*.js*' -delete", + "build:types": "rm -rf target/types && ./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir target/types/src && find target/types/src -type f -name '*.js*' -delete && cp src/app/modules/common/modules-map.ts target/types/src/app/modules/common/modules-map.ts", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e", From a1cd5e6a132710e546fbc1625436dc18e48a2188 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 21 Jan 2022 16:16:41 +0200 Subject: [PATCH 20/20] UI: Created script generate-types --- ui-ngx/generate-types.js | 66 ++++++++++++++++++++++++++++++++++++++++ ui-ngx/package.json | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 ui-ngx/generate-types.js diff --git a/ui-ngx/generate-types.js b/ui-ngx/generate-types.js new file mode 100644 index 0000000000..a24673cbd5 --- /dev/null +++ b/ui-ngx/generate-types.js @@ -0,0 +1,66 @@ +/* + * Copyright © 2016-2022 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. + */ + +const child_process = require("child_process"); +const fs = require('fs'); +const path = require('path'); +const typeDir = './target/types'; +const srcDir = typeDir + '/src'; +const moduleMapPath = "src/app/modules/common/modules-map.ts"; + +console.log(`Remove directory: ${typeDir}`); +try { + fs.rmSync(typeDir, {recursive: true, force: true,}); +} catch (err) { + console.error(`Remove directory error: ${err}`); +} + +const cliCommand = `./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir ${srcDir}`; +console.log(cliCommand); +try { + child_process.execSync(cliCommand); +} catch (err) { + console.error("Build types", err); + process.exit(1); +} + +function fromDir(startPath, filter, callback) { + if (!fs.existsSync(startPath)) { + console.log("not dirs", startPath); + process.exit(1); + } + + const files = fs.readdirSync(startPath); + for (let i = 0; i < files.length; i++) { + const filename = path.join(startPath, files[i]); + const stat = fs.lstatSync(filename); + if (stat.isDirectory()) { + fromDir(filename, filter, callback); + } else if (filter.test(filename)) { + callback(filename) + } + } +} + + +fromDir(srcDir, /(\.js|\.js\.map)$/, function (filename) { + try { + fs.rmSync(filename); + } catch (err) { + console.error(`Remove file error ${filename}: ${err}`); + } +}); +fs.cpSync(moduleMapPath, `${typeDir}/${moduleMapPath}`); diff --git a/ui-ngx/package.json b/ui-ngx/package.json index ea004ccfa2..6c912e1fdf 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -6,7 +6,7 @@ "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", "build": "ng build", "build:prod": "ng build --configuration production --vendor-chunk", - "build:types": "rm -rf target/types && ./node_modules/.bin/ngc --p src/tsconfig.app.json --declaration --outDir target/types/src && find target/types/src -type f -name '*.js*' -delete && cp src/app/modules/common/modules-map.ts target/types/src/app/modules/common/modules-map.ts", + "build:types": "node generate-types.js", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e",