diff --git a/application/pom.xml b/application/pom.xml index 4d89099d5b..47d69d34dd 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -140,6 +140,10 @@ org.eclipse.paho org.eclipse.paho.client.mqttv3 + + org.eclipse.paho + org.eclipse.paho.mqttv5.client + org.cassandraunit cassandra-unit diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java index b5d256bfa8..5f4395fb47 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/AlarmEdgeProcessor.java @@ -51,7 +51,7 @@ import java.util.UUID; public class AlarmEdgeProcessor extends BaseEdgeProcessor { public ListenableFuture processAlarmFromEdge(TenantId tenantId, AlarmUpdateMsg alarmUpdateMsg) { - log.trace("[{}] onAlarmUpdate [{}]", tenantId, alarmUpdateMsg); + log.trace("[{}] processAlarmFromEdge [{}]", tenantId, alarmUpdateMsg); EntityId originatorId = getAlarmOriginator(tenantId, alarmUpdateMsg.getOriginatorName(), EntityType.valueOf(alarmUpdateMsg.getOriginatorType())); if (originatorId == null) { diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java index 81e7970611..02aca5165c 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java @@ -82,7 +82,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { private static final ReentrantLock deviceCreationLock = new ReentrantLock(); public ListenableFuture processDeviceFromEdge(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) { - log.trace("[{}] onDeviceUpdate [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); + log.trace("[{}] processDeviceFromEdge [{}] from edge [{}]", tenantId, deviceUpdateMsg, edge.getName()); switch (deviceUpdateMsg.getMsgType()) { case ENTITY_CREATED_RPC_MESSAGE: String deviceName = deviceUpdateMsg.getName(); @@ -155,7 +155,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { } public ListenableFuture processDeviceCredentialsFromEdge(TenantId tenantId, DeviceCredentialsUpdateMsg deviceCredentialsUpdateMsg) { - log.debug("Executing onDeviceCredentialsUpdate, deviceCredentialsUpdateMsg [{}]", deviceCredentialsUpdateMsg); + log.debug("[{}] Executing processDeviceCredentialsFromEdge, deviceCredentialsUpdateMsg [{}]", tenantId, deviceCredentialsUpdateMsg); DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsUpdateMsg.getDeviceIdMSB(), deviceCredentialsUpdateMsg.getDeviceIdLSB())); ListenableFuture deviceFuture = deviceService.findDeviceByIdAsync(tenantId, deviceId); return Futures.transform(deviceFuture, device -> { @@ -201,9 +201,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { device.setCustomerId(getCustomerId(deviceUpdateMsg)); Optional deviceDataOpt = dataDecodingEncodingService.decode(deviceUpdateMsg.getDeviceDataBytes().toByteArray()); - if (deviceDataOpt.isPresent()) { - device.setDeviceData(deviceDataOpt.get()); - } + deviceDataOpt.ifPresent(device::setDeviceData); Device savedDevice = deviceService.saveDevice(device); tbClusterService.onDeviceUpdated(savedDevice, device, false); return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null); @@ -462,7 +460,6 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor { } private DownlinkMsg convertRpcCallEventToDownlink(EdgeEvent edgeEvent) { - log.trace("Executing convertRpcCallEventToDownlink, edgeEvent [{}]", edgeEvent); return DownlinkMsg.newBuilder() .setDownlinkMsgId(EdgeUtils.nextPositiveInt()) .addDeviceRpcCallMsg(deviceMsgConstructor.constructDeviceRpcCallMsg(edgeEvent.getEntityId(), edgeEvent.getBody())) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java index 2998001a0a..8b07d771d6 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java @@ -58,7 +58,7 @@ import java.util.UUID; public class RelationEdgeProcessor extends BaseEdgeProcessor { public ListenableFuture processRelationFromEdge(TenantId tenantId, RelationUpdateMsg relationUpdateMsg) { - log.trace("[{}] onRelationUpdate [{}]", tenantId, relationUpdateMsg); + log.trace("[{}] processRelationFromEdge [{}]", tenantId, relationUpdateMsg); try { EntityRelation entityRelation = new EntityRelation(); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java index 4be7ddb1c8..2f72d96770 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java @@ -45,6 +45,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.kv.DataType; +import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; import org.thingsboard.server.common.data.relation.EntitySearchDirection; @@ -52,13 +53,10 @@ import org.thingsboard.server.common.data.relation.RelationTypeGroup; import org.thingsboard.server.common.data.relation.RelationsSearchParameters; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetsBundle; -import org.thingsboard.server.dao.asset.AssetProfileService; -import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.attributes.AttributesService; -import org.thingsboard.server.dao.device.DeviceProfileService; -import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.relation.RelationService; +import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.widget.WidgetTypeService; import org.thingsboard.server.dao.widget.WidgetsBundleService; import org.thingsboard.server.gen.edge.v1.AttributesRequestMsg; @@ -93,24 +91,15 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { private AttributesService attributesService; @Autowired - private RelationService relationService; - + private TimeseriesService timeseriesService; + @Autowired - private DeviceService deviceService; - - @Autowired - private AssetService assetService; + private RelationService relationService; @Lazy @Autowired private TbEntityViewService entityViewService; - @Autowired - private DeviceProfileService deviceProfileService; - - @Autowired - private AssetProfileService assetProfileService; - @Autowired private WidgetsBundleService widgetsBundleService; @@ -141,77 +130,89 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService { EntityId entityId = EntityIdFactory.getByTypeAndUuid( EntityType.valueOf(attributesRequestMsg.getEntityType()), new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB())); - final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); - if (type == null) { + final EdgeEventType entityType = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType()); + if (entityType == null) { log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType()); return Futures.immediateFuture(null); } - SettableFuture futureToSet = SettableFuture.create(); String scope = attributesRequestMsg.getScope(); ListenableFuture> findAttrFuture = attributesService.findAll(tenantId, entityId, scope); - Futures.addCallback(findAttrFuture, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable List ssAttributes) { - if (ssAttributes == null || ssAttributes.isEmpty()) { - log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId, - edge.getName(), - entityId.getEntityType(), - entityId.getId()); - futureToSet.set(null); - return; - } - - try { - Map entityData = new HashMap<>(); - ObjectNode attributes = JacksonUtil.OBJECT_MAPPER.createObjectNode(); - for (AttributeKvEntry attr : ssAttributes) { - if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(attr.getKey()) - && !DefaultDeviceStateService.INACTIVITY_TIMEOUT.equals(attr.getKey())) { - continue; - } - if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { - attributes.put(attr.getKey(), attr.getBooleanValue().get()); - } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { - attributes.put(attr.getKey(), attr.getDoubleValue().get()); - } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) { - attributes.put(attr.getKey(), attr.getLongValue().get()); - } else { - attributes.put(attr.getKey(), attr.getValueAsString()); - } - } - entityData.put("kv", attributes); - entityData.put("scope", scope); - JsonNode body = JacksonUtil.OBJECT_MAPPER.valueToTree(entityData); - log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body); - ListenableFuture future = saveEdgeEvent(tenantId, edge.getId(), type, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body); - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void unused) { - futureToSet.set(null); - } + return Futures.transformAsync(findAttrFuture, ssAttributes -> { + if (ssAttributes == null || ssAttributes.isEmpty()) { + log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId, + edge.getName(), + entityId.getEntityType(), + entityId.getId()); + return Futures.immediateFuture(null); + } + return processEntityAttributesAndAddToEdgeQueue(tenantId, entityId, edge, entityType, scope, ssAttributes, attributesRequestMsg); + }, dbCallbackExecutorService); + } - @Override - public void onFailure(Throwable throwable) { - String errMsg = String.format("[%s] Failed to save edge event [%s]", edge.getId(), attributesRequestMsg); - log.error(errMsg, throwable); - futureToSet.setException(new RuntimeException(errMsg, throwable)); - } - }, dbCallbackExecutorService); - } catch (Exception e) { - String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg); - log.error(errMsg, e); - futureToSet.setException(new RuntimeException(errMsg, e)); + private ListenableFuture processEntityAttributesAndAddToEdgeQueue(TenantId tenantId, EntityId entityId, Edge edge, + EdgeEventType entityType, String scope, List ssAttributes, + AttributesRequestMsg attributesRequestMsg) { + try { + Map entityData = new HashMap<>(); + ObjectNode attributes = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + for (AttributeKvEntry attr : ssAttributes) { + if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(attr.getKey()) + && !DefaultDeviceStateService.INACTIVITY_TIMEOUT.equals(attr.getKey())) { + continue; + } + if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) { + attributes.put(attr.getKey(), attr.getBooleanValue().get()); + } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) { + attributes.put(attr.getKey(), attr.getDoubleValue().get()); + } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) { + attributes.put(attr.getKey(), attr.getLongValue().get()); + } else { + attributes.put(attr.getKey(), attr.getValueAsString()); } } - - @Override - public void onFailure(Throwable t) { - String errMsg = String.format("[%s] Can't find attributes [%s]", edge.getId(), attributesRequestMsg); - log.error(errMsg, t); - futureToSet.setException(new RuntimeException(errMsg, t)); + ListenableFuture future; + if (attributes.size() > 0) { + entityData.put("kv", attributes); + entityData.put("scope", scope); + JsonNode body = JacksonUtil.OBJECT_MAPPER.valueToTree(entityData); + log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body); + future = saveEdgeEvent(tenantId, edge.getId(), entityType, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body); + } else { + future = Futures.immediateFuture(null); } + return Futures.transformAsync(future, v -> processLatestTimeseriesAndAddToEdgeQueue(tenantId, entityId, edge, entityType), dbCallbackExecutorService); + } catch (Exception e) { + String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg); + log.error(errMsg, e); + return Futures.immediateFailedFuture(new RuntimeException(errMsg, e)); + } + } + + private ListenableFuture processLatestTimeseriesAndAddToEdgeQueue(TenantId tenantId, EntityId entityId, Edge edge, + EdgeEventType entityType) { + ListenableFuture> getAllLatestFuture = timeseriesService.findAllLatest(tenantId, entityId); + return Futures.transformAsync(getAllLatestFuture, tsKvEntries -> { + if (tsKvEntries == null || tsKvEntries.isEmpty()) { + log.trace("[{}][{}] No timeseries found for entity {} [{}]", tenantId, + edge.getName(), + entityId.getEntityType(), + entityId.getId()); + return Futures.immediateFuture(null); + } + List> futures = new ArrayList<>(); + for (TsKvEntry tsKvEntry : tsKvEntries) { + if (DefaultDeviceStateService.PERSISTENT_ATTRIBUTES.contains(tsKvEntry.getKey())) { + continue; + } + ObjectNode entityBody = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + ObjectNode ts = JacksonUtil.OBJECT_MAPPER.createObjectNode(); + ts.put(tsKvEntry.getKey(), tsKvEntry.getValueAsString()); + entityBody.set("data", ts); + entityBody.put("ts", tsKvEntry.getTs()); + futures.add(saveEdgeEvent(tenantId, edge.getId(), entityType, EdgeEventActionType.TIMESERIES_UPDATED, entityId, JacksonUtil.valueToTree(entityBody))); + } + return Futures.transform(Futures.allAsList(futures), v -> null, dbCallbackExecutorService); }, dbCallbackExecutorService); - return futureToSet; } @Override diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index ee34bd7f23..9532bc3044 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -561,7 +561,7 @@ public class DefaultDataUpdateService implements DataUpdateService { while (hasNext) { for (Alarm alarm : alarms.getData()) { if (alarm.getCustomerId() == null && alarm.getOriginator() != null) { - alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator())); + alarm.setCustomerId(entityService.fetchEntityCustomerId(tenantId, alarm.getOriginator()).get()); alarmDao.save(tenantId, alarm); } if (processed.incrementAndGet() % 1000 == 0) { diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 02406da08a..5314d4872f 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -18,7 +18,6 @@ package org.thingsboard.server.edge; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.google.protobuf.AbstractMessage; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.MessageLite; import org.junit.After; @@ -38,9 +37,6 @@ import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; -import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; -import org.thingsboard.server.common.data.device.data.DeviceData; -import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; import org.thingsboard.server.common.data.device.profile.AlarmCondition; import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; import org.thingsboard.server.common.data.device.profile.AlarmConditionFilterKey; @@ -447,11 +443,6 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } protected Device saveDeviceOnCloudAndVerifyDeliveryToEdge() throws Exception { - // create ota package - edgeImitator.expectMessageAmount(1); - OtaPackageInfo firmwareOtaPackageInfo = saveOtaPackageInfo(thermostatDeviceProfile.getId()); - Assert.assertTrue(edgeImitator.waitForMessages()); - // create device and assign to edge Device savedDevice = saveDevice(StringUtils.randomAlphanumeric(15), thermostatDeviceProfile.getName()); edgeImitator.expectMessageAmount(2); // device and device profile messages @@ -471,38 +462,6 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, deviceProfileUpdateMsg.getMsgType()); Assert.assertEquals(thermostatDeviceProfile.getUuidId().getMostSignificantBits(), deviceProfileUpdateMsg.getIdMSB()); Assert.assertEquals(thermostatDeviceProfile.getUuidId().getLeastSignificantBits(), deviceProfileUpdateMsg.getIdLSB()); - - // update device - edgeImitator.expectMessageAmount(1); - savedDevice.setFirmwareId(firmwareOtaPackageInfo.getId()); - - DeviceData deviceData = new DeviceData(); - deviceData.setConfiguration(new DefaultDeviceConfiguration()); - MqttDeviceTransportConfiguration transportConfiguration = new MqttDeviceTransportConfiguration(); - transportConfiguration.getProperties().put("topic", "tb_rule_engine.thermostat"); - deviceData.setTransportConfiguration(transportConfiguration); - savedDevice.setDeviceData(deviceData); - - savedDevice = doPost("/api/device", savedDevice, Device.class); - Assert.assertTrue(edgeImitator.waitForMessages()); - AbstractMessage latestMessage = edgeImitator.getLatestMessage(); - Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg); - deviceUpdateMsg = (DeviceUpdateMsg) latestMessage; - Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, deviceUpdateMsg.getMsgType()); - Assert.assertEquals(savedDevice.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getIdMSB()); - Assert.assertEquals(savedDevice.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getIdLSB()); - Assert.assertEquals(savedDevice.getName(), deviceUpdateMsg.getName()); - Assert.assertEquals(savedDevice.getType(), deviceUpdateMsg.getType()); - Assert.assertEquals(firmwareOtaPackageInfo.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getFirmwareIdMSB()); - Assert.assertEquals(firmwareOtaPackageInfo.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getFirmwareIdLSB()); - Optional deviceDataOpt = - dataDecodingEncodingService.decode(deviceUpdateMsg.getDeviceDataBytes().toByteArray()); - Assert.assertTrue(deviceDataOpt.isPresent()); - deviceData = deviceDataOpt.get(); - Assert.assertTrue(deviceData.getTransportConfiguration() instanceof MqttDeviceTransportConfiguration); - MqttDeviceTransportConfiguration mqttDeviceTransportConfiguration = - (MqttDeviceTransportConfiguration) deviceData.getTransportConfiguration(); - Assert.assertEquals("tb_rule_engine.thermostat", mqttDeviceTransportConfiguration.getProperties().get("topic")); return savedDevice; } diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java index e5fe165a1e..4af8fede14 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseDeviceEdgeTest.java @@ -31,8 +31,12 @@ import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.device.data.DefaultDeviceConfiguration; +import org.thingsboard.server.common.data.device.data.DeviceData; +import org.thingsboard.server.common.data.device.data.MqttDeviceTransportConfiguration; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; import org.thingsboard.server.common.data.edge.EdgeEventActionType; @@ -57,8 +61,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.UplinkMsg; import org.thingsboard.server.gen.edge.v1.UplinkResponseMsg; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import java.util.List; import java.util.Map; @@ -170,6 +174,8 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { // create device and assign to edge; update device Device savedDevice = saveDeviceOnCloudAndVerifyDeliveryToEdge(); + verifyUpdateFirmwareIdAndDeviceData(savedDevice); + // update device credentials - ACCESS_TOKEN edgeImitator.expectMessageAmount(1); DeviceCredentials deviceCredentials = @@ -204,6 +210,45 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { Assert.assertEquals(deviceCredentials.getCredentialsValue(), deviceCredentialsUpdateMsg.getCredentialsValue()); } + private void verifyUpdateFirmwareIdAndDeviceData(Device savedDevice) throws InterruptedException { + // create ota package + edgeImitator.expectMessageAmount(1); + OtaPackageInfo firmwareOtaPackageInfo = saveOtaPackageInfo(thermostatDeviceProfile.getId()); + Assert.assertTrue(edgeImitator.waitForMessages()); + + // update device + edgeImitator.expectMessageAmount(1); + savedDevice.setFirmwareId(firmwareOtaPackageInfo.getId()); + + DeviceData deviceData = new DeviceData(); + deviceData.setConfiguration(new DefaultDeviceConfiguration()); + MqttDeviceTransportConfiguration transportConfiguration = new MqttDeviceTransportConfiguration(); + transportConfiguration.getProperties().put("topic", "tb_rule_engine.thermostat"); + deviceData.setTransportConfiguration(transportConfiguration); + savedDevice.setDeviceData(deviceData); + + savedDevice = doPost("/api/device", savedDevice, Device.class); + Assert.assertTrue(edgeImitator.waitForMessages()); + AbstractMessage latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof DeviceUpdateMsg); + DeviceUpdateMsg deviceUpdateMsg = (DeviceUpdateMsg) latestMessage; + Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, deviceUpdateMsg.getMsgType()); + Assert.assertEquals(savedDevice.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getIdMSB()); + Assert.assertEquals(savedDevice.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getIdLSB()); + Assert.assertEquals(savedDevice.getName(), deviceUpdateMsg.getName()); + Assert.assertEquals(savedDevice.getType(), deviceUpdateMsg.getType()); + Assert.assertEquals(firmwareOtaPackageInfo.getUuidId().getMostSignificantBits(), deviceUpdateMsg.getFirmwareIdMSB()); + Assert.assertEquals(firmwareOtaPackageInfo.getUuidId().getLeastSignificantBits(), deviceUpdateMsg.getFirmwareIdLSB()); + Optional deviceDataOpt = + dataDecodingEncodingService.decode(deviceUpdateMsg.getDeviceDataBytes().toByteArray()); + Assert.assertTrue(deviceDataOpt.isPresent()); + deviceData = deviceDataOpt.get(); + Assert.assertTrue(deviceData.getTransportConfiguration() instanceof MqttDeviceTransportConfiguration); + MqttDeviceTransportConfiguration mqttDeviceTransportConfiguration = + (MqttDeviceTransportConfiguration) deviceData.getTransportConfiguration(); + Assert.assertEquals("tb_rule_engine.thermostat", mqttDeviceTransportConfiguration.getProperties().get("topic")); + } + @Test public void testDeviceReachedMaximumAllowedOnCloud() throws Exception { // update tenant profile configuration @@ -323,6 +368,9 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { "inactivityTimeout", "3600000"); sendAttributesRequestAndVerify(device, DataConstants.SHARED_SCOPE, "{\"key2\":\"value2\"}", "key2", "value2"); + + doDelete("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/" + DataConstants.SERVER_SCOPE, "keys","key1, inactivityTimeout"); + doDelete("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/" + DataConstants.SHARED_SCOPE, "keys", "key2"); } @Test @@ -640,4 +688,53 @@ abstract public class BaseDeviceEdgeTest extends AbstractEdgeTest { client.disconnect(); } + + @Test + public void testVerifyDeliveryOfLatestTimeseriesOnAttributesRequest() throws Exception { + Device device = findDeviceByName("Edge Device 1"); + + JsonNode timeseriesData = mapper.readTree("{\"temperature\":25}"); + + doPost("/api/plugins/telemetry/DEVICE/" + device.getUuidId() + "/timeseries/" + DataConstants.SERVER_SCOPE, + timeseriesData); + + // Wait before device timeseries saved to database before requesting them from edge + Awaitility.await() + .atMost(10, TimeUnit.SECONDS) + .until(() -> { + String urlTemplate = "/api/plugins/telemetry/DEVICE/" + device.getId() + "/keys/timeseries"; + List actualKeys = doGetAsyncTyped(urlTemplate, new TypeReference<>() {}); + return actualKeys != null && !actualKeys.isEmpty() && actualKeys.contains("temperature"); + }); + + UplinkMsg.Builder uplinkMsgBuilder = UplinkMsg.newBuilder(); + AttributesRequestMsg.Builder attributesRequestMsgBuilder = AttributesRequestMsg.newBuilder(); + attributesRequestMsgBuilder.setEntityIdMSB(device.getUuidId().getMostSignificantBits()); + attributesRequestMsgBuilder.setEntityIdLSB(device.getUuidId().getLeastSignificantBits()); + attributesRequestMsgBuilder.setEntityType(EntityType.DEVICE.name()); + attributesRequestMsgBuilder.setScope(DataConstants.SERVER_SCOPE); + uplinkMsgBuilder.addAttributesRequestMsg(attributesRequestMsgBuilder.build()); + + edgeImitator.expectResponsesAmount(1); + edgeImitator.expectMessageAmount(1); + edgeImitator.sendUplinkMsg(uplinkMsgBuilder.build()); + Assert.assertTrue(edgeImitator.waitForResponses()); + Assert.assertTrue(edgeImitator.waitForMessages()); + + AbstractMessage latestMessage = edgeImitator.getLatestMessage(); + Assert.assertTrue(latestMessage instanceof EntityDataProto); + EntityDataProto latestEntityDataMsg = (EntityDataProto) latestMessage; + Assert.assertEquals(device.getUuidId().getMostSignificantBits(), latestEntityDataMsg.getEntityIdMSB()); + Assert.assertEquals(device.getUuidId().getLeastSignificantBits(), latestEntityDataMsg.getEntityIdLSB()); + Assert.assertEquals(device.getId().getEntityType().name(), latestEntityDataMsg.getEntityType()); + Assert.assertTrue(latestEntityDataMsg.hasPostTelemetryMsg()); + + TransportProtos.PostTelemetryMsg timeseriesUpdatedMsg = latestEntityDataMsg.getPostTelemetryMsg(); + Assert.assertEquals(1, timeseriesUpdatedMsg.getTsKvListList().size()); + TransportProtos.TsKvListProto tsKvListProto = timeseriesUpdatedMsg.getTsKvListList().get(0); + Assert.assertEquals(1, tsKvListProto.getKvList().size()); + TransportProtos.KeyValueProto keyValueProto = tsKvListProto.getKvList().get(0); + Assert.assertEquals(25, keyValueProto.getLongV()); + Assert.assertEquals("temperature", keyValueProto.getKey()); + } } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestCallback.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestCallback.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestCallback.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestCallback.java index 18815d1c38..8c2bc5d488 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestCallback.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestCallback.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt; +package org.thingsboard.server.transport.mqtt.mqttv3; import lombok.Data; import lombok.extern.slf4j.Slf4j; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestClient.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestClient.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestClient.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestClient.java index 96846f8678..a0aa1905eb 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/MqttTestClient.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/MqttTestClient.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt; +package org.thingsboard.server.transport.mqtt.mqttv3; import io.netty.handler.codec.mqtt.MqttQoS; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; @@ -104,6 +104,10 @@ public class MqttTestClient { return client.subscribe(topic, qoS.value()); } + public boolean isConnected() { + return client.isConnected(); + } + public void enableManualAcks() { client.setManualAcks(true); } @@ -112,6 +116,10 @@ public class MqttTestClient { client.messageArrivedComplete(mqttMessage.getId(), mqttMessage.getQos()); } + private MqttAsyncClient createClient() throws MqttException { + return createClient(null); + } + private MqttAsyncClient createClient(String clientId) throws MqttException { if (StringUtils.isEmpty(clientId)) { clientId = MqttAsyncClient.generateClientId(); @@ -119,8 +127,4 @@ public class MqttTestClient { return new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); } - private MqttAsyncClient createClient() throws MqttException { - return createClient(null); - } - } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java index 56d9ef5e9e..8811767326 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/AbstractMqttAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/AbstractMqttAttributesIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes; import com.github.os72.protobuf.dynamic.DynamicSchema; import com.google.protobuf.Descriptors; @@ -22,7 +22,6 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.squareup.wire.schema.internal.parser.ProtoFileElement; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; -import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DynamicProtoUtils; @@ -41,8 +40,8 @@ import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.service.telemetry.cmd.v2.EntityDataUpdate; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import java.util.ArrayList; import java.util.List; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java index 2231cb89eb..e9337b5446 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestBackwardCompatibilityIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.request; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request; import lombok.extern.slf4j.Slf4j; import org.junit.Test; @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import java.util.ArrayList; import java.util.List; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestIntegrationTest.java similarity index 93% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestIntegrationTest.java index c4da6b3184..a9dc90f3c7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.request; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -21,7 +21,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; @Slf4j @DaoSqlTest diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestJsonIntegrationTest.java similarity index 93% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestJsonIntegrationTest.java index a27c9391fd..d8e2f4428e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestJsonIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.request; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; @Slf4j @DaoSqlTest diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestProtoIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestProtoIntegrationTest.java index d330cdbbaf..ef8533e582 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/request/MqttAttributesRequestProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/request/MqttAttributesRequestProtoIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.request; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.request; import lombok.extern.slf4j.Slf4j; import org.junit.Test; @@ -22,7 +22,7 @@ import org.thingsboard.server.common.data.device.profile.MqttTopics; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import java.util.ArrayList; import java.util.List; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java index 05253cd969..3332b962e2 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesBackwardCompatibilityIntegrationTest.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.updates; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesIntegrationTest.java similarity index 93% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesIntegrationTest.java index 01a33c5b5c..830c40aa91 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.updates; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -21,7 +21,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java similarity index 93% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java index f35ce1e084..834a01fb03 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesJsonIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.updates; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -21,7 +21,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java similarity index 94% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java index dc7e92a128..91c302f322 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/attributes/updates/MqttAttributesUpdatesProtoIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.attributes.updates; +package org.thingsboard.server.transport.mqtt.mqttv3.attributes.updates; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -21,7 +21,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; -import org.thingsboard.server.transport.mqtt.attributes.AbstractMqttAttributesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.attributes.AbstractMqttAttributesIntegrationTest; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimBackwardCompatibilityDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimBackwardCompatibilityDeviceTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimBackwardCompatibilityDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimBackwardCompatibilityDeviceTest.java index e7670b5170..00a77c2e2b 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimBackwardCompatibilityDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimBackwardCompatibilityDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.claim; +package org.thingsboard.server.transport.mqtt.mqttv3.claim; import lombok.extern.slf4j.Slf4j; import org.junit.Before; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimDeviceTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimDeviceTest.java index df3ac12e45..c46b78b77d 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.claim; +package org.thingsboard.server.transport.mqtt.mqttv3.claim; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -28,7 +28,7 @@ import org.thingsboard.server.dao.device.claim.ClaimResult; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import static org.junit.Assert.assertEquals; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimJsonDeviceTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimJsonDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimJsonDeviceTest.java index 05d4974f9d..3c90eda7ed 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimJsonDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.claim; +package org.thingsboard.server.transport.mqtt.mqttv3.claim; import lombok.extern.slf4j.Slf4j; import org.junit.Before; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimProtoDeviceTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimProtoDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimProtoDeviceTest.java index 89c8c5f231..0bfc057806 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/claim/MqttClaimProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/claim/MqttClaimProtoDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.claim; +package org.thingsboard.server.transport.mqtt.mqttv3.claim; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -21,7 +21,7 @@ import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.transport.TransportApiProtos; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; @Slf4j diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/AbstractMqttClientConnectionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/AbstractMqttClientConnectionTest.java new file mode 100644 index 0000000000..634458c07d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/AbstractMqttClientConnectionTest.java @@ -0,0 +1,50 @@ +/** + * 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.server.transport.mqtt.mqttv3.client; + +import org.eclipse.paho.client.mqttv3.MqttException; +import org.junit.Assert; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; + +public abstract class AbstractMqttClientConnectionTest extends AbstractMqttIntegrationTest { + + protected void processClientWithCorrectAccessTokenTest() throws Exception { + MqttTestClient client = new MqttTestClient(); + client.connectAndWait(accessToken); + Assert.assertTrue(client.isConnected()); + client.disconnect(); + } + + protected void processClientWithWrongAccessTokenTest() throws Exception { + MqttTestClient client = new MqttTestClient(); + try { + client.connectAndWait("wrongAccessToken"); + } catch (MqttException e) { + Assert.assertEquals(MqttException.REASON_CODE_FAILED_AUTHENTICATION, e.getReasonCode()); + } + } + + protected void processClientWithWrongClientIdAndEmptyUsernamePasswordTest() throws Exception { + MqttTestClient client = new MqttTestClient("unknownClientId"); + try { + client.connectAndWait(); + } catch (MqttException e) { + Assert.assertEquals(MqttException.REASON_CODE_INVALID_CLIENT_ID, e.getReasonCode()); + } + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/MqttClientConnectionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/MqttClientConnectionTest.java new file mode 100644 index 0000000000..5e6e6e0188 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/client/MqttClientConnectionTest.java @@ -0,0 +1,48 @@ +/** + * 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.server.transport.mqtt.mqttv3.client; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttClientConnectionTest extends AbstractMqttClientConnectionTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test MqttV5 client device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testClientWithCorrectAccessToken() throws Exception { + processClientWithCorrectAccessTokenTest(); + } + + @Test + public void testClientWithWrongAccessToken() throws Exception { + processClientWithWrongAccessTokenTest(); + } + + @Test + public void testClientWithWrongClientIdAndEmptyUsernamePassword() throws Exception { + processClientWithWrongClientIdAndEmptyUsernamePasswordTest(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/credentials/BasicMqttCredentialsTest.java similarity index 93% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/credentials/BasicMqttCredentialsTest.java index 0884f1457c..af463e320e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/credentials/BasicMqttCredentialsTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/credentials/BasicMqttCredentialsTest.java @@ -13,10 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.credentials; +package org.thingsboard.server.transport.mqtt.mqttv3.credentials; import com.fasterxml.jackson.core.type.TypeReference; -import org.eclipse.paho.client.mqttv3.MqttSecurityException; +import org.eclipse.paho.client.mqttv3.MqttException; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.thingsboard.common.util.JacksonUtil; @@ -27,7 +28,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.common.data.security.DeviceCredentialsType; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import java.util.Arrays; import java.util.HashSet; @@ -114,11 +115,16 @@ public class BasicMqttCredentialsTest extends AbstractMqttIntegrationTest { testTelemetryIsDelivered(accessToken2Device, mqttTestClient5); } - @Test(expected = MqttSecurityException.class) + @Test(expected = MqttException.class) public void testCorrectClientIdAndUserNameButWrongPassword() throws Exception { // Not correct. Correct clientId and username, but wrong password MqttTestClient mqttTestClient = new MqttTestClient(CLIENT_ID); - mqttTestClient.connectAndWait(USER_NAME3, "WRONG PASSWORD"); + try { + mqttTestClient.connectAndWait(USER_NAME3, "WRONG PASSWORD"); + Assert.fail(); // This should not happens, because we have a wrong password + } catch (MqttException e) { + Assert.assertEquals(4, e.getReasonCode()); // 4 - Reason code for bad username or password in MQTT v3 + } testTelemetryIsNotDelivered(clientIdAndUserNameAndPasswordDevice3, mqttTestClient); } diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionJsonDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionJsonDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java index 0a06f99209..deb2685bf7 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionJsonDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionJsonDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.provision; +package org.thingsboard.server.transport.mqtt.mqttv3.provision; import com.fasterxml.jackson.databind.JsonNode; import io.netty.handler.codec.mqtt.MqttQoS; @@ -33,8 +33,8 @@ import org.thingsboard.server.dao.device.DeviceService; import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.concurrent.TimeUnit; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionProtoDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionProtoDeviceTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java index 9e61b69ebf..ce994a3057 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/provision/MqttProvisionProtoDeviceTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/provision/MqttProvisionProtoDeviceTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.provision; +package org.thingsboard.server.transport.mqtt.mqttv3.provision; import io.netty.handler.codec.mqtt.MqttQoS; import lombok.extern.slf4j.Slf4j; @@ -41,8 +41,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.ValidateBasicMqttCre import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceTokenRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.ValidateDeviceX509CertRequestMsg; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.concurrent.TimeUnit; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java index 2cdfb76645..483c2bb350 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/AbstractMqttServerSideRpcIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/AbstractMqttServerSideRpcIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.rpc; +package org.thingsboard.server.transport.mqtt.mqttv3.rpc; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -39,8 +39,8 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import java.util.ArrayList; import java.util.List; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java index 5fb123666f..d8a896a83e 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcBackwardCompatibilityIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.rpc; +package org.thingsboard.server.transport.mqtt.mqttv3.rpc; import lombok.extern.slf4j.Slf4j; import org.junit.Test; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcDefaultIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcDefaultIntegrationTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcDefaultIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcDefaultIntegrationTest.java index 95e3b7fde3..042e2808b3 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcDefaultIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcDefaultIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.rpc; +package org.thingsboard.server.transport.mqtt.mqttv3.rpc; import com.datastax.oss.driver.api.core.uuid.Uuids; import lombok.extern.slf4j.Slf4j; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcJsonIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcJsonIntegrationTest.java index b3c3a994d1..508ce02fcd 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcJsonIntegrationTest.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.rpc; +package org.thingsboard.server.transport.mqtt.mqttv3.rpc; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcProtoIntegrationTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcProtoIntegrationTest.java index e888f49ff4..0286c20f3f 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/MqttServerSideRpcProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/rpc/MqttServerSideRpcProtoIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.rpc; +package org.thingsboard.server.transport.mqtt.mqttv3.rpc; import lombok.extern.slf4j.Slf4j; import org.junit.Before; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesIntegrationTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesIntegrationTest.java index 1d986d0453..04cbbe9a30 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.attributes; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.Arrays; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesJsonIntegrationTest.java similarity index 96% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesJsonIntegrationTest.java index f77885c0fd..17e0edb14c 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesJsonIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.attributes; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes; import lombok.extern.slf4j.Slf4j; import org.junit.Before; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesProtoIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesProtoIntegrationTest.java index 7b2fa1143d..da25f39def 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/attributes/MqttAttributesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/attributes/MqttAttributesProtoIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.attributes; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.attributes; import com.github.os72.protobuf.dynamic.DynamicSchema; import com.google.protobuf.Descriptors; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java similarity index 98% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java index 5bb0d28a21..0a58804e92 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries; import com.fasterxml.jackson.core.type.TypeReference; import io.netty.handler.codec.mqtt.MqttQoS; @@ -23,8 +23,8 @@ import org.junit.Test; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.Arrays; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java similarity index 97% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java index 4a7037f6e8..dc94f53f38 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesJsonIntegrationTest.java @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries; import lombok.extern.slf4j.Slf4j; import org.junit.Before; import org.junit.Test; import org.thingsboard.server.common.data.TransportPayloadType; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.Arrays; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java similarity index 99% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java index 9c92e3f4f0..0b67f0e48a 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/AbstractMqttTimeseriesProtoIntegrationTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries; import com.github.os72.protobuf.dynamic.DynamicSchema; import com.google.protobuf.Descriptors; @@ -31,8 +31,8 @@ import org.thingsboard.server.common.data.device.profile.ProtoTransportPayloadCo import org.thingsboard.server.common.data.device.profile.TransportPayloadTypeConfiguration; import org.thingsboard.server.gen.transport.TransportApiProtos; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.transport.mqtt.MqttTestCallback; -import org.thingsboard.server.transport.mqtt.MqttTestClient; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestCallback; +import org.thingsboard.server.transport.mqtt.mqttv3.MqttTestClient; import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; import java.util.Arrays; diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java index 7006638eb1..1d9baa5b08 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql; import org.thingsboard.server.dao.service.DaoNoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest; @DaoNoSqlTest public class MqttTimeseriesNoSqlIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java index 8e6e2cf679..999e5717b4 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlJsonIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql; import org.thingsboard.server.dao.service.DaoNoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; @DaoNoSqlTest public class MqttTimeseriesNoSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java index e91d5982d7..06f2bff3b5 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/nosql/MqttTimeseriesNoSqlProtoIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.nosql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.nosql; import org.thingsboard.server.dao.service.DaoNoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; @DaoNoSqlTest public class MqttTimeseriesNoSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java index de9a596d43..e317debabc 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesIntegrationTest; @DaoSqlTest public class MqttTimeseriesSqlIntegrationTest extends AbstractMqttTimeseriesIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java index 323dd751f1..bf991c0c06 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlJsonIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesJsonIntegrationTest; @DaoSqlTest public class MqttTimeseriesSqlJsonIntegrationTest extends AbstractMqttTimeseriesJsonIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java similarity index 80% rename from application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java rename to application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java index ebfc1d49cf..7e17d30844 100644 --- a/application/src/test/java/org/thingsboard/server/transport/mqtt/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv3/telemetry/timeseries/sql/MqttTimeseriesSqlProtoIntegrationTest.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.thingsboard.server.transport.mqtt.telemetry.timeseries.sql; +package org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.sql; import org.thingsboard.server.dao.service.DaoSqlTest; -import org.thingsboard.server.transport.mqtt.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv3.telemetry.timeseries.AbstractMqttTimeseriesProtoIntegrationTest; @DaoSqlTest public class MqttTimeseriesSqlProtoIntegrationTest extends AbstractMqttTimeseriesProtoIntegrationTest { diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/AbstractMqttV5Test.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/AbstractMqttV5Test.java new file mode 100644 index 0000000000..4714184f0e --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/AbstractMqttV5Test.java @@ -0,0 +1,21 @@ +/** + * 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.server.transport.mqtt.mqttv5; + +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; + +public abstract class AbstractMqttV5Test extends AbstractMqttIntegrationTest { +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestCallback.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestCallback.java new file mode 100644 index 0000000000..7979936659 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestCallback.java @@ -0,0 +1,110 @@ +/** + * 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.server.transport.mqtt.mqttv5; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.client.MqttCallback; +import org.eclipse.paho.mqttv5.client.MqttDisconnectResponse; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; +import org.eclipse.paho.mqttv5.common.packet.MqttProperties; +import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; + +import java.util.concurrent.CountDownLatch; + +@Slf4j +@Data +public class MqttV5TestCallback implements MqttCallback { + + protected CountDownLatch subscribeLatch; + protected final CountDownLatch deliveryLatch; + protected int qoS; + protected byte[] payloadBytes; + protected String awaitSubTopic; + protected boolean pubAckReceived; + protected MqttMessage lastReceivedMessage; + + public MqttV5TestCallback() { + this.subscribeLatch = new CountDownLatch(1); + this.deliveryLatch = new CountDownLatch(1); + } + + public MqttV5TestCallback(int subscribeCount) { + this.subscribeLatch = new CountDownLatch(subscribeCount); + this.deliveryLatch = new CountDownLatch(1); + } + + public MqttV5TestCallback(String awaitSubTopic) { + this.subscribeLatch = new CountDownLatch(1); + this.deliveryLatch = new CountDownLatch(1); + this.awaitSubTopic = awaitSubTopic; + } + + @Override + public void disconnected(MqttDisconnectResponse mqttDisconnectResponse) { + if (mqttDisconnectResponse.getException() != null) { + log.warn("connectionLost: ", mqttDisconnectResponse.getException()); + deliveryLatch.countDown(); + } + log.warn("Disconnected with reason: {}", mqttDisconnectResponse.getReasonString()); + } + + @Override + public void mqttErrorOccurred(MqttException e) { + log.warn("Error occurred:", e); + } + + @Override + public void messageArrived(String requestTopic, MqttMessage mqttMessage) { + lastReceivedMessage = mqttMessage; + if (awaitSubTopic == null) { + log.warn("messageArrived on topic: {}", requestTopic); + qoS = mqttMessage.getQos(); + payloadBytes = mqttMessage.getPayload(); + subscribeLatch.countDown(); + } else { + messageArrivedOnAwaitSubTopic(requestTopic, mqttMessage); + } + } + + protected void messageArrivedOnAwaitSubTopic(String requestTopic, MqttMessage mqttMessage) { + log.warn("messageArrived on topic: {}, awaitSubTopic: {}", requestTopic, awaitSubTopic); + if (awaitSubTopic.equals(requestTopic)) { + qoS = mqttMessage.getQos(); + payloadBytes = mqttMessage.getPayload(); + subscribeLatch.countDown(); + } + } + + @Override + public void deliveryComplete(IMqttToken iMqttToken) { + log.warn("delivery complete: {}", iMqttToken.getResponse()); + pubAckReceived = iMqttToken.getResponse().getType() == MqttWireMessage.MESSAGE_TYPE_PUBACK; + deliveryLatch.countDown(); + } + + @Override + public void connectComplete(boolean reconnect, String serverURI) { + log.warn("Connect completed: reconnect - {}, serverURI - {}", reconnect, serverURI); + } + + @Override + public void authPacketArrived(int reasonCode, MqttProperties mqttProperties) { + log.warn("Auth package received: reasonCode - {}, mqtt properties - {}", reasonCode, mqttProperties); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestClient.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestClient.java new file mode 100644 index 0000000000..0671dd6f95 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/MqttV5TestClient.java @@ -0,0 +1,175 @@ +/** + * 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.server.transport.mqtt.mqttv5; + +import io.netty.handler.codec.mqtt.MqttQoS; +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.client.MqttAsyncClient; +import org.eclipse.paho.mqttv5.client.MqttCallback; +import org.eclipse.paho.mqttv5.client.MqttConnectionOptions; +import org.eclipse.paho.mqttv5.client.persist.MemoryPersistence; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; +import org.thingsboard.server.common.data.StringUtils; + +import java.util.concurrent.TimeUnit; + +public class MqttV5TestClient { // We should copy part of MqttV3TestClient, due to different package names in import + + private static final String MQTT_URL = "tcp://localhost:1883"; + private static final int TIMEOUT = 30; // seconds + private static final long TIMEOUT_MS = TimeUnit.SECONDS.toMillis(TIMEOUT); + + private final MqttAsyncClient client; + + public void setCallback(MqttCallback callback) { + client.setCallback(callback); + } + + public MqttV5TestClient() throws MqttException { + this.client = createClient(); + } + + public MqttV5TestClient(String clientId) throws MqttException { + this.client = createClient(clientId); + } + + public MqttV5TestClient(boolean generateClientId) throws MqttException { + this.client = createClient(generateClientId); + } + + public IMqttToken connectAndWait(String userName, String password) throws MqttException { + IMqttToken connect = connect(userName, password); + connect.waitForCompletion(TIMEOUT_MS); + return connect; + } + + public IMqttToken connectAndWait(String userName) throws MqttException { + return connectAndWait(userName, null); + } + + public IMqttToken connectAndWait() throws MqttException { + return connectAndWait(null, null); + } + + public IMqttToken connectAndWait(MqttConnectionOptions options) throws MqttException { + IMqttToken iMqttToken = connect(options); + iMqttToken.waitForCompletion(TIMEOUT_MS); + return iMqttToken; + } + + private IMqttToken connect(String userName, String password) throws MqttException { + if (client == null) { + throw new RuntimeException("Failed to connect! MqttAsyncClient is not initialized!"); + } + MqttConnectionOptions options = new MqttConnectionOptions(); + if (StringUtils.isNotEmpty(userName)) { + options.setUserName(userName); + } + if (StringUtils.isNotEmpty(password)) { + options.setPassword(password.getBytes()); + } + return client.connect(options); + } + + public IMqttToken connect(MqttConnectionOptions options) throws MqttException { + if (client == null) { + throw new RuntimeException("Failed to connect! MqttAsyncClient is not initialized!"); + } + return client.connect(options); + } + + public void disconnectAndWait() throws MqttException { + disconnect().waitForCompletion(TIMEOUT_MS); + } + + public IMqttToken disconnect() throws MqttException { + return client.disconnect(); + } + + public void disconnectForcibly() throws MqttException { + client.disconnectForcibly(TIMEOUT_MS); + } + + public IMqttToken publishAndWait(String topic, byte[] payload) throws MqttException { + IMqttToken iMqttToken = publish(topic, payload); + iMqttToken.waitForCompletion(TIMEOUT_MS); + return iMqttToken; + } + + public IMqttToken publish(String topic, byte[] payload) throws MqttException { + MqttMessage message = new MqttMessage(); + message.setPayload(payload); + return publish(topic, message); + } + + public IMqttToken publish(String topic, MqttMessage message) throws MqttException { + return publish(topic, message.getPayload(), message.getQos(), message.isRetained()); + } + + public IMqttToken publish(String topic, byte[] payload, int qos, boolean retain) throws MqttException { + return client.publish(topic, payload, qos, retain); + } + + public IMqttToken subscribeAndWait(String topic, MqttQoS qoS) throws MqttException { + IMqttToken iMqttToken = subscribe(topic, qoS); + iMqttToken.waitForCompletion(TIMEOUT_MS); + return iMqttToken; + } + + public IMqttToken subscribe(String topic, MqttQoS qoS) throws MqttException { + return client.subscribe(topic, qoS.value()); + } + + public IMqttToken unsubscribeAndWait(String topic) throws MqttException { + IMqttToken iMqttToken = unsubscribe(topic); + iMqttToken.waitForCompletion(TIMEOUT_MS); + return iMqttToken; + } + + public IMqttToken unsubscribe(String topic) throws MqttException { + return client.unsubscribe(topic); + } + + public boolean isConnected() { + return client.isConnected(); + } + + public void enableManualAcks() { + client.setManualAcks(true); + } + + public void messageArrivedComplete(MqttMessage mqttMessage) throws MqttException { + client.messageArrivedComplete(mqttMessage.getId(), mqttMessage.getQos()); + } + + private MqttAsyncClient createClient() throws MqttException { + return createClient(true); + } + + private MqttAsyncClient createClient(boolean generateClientId) throws MqttException { + String clientId = null; + if (generateClientId) { + clientId = "test" + System.nanoTime(); + } + return createClient(clientId); + } + + private MqttAsyncClient createClient(String clientId) throws MqttException { + return new MqttAsyncClient(MQTT_URL, clientId, new MemoryPersistence()); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java new file mode 100644 index 0000000000..204c66e597 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/AbstractAttributesMqttV5Test.java @@ -0,0 +1,161 @@ +/** + * 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.server.transport.mqtt.mqttv5.attributes; + +import com.fasterxml.jackson.core.type.TypeReference; +import io.netty.handler.codec.mqtt.MqttQoS; +import org.junit.Before; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; +import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public abstract class AbstractAttributesMqttV5Test extends AbstractMqttV5Test { + + private static final String SHARED_ATTRIBUTES_PAYLOAD = "{\"sharedStr\":\"value1\",\"sharedBool\":true,\"sharedDbl\":42.0,\"sharedLong\":73," + + "\"sharedJson\":{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}}"; + + private static final String SHARED_ATTRIBUTES_DELETED_RESPONSE = "{\"deleted\":[\"sharedJson\"]}"; + + protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Post Attributes device") + .build(); + processBeforeTest(configProperties); + } + + protected void processAttributesPublishTest() throws Exception { + List expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); + + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, PAYLOAD_VALUES_STR.getBytes()); + client.disconnectAndWait(); + + DeviceId deviceId = savedDevice.getId(); + + long start = System.currentTimeMillis(); + long end = System.currentTimeMillis() + 5000; + + List actualKeys = null; + while (start <= end) { + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/attributes/CLIENT_SCOPE", new TypeReference<>() { + }); + if (actualKeys.size() == expectedKeys.size()) { + break; + } + Thread.sleep(100); + start += 100; + } + assertNotNull(actualKeys); + + Set actualKeySet = new HashSet<>(actualKeys); + + Set expectedKeySet = new HashSet<>(expectedKeys); + + assertEquals(expectedKeySet, actualKeySet); + + String getAttributesValuesUrl = getAttributesValuesUrl(deviceId, actualKeySet); + List> values = doGetAsyncTyped(getAttributesValuesUrl, new TypeReference<>() { + }); + assertAttributesValues(values, actualKeySet); + String deleteAttributesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); + doDelete(deleteAttributesUrl); + } + + protected void processAttributesUpdatesTest() throws Exception { + + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback(); + client.setCallback(onUpdateCallback); + client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", SHARED_ATTRIBUTES_PAYLOAD, String.class, status().isOk()); + onUpdateCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + + validateUpdateAttributesResponse(onUpdateCallback, SHARED_ATTRIBUTES_PAYLOAD); + + MqttV5TestCallback onDeleteCallback = new MqttV5TestCallback(); + client.setCallback(onDeleteCallback); + doDelete("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/SHARED_SCOPE?keys=sharedJson", String.class); + onDeleteCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + + validateUpdateAttributesResponse(onDeleteCallback, SHARED_ATTRIBUTES_DELETED_RESPONSE); + + client.disconnect(); + } + + private String getAttributesValuesUrl(DeviceId deviceId, Set actualKeySet) { + return "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/attributes/CLIENT_SCOPE?keys=" + String.join(",", actualKeySet); + } + + protected void assertAttributesValues(List> deviceValues, Set keySet) { + for (Map map : deviceValues) { + String key = (String) map.get("key"); + Object value = map.get("value"); + assertTrue(keySet.contains(key)); + switch (key) { + case "key1": + assertEquals("value1", value); + break; + case "key2": + assertEquals(true, value); + break; + case "key3": + assertEquals(3.0, value); + break; + case "key4": + assertEquals(4, value); + break; + case "key5": + assertNotNull(value); + assertEquals(3, ((LinkedHashMap) value).size()); + assertEquals(42, ((LinkedHashMap) value).get("someNumber")); + assertEquals(Arrays.asList(1, 2, 3), ((LinkedHashMap) value).get("someArray")); + LinkedHashMap someNestedObject = (LinkedHashMap) ((LinkedHashMap) value).get("someNestedObject"); + assertEquals("value", someNestedObject.get("key")); + break; + } + } + } + + protected void validateUpdateAttributesResponse(MqttV5TestCallback callback, String expectedResponse) { + assertNotNull(callback.getPayloadBytes()); + assertEquals(JacksonUtil.toJsonNode(expectedResponse), JacksonUtil.fromBytes(callback.getPayloadBytes())); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/updates/AttributesUpdatesTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/updates/AttributesUpdatesTest.java new file mode 100644 index 0000000000..cd37ae4b9c --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/updates/AttributesUpdatesTest.java @@ -0,0 +1,43 @@ +/** + * 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.server.transport.mqtt.mqttv5.attributes.updates; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; +import org.thingsboard.server.transport.mqtt.mqttv5.attributes.AbstractAttributesMqttV5Test; + +@Slf4j +@DaoSqlTest +public class AttributesUpdatesTest extends AbstractAttributesMqttV5Test { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Subscribe to attribute updates") + .transportPayloadType(TransportPayloadType.JSON) + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testAttributeMqttV5SimpleClientUpdates() throws Exception { + processAttributesUpdatesTest(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/upload/AttributesPublishTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/upload/AttributesPublishTest.java new file mode 100644 index 0000000000..03b74a0819 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/attributes/upload/AttributesPublishTest.java @@ -0,0 +1,38 @@ +/** + * 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.server.transport.mqtt.mqttv5.attributes.upload; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; +import org.thingsboard.server.transport.mqtt.mqttv5.attributes.AbstractAttributesMqttV5Test; + +@DaoSqlTest +public class AttributesPublishTest extends AbstractAttributesMqttV5Test { + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Post Attributes device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testMqttV5AttributePublishTest() throws Exception { + processAttributesPublishTest(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/AbstractMqttV5ClaimTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/AbstractMqttV5ClaimTest.java new file mode 100644 index 0000000000..4edfce992e --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/AbstractMqttV5ClaimTest.java @@ -0,0 +1,101 @@ +/** + * 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.server.transport.mqtt.mqttv5.claim; + +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.ClaimRequest; +import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.dao.device.claim.ClaimResponse; +import org.thingsboard.server.dao.device.claim.ClaimResult; +import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_CLAIM_TOPIC; + +@Slf4j +public abstract class AbstractMqttV5ClaimTest extends AbstractMqttV5Test { + protected static final String CUSTOMER_USER_PASSWORD = "customerUser123!"; + + protected User customerAdmin; + protected Customer savedCustomer; + + protected void processTestClaimingDevice() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + byte[] payloadBytes; + byte[] failurePayloadBytes; + payloadBytes = "{\"secretKey\":\"value\", \"durationMs\":60000}".getBytes(); + failurePayloadBytes = "{\"secretKey\":\"value\", \"durationMs\":1}".getBytes(); + validateClaimResponse(client, payloadBytes, failurePayloadBytes); + } + + protected void validateClaimResponse(MqttV5TestClient client, byte[] payloadBytes, byte[] failurePayloadBytes) throws Exception { + client.publishAndWait(DEVICE_CLAIM_TOPIC, failurePayloadBytes); + + loginUser(customerAdmin.getName(), CUSTOMER_USER_PASSWORD); + ClaimRequest claimRequest = new ClaimRequest("value"); + + ClaimResponse claimResponse = doExecuteWithRetriesAndInterval( + () -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()), + 20, + 100 + ); + + assertEquals(claimResponse, ClaimResponse.FAILURE); + + client.publishAndWait(DEVICE_CLAIM_TOPIC, payloadBytes); + client.disconnect(); + + ClaimResult claimResult = doExecuteWithRetriesAndInterval( + () -> doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResult.class, status().isOk()), + 20, + 100 + ); + assertEquals(claimResult.getResponse(), ClaimResponse.SUCCESS); + Device claimedDevice = claimResult.getDevice(); + assertNotNull(claimedDevice); + assertNotNull(claimedDevice.getCustomerId()); + assertEquals(customerAdmin.getCustomerId(), claimedDevice.getCustomerId()); + + claimResponse = doPostClaimAsync("/api/customer/device/" + savedDevice.getName() + "/claim", claimRequest, ClaimResponse.class, status().isBadRequest()); + assertEquals(claimResponse, ClaimResponse.CLAIMED); + } + + protected void createCustomerAndUser() throws Exception { + Customer customer = new Customer(); + customer.setTenantId(tenantId); + customer.setTitle("Test Claiming Customer"); + savedCustomer = doPost("/api/customer", customer, Customer.class); + assertNotNull(savedCustomer); + assertEquals(tenantId, savedCustomer.getTenantId()); + + User user = new User(); + user.setAuthority(Authority.CUSTOMER_USER); + user.setTenantId(tenantId); + user.setCustomerId(savedCustomer.getId()); + user.setEmail("customer@thingsboard.org"); + + customerAdmin = createUser(user, CUSTOMER_USER_PASSWORD); + assertNotNull(customerAdmin); + assertEquals(customerAdmin.getCustomerId(), savedCustomer.getId()); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/MqttV5ClaimTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/MqttV5ClaimTest.java new file mode 100644 index 0000000000..5111cbec56 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/claim/MqttV5ClaimTest.java @@ -0,0 +1,39 @@ +/** + * 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.server.transport.mqtt.mqttv5.claim; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5ClaimTest extends AbstractMqttV5ClaimTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Claim device") + .build(); + processBeforeTest(configProperties); + createCustomerAndUser(); + } + + @Test + public void testClaimingDevice() throws Exception { + processTestClaimingDevice(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java new file mode 100644 index 0000000000..875cf7a020 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/AbstractMqttV5ClientConnectionTest.java @@ -0,0 +1,111 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.connection; + +import io.netty.handler.codec.mqtt.MqttQoS; +import org.apache.commons.lang3.StringUtils; +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.client.MqttConnectionOptions; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.packet.MqttConnAck; +import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode; +import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; +import org.junit.Assert; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import java.util.concurrent.TimeUnit; + +import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_CONNACK; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +public abstract class AbstractMqttV5ClientConnectionTest extends AbstractMqttIntegrationTest { + + protected void processClientWithCorrectAccessTokenTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + IMqttToken connectionResult = client.connectAndWait(accessToken); + MqttWireMessage response = connectionResult.getResponse(); + + Assert.assertEquals(MESSAGE_TYPE_CONNACK, response.getType()); + + MqttConnAck connAckMsg = (MqttConnAck) response; + + Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, connAckMsg.getReturnCode()); + client.disconnect(); + } + + protected void processClientWithWrongAccessTokenTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + try { + client.connectAndWait("wrongAccessToken"); + } catch (MqttException e) { + Assert.assertEquals(MqttReturnCode.RETURN_CODE_BAD_USERNAME_OR_PASSWORD, e.getReasonCode()); + } + } + + protected void processClientWithWrongClientIdAndEmptyUsernamePasswordTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient("unknownClientId"); + try { + client.connectAndWait(); + } catch (MqttException e) { + Assert.assertEquals(MqttReturnCode.RETURN_CODE_IDENTIFIER_NOT_VALID, e.getReasonCode()); + } + } + + protected void processClientWithNoCredentialsTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(false); + try { + client.connectAndWait(); + } catch (MqttException e) { + Assert.assertEquals(MqttReturnCode.RETURN_CODE_NOT_AUTHORIZED, e.getReasonCode()); + } + } + + protected void processClientWithPacketSizeLimitationTest() throws Exception { + int packetSizeLimit = 99; + MqttConnectionOptions options = new MqttConnectionOptions(); + options.setMaximumPacketSize((long) packetSizeLimit); + options.setUserName(accessToken); + + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(options); + + MqttV5TestCallback possibleSizeCallback = updateAttributeWithStringValue(client, packetSizeLimit / 2); + + Assert.assertTrue("Server should send messages if size less then limitation.", possibleSizeCallback.getPayloadBytes().length < packetSizeLimit); + + MqttV5TestCallback bigMessageCallback = updateAttributeWithStringValue(client, packetSizeLimit * 2); + + Assert.assertNull("Server should not send a message if the message size bigger then set limit.", bigMessageCallback.getLastReceivedMessage()); + + client.disconnect(); + + } + + private MqttV5TestCallback updateAttributeWithStringValue(MqttV5TestClient client, int valueLen) throws Exception { + MqttV5TestCallback onUpdateCallback = new MqttV5TestCallback(); + client.setCallback(onUpdateCallback); + client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + + String payload = "{\"sharedStr\":\"" + StringUtils.repeat("*", valueLen) + "\"}"; + + doPostAsync("/api/plugins/telemetry/DEVICE/" + savedDevice.getId().getId() + "/attributes/SHARED_SCOPE", payload, String.class, status().isOk()); + onUpdateCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + return onUpdateCallback; + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/MqttV5ClientConnectionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/MqttV5ClientConnectionTest.java new file mode 100644 index 0000000000..87f9968b8b --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/connection/MqttV5ClientConnectionTest.java @@ -0,0 +1,60 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.connection; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5ClientConnectionTest extends AbstractMqttV5ClientConnectionTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test MqttV5 client device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testClientWithCorrectAccessToken() throws Exception { + processClientWithCorrectAccessTokenTest(); + } + + @Test + public void testClientWithWrongAccessToken() throws Exception { + processClientWithWrongAccessTokenTest(); + } + + @Test + public void testClientWithWrongClientIdAndEmptyUsernamePassword() throws Exception { + processClientWithWrongClientIdAndEmptyUsernamePasswordTest(); + } + + @Test + public void testClientWithNoCredentialsTest() throws Exception { + processClientWithNoCredentialsTest(); + } + + @Test + @Ignore("Not implemented on the server.") + public void testClientWithPacketSizeLimitation() throws Exception { + processClientWithPacketSizeLimitationTest(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/AbstractMqttV5ClientPublishTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/AbstractMqttV5ClientPublishTest.java new file mode 100644 index 0000000000..bd4c6b4bb8 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/AbstractMqttV5ClientPublishTest.java @@ -0,0 +1,77 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.publish; + +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.common.packet.MqttPubAck; +import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode; +import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; +import org.junit.Assert; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_PUBACK; + +public abstract class AbstractMqttV5ClientPublishTest extends AbstractMqttIntegrationTest { + + protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; + + protected static final String INVALID_PAYLOAD_VALUES_STR = "\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; + + protected void processClientPublishToCorrectTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken publishResult = client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, PAYLOAD_VALUES_STR.getBytes()); + MqttWireMessage response = publishResult.getResponse(); + + Assert.assertEquals(MESSAGE_TYPE_PUBACK, response.getType()); + + MqttPubAck pubAckMsg = (MqttPubAck) response; + + Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, pubAckMsg.getReturnCode()); + + client.disconnect(); + } + + protected void processClientPublishToWrongTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken iMqttToken = client.publishAndWait("wrong/topic/", PAYLOAD_VALUES_STR.getBytes()); + Assert.assertEquals(MESSAGE_TYPE_PUBACK,iMqttToken.getResponse().getType()); + MqttPubAck pubAck = (MqttPubAck) iMqttToken.getResponse(); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_TOPIC_NAME_INVALID, pubAck.getReturnCode()); + + client.disconnect(); + } + + protected void processClientPublishWithInvalidPayloadTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken iMqttToken = client.publishAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, INVALID_PAYLOAD_VALUES_STR.getBytes()); + Assert.assertEquals(MESSAGE_TYPE_PUBACK,iMqttToken.getResponse().getType()); + MqttPubAck pubAck = (MqttPubAck) iMqttToken.getResponse(); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_PAYLOAD_FORMAT_INVALID, pubAck.getReturnCode()); + + client.disconnect(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/MqttV5ClientPublishTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/MqttV5ClientPublishTest.java new file mode 100644 index 0000000000..0fad9d8a13 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/publish/MqttV5ClientPublishTest.java @@ -0,0 +1,49 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.publish; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5ClientPublishTest extends AbstractMqttV5ClientPublishTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test MqttV5 client device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testClientPublishToCorrectTopic() throws Exception { + processClientPublishToCorrectTopicTest(); + } + + @Test + public void testClientPublishToWrongTopic() throws Exception { + processClientPublishToWrongTopicTest(); + } + + @Test + public void testClientPublishWithInvalidPayload() throws Exception { + processClientPublishWithInvalidPayloadTest(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java new file mode 100644 index 0000000000..edab7b5b8d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/AbstractMqttV5ClientSubscriptionTest.java @@ -0,0 +1,63 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.subscribe; + +import io.netty.handler.codec.mqtt.MqttQoS; +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode; +import org.eclipse.paho.mqttv5.common.packet.MqttSubAck; +import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; +import org.junit.Assert; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_SUBACK; + +public abstract class AbstractMqttV5ClientSubscriptionTest extends AbstractMqttIntegrationTest { + + protected void processClientSubscriptionToCorrectTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken subscriptionResult = client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + + MqttWireMessage response = subscriptionResult.getResponse(); + + Assert.assertEquals(MESSAGE_TYPE_SUBACK, response.getType()); + + MqttSubAck subAckMsg = (MqttSubAck) response; + + Assert.assertEquals(1, subAckMsg.getReturnCodes().length); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, subAckMsg.getReturnCodes()[0]); + + client.disconnect(); + } + + protected void processClientSubscriptionToWrongTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken iMqttToken = client.subscribeAndWait("wrong/topic/+", MqttQoS.AT_MOST_ONCE); + Assert.assertEquals(MESSAGE_TYPE_SUBACK,iMqttToken.getResponse().getType()); + MqttSubAck subAck = (MqttSubAck) iMqttToken.getResponse(); + Assert.assertEquals(1, subAck.getReturnCodes().length); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_TOPIC_FILTER_NOT_VALID, subAck.getReturnCodes()[0]); + + client.disconnect(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/MqttV5ClientSubscriptionTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/MqttV5ClientSubscriptionTest.java new file mode 100644 index 0000000000..e40363357a --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/subscribe/MqttV5ClientSubscriptionTest.java @@ -0,0 +1,44 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.subscribe; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5ClientSubscriptionTest extends AbstractMqttV5ClientSubscriptionTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test MqttV5 client device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testClientSubscriptionToCorrectTopic() throws Exception { + processClientSubscriptionToCorrectTopicTest(); + } + + @Test + public void testClientSubscriptionToWrongTopic() throws Exception { + processClientSubscriptionToWrongTopicTest(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java new file mode 100644 index 0000000000..79f529fa0d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/AbstractMqttV5ClientUnsubscribeTest.java @@ -0,0 +1,60 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.unsubscribe; + +import io.netty.handler.codec.mqtt.MqttQoS; +import org.eclipse.paho.mqttv5.client.IMqttToken; +import org.eclipse.paho.mqttv5.common.packet.MqttReturnCode; +import org.eclipse.paho.mqttv5.common.packet.MqttUnsubAck; +import org.eclipse.paho.mqttv5.common.packet.MqttWireMessage; +import org.junit.Assert; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.transport.mqtt.AbstractMqttIntegrationTest; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import static org.eclipse.paho.mqttv5.common.packet.MqttWireMessage.MESSAGE_TYPE_UNSUBACK; + +public abstract class AbstractMqttV5ClientUnsubscribeTest extends AbstractMqttIntegrationTest { + + protected void processClientUnsubscribeFromCorrectTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + client.subscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC, MqttQoS.AT_MOST_ONCE); + IMqttToken unsubscribeResult = client.unsubscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); + MqttWireMessage response = unsubscribeResult.getResponse(); + Assert.assertEquals(MESSAGE_TYPE_UNSUBACK, response.getType()); + MqttUnsubAck unsubAckMsg = (MqttUnsubAck) response; + Assert.assertEquals(1, unsubAckMsg.getReturnCodes().length); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_SUCCESS, unsubAckMsg.getReturnCodes()[0]); + + client.disconnect(); + } + + protected void processClientUnsubscribeWithoutSubscribeTopicTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + + IMqttToken iMqttToken = client.unsubscribeAndWait(MqttTopics.DEVICE_ATTRIBUTES_TOPIC); + Assert.assertEquals(MESSAGE_TYPE_UNSUBACK, iMqttToken.getResponse().getType()); + MqttUnsubAck unsubAck = (MqttUnsubAck) iMqttToken.getResponse(); + Assert.assertEquals(1, unsubAck.getReturnCodes().length); + Assert.assertEquals(MqttReturnCode.RETURN_CODE_NO_SUBSCRIPTION_EXISTED, unsubAck.getReturnCodes()[0]); + + client.disconnect(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/MqttV5ClientUnsubscribeTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/MqttV5ClientUnsubscribeTest.java new file mode 100644 index 0000000000..83c9843923 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/client/unsubscribe/MqttV5ClientUnsubscribeTest.java @@ -0,0 +1,44 @@ +/** + * 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.server.transport.mqtt.mqttv5.client.unsubscribe; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5ClientUnsubscribeTest extends AbstractMqttV5ClientUnsubscribeTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test MqttV5 client device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testClientUnsubscribeFromCorrectTopic() throws Exception { + processClientUnsubscribeFromCorrectTopicTest(); + } + + @Test + public void testClientUnsubscribeWithoutSubscribeTopic() throws Exception { + processClientUnsubscribeWithoutSubscribeTopicTest(); + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/provision/MqttV5ProvisionDeviceTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/provision/MqttV5ProvisionDeviceTest.java new file mode 100644 index 0000000000..3fc41e83e2 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/provision/MqttV5ProvisionDeviceTest.java @@ -0,0 +1,94 @@ +/** + * 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.server.transport.mqtt.mqttv5.provision; + +import com.fasterxml.jackson.databind.JsonNode; +import io.netty.handler.codec.mqtt.MqttQoS; +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.Device; +import org.thingsboard.server.common.data.DeviceProfileProvisionType; +import org.thingsboard.server.common.data.TransportPayloadType; +import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.dao.device.DeviceCredentialsService; +import org.thingsboard.server.dao.device.DeviceService; +import org.thingsboard.server.dao.device.provision.ProvisionResponseStatus; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; +import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import java.util.concurrent.TimeUnit; + +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_PROVISION_REQUEST_TOPIC; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC; + +@Slf4j +@DaoSqlTest +public class MqttV5ProvisionDeviceTest extends AbstractMqttV5Test { + + @Autowired + DeviceCredentialsService deviceCredentialsService; + + @Autowired + DeviceService deviceService; + + @Test + public void testProvisioningCreateNewDeviceWithoutCredentials() throws Exception { + processTestProvisioningCreateNewDeviceWithoutCredentials(); + } + + protected void processTestProvisioningCreateNewDeviceWithoutCredentials() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Provision device3") + .transportPayloadType(TransportPayloadType.JSON) + .provisionType(DeviceProfileProvisionType.ALLOW_CREATE_NEW_DEVICES) + .provisionKey("testProvisionKey") + .provisionSecret("testProvisionSecret") + .build(); + super.processBeforeTest(configProperties); + byte[] result = createMqttClientAndPublish(); + JsonNode response = JacksonUtil.fromBytes(result); + Assert.assertTrue(response.hasNonNull("credentialsType")); + Assert.assertTrue(response.hasNonNull("status")); + + Device createdDevice = deviceService.findDeviceByTenantIdAndName(tenantId, "Test Provision device"); + + Assert.assertNotNull(createdDevice); + + DeviceCredentials deviceCredentials = deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, createdDevice.getId()); + + Assert.assertEquals(deviceCredentials.getCredentialsType().name(), response.get("credentialsType").asText()); + Assert.assertEquals(ProvisionResponseStatus.SUCCESS.name(), response.get("status").asText()); + } + + protected byte[] createMqttClientAndPublish() throws Exception { + String provisionRequestMsg = "{\"deviceName\":\"Test Provision device\",\"provisionDeviceKey\":\"testProvisionKey\", \"provisionDeviceSecret\":\"testProvisionSecret\"}"; + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait("provision"); + MqttV5TestCallback onProvisionCallback = new MqttV5TestCallback(DEVICE_PROVISION_RESPONSE_TOPIC); + client.setCallback(onProvisionCallback); + client.subscribe(DEVICE_PROVISION_RESPONSE_TOPIC, MqttQoS.AT_MOST_ONCE); + client.publishAndWait(DEVICE_PROVISION_REQUEST_TOPIC, provisionRequestMsg.getBytes()); + onProvisionCallback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + client.disconnect(); + return onProvisionCallback.getPayloadBytes(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java new file mode 100644 index 0000000000..98c42c39fe --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/AbstractMqttV5RpcTest.java @@ -0,0 +1,98 @@ +/** + * 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.server.transport.mqtt.mqttv5.rpc; + +import com.nimbusds.jose.util.StandardCharset; +import io.netty.handler.codec.mqtt.MqttQoS; +import lombok.extern.slf4j.Slf4j; +import org.eclipse.paho.mqttv5.common.MqttException; +import org.eclipse.paho.mqttv5.common.MqttMessage; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.StringUtils; +import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestCallback; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.common.data.device.profile.MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC; + +@Slf4j +public abstract class AbstractMqttV5RpcTest extends AbstractMqttV5Test { + + private static final String DEVICE_RESPONSE = "{\"value1\":\"A\",\"value2\":\"B\"}"; + + + protected void processOneWayRpcTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + MqttV5TestCallback callback = new MqttV5TestCallback(DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0")); + client.setCallback(callback); + client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_MOST_ONCE); + + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"23\",\"value\": 1}}"; + String result = doPostAsync("/api/rpc/oneway/" + savedDevice.getId(), setGpioRequest, String.class, status().isOk()); + assertTrue(StringUtils.isEmpty(result)); + callback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + assertEquals(JacksonUtil.toJsonNode(setGpioRequest), JacksonUtil.fromBytes(callback.getPayloadBytes())); + assertEquals(MqttQoS.AT_MOST_ONCE.value(), callback.getQoS()); + client.disconnect(); + } + + protected void processJsonTwoWayRpcTest() throws Exception { + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + client.subscribeAndWait(DEVICE_RPC_REQUESTS_SUB_TOPIC, MqttQoS.AT_LEAST_ONCE); + MqttV5TestRpcCallback callback = new MqttV5TestRpcCallback(client, DEVICE_RPC_REQUESTS_SUB_TOPIC.replace("+", "0")); + client.setCallback(callback); + String setGpioRequest = "{\"method\":\"setGpio\",\"params\":{\"pin\": \"26\",\"value\": 1}}"; + String actualRpcResponse = doPostAsync("/api/rpc/twoway/" + savedDevice.getId(), setGpioRequest, String.class, status().isOk()); + callback.getSubscribeLatch().await(3, TimeUnit.SECONDS); + assertEquals(JacksonUtil.toJsonNode(setGpioRequest), JacksonUtil.fromBytes(callback.getPayloadBytes())); + assertEquals("{\"value1\":\"A\",\"value2\":\"B\"}", actualRpcResponse); + client.disconnect(); + } + + protected class MqttV5TestRpcCallback extends MqttV5TestCallback { + + private final MqttV5TestClient client; + + public MqttV5TestRpcCallback(MqttV5TestClient client, String awaitSubTopic) { + super(awaitSubTopic); + this.client = client; + } + + @Override + protected void messageArrivedOnAwaitSubTopic(String requestTopic, MqttMessage mqttMessage) { + log.warn("messageArrived on topic: {}, awaitSubTopic: {}", requestTopic, awaitSubTopic); + if (awaitSubTopic.equals(requestTopic)) { + qoS = mqttMessage.getQos(); + payloadBytes = mqttMessage.getPayload(); + String responseTopic = requestTopic.replace("request", "response"); + try { + client.publish(responseTopic, DEVICE_RESPONSE.getBytes(StandardCharset.UTF_8)); + } catch (MqttException e) { + log.warn("Failed to publish response on topic: {} due to: ", responseTopic, e); + } + subscribeLatch.countDown(); + } + } + } + +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/MqttV5RpcTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/MqttV5RpcTest.java new file mode 100644 index 0000000000..caf188381b --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/rpc/MqttV5RpcTest.java @@ -0,0 +1,43 @@ +/** + * 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.server.transport.mqtt.mqttv5.rpc; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5RpcTest extends AbstractMqttV5RpcTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("RPC test device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testServerMqttV5SimpleClientOneWayRpc() throws Exception { + processOneWayRpcTest(); + } + + @Test + public void testServerMqttV5SimpleClientTwoWayRpc() throws Exception { + processJsonTwoWayRpcTest(); + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/AbstractMqttV5TimeseriesTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/AbstractMqttV5TimeseriesTest.java new file mode 100644 index 0000000000..4b08926d8d --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/AbstractMqttV5TimeseriesTest.java @@ -0,0 +1,132 @@ +/** + * 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.server.transport.mqtt.mqttv5.timeseries; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.thingsboard.server.common.data.device.profile.MqttTopics; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.transport.mqtt.mqttv5.AbstractMqttV5Test; +import org.thingsboard.server.transport.mqtt.mqttv5.MqttV5TestClient; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public abstract class AbstractMqttV5TimeseriesTest extends AbstractMqttV5Test { + + protected static final String PAYLOAD_VALUES_STR = "{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4," + + " \"key5\": {\"someNumber\": 42, \"someArray\": [1,2,3], \"someNestedObject\": {\"key\": \"value\"}}}"; + + protected void processTimeseriesMqttV5UploadTest() throws Exception { + + List expectedKeys = Arrays.asList("key1", "key2", "key3", "key4", "key5"); + + MqttV5TestClient client = new MqttV5TestClient(); + client.connectAndWait(accessToken); + client.publishAndWait(MqttTopics.DEVICE_TELEMETRY_TOPIC, PAYLOAD_VALUES_STR.getBytes()); + client.disconnect(); + + DeviceId deviceId = savedDevice.getId(); + + List actualKeys = getActualKeysList(deviceId, expectedKeys); + assertNotNull(actualKeys); + + Set actualKeySet = new HashSet<>(actualKeys); + Set expectedKeySet = new HashSet<>(expectedKeys); + + assertEquals(expectedKeySet, actualKeySet); + + String getTelemetryValuesUrl; + getTelemetryValuesUrl = "/api/plugins/telemetry/DEVICE/" + deviceId + "/values/timeseries?keys=" + String.join(",", actualKeySet); + long start = System.currentTimeMillis(); + long end = System.currentTimeMillis() + 5000; + Map>> values = null; + while (start <= end) { + values = doGetAsyncTyped(getTelemetryValuesUrl, new TypeReference<>() { + }); + boolean valid = values.size() == expectedKeys.size(); + if (valid) { + for (String key : expectedKeys) { + List> tsValues = values.get(key); + if (tsValues != null && tsValues.size() > 0) { + Object ts = tsValues.get(0).get("ts"); + if (ts == null) { + valid = false; + break; + } + } else { + valid = false; + break; + } + } + } + if (valid) { + break; + } + Thread.sleep(100); + start += 100; + } + assertNotNull(values); + assertValues(values); + } + + private List getActualKeysList(DeviceId deviceId, List expectedKeys) throws Exception { + long start = System.currentTimeMillis(); + long end = System.currentTimeMillis() + 3000; + + List actualKeys = null; + while (start <= end) { + actualKeys = doGetAsyncTyped("/api/plugins/telemetry/DEVICE/" + deviceId + "/keys/timeseries", new TypeReference<>() { + }); + if (actualKeys.size() == expectedKeys.size()) { + break; + } + Thread.sleep(100); + start += 100; + } + return actualKeys; + } + + private void assertValues(Map>> deviceValues) { + for (Map.Entry>> entry : deviceValues.entrySet()) { + String key = entry.getKey(); + List> tsKv = entry.getValue(); + String value = (String) tsKv.get(0).get("value"); + switch (key) { + case "key1": + assertEquals("value1", value); + break; + case "key2": + assertEquals("true", value); + break; + case "key3": + assertEquals("3.0", value); + break; + case "key4": + assertEquals("4", value); + break; + case "key5": + assertEquals("{\"someNumber\":42,\"someArray\":[1,2,3],\"someNestedObject\":{\"key\":\"value\"}}", value); + break; + } + } + } +} diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/MqttV5TimeseriesTest.java b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/MqttV5TimeseriesTest.java new file mode 100644 index 0000000000..60b935e661 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/transport/mqtt/mqttv5/timeseries/MqttV5TimeseriesTest.java @@ -0,0 +1,39 @@ +/** + * 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.server.transport.mqtt.mqttv5.timeseries; + +import org.junit.Before; +import org.junit.Test; +import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.transport.mqtt.MqttTestConfigProperties; + +@DaoSqlTest +public class MqttV5TimeseriesTest extends AbstractMqttV5TimeseriesTest { + + @Before + public void beforeTest() throws Exception { + MqttTestConfigProperties configProperties = MqttTestConfigProperties.builder() + .deviceName("Test Post Telemetry device") + .build(); + processBeforeTest(configProperties); + } + + @Test + public void testTimeseriesMqttV5SimpleClientUpload() throws Exception { + processTimeseriesMqttV5UploadTest(); + } + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java index b5bbdc761c..793f020045 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/alarm/AlarmService.java @@ -30,13 +30,14 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; import org.thingsboard.server.common.data.query.AlarmDataQuery; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Collection; /** * Created by ashvayka on 11.05.17. */ -public interface AlarmService { +public interface AlarmService extends EntityDaoService { AlarmOperationResult createOrUpdateAlarm(Alarm alarm); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java index c86463336a..1d702c7ec0 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetProfileService.java @@ -21,8 +21,9 @@ import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; -public interface AssetProfileService { +public interface AssetProfileService extends EntityDaoService { AssetProfile findAssetProfileById(TenantId tenantId, AssetProfileId assetProfileId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java index 955444ac52..721386b2c7 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/asset/AssetService.java @@ -27,10 +27,11 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface AssetService { +public interface AssetService extends EntityDaoService { AssetInfo findAssetInfoById(TenantId tenantId, AssetId assetId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java index 3f28512946..12fcc04768 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/customer/CustomerService.java @@ -21,10 +21,11 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Optional; -public interface CustomerService { +public interface CustomerService extends EntityDaoService { Customer findCustomerById(TenantId tenantId, CustomerId customerId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java index 4032797b5b..e718e53367 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/dashboard/DashboardService.java @@ -24,10 +24,11 @@ import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface DashboardService { +public interface DashboardService extends EntityDaoService { Dashboard findDashboardById(TenantId tenantId, DashboardId dashboardId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java index fdf3b8e594..2e65e159cd 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceProfileService.java @@ -17,13 +17,13 @@ package org.thingsboard.server.dao.device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.DeviceProfileInfo; -import org.thingsboard.server.common.data.EntityInfo; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; -public interface DeviceProfileService { +public interface DeviceProfileService extends EntityDaoService { DeviceProfile findDeviceProfileById(TenantId tenantId, DeviceProfileId deviceProfileId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java index d68e8e1bf6..4c4bcd4d40 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/device/DeviceService.java @@ -33,11 +33,12 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.device.provision.ProvisionRequest; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; import java.util.UUID; -public interface DeviceService { +public interface DeviceService extends EntityDaoService { DeviceInfo findDeviceInfoById(TenantId tenantId, DeviceId deviceId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java index b3372bf30c..b7f5ecfc45 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/edge/EdgeService.java @@ -26,11 +26,12 @@ import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; import java.util.Optional; -public interface EdgeService { +public interface EdgeService extends EntityDaoService { Edge findEdgeById(TenantId tenantId, EdgeId edgeId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java new file mode 100644 index 0000000000..f8a7c4a5b9 --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityDaoService.java @@ -0,0 +1,31 @@ +/** + * 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.server.dao.entity; + +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.util.Optional; + +public interface EntityDaoService { + + Optional> findEntity(TenantId tenantId, EntityId entityId); + + EntityType getEntityType(); + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java index 986da96d46..aa5c70867f 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityService.java @@ -15,7 +15,6 @@ */ package org.thingsboard.server.dao.entity; -import com.google.common.util.concurrent.ListenableFuture; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -24,11 +23,13 @@ import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityDataQuery; +import java.util.Optional; + public interface EntityService { - ListenableFuture fetchEntityNameAsync(TenantId tenantId, EntityId entityId); + Optional fetchEntityName(TenantId tenantId, EntityId entityId); - CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId); + Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId); long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityServiceRegistry.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityServiceRegistry.java new file mode 100644 index 0000000000..3bbaa8f06e --- /dev/null +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entity/EntityServiceRegistry.java @@ -0,0 +1,24 @@ +/** + * 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.server.dao.entity; + +import org.thingsboard.server.common.data.EntityType; + +public interface EntityServiceRegistry { + + EntityDaoService getServiceByEntityType(EntityType entityType); + +} diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java index bb790c78cb..f3efd99528 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/entityview/EntityViewService.java @@ -27,13 +27,14 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; /** * Created by Victor Basanets on 8/27/2017. */ -public interface EntityViewService { +public interface EntityViewService extends EntityDaoService { EntityView saveEntityView(EntityView entityView); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java index c643ae4797..09d37fd81a 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/ota/OtaPackageService.java @@ -25,10 +25,11 @@ import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.nio.ByteBuffer; -public interface OtaPackageService { +public interface OtaPackageService extends EntityDaoService { OtaPackageInfo saveOtaPackageInfo(OtaPackageInfo otaPackageInfo, boolean isUrl); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java index acc3190da9..f9bb3e834d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/queue/QueueService.java @@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface QueueService { +public interface QueueService extends EntityDaoService { Queue saveQueue(Queue queue); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java index 1cce5ae62a..04b4044ca0 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/resource/ResourceService.java @@ -23,10 +23,12 @@ import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface ResourceService { +public interface ResourceService extends EntityDaoService { + TbResource saveResource(TbResource resource); TbResource getResource(TenantId tenantId, ResourceType resourceType, String resourceId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java index 25a82e6113..319247e84e 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rpc/RpcService.java @@ -23,8 +23,10 @@ import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.rpc.Rpc; import org.thingsboard.server.common.data.rpc.RpcStatus; +import org.thingsboard.server.dao.entity.EntityDaoService; + +public interface RpcService extends EntityDaoService { -public interface RpcService { Rpc save(Rpc rpc); void deleteRpc(TenantId tenantId, RpcId id); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java index 9a856ae66a..20d4667a3c 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/rule/RuleChainService.java @@ -31,6 +31,7 @@ import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.rule.RuleChainType; import org.thingsboard.server.common.data.rule.RuleChainUpdateResult; import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.Collection; import java.util.List; @@ -38,7 +39,7 @@ import java.util.List; /** * Created by igor on 3/12/18. */ -public interface RuleChainService { +public interface RuleChainService extends EntityDaoService { RuleChain saveRuleChain(RuleChain ruleChain); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileService.java index c15ac84b3a..1728837569 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileService.java @@ -21,8 +21,9 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; -public interface TenantProfileService { +public interface TenantProfileService extends EntityDaoService { TenantProfile findTenantProfileById(TenantId tenantId, TenantProfileId tenantProfileId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java index 2dcccc843f..af7c4c5892 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/tenant/TenantService.java @@ -22,10 +22,11 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface TenantService { +public interface TenantService extends EntityDaoService { Tenant findTenantById(TenantId tenantId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateService.java index 44950d2803..50208c859d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateService.java @@ -19,8 +19,9 @@ import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.id.ApiUsageStateId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.dao.entity.EntityDaoService; -public interface ApiUsageStateService { +public interface ApiUsageStateService extends EntityDaoService { ApiUsageState createDefaultApiUsageState(TenantId id, EntityId entityId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java index 76891e950f..d52f11e548 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/user/UserService.java @@ -24,8 +24,9 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.UserCredentials; +import org.thingsboard.server.dao.entity.EntityDaoService; -public interface UserService { +public interface UserService extends EntityDaoService { User findUserById(TenantId tenantId, UserId userId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index 15875bfb9a..52beb62a25 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface WidgetTypeService { +public interface WidgetTypeService extends EntityDaoService { WidgetType findWidgetTypeById(TenantId tenantId, WidgetTypeId widgetTypeId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java index f9a5844606..c037cfb612 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java @@ -20,10 +20,11 @@ import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import org.thingsboard.server.dao.entity.EntityDaoService; import java.util.List; -public interface WidgetsBundleService { +public interface WidgetsBundleService extends EntityDaoService { WidgetsBundle findWidgetsBundleById(TenantId tenantId, WidgetsBundleId widgetsBundleId); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java index 2a320cc2ac..7515a1fcd2 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java @@ -26,6 +26,7 @@ import io.netty.handler.codec.mqtt.MqttConnectMessage; import io.netty.handler.codec.mqtt.MqttConnectReturnCode; import io.netty.handler.codec.mqtt.MqttFixedHeader; import io.netty.handler.codec.mqtt.MqttMessage; +import io.netty.handler.codec.mqtt.MqttMessageBuilders; import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader; import io.netty.handler.codec.mqtt.MqttPubAckMessage; import io.netty.handler.codec.mqtt.MqttPublishMessage; @@ -35,17 +36,18 @@ import io.netty.handler.codec.mqtt.MqttSubAckPayload; import io.netty.handler.codec.mqtt.MqttSubscribeMessage; import io.netty.handler.codec.mqtt.MqttTopicSubscription; import io.netty.handler.codec.mqtt.MqttUnsubscribeMessage; +import io.netty.handler.codec.mqtt.MqttVersion; import io.netty.handler.ssl.SslHandler; import io.netty.util.CharsetUtil; import io.netty.util.ReferenceCountUtil; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; 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.device.profile.MqttTopics; import org.thingsboard.server.common.data.id.DeviceId; @@ -72,6 +74,8 @@ import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; import org.thingsboard.server.transport.mqtt.session.DeviceSessionCtx; import org.thingsboard.server.transport.mqtt.session.GatewaySessionHandler; import org.thingsboard.server.transport.mqtt.session.MqttTopicMatcher; +import org.thingsboard.server.transport.mqtt.util.ReturnCode; +import org.thingsboard.server.transport.mqtt.util.ReturnCodeResolver; import javax.net.ssl.SSLPeerUnverifiedException; import java.io.IOException; @@ -79,6 +83,7 @@ import java.net.InetSocketAddress; import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.UUID; @@ -90,17 +95,13 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import static com.amazonaws.util.StringUtils.UTF8; -import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_ACCEPTED; -import static io.netty.handler.codec.mqtt.MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; import static io.netty.handler.codec.mqtt.MqttMessageType.CONNACK; import static io.netty.handler.codec.mqtt.MqttMessageType.CONNECT; import static io.netty.handler.codec.mqtt.MqttMessageType.PINGRESP; -import static io.netty.handler.codec.mqtt.MqttMessageType.PUBACK; import static io.netty.handler.codec.mqtt.MqttMessageType.SUBACK; import static io.netty.handler.codec.mqtt.MqttMessageType.UNSUBACK; import static io.netty.handler.codec.mqtt.MqttQoS.AT_LEAST_ONCE; import static io.netty.handler.codec.mqtt.MqttQoS.AT_MOST_ONCE; -import static io.netty.handler.codec.mqtt.MqttQoS.FAILURE; import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_CLOSED; import static org.thingsboard.server.common.transport.service.DefaultTransportService.SESSION_EVENT_MSG_OPEN; @@ -355,10 +356,11 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement gatewaySessionHandler.onDeviceDisconnect(mqttMsg); break; default: - ack(ctx, msgId); + ack(ctx, msgId, ReturnCode.TOPIC_NAME_INVALID); } } catch (RuntimeException e) { log.warn("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e); + ack(ctx, msgId, ReturnCode.IMPLEMENTATION_SPECIFIC); ctx.close(); } catch (AdaptorException e) { log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e); @@ -447,7 +449,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement attrReqTopicType = TopicType.V2; } else { transportService.reportActivity(deviceSessionCtx.getSessionInfo()); - ack(ctx, msgId); + ack(ctx, msgId, ReturnCode.TOPIC_NAME_INVALID); } } catch (AdaptorException e) { log.debug("[{}] Failed to process publish msg [{}][{}]", sessionId, topicName, msgId, e); @@ -456,9 +458,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } private void sendAckOrCloseSession(ChannelHandlerContext ctx, String topicName, int msgId) { - if (deviceSessionCtx.isSendAckOnValidationException() && msgId > 0) { + if ((deviceSessionCtx.isSendAckOnValidationException() || MqttVersion.MQTT_5.equals(deviceSessionCtx.getMqttVersion())) && msgId > 0) { log.debug("[{}] Send pub ack on invalid publish msg [{}][{}]", sessionId, topicName, msgId); - ctx.writeAndFlush(createMqttPubAckMsg(msgId)); + ctx.writeAndFlush(createMqttPubAckMsg(deviceSessionCtx, msgId, ReturnCode.PAYLOAD_FORMAT_INVALID)); } else { log.info("[{}] Closing current session due to invalid publish msg [{}][{}]", sessionId, topicName, msgId); ctx.close(); @@ -500,9 +502,9 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } } - private void ack(ChannelHandlerContext ctx, int msgId) { + private void ack(ChannelHandlerContext ctx, int msgId, ReturnCode returnCode) { if (msgId > 0) { - ctx.writeAndFlush(createMqttPubAckMsg(msgId)); + ctx.writeAndFlush(createMqttPubAckMsg(deviceSessionCtx, msgId, returnCode)); } } @@ -511,7 +513,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onSuccess(Void dummy) { log.trace("[{}] Published msg: {}", sessionId, msg); - ack(ctx, msgId); + ack(ctx, msgId, ReturnCode.SUCCESS); } @Override @@ -536,7 +538,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onSuccess(TransportProtos.ProvisionDeviceResponseMsg provisionResponseMsg) { log.trace("[{}] Published msg: {}", sessionId, msg); - ack(ctx, msgId); + ack(ctx, msgId, ReturnCode.SUCCESS); try { if (deviceSessionCtx.getProvisionPayloadType().equals(TransportPayloadType.JSON)) { deviceSessionCtx.getContext().getJsonMqttAdaptor().convertToPublish(deviceSessionCtx, provisionResponseMsg).ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); @@ -545,13 +547,14 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } scheduler.schedule((Callable) ctx::close, 60, TimeUnit.SECONDS); } catch (Exception e) { - log.trace("[{}] Failed to convert device attributes response to MQTT msg", sessionId, e); + log.trace("[{}] Failed to convert device provision response to MQTT msg", sessionId, e); } } @Override public void onError(Throwable e) { log.trace("[{}] Failed to publish msg: {}", sessionId, msg, e); + ack(ctx, msgId, ReturnCode.IMPLEMENTATION_SPECIFIC); ctx.close(); } } @@ -593,7 +596,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private void sendOtaPackage(ChannelHandlerContext ctx, int msgId, String firmwareId, String requestId, int chunkSize, int chunk, OtaPackageType type) { log.trace("[{}] Send firmware [{}] to device!", sessionId, firmwareId); - ack(ctx, msgId); + ack(ctx, msgId, ReturnCode.SUCCESS); try { byte[] firmwareChunk = context.getOtaPackageDataCache().get(firmwareId, chunkSize, chunk); deviceSessionCtx.getPayloadAdaptor() @@ -614,6 +617,8 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private void processSubscribe(ChannelHandlerContext ctx, MqttSubscribeMessage mqttMsg) { if (!checkConnected(ctx, mqttMsg)) { + int returnCode = ReturnCodeResolver.getSubscriptionReturnCode(deviceSessionCtx.getMqttVersion(), ReturnCode.NOT_AUTHORIZED_5); + ctx.writeAndFlush(createSubAckMessage(mqttMsg.variableHeader().messageId(), Collections.singletonList(returnCode))); return; } log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId()); @@ -684,12 +689,12 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement break; default: log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS); - grantedQoSList.add(FAILURE.value()); + grantedQoSList.add(ReturnCodeResolver.getSubscriptionReturnCode(deviceSessionCtx.getMqttVersion(), ReturnCode.TOPIC_FILTER_INVALID)); break; } } catch (Exception e) { log.warn("[{}] Failed to subscribe to [{}][{}]", sessionId, topic, reqQoS, e); - grantedQoSList.add(FAILURE.value()); + grantedQoSList.add(ReturnCodeResolver.getSubscriptionReturnCode(deviceSessionCtx.getMqttVersion(), ReturnCode.IMPLEMENTATION_SPECIFIC)); } } if (!activityReported) { @@ -717,76 +722,93 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private void processUnsubscribe(ChannelHandlerContext ctx, MqttUnsubscribeMessage mqttMsg) { if (!checkConnected(ctx, mqttMsg)) { + ctx.writeAndFlush(createUnSubAckMessage(mqttMsg.variableHeader().messageId(), Collections.singletonList(ReturnCode.NOT_AUTHORIZED_5.shortValue()))); return; } boolean activityReported = false; + List unSubResults = new ArrayList<>(); log.trace("[{}] Processing subscription [{}]!", sessionId, mqttMsg.variableHeader().messageId()); for (String topicName : mqttMsg.payload().topics()) { - mqttQoSMap.remove(new MqttTopicMatcher(topicName)); - try { - switch (topicName) { - case MqttTopics.DEVICE_ATTRIBUTES_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC: { - transportService.process(deviceSessionCtx.getSessionInfo(), - TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(), null); - activityReported = true; - break; - } - case MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC: - case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC: - case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC: - case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC: { - transportService.process(deviceSessionCtx.getSessionInfo(), - TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(), null); - activityReported = true; - break; - } - case MqttTopics.DEVICE_RPC_RESPONSE_SUB_TOPIC: - case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_TOPIC: - case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_JSON_TOPIC: - case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_PROTO_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC: - case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC: - case MqttTopics.GATEWAY_ATTRIBUTES_TOPIC: - case MqttTopics.GATEWAY_RPC_TOPIC: - case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: - case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: - case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: - case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: - case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC: - case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC: { - activityReported = true; - break; + MqttTopicMatcher matcher = new MqttTopicMatcher(topicName); + if (mqttQoSMap.containsKey(matcher)) { + mqttQoSMap.remove(matcher); + try { + short resultValue = ReturnCode.SUCCESS.shortValue(); + switch (topicName) { + case MqttTopics.DEVICE_ATTRIBUTES_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_SHORT_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_SHORT_PROTO_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_SHORT_JSON_TOPIC: { + transportService.process(deviceSessionCtx.getSessionInfo(), + TransportProtos.SubscribeToAttributeUpdatesMsg.newBuilder().setUnsubscribe(true).build(), null); + activityReported = true; + break; + } + case MqttTopics.DEVICE_RPC_REQUESTS_SUB_TOPIC: + case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_TOPIC: + case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_JSON_TOPIC: + case MqttTopics.DEVICE_RPC_REQUESTS_SUB_SHORT_PROTO_TOPIC: { + transportService.process(deviceSessionCtx.getSessionInfo(), + TransportProtos.SubscribeToRPCMsg.newBuilder().setUnsubscribe(true).build(), null); + activityReported = true; + break; + } + case MqttTopics.DEVICE_RPC_RESPONSE_SUB_TOPIC: + case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_TOPIC: + case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_JSON_TOPIC: + case MqttTopics.DEVICE_RPC_RESPONSE_SUB_SHORT_PROTO_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_JSON_TOPIC: + case MqttTopics.DEVICE_ATTRIBUTES_RESPONSES_SHORT_PROTO_TOPIC: + case MqttTopics.GATEWAY_ATTRIBUTES_TOPIC: + case MqttTopics.GATEWAY_RPC_TOPIC: + case MqttTopics.GATEWAY_ATTRIBUTES_RESPONSE_TOPIC: + case MqttTopics.DEVICE_PROVISION_RESPONSE_TOPIC: + case MqttTopics.DEVICE_FIRMWARE_RESPONSES_TOPIC: + case MqttTopics.DEVICE_FIRMWARE_ERROR_TOPIC: + case MqttTopics.DEVICE_SOFTWARE_RESPONSES_TOPIC: + case MqttTopics.DEVICE_SOFTWARE_ERROR_TOPIC: { + activityReported = true; + break; + } + default: + log.trace("[{}] Failed to process unsubscription [{}] to [{}]", sessionId, mqttMsg.variableHeader().messageId(), topicName); + resultValue = ReturnCode.TOPIC_FILTER_INVALID.shortValue(); } + unSubResults.add(resultValue); + } catch (Exception e) { + log.debug("[{}] Failed to process unsubscription [{}] to [{}]", sessionId, mqttMsg.variableHeader().messageId(), topicName); + unSubResults.add(ReturnCode.IMPLEMENTATION_SPECIFIC.shortValue()); } - } catch (Exception e) { - log.debug("[{}] Failed to process unsubscription [{}] to [{}]", sessionId, mqttMsg.variableHeader().messageId(), topicName); + } else { + log.debug("[{}] Failed to process unsubscription [{}] to [{}] - Subscription not found", sessionId, mqttMsg.variableHeader().messageId(), topicName); + unSubResults.add(ReturnCode.NO_SUBSCRIPTION_EXISTED.shortValue()); } } if (!activityReported) { transportService.reportActivity(deviceSessionCtx.getSessionInfo()); } - ctx.writeAndFlush(createUnSubAckMessage(mqttMsg.variableHeader().messageId())); + ctx.writeAndFlush(createUnSubAckMessage(mqttMsg.variableHeader().messageId(), unSubResults)); } - private MqttMessage createUnSubAckMessage(int msgId) { - MqttFixedHeader mqttFixedHeader = - new MqttFixedHeader(UNSUBACK, false, AT_MOST_ONCE, false, 0); - MqttMessageIdVariableHeader mqttMessageIdVariableHeader = MqttMessageIdVariableHeader.from(msgId); - return new MqttMessage(mqttFixedHeader, mqttMessageIdVariableHeader); + private MqttMessage createUnSubAckMessage(int msgId, List resultCodes) { + MqttMessageBuilders.UnsubAckBuilder unsubAckBuilder = MqttMessageBuilders.unsubAck(); + unsubAckBuilder.packetId(msgId); + if (MqttVersion.MQTT_5.equals(deviceSessionCtx.getMqttVersion())) { + unsubAckBuilder.addReasonCodes(resultCodes.toArray(Short[]::new)); + } + return unsubAckBuilder.build(); } void processConnect(ChannelHandlerContext ctx, MqttConnectMessage msg) { log.debug("[{}][{}] Processing connect msg for client: {}!", address, sessionId, msg.payload().clientIdentifier()); String userName = msg.payload().userName(); String clientId = msg.payload().clientIdentifier(); + deviceSessionCtx.setMqttVersion(getMqttVersion(msg.variableHeader().version())); if (DataConstants.PROVISION.equals(userName) || DataConstants.PROVISION.equals(clientId)) { deviceSessionCtx.setProvisionOnly(true); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, msg)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SUCCESS, msg)); } else { X509Certificate cert; if (sslHandler != null && (cert = getX509Certificate()) != null) { @@ -820,7 +842,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, userName, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SERVER_UNAVAILABLE_5, connectMessage)); ctx.close(); } }); @@ -843,13 +865,13 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement @Override public void onError(Throwable e) { log.trace("[{}] Failed to process credentials: {}", address, sha3Hash, e); - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SERVER_UNAVAILABLE_5, connectMessage)); ctx.close(); } }); } catch (Exception e) { context.onAuthFailure(address); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.NOT_AUTHORIZED_5, connectMessage)); log.trace("[{}] X509 auth failure: {}", sessionId, address, e); ctx.close(); } @@ -868,12 +890,12 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement return null; } - private MqttConnAckMessage createMqttConnAckMsg(MqttConnectReturnCode returnCode, MqttConnectMessage msg) { - MqttFixedHeader mqttFixedHeader = - new MqttFixedHeader(CONNACK, false, AT_MOST_ONCE, false, 0); - MqttConnAckVariableHeader mqttConnAckVariableHeader = - new MqttConnAckVariableHeader(returnCode, !msg.variableHeader().isCleanSession()); - return new MqttConnAckMessage(mqttFixedHeader, mqttConnAckVariableHeader); + private MqttConnAckMessage createMqttConnAckMsg(ReturnCode returnCode, MqttConnectMessage msg) { + MqttMessageBuilders.ConnAckBuilder connAckBuilder = MqttMessageBuilders.connAck(); + connAckBuilder.sessionPresent(!msg.variableHeader().isCleanSession()); + MqttConnectReturnCode finalReturnCode = ReturnCodeResolver.getConnectionReturnCode(deviceSessionCtx.getMqttVersion(), returnCode); + connAckBuilder.returnCode(finalReturnCode); + return connAckBuilder.build(); } @Override @@ -918,12 +940,23 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement return Math.min(reqQoS.value(), MAX_SUPPORTED_QOS_LVL.value()); } - public static MqttPubAckMessage createMqttPubAckMsg(int requestId) { - MqttFixedHeader mqttFixedHeader = - new MqttFixedHeader(PUBACK, false, AT_MOST_ONCE, false, 0); - MqttMessageIdVariableHeader mqttMsgIdVariableHeader = - MqttMessageIdVariableHeader.from(requestId); - return new MqttPubAckMessage(mqttFixedHeader, mqttMsgIdVariableHeader); + private static MqttVersion getMqttVersion(int versionCode) { + switch (versionCode) { + case 3: + return MqttVersion.MQTT_3_1; + case 5: + return MqttVersion.MQTT_5; + default: + return MqttVersion.MQTT_3_1_1; + } + } + + public static MqttMessage createMqttPubAckMsg(DeviceSessionCtx deviceSessionCtx, int requestId, ReturnCode returnCode) { + MqttMessageBuilders.PubAckBuilder pubAckMsgBuilder = MqttMessageBuilders.pubAck().packetId(requestId); + if (MqttVersion.MQTT_5.equals(deviceSessionCtx.getMqttVersion())) { + pubAckMsgBuilder.reasonCode(returnCode.byteValue()); + } + return pubAckMsgBuilder.build(); } private boolean checkConnected(ChannelHandlerContext ctx, MqttMessage msg) { @@ -976,7 +1009,19 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement private void onValidateDeviceResponse(ValidateDeviceCredentialsResponse msg, ChannelHandlerContext ctx, MqttConnectMessage connectMessage) { if (!msg.hasDeviceInfo()) { context.onAuthFailure(address); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_REFUSED_NOT_AUTHORIZED, connectMessage)); + ReturnCode returnCode = ReturnCode.NOT_AUTHORIZED_5; + if (sslHandler == null || getX509Certificate() == null) { + String username = connectMessage.payload().userName(); + byte[] passwordBytes = connectMessage.payload().passwordInBytes(); + String clientId = connectMessage.payload().clientIdentifier(); + if ((username != null && passwordBytes != null && clientId != null) + || (username == null ^ passwordBytes == null)) { + returnCode = ReturnCode.BAD_USERNAME_OR_PASSWORD; + } else if (!StringUtils.isBlank(clientId)) { + returnCode = ReturnCode.CLIENT_IDENTIFIER_NOT_VALID; + } + } + ctx.writeAndFlush(createMqttConnAckMsg(returnCode, connectMessage)); ctx.close(); } else { context.onAuthSuccess(address); @@ -988,7 +1033,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement public void onSuccess(Void msg) { SessionMetaData sessionMetaData = transportService.registerAsyncSession(deviceSessionCtx.getSessionInfo(), MqttTransportHandler.this); checkGatewaySession(sessionMetaData); - ctx.writeAndFlush(createMqttConnAckMsg(CONNECTION_ACCEPTED, connectMessage)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SUCCESS, connectMessage)); deviceSessionCtx.setConnected(true); log.debug("[{}] Client connected!", sessionId); transportService.getCallbackExecutor().execute(() -> processMsgQueue(ctx)); //this callback will execute in Producer worker thread and hard or blocking work have to be submitted to the separate thread. @@ -1001,7 +1046,7 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement } else { log.warn("[{}] Failed to submit session event", sessionId, e); } - ctx.writeAndFlush(createMqttConnAckMsg(MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE, connectMessage)); + ctx.writeAndFlush(createMqttConnAckMsg(ReturnCode.SERVER_UNAVAILABLE_5, connectMessage)); ctx.close(); } }); diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java index 2163610b38..7189b46469 100644 --- a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/session/DeviceSessionCtx.java @@ -19,6 +19,7 @@ import com.google.protobuf.Descriptors; import com.google.protobuf.DynamicMessage; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.mqtt.MqttMessage; +import io.netty.handler.codec.mqtt.MqttVersion; import io.netty.util.ReferenceCountUtil; import lombok.Getter; import lombok.Setter; @@ -74,6 +75,10 @@ public class DeviceSessionCtx extends MqttDeviceAwareSessionContext { @Setter private boolean provisionOnly = false; + @Getter + @Setter + private MqttVersion mqttVersion; + private volatile MqttTopicFilter telemetryTopicFilter = MqttTopicFilterFactory.getDefaultTelemetryFilter(); private volatile MqttTopicFilter attributesTopicFilter = MqttTopicFilterFactory.getDefaultAttributesFilter(); private volatile TransportPayloadType payloadType = TransportPayloadType.JSON; 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 fad67470ba..c3c4e91d0a 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 @@ -53,6 +53,7 @@ import org.thingsboard.server.transport.mqtt.MqttTransportHandler; import org.thingsboard.server.transport.mqtt.adaptors.JsonMqttAdaptor; import org.thingsboard.server.transport.mqtt.adaptors.MqttTransportAdaptor; import org.thingsboard.server.transport.mqtt.adaptors.ProtoMqttAdaptor; +import org.thingsboard.server.transport.mqtt.util.ReturnCode; import javax.annotation.Nullable; import java.util.Collections; @@ -220,7 +221,7 @@ public class GatewaySessionHandler { Futures.addCallback(onDeviceConnect(deviceName, deviceType), new FutureCallback() { @Override public void onSuccess(@Nullable GatewayDeviceSessionCtx result) { - ack(msg); + ack(msg, ReturnCode.SUCCESS); log.trace("[{}] onDeviceConnectOk: {}", sessionId, deviceName); } @@ -336,7 +337,7 @@ public class GatewaySessionHandler { private void processOnDisconnect(MqttPublishMessage msg, String deviceName) { deregisterSession(deviceName); - ack(msg); + ack(msg, ReturnCode.SUCCESS); } private void onDeviceTelemetryJson(int msgId, ByteBuf payload) throws AdaptorException { @@ -663,7 +664,7 @@ public class GatewaySessionHandler { @Override public void onFailure(Throwable t) { - ack(mqttMsg); + ack(mqttMsg, ReturnCode.IMPLEMENTATION_SPECIFIC); log.debug("[{}] Failed to process device attributes request command: {}", sessionId, deviceName, t); } }, context.getExecutor()); @@ -716,10 +717,10 @@ public class GatewaySessionHandler { return ProtoMqttAdaptor.toBytes(payload); } - private void ack(MqttPublishMessage msg) { + private void ack(MqttPublishMessage msg, ReturnCode returnCode) { int msgId = getMsgId(msg); if (msgId > 0) { - writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(msgId)); + writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(deviceSessionCtx, msgId, returnCode)); } } @@ -735,7 +736,7 @@ public class GatewaySessionHandler { public void onSuccess(Void dummy) { log.trace("[{}][{}] Published msg: {}", sessionId, deviceName, msg); if (msgId > 0) { - ctx.writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(msgId)); + ctx.writeAndFlush(MqttTransportHandler.createMqttPubAckMsg(deviceSessionCtx, msgId, ReturnCode.SUCCESS)); } } diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCode.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCode.java new file mode 100644 index 0000000000..f7b9218d69 --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCode.java @@ -0,0 +1,104 @@ +/** + * 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.server.transport.mqtt.util; + +public enum ReturnCode { + SUCCESS((byte) 0x00), + //MQTT 3 codes + UNACCEPTABLE_PROTOCOL_VERSION((byte) 0X01), + IDENTIFIER_REJECTED((byte) 0x02), + SERVER_UNAVAILABLE((byte) 0x03), + BAD_USER_NAME_OR_PASSWORD((byte) 0x04), + NOT_AUTHORIZED((byte) 0x05), + //MQTT 5 codes + NO_MATCHING_SUBSCRIBERS((byte) 0x10), + NO_SUBSCRIPTION_EXISTED((byte) 0x11), + CONTINUE_AUTHENTICATION((byte) 0x18), + REAUTHENTICATE((byte) 0x19), + UNSPECIFIED_ERROR((byte) 0x80), + MALFORMED_PACKET((byte) 0x81), + PROTOCOL_ERROR((byte) 0x82), + IMPLEMENTATION_SPECIFIC((byte) 0x83), + UNSUPPORTED_PROTOCOL_VERSION((byte) 0x84), + CLIENT_IDENTIFIER_NOT_VALID((byte) 0x85), + BAD_USERNAME_OR_PASSWORD((byte) 0x86), + NOT_AUTHORIZED_5((byte) 0x87), + SERVER_UNAVAILABLE_5((byte) 0x88), + SERVER_BUSY((byte) 0x89), + BANNED((byte) 0x8A), + SERVER_SHUTTING_DOWN((byte) 0x8B), + BAD_AUTHENTICATION_METHOD((byte) 0x8C), + KEEP_ALIVE_TIMEOUT((byte) 0x8D), + SESSION_TAKEN_OVER((byte) 0x8E), + TOPIC_FILTER_INVALID((byte) 0x8F), + TOPIC_NAME_INVALID((byte) 0x90), + PACKET_IDENTIFIER_IN_USE((byte) 0x91), + PACKET_IDENTIFIER_NOT_FOUND((byte) 0x92), + RECEIVE_MAXIMUM_EXCEEDED((byte) 0x93), + TOPIC_ALIAS_INVALID((byte) 0x94), + PACKET_TOO_LARGE((byte) 0x95), + MESSAGE_RATE_TOO_HIGH((byte) 0x96), + QUOTA_EXCEEDED((byte) 0x97), + ADMINISTRATIVE_ACTION((byte) 0x98), + PAYLOAD_FORMAT_INVALID((byte) 0x99), + RETAIN_NOT_SUPPORTED((byte) 0x9A), + QOS_NOT_SUPPORTED((byte) 0x9B), + USE_ANOTHER_SERVER((byte) 0x9C), + SERVER_MOVED((byte) 0x9D), + SHARED_SUBSCRIPTION_NOT_SUPPORTED((byte) 0x9E), + CONNECTION_RATE_EXCEEDED((byte) 0x9F), + MAXIMUM_CONNECT_TIME((byte) 0xA0), + SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED((byte) 0xA1), + WILDCARD_SUBSCRIPTION_NOT_SUPPORTED((byte) 0xA2); + + private static final ReturnCode[] VALUES; + + static { + ReturnCode[] values = values(); + VALUES = new ReturnCode[163]; + for (ReturnCode code : values) { + final int unsignedByte = code.byteValue & 0xFF; + // Suppress a warning about out of bounds access since the enum contains only correct values + VALUES[unsignedByte] = code; // lgtm [java/index-out-of-bounds] + } + } + + private final byte byteValue; + + ReturnCode(byte byteValue) { + this.byteValue = byteValue; + } + + public byte byteValue() { + return byteValue; + } + + public short shortValue(){return byteValue;} + + public static ReturnCode valueOf(byte b) { + final int unsignedByte = b & 0xFF; + ReturnCode mqttConnectReturnCode = null; + try { + mqttConnectReturnCode = VALUES[unsignedByte]; + } catch (ArrayIndexOutOfBoundsException ignored) { + // no op + } + if (mqttConnectReturnCode == null) { + throw new IllegalArgumentException("unknown connect return code: " + unsignedByte); + } + return mqttConnectReturnCode; + } +} \ No newline at end of file diff --git a/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCodeResolver.java b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCodeResolver.java new file mode 100644 index 0000000000..a187dd71f5 --- /dev/null +++ b/common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/util/ReturnCodeResolver.java @@ -0,0 +1,61 @@ +/** + * 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.server.transport.mqtt.util; + +import io.netty.handler.codec.mqtt.MqttConnectReturnCode; +import io.netty.handler.codec.mqtt.MqttQoS; +import io.netty.handler.codec.mqtt.MqttVersion; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class ReturnCodeResolver { + + public static MqttConnectReturnCode getConnectionReturnCode(MqttVersion mqttVersion, ReturnCode returnCode) { + if (!MqttVersion.MQTT_5.equals(mqttVersion) && !ReturnCode.SUCCESS.equals(returnCode)) { + switch (returnCode) { + case BAD_USERNAME_OR_PASSWORD: + return MqttConnectReturnCode.CONNECTION_REFUSED_BAD_USER_NAME_OR_PASSWORD; + case NOT_AUTHORIZED_5: + return MqttConnectReturnCode.CONNECTION_REFUSED_NOT_AUTHORIZED; + case SERVER_UNAVAILABLE_5: + return MqttConnectReturnCode.CONNECTION_REFUSED_SERVER_UNAVAILABLE; + case CLIENT_IDENTIFIER_NOT_VALID: + return MqttConnectReturnCode.CONNECTION_REFUSED_IDENTIFIER_REJECTED; + default: + log.warn("Unknown return code for conversion: {}", returnCode.name()); + } + } + return MqttConnectReturnCode.valueOf(returnCode.byteValue()); + } + + public static int getSubscriptionReturnCode(MqttVersion mqttVersion, ReturnCode returnCode) { + if (!MqttVersion.MQTT_5.equals(mqttVersion) && !ReturnCode.SUCCESS.equals(returnCode)) { + switch (returnCode) { + case UNSPECIFIED_ERROR: + case TOPIC_FILTER_INVALID: + case IMPLEMENTATION_SPECIFIC: + case NOT_AUTHORIZED_5: + case PACKET_IDENTIFIER_IN_USE: + case QUOTA_EXCEEDED: + case SHARED_SUBSCRIPTION_NOT_SUPPORTED: + case SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED: + case WILDCARD_SUBSCRIPTION_NOT_SUPPORTED: + return MqttQoS.FAILURE.value(); + } + } + return returnCode.byteValue(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java index 76637218dc..c76be82956 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/alarm/BaseAlarmService.java @@ -27,6 +27,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.CollectionUtils; import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmInfo; import org.thingsboard.server.common.data.alarm.AlarmQuery; @@ -38,6 +39,7 @@ import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededExcept import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.AlarmData; @@ -58,6 +60,7 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -68,7 +71,7 @@ import java.util.stream.Stream; import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("AlarmDaoService") @Slf4j public class BaseAlarmService extends AbstractEntityService implements AlarmService { @@ -113,7 +116,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ if (alarm.getEndTs() == 0L) { alarm.setEndTs(alarm.getStartTs()); } - alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator())); + alarm.setCustomerId(entityService.fetchEntityCustomerId(alarm.getTenantId(), alarm.getOriginator()).get()); if (alarm.getId() == null) { Alarm existing = alarmDao.findLatestByOriginatorAndType(alarm.getTenantId(), alarm.getOriginator(), alarm.getType()); if (existing == null || existing.getStatus().isCleared()) { @@ -281,14 +284,12 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ public ListenableFuture findAlarmInfoByIdAsync(TenantId tenantId, AlarmId alarmId) { log.trace("Executing findAlarmInfoByIdAsync [{}]", alarmId); validateId(alarmId, "Incorrect alarmId " + alarmId); - return Futures.transformAsync(alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()), + return Futures.transform(alarmDao.findAlarmByIdAsync(tenantId, alarmId.getId()), a -> { AlarmInfo alarmInfo = new AlarmInfo(a); - return Futures.transform( - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { - alarmInfo.setOriginatorName(originatorName); - return alarmInfo; - }, MoreExecutors.directExecutor()); + alarmInfo.setOriginatorName( + entityService.fetchEntityName(tenantId, alarmInfo.getOriginator()).orElse("N/A")); + return alarmInfo; }, MoreExecutors.directExecutor()); } @@ -313,15 +314,9 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ private ListenableFuture> fetchAlarmsOriginators(TenantId tenantId, PageData alarms) { List> alarmFutures = new ArrayList<>(alarms.getData().size()); for (AlarmInfo alarmInfo : alarms.getData()) { - alarmFutures.add(Futures.transform( - entityService.fetchEntityNameAsync(tenantId, alarmInfo.getOriginator()), originatorName -> { - if (originatorName == null) { - originatorName = "Deleted"; - } - alarmInfo.setOriginatorName(originatorName); - return alarmInfo; - }, MoreExecutors.directExecutor() - )); + alarmInfo.setOriginatorName( + entityService.fetchEntityName(tenantId, alarmInfo.getOriginator()).orElse("Deleted")); + alarmFutures.add(Futures.immediateFuture(alarmInfo)); } return Futures.transform(Futures.successfulAsList(alarmFutures), alarmInfos -> new PageData<>(alarmInfos, alarms.getTotalPages(), alarms.getTotalElements(), @@ -411,4 +406,15 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ Alarm entity = alarmDao.findAlarmById(tenantId, alarmId.getId()); return function.apply(entity); } + + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findAlarmById(tenantId, new AlarmId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.ALARM; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java index 58470cfc6b..98e7bbc488 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/AssetProfileServiceImpl.java @@ -21,11 +21,14 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfileInfo; import org.thingsboard.server.common.data.id.AssetProfileId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -38,10 +41,11 @@ import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("AssetProfileDaoService") @Slf4j public class AssetProfileServiceImpl extends AbstractCachedEntityService implements AssetProfileService { @@ -264,6 +268,16 @@ public class AssetProfileServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findAssetProfileById(tenantId, new AssetProfileId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.ASSET_PROFILE; + } + private PaginatedRemover tenantAssetProfilesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java index 15d6df1327..e8db9e5601 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/asset/BaseAssetService.java @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -53,6 +54,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static org.thingsboard.server.dao.DaoUtil.toUUIDs; @@ -61,7 +63,7 @@ import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -@Service +@Service("AssetDaoService") @Slf4j public class BaseAssetService extends AbstractCachedEntityService implements AssetService { @@ -429,4 +431,15 @@ public class BaseAssetService extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findAssetById(tenantId, new AssetId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.ASSET; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index c5976ee2c1..3df41be1e3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -121,13 +121,13 @@ public class AuditLogServiceImpl implements AuditLogService { JsonNode actionData = constructActionData(entityId, entity, actionType, additionalInfo); ActionStatus actionStatus = ActionStatus.SUCCESS; String failureDetails = ""; - String entityName = ""; + String entityName = "N/A"; if (entity != null) { entityName = entity.getName(); } else { try { - entityName = entityService.fetchEntityNameAsync(tenantId, entityId).get(); - } catch (Exception ex) { + entityName = entityService.fetchEntityName(tenantId, entityId).orElse(entityName); + } catch (Exception ignored) { } } if (e != null) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java index 8f4ebb9102..0b1efaf82e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java @@ -58,4 +58,5 @@ public class DummyAuditLogServiceImpl implements AuditLogService { public ListenableFuture> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { return null; } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java index 093ad4b65c..a1ca76cb85 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/customer/CustomerServiceImpl.java @@ -24,7 +24,10 @@ import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -44,7 +47,7 @@ import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("CustomerDaoService") @Slf4j public class CustomerServiceImpl extends AbstractEntityService implements CustomerService { @@ -178,4 +181,15 @@ public class CustomerServiceImpl extends AbstractEntityService implements Custom deleteCustomer(tenantId, new CustomerId(entity.getUuidId())); } }; + + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findCustomerById(tenantId, new CustomerId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.CUSTOMER; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java index 2de73826e3..1f72b7c677 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/dashboard/DashboardServiceImpl.java @@ -24,10 +24,13 @@ import org.springframework.transaction.annotation.Transactional; import org.thingsboard.server.common.data.Customer; import org.thingsboard.server.common.data.Dashboard; import org.thingsboard.server.common.data.DashboardInfo; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.EdgeId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -42,10 +45,11 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; import java.util.List; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("DashboardDaoService") @Slf4j public class DashboardServiceImpl extends AbstractEntityService implements DashboardService { @@ -307,6 +311,16 @@ public class DashboardServiceImpl extends AbstractEntityService implements Dashb } }; + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findDashboardById(tenantId, new DashboardId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.DASHBOARD; + } + private class CustomerDashboardsUnassigner extends PaginatedRemover { private Customer customer; diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 40d190162f..9dad6a22d9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -28,12 +28,15 @@ import org.thingsboard.server.common.data.DeviceProfileInfo; import org.thingsboard.server.common.data.DeviceProfileProvisionType; import org.thingsboard.server.common.data.DeviceProfileType; import org.thingsboard.server.common.data.DeviceTransportType; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileConfiguration; import org.thingsboard.server.common.data.device.profile.DefaultDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; import org.thingsboard.server.common.data.device.profile.DisabledDeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -47,10 +50,11 @@ import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("DeviceProfileDaoService") @Slf4j public class DeviceProfileServiceImpl extends AbstractCachedEntityService implements DeviceProfileService { @@ -286,6 +290,16 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findDeviceProfileById(tenantId, new DeviceProfileId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.DEVICE_PROFILE; + } + private PaginatedRemover tenantDeviceProfilesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java index 486570dc2e..e5ae9de626 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceServiceImpl.java @@ -53,6 +53,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.OtaPackageType; import org.thingsboard.server.common.data.page.PageData; @@ -76,6 +77,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; @@ -85,7 +87,7 @@ import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -@Service +@Service("DeviceDaoService") @Slf4j public class DeviceServiceImpl extends AbstractCachedEntityService implements DeviceService { @@ -705,4 +707,15 @@ public class DeviceServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findDeviceById(tenantId, new DeviceId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.DEVICE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java index 3ab3f6d905..2f77856628 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/edge/EdgeServiceImpl.java @@ -40,6 +40,7 @@ import org.thingsboard.server.common.data.edge.EdgeSearchQuery; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.IdBased; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.TenantId; @@ -75,7 +76,7 @@ import static org.thingsboard.server.dao.service.Validator.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -@Service +@Service("EdgeDaoService") @Slf4j public class EdgeServiceImpl extends AbstractCachedEntityService implements EdgeService { @@ -519,4 +520,15 @@ public class EdgeServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findEdgeById(tenantId, new EdgeId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.EDGE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java index bb1c633f85..0a9b3c631a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/BaseEntityService.java @@ -15,51 +15,27 @@ */ package org.thingsboard.server.dao.entity; -import com.google.common.base.Function; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.MoreExecutors; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.thingsboard.server.common.data.HasCustomerId; import org.thingsboard.server.common.data.HasName; -import org.thingsboard.server.common.data.id.AlarmId; -import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.CustomerId; -import org.thingsboard.server.common.data.id.DashboardId; -import org.thingsboard.server.common.data.id.DeviceId; -import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.EntityViewId; -import org.thingsboard.server.common.data.id.OtaPackageId; -import org.thingsboard.server.common.data.id.RuleChainId; -import org.thingsboard.server.common.data.id.TbResourceId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.EntityCountQuery; import org.thingsboard.server.common.data.query.EntityData; -import org.thingsboard.server.common.data.query.EntityDataPageLink; import org.thingsboard.server.common.data.query.EntityDataQuery; import org.thingsboard.server.common.data.query.EntityFilterType; import org.thingsboard.server.common.data.query.RelationsQueryFilter; -import org.thingsboard.server.dao.alarm.AlarmService; -import org.thingsboard.server.dao.asset.AssetService; -import org.thingsboard.server.dao.customer.CustomerService; -import org.thingsboard.server.dao.dashboard.DashboardService; -import org.thingsboard.server.dao.device.DeviceService; -import org.thingsboard.server.dao.entityview.EntityViewService; import org.thingsboard.server.dao.exception.IncorrectParameterException; -import org.thingsboard.server.dao.ota.OtaPackageService; -import org.thingsboard.server.dao.resource.ResourceService; -import org.thingsboard.server.dao.rule.RuleChainService; -import org.thingsboard.server.dao.tenant.TenantService; -import org.thingsboard.server.dao.user.UserService; -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; +import java.util.Optional; + +import static org.thingsboard.server.common.data.id.EntityId.NULL_UUID; import static org.thingsboard.server.dao.service.Validator.validateEntityDataPageLink; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -72,42 +48,13 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId "; - - @Autowired - private AssetService assetService; - - @Autowired - private DeviceService deviceService; - - @Autowired - private EntityViewService entityViewService; - - @Autowired - private TenantService tenantService; - - @Autowired - private CustomerService customerService; - - @Autowired - private UserService userService; - - @Autowired - private DashboardService dashboardService; - - @Autowired - private AlarmService alarmService; - - @Autowired - private RuleChainService ruleChainService; + public static final CustomerId NULL_CUSTOMER_ID = new CustomerId(NULL_UUID); @Autowired private EntityQueryDao entityQueryDao; @Autowired - private ResourceService resourceService; - - @Autowired - private OtaPackageService otaPackageService; + EntityServiceRegistry entityServiceRegistry; @Override public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { @@ -127,100 +74,38 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, query); } - //TODO: 3.1 Remove this from project. @Override - public ListenableFuture fetchEntityNameAsync(TenantId tenantId, EntityId entityId) { - log.trace("Executing fetchEntityNameAsync [{}]", entityId); - ListenableFuture entityName; - ListenableFuture hasName; - switch (entityId.getEntityType()) { - case ASSET: - hasName = assetService.findAssetByIdAsync(tenantId, new AssetId(entityId.getId())); - break; - case DEVICE: - hasName = deviceService.findDeviceByIdAsync(tenantId, new DeviceId(entityId.getId())); - break; - case ENTITY_VIEW: - hasName = entityViewService.findEntityViewByIdAsync(tenantId, new EntityViewId(entityId.getId())); - break; - case TENANT: - hasName = tenantService.findTenantByIdAsync(tenantId, TenantId.fromUUID(entityId.getId())); - break; - case CUSTOMER: - hasName = customerService.findCustomerByIdAsync(tenantId, new CustomerId(entityId.getId())); - break; - case USER: - hasName = userService.findUserByIdAsync(tenantId, new UserId(entityId.getId())); - break; - case DASHBOARD: - hasName = dashboardService.findDashboardInfoByIdAsync(tenantId, new DashboardId(entityId.getId())); - break; - case ALARM: - hasName = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId())); - break; - case RULE_CHAIN: - hasName = ruleChainService.findRuleChainByIdAsync(tenantId, new RuleChainId(entityId.getId())); - break; - case EDGE: - hasName = edgeService.findEdgeByIdAsync(tenantId, new EdgeId(entityId.getId())); - break; - case TB_RESOURCE: - hasName = resourceService.findResourceInfoByIdAsync(tenantId, new TbResourceId(entityId.getId())); - break; - case OTA_PACKAGE: - hasName = otaPackageService.findOtaPackageInfoByIdAsync(tenantId, new OtaPackageId(entityId.getId())); - break; - default: - throw new IllegalStateException("Not Implemented!"); + public Optional fetchEntityName(TenantId tenantId, EntityId entityId) { + log.trace("Executing fetchEntityName [{}]", entityId); + EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); + Optional> hasIdOpt = entityDaoService.findEntity(tenantId, entityId); + if (hasIdOpt.isPresent()) { + HasId hasId = hasIdOpt.get(); + if (hasId instanceof HasName) { + HasName hasName = (HasName) hasId; + return Optional.ofNullable(hasName.getName()); + } } - entityName = Futures.transform(hasName, (Function) hasName1 -> hasName1 != null ? hasName1.getName() : null, MoreExecutors.directExecutor()); - return entityName; + return Optional.empty(); } @Override - public CustomerId fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { + public Optional fetchEntityCustomerId(TenantId tenantId, EntityId entityId) { log.trace("Executing fetchEntityCustomerId [{}]", entityId); - HasCustomerId hasCustomerId = null; - switch (entityId.getEntityType()) { - case TENANT: - case RULE_CHAIN: - case RULE_NODE: - case DASHBOARD: - case WIDGETS_BUNDLE: - case WIDGET_TYPE: - case TENANT_PROFILE: - case DEVICE_PROFILE: - case ASSET_PROFILE: - case API_USAGE_STATE: - case TB_RESOURCE: - case OTA_PACKAGE: - break; - case CUSTOMER: - hasCustomerId = () -> new CustomerId(entityId.getId()); - break; - case USER: - hasCustomerId = userService.findUserById(tenantId, new UserId(entityId.getId())); - break; - case ASSET: - hasCustomerId = assetService.findAssetById(tenantId, new AssetId(entityId.getId())); - break; - case DEVICE: - hasCustomerId = deviceService.findDeviceById(tenantId, new DeviceId(entityId.getId())); - break; - case ALARM: - try { - hasCustomerId = alarmService.findAlarmByIdAsync(tenantId, new AlarmId(entityId.getId())).get(); - } catch (Exception e) { + EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityId.getEntityType()); + Optional> hasIdOpt = entityDaoService.findEntity(tenantId, entityId); + if (hasIdOpt.isPresent()) { + HasId hasId = hasIdOpt.get(); + if (hasId instanceof HasCustomerId) { + HasCustomerId hasCustomerId = (HasCustomerId) hasId; + CustomerId customerId = hasCustomerId.getCustomerId(); + if (customerId == null) { + customerId = NULL_CUSTOMER_ID; } - break; - case ENTITY_VIEW: - hasCustomerId = entityViewService.findEntityViewById(tenantId, new EntityViewId(entityId.getId())); - break; - case EDGE: - hasCustomerId = edgeService.findEdgeById(tenantId, new EdgeId(entityId.getId())); - break; + return Optional.of(customerId); + } } - return hasCustomerId != null ? hasCustomerId.getCustomerId() : new CustomerId(NULL_UUID); + return Optional.of(NULL_CUSTOMER_ID); } private static void validateEntityCountQuery(EntityCountQuery query) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java new file mode 100644 index 0000000000..d93381f66c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/entity/DefaultEntityServiceRegistry.java @@ -0,0 +1,53 @@ +/** + * 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.server.dao.entity; + +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; + +import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.Map; + +@Service +public class DefaultEntityServiceRegistry implements EntityServiceRegistry { + + private final ApplicationContext applicationContext; + private final Map entityDaoServicesMap; + + public DefaultEntityServiceRegistry(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + this.entityDaoServicesMap = new HashMap<>(); + } + + @PostConstruct + public void init() { + applicationContext.getBeansOfType(EntityDaoService.class).values().forEach(entityDaoService -> { + EntityType entityType = entityDaoService.getEntityType(); + entityDaoServicesMap.put(entityType, entityDaoService); + if (EntityType.RULE_CHAIN.equals(entityType)) { + entityDaoServicesMap.put(EntityType.RULE_NODE, entityDaoService); + } + }); + } + + @Override + public EntityDaoService getServiceByEntityType(EntityType entityType) { + return entityDaoServicesMap.get(entityType); + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java index f9b6ee076a..a510c9d50d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/entityview/EntityViewServiceImpl.java @@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityViewId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -52,6 +53,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import static org.thingsboard.server.dao.service.Validator.validateId; @@ -61,7 +63,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString; /** * Created by Victor Basanets on 8/28/2017. */ -@Service +@Service("EntityViewDaoService") @Slf4j public class EntityViewServiceImpl extends AbstractCachedEntityService implements EntityViewService { @@ -408,4 +410,15 @@ public class EntityViewServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findEntityViewById(tenantId, new EntityViewId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.ENTITY_VIEW; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java index 26e6b611ec..55a98a9549 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java @@ -148,4 +148,5 @@ public class BaseEventService implements EventService { private List convert(EntityType entityType, List list) { return list == null ? null : list.stream().map(e -> e.toInfo(entityType)).collect(Collectors.toList()); } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java index 841ff82441..5a4625cd5b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/ota/BaseOtaPackageService.java @@ -24,10 +24,13 @@ import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.server.cache.ota.OtaPackageDataCache; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.OtaPackage; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.DeviceProfileId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.OtaPackageId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.ota.ChecksumAlgorithm; @@ -45,7 +48,7 @@ import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; -@Service +@Service("OtaPackageDaoService") @Slf4j @RequiredArgsConstructor public class BaseOtaPackageService extends AbstractCachedEntityService implements OtaPackageService { @@ -234,4 +237,14 @@ public class BaseOtaPackageService extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findOtaPackageInfoById(tenantId, new OtaPackageId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.OTA_PACKAGE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java index 45b5b2cc7e..b48f26ac25 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/queue/BaseQueueService.java @@ -21,7 +21,10 @@ import org.hibernate.exception.ConstraintViolationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -35,8 +38,9 @@ import org.thingsboard.server.dao.service.Validator; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import java.util.List; +import java.util.Optional; -@Service +@Service("QueueDaoService") @Slf4j @RequiredArgsConstructor public class BaseQueueService extends AbstractEntityService implements QueueService { @@ -119,6 +123,16 @@ public class BaseQueueService extends AbstractEntityService implements QueueServ tenantQueuesRemover.removeEntities(tenantId, tenantId); } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findQueueById(tenantId, new QueueId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.QUEUE; + } + private PaginatedRemover tenantQueuesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index ceda7eb52c..5cd57b557e 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -57,6 +57,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -374,12 +375,10 @@ public class BaseRelationService implements RelationService { private ListenableFuture fetchRelationInfoAsync(TenantId tenantId, EntityRelation relation, Function entityIdGetter, BiConsumer entityNameSetter) { - ListenableFuture entityName = entityService.fetchEntityNameAsync(tenantId, entityIdGetter.apply(relation)); - return Futures.transform(entityName, entityName1 -> { - EntityRelationInfo entityRelationInfo1 = new EntityRelationInfo(relation); - entityNameSetter.accept(entityRelationInfo1, entityName1); - return entityRelationInfo1; - }, MoreExecutors.directExecutor()); + EntityRelationInfo relationInfo = new EntityRelationInfo(relation); + entityNameSetter.accept(relationInfo, + entityService.fetchEntityName(tenantId, entityIdGetter.apply(relation)).orElse("N/A")); + return Futures.immediateFuture(relationInfo); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java index dd13f5b200..5988970ad5 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/resource/BaseResourceService.java @@ -20,9 +20,12 @@ import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hibernate.exception.ConstraintViolationException; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.ResourceType; import org.thingsboard.server.common.data.TbResource; import org.thingsboard.server.common.data.TbResourceInfo; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TbResourceId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -38,7 +41,7 @@ import java.util.Optional; import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("TbResourceDaoService") @Slf4j @AllArgsConstructor public class BaseResourceService implements ResourceService { @@ -134,6 +137,16 @@ public class BaseResourceService implements ResourceService { tenantResourcesRemover.removeEntities(tenantId, tenantId); } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findResourceInfoById(tenantId, new TbResourceId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.TB_RESOURCE; + } + @Override public long sumDataSizeByTenantId(TenantId tenantId) { return resourceDao.sumDataSizeByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java index 13afd60aba..27c4b37145 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rpc/BaseRpcService.java @@ -19,7 +19,10 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.RpcId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; @@ -28,10 +31,12 @@ import org.thingsboard.server.common.data.rpc.Rpc; import org.thingsboard.server.common.data.rpc.RpcStatus; import org.thingsboard.server.dao.service.PaginatedRemover; +import java.util.Optional; + import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; -@Service +@Service("RpcDaoService") @Slf4j @RequiredArgsConstructor public class BaseRpcService implements RpcService { @@ -93,6 +98,16 @@ public class BaseRpcService implements RpcService { return rpcDao.findAllByDeviceId(tenantId, deviceId, pageLink); } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findById(tenantId, new RpcId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.RPC; + } + private PaginatedRemover tenantRpcRemover = new PaginatedRemover<>() { @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java index 023f98c18a..cc1f605683 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/rule/BaseRuleChainService.java @@ -32,6 +32,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.id.EdgeId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.RuleChainId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -75,7 +76,7 @@ import static org.thingsboard.server.dao.service.Validator.validateString; /** * Created by igor on 3/12/18. */ -@Service +@Service("RuleChainDaoService") @Slf4j public class BaseRuleChainService extends AbstractEntityService implements RuleChainService { @@ -727,6 +728,20 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC deleteEntityRelations(tenantId, ruleChainId); } + + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + HasId hasId = EntityType.RULE_NODE.equals(entityId.getEntityType()) ? + findRuleNodeById(tenantId, new RuleNodeId(entityId.getId())) : + findRuleChainById(tenantId, new RuleChainId(entityId.getId())); + return Optional.ofNullable(hasId); + } + + @Override + public EntityType getEntityType() { + return EntityType.RULE_CHAIN; + } + private List getRuleChainToNodeRelations(TenantId tenantId, RuleChainId ruleChainId) { return relationService.findByFrom(tenantId, ruleChainId, RelationTypeGroup.RULE_CHAIN); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java index a1ffde92d5..078bf77626 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantProfileServiceImpl.java @@ -21,7 +21,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.server.common.data.EntityInfo; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; @@ -36,10 +39,11 @@ import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("TenantProfileDaoService") @Slf4j public class TenantProfileServiceImpl extends AbstractCachedEntityService implements TenantProfileService { @@ -204,6 +208,16 @@ public class TenantProfileServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findTenantProfileById(tenantId, new TenantProfileId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.TENANT_PROFILE; + } + private final PaginatedRemover tenantProfilesRemover = new PaginatedRemover<>() { diff --git a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java index 7c5d951c2a..106ac695d8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/tenant/TenantServiceImpl.java @@ -23,9 +23,12 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.event.TransactionalEventListener; import org.thingsboard.server.cache.TbTransactionalCache; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantInfo; import org.thingsboard.server.common.data.TenantProfile; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.data.page.PageData; @@ -51,10 +54,11 @@ import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.dao.widget.WidgetsBundleService; import java.util.List; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("TenantDaoService") @Slf4j public class TenantServiceImpl extends AbstractCachedEntityService implements TenantService { @@ -256,4 +260,15 @@ public class TenantServiceImpl extends AbstractCachedEntityService> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findTenantById(new TenantId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.TENANT; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index f2bd8e47c1..b8c55d876b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.Tenant; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.ApiUsageStateId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; @@ -42,10 +43,11 @@ import org.thingsboard.server.dao.timeseries.TimeseriesService; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; -@Service +@Service("ApiUsageStateDaoService") @Slf4j public class ApiUsageStateServiceImpl extends AbstractEntityService implements ApiUsageStateService { public static final String INCORRECT_TENANT_ID = "Incorrect tenantId "; @@ -161,4 +163,14 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A return apiUsageStateDao.findById(tenantId, id.getId()); } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findApiUsageStateById(tenantId, new ApiUsageStateId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.API_USAGE_STATE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java index 41d121b889..912a10b44c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/user/UserServiceImpl.java @@ -28,9 +28,12 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.UserCredentialsId; import org.thingsboard.server.common.data.id.UserId; @@ -45,12 +48,13 @@ import org.thingsboard.server.dao.service.PaginatedRemover; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import static org.thingsboard.server.dao.service.Validator.validateId; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validateString; -@Service +@Service("UserDaoService") @Slf4j @RequiredArgsConstructor public class UserServiceImpl extends AbstractEntityService implements UserService { @@ -397,4 +401,14 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic } }; + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findUserById(tenantId, new UserId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.USER; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java index 4c45239921..b6b6c5efa7 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/AbstractBufferedRateExecutor.java @@ -44,6 +44,7 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import javax.annotation.Nullable; import java.util.HashMap; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; @@ -326,11 +327,12 @@ public abstract class AbstractBufferedRateExecutor { + String defaultName = "N/A"; try { - return entityService.fetchEntityNameAsync(TenantId.SYS_TENANT_ID, tenantId).get(); + return entityService.fetchEntityName(TenantId.SYS_TENANT_ID, tenantId).orElse(defaultName); } catch (Exception e) { log.error("[{}] Failed to get tenant name", tenantId, e); - return "N/A"; + return defaultName; } }); log.info("[{}][{}] Rate limited requests: {}", tenantId, name, rateLimitedRequests); diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java index 9b64dc0d68..a26fc49c78 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java @@ -18,6 +18,9 @@ package org.thingsboard.server.dao.widget; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.widget.WidgetType; @@ -27,8 +30,9 @@ import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.Validator; import java.util.List; +import java.util.Optional; -@Service +@Service("WidgetTypeDaoService") @Slf4j public class WidgetTypeServiceImpl implements WidgetTypeService { @@ -112,4 +116,14 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { } } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findWidgetTypeById(tenantId, new WidgetTypeId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.WIDGET_TYPE; + } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java index 737043ccba..e32366e3a3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleServiceImpl.java @@ -18,6 +18,9 @@ package org.thingsboard.server.dao.widget; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.HasId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; @@ -31,8 +34,9 @@ import org.thingsboard.server.dao.service.Validator; import java.util.ArrayList; import java.util.List; +import java.util.Optional; -@Service +@Service("WidgetsBundleDaoService") @Slf4j public class WidgetsBundleServiceImpl implements WidgetsBundleService { @@ -151,6 +155,16 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { tenantWidgetsBundleRemover.removeEntities(tenantId, tenantId); } + @Override + public Optional> findEntity(TenantId tenantId, EntityId entityId) { + return Optional.ofNullable(findWidgetsBundleById(tenantId, new WidgetsBundleId(entityId.getId()))); + } + + @Override + public EntityType getEntityType() { + return EntityType.WIDGETS_BUNDLE; + } + private PaginatedRemover tenantWidgetsBundleRemover = new PaginatedRemover() { diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java new file mode 100644 index 0000000000..81c6159d4a --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/BaseEntityServiceRegistryTest.java @@ -0,0 +1,46 @@ +/** + * 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.server.dao.service; + +import lombok.extern.slf4j.Slf4j; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.dao.entity.EntityDaoService; +import org.thingsboard.server.dao.entity.EntityServiceRegistry; +import org.thingsboard.server.dao.rule.RuleChainService; + +@Slf4j +public abstract class BaseEntityServiceRegistryTest extends AbstractServiceTest { + + @Autowired + private EntityServiceRegistry entityServiceRegistry; + + @Test + public void givenAllEntityTypes_whenGetServiceByEntityTypeCalled_thenAllBeansExists() { + for (EntityType entityType : EntityType.values()) { + EntityDaoService entityDaoService = entityServiceRegistry.getServiceByEntityType(entityType); + Assert.assertNotNull("entityDaoService bean is missed for type: " + entityType.name(), entityDaoService); + } + } + + @Test + public void givenRuleNodeEntityType_whenGetServiceByEntityTypeCalled_thenReturnedRuleChainService() { + Assert.assertTrue(entityServiceRegistry.getServiceByEntityType(EntityType.RULE_NODE) instanceof RuleChainService); + } + +} diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceRegistrySqlTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceRegistrySqlTest.java new file mode 100644 index 0000000000..40d6d2ae77 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/sql/EntityServiceRegistrySqlTest.java @@ -0,0 +1,24 @@ +/** + * 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.server.dao.service.sql; + +import org.thingsboard.server.dao.service.BaseEntityServiceRegistryTest; +import org.thingsboard.server.dao.service.DaoSqlTest; + +@DaoSqlTest +public class EntityServiceRegistrySqlTest extends BaseEntityServiceRegistryTest { + +} diff --git a/pom.xml b/pom.xml index df1cf68006..92f13121d6 100755 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,7 @@ 1.0.5 1.18.18 1.2.4 + 1.2.5 4.1.75.Final 2.0.51.Final 1.7.0 @@ -1713,6 +1714,11 @@ org.eclipse.paho.client.mqttv3 ${paho.client.version} + + org.eclipse.paho + org.eclipse.paho.mqttv5.client + ${paho.mqttv5.client.version} + org.apache.curator curator-x-discovery diff --git a/pull_request_template.md b/pull_request_template.md index 21362429dc..4fd83ec4f0 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -12,7 +12,7 @@ Put your PR description here instead of this sentence. - [ ] Description contains brief notes about what needs to be added to the documentation. - [ ] No merge conflicts, commented blocks of code, code formatting issues. - [ ] Changes are backward compatible or upgrade script is provided. -- [ ] Similar PR is opened for PE version to simplify merge. Required for internal contributors only. +- [ ] Similar PR is opened for PE version to simplify merge. Crosslinks between PRs added. Required for internal contributors only. ## Front-End feature checklist