202 changed files with 6629 additions and 476 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,77 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.edge.rpc.processor.asset; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.util.Pair; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
import org.thingsboard.server.common.data.asset.Asset; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.AssetUpdateMsg; |
|||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Slf4j |
|||
public abstract class BaseAssetProcessor extends BaseEdgeProcessor { |
|||
|
|||
protected Pair<Boolean, Boolean> saveOrUpdateAsset(TenantId tenantId, AssetId assetId, AssetUpdateMsg assetUpdateMsg, CustomerId customerId) { |
|||
boolean created = false; |
|||
boolean assetNameUpdated = false; |
|||
assetCreationLock.lock(); |
|||
try { |
|||
Asset asset = assetService.findAssetById(tenantId, assetId); |
|||
String assetName = assetUpdateMsg.getName(); |
|||
if (asset == null) { |
|||
created = true; |
|||
asset = new Asset(); |
|||
asset.setTenantId(tenantId); |
|||
asset.setCreatedTime(Uuids.unixTimestamp(assetId.getId())); |
|||
} |
|||
Asset assetByName = assetService.findAssetByTenantIdAndName(tenantId, assetName); |
|||
if (assetByName != null && !assetByName.getId().equals(assetId)) { |
|||
assetName = assetName + "_" + StringUtils.randomAlphanumeric(15); |
|||
log.warn("Asset with name {} already exists. Renaming asset name to {}", |
|||
assetUpdateMsg.getName(), assetName); |
|||
assetNameUpdated = true; |
|||
} |
|||
asset.setName(assetName); |
|||
asset.setType(assetUpdateMsg.getType()); |
|||
asset.setLabel(assetUpdateMsg.hasLabel() ? assetUpdateMsg.getLabel() : null); |
|||
asset.setAdditionalInfo(assetUpdateMsg.hasAdditionalInfo() |
|||
? JacksonUtil.toJsonNode(assetUpdateMsg.getAdditionalInfo()) : null); |
|||
|
|||
UUID assetProfileUUID = safeGetUUID(assetUpdateMsg.getAssetProfileIdMSB(), assetUpdateMsg.getAssetProfileIdLSB()); |
|||
asset.setAssetProfileId(assetProfileUUID != null ? new AssetProfileId(assetProfileUUID) : null); |
|||
|
|||
asset.setCustomerId(customerId); |
|||
|
|||
assetValidator.validate(asset, Asset::getTenantId); |
|||
if (created) { |
|||
asset.setId(assetId); |
|||
} |
|||
assetService.saveAsset(asset, false); |
|||
} finally { |
|||
assetCreationLock.unlock(); |
|||
} |
|||
return Pair.of(created, assetNameUpdated); |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.edge.rpc.processor.asset; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.asset.AssetProfile; |
|||
import org.thingsboard.server.common.data.id.AssetProfileId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.AssetProfileUpdateMsg; |
|||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.UUID; |
|||
|
|||
@Slf4j |
|||
public class BaseAssetProfileProcessor extends BaseEdgeProcessor { |
|||
|
|||
protected boolean saveOrUpdateAssetProfile(TenantId tenantId, AssetProfileId assetProfileId, AssetProfileUpdateMsg assetProfileUpdateMsg) { |
|||
boolean created = false; |
|||
assetCreationLock.lock(); |
|||
try { |
|||
AssetProfile assetProfile = assetProfileService.findAssetProfileById(tenantId, assetProfileId); |
|||
String assetProfileName = assetProfileUpdateMsg.getName(); |
|||
if (assetProfile == null) { |
|||
created = true; |
|||
assetProfile = new AssetProfile(); |
|||
assetProfile.setTenantId(tenantId); |
|||
assetProfile.setCreatedTime(Uuids.unixTimestamp(assetProfileId.getId())); |
|||
} |
|||
assetProfile.setName(assetProfileName); |
|||
assetProfile.setDefault(assetProfileUpdateMsg.getDefault()); |
|||
assetProfile.setDefaultQueueName(assetProfileUpdateMsg.hasDefaultQueueName() ? assetProfileUpdateMsg.getDefaultQueueName() : null); |
|||
assetProfile.setDescription(assetProfileUpdateMsg.hasDescription() ? assetProfileUpdateMsg.getDescription() : null); |
|||
assetProfile.setImage(assetProfileUpdateMsg.hasImage() |
|||
? new String(assetProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null); |
|||
|
|||
UUID defaultRuleChainUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultRuleChainIdMSB(), assetProfileUpdateMsg.getDefaultRuleChainIdLSB()); |
|||
assetProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null); |
|||
|
|||
UUID defaultDashboardUUID = safeGetUUID(assetProfileUpdateMsg.getDefaultDashboardIdMSB(), assetProfileUpdateMsg.getDefaultDashboardIdLSB()); |
|||
assetProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); |
|||
|
|||
assetProfileValidator.validate(assetProfile, AssetProfile::getTenantId); |
|||
if (created) { |
|||
assetProfile.setId(assetProfileId); |
|||
} |
|||
assetProfileService.saveAssetProfile(assetProfile, false); |
|||
} finally { |
|||
assetCreationLock.unlock(); |
|||
} |
|||
return created; |
|||
} |
|||
} |
|||
@ -0,0 +1,77 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.edge.rpc.processor.dashboard; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import com.fasterxml.jackson.core.type.TypeReference; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.Dashboard; |
|||
import org.thingsboard.server.common.data.ShortCustomerInfo; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.DashboardUpdateMsg; |
|||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; |
|||
|
|||
import java.util.Set; |
|||
|
|||
@Slf4j |
|||
public abstract class BaseDashboardProcessor extends BaseEdgeProcessor { |
|||
|
|||
protected boolean saveOrUpdateDashboard(TenantId tenantId, DashboardId dashboardId, DashboardUpdateMsg dashboardUpdateMsg, CustomerId customerId) { |
|||
boolean created = false; |
|||
Dashboard dashboard = dashboardService.findDashboardById(tenantId, dashboardId); |
|||
if (dashboard == null) { |
|||
created = true; |
|||
dashboard = new Dashboard(); |
|||
dashboard.setTenantId(tenantId); |
|||
dashboard.setCreatedTime(Uuids.unixTimestamp(dashboardId.getId())); |
|||
} |
|||
dashboard.setTitle(dashboardUpdateMsg.getTitle()); |
|||
dashboard.setConfiguration(JacksonUtil.toJsonNode(dashboardUpdateMsg.getConfiguration())); |
|||
Set<ShortCustomerInfo> assignedCustomers = null; |
|||
if (dashboardUpdateMsg.hasAssignedCustomers()) { |
|||
assignedCustomers = JacksonUtil.fromString(dashboardUpdateMsg.getAssignedCustomers(), new TypeReference<>() { |
|||
}); |
|||
dashboard.setAssignedCustomers(assignedCustomers); |
|||
} |
|||
|
|||
dashboardValidator.validate(dashboard, Dashboard::getTenantId); |
|||
if (created) { |
|||
dashboard.setId(dashboardId); |
|||
} |
|||
Dashboard savedDashboard = dashboardService.saveDashboard(dashboard, false); |
|||
if (assignedCustomers != null && !assignedCustomers.isEmpty()) { |
|||
for (ShortCustomerInfo assignedCustomer : assignedCustomers) { |
|||
if (assignedCustomer.getCustomerId().equals(customerId)) { |
|||
dashboardService.assignDashboardToCustomer(tenantId, dashboardId, assignedCustomer.getCustomerId()); |
|||
} |
|||
} |
|||
} else { |
|||
unassignCustomersFromDashboard(tenantId, savedDashboard); |
|||
} |
|||
return created; |
|||
} |
|||
|
|||
private void unassignCustomersFromDashboard(TenantId tenantId, Dashboard dashboard) { |
|||
if (dashboard.getAssignedCustomers() != null && !dashboard.getAssignedCustomers().isEmpty()) { |
|||
for (ShortCustomerInfo assignedCustomer : dashboard.getAssignedCustomers()) { |
|||
dashboardService.unassignDashboardFromCustomer(tenantId, dashboard.getId(), assignedCustomer.getCustomerId()); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.edge.rpc.processor.device; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.thingsboard.server.common.data.DeviceProfile; |
|||
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.StringUtils; |
|||
import org.thingsboard.server.common.data.device.profile.DeviceProfileData; |
|||
import org.thingsboard.server.common.data.id.DashboardId; |
|||
import org.thingsboard.server.common.data.id.DeviceProfileId; |
|||
import org.thingsboard.server.common.data.id.OtaPackageId; |
|||
import org.thingsboard.server.common.data.id.RuleChainId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.DeviceProfileUpdateMsg; |
|||
import org.thingsboard.server.queue.util.DataDecodingEncodingService; |
|||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.Optional; |
|||
import java.util.UUID; |
|||
|
|||
@Slf4j |
|||
public class BaseDeviceProfileProcessor extends BaseEdgeProcessor { |
|||
|
|||
@Autowired |
|||
private DataDecodingEncodingService dataDecodingEncodingService; |
|||
|
|||
protected boolean saveOrUpdateDeviceProfile(TenantId tenantId, DeviceProfileId deviceProfileId, DeviceProfileUpdateMsg deviceProfileUpdateMsg) { |
|||
boolean created = false; |
|||
deviceCreationLock.lock(); |
|||
try { |
|||
DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId); |
|||
if (deviceProfile == null) { |
|||
created = true; |
|||
deviceProfile = new DeviceProfile(); |
|||
deviceProfile.setTenantId(tenantId); |
|||
deviceProfile.setCreatedTime(Uuids.unixTimestamp(deviceProfileId.getId())); |
|||
} |
|||
deviceProfile.setName(deviceProfileUpdateMsg.getName()); |
|||
deviceProfile.setDescription(deviceProfileUpdateMsg.hasDescription() ? deviceProfileUpdateMsg.getDescription() : null); |
|||
deviceProfile.setDefault(deviceProfileUpdateMsg.getDefault()); |
|||
deviceProfile.setType(DeviceProfileType.valueOf(deviceProfileUpdateMsg.getType())); |
|||
deviceProfile.setTransportType(deviceProfileUpdateMsg.hasTransportType() |
|||
? DeviceTransportType.valueOf(deviceProfileUpdateMsg.getTransportType()) : DeviceTransportType.DEFAULT); |
|||
deviceProfile.setImage(deviceProfileUpdateMsg.hasImage() |
|||
? new String(deviceProfileUpdateMsg.getImage().toByteArray(), StandardCharsets.UTF_8) : null); |
|||
deviceProfile.setProvisionType(deviceProfileUpdateMsg.hasProvisionType() |
|||
? DeviceProfileProvisionType.valueOf(deviceProfileUpdateMsg.getProvisionType()) : DeviceProfileProvisionType.DISABLED); |
|||
deviceProfile.setProvisionDeviceKey(deviceProfileUpdateMsg.hasProvisionDeviceKey() |
|||
? deviceProfileUpdateMsg.getProvisionDeviceKey() : null); |
|||
deviceProfile.setDefaultQueueName(deviceProfileUpdateMsg.getDefaultQueueName()); |
|||
|
|||
Optional<DeviceProfileData> profileDataOpt = |
|||
dataDecodingEncodingService.decode(deviceProfileUpdateMsg.getProfileDataBytes().toByteArray()); |
|||
deviceProfile.setProfileData(profileDataOpt.orElse(null)); |
|||
|
|||
UUID defaultRuleChainUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultRuleChainIdMSB(), deviceProfileUpdateMsg.getDefaultRuleChainIdLSB()); |
|||
deviceProfile.setDefaultRuleChainId(defaultRuleChainUUID != null ? new RuleChainId(defaultRuleChainUUID) : null); |
|||
|
|||
UUID defaultDashboardUUID = safeGetUUID(deviceProfileUpdateMsg.getDefaultDashboardIdMSB(), deviceProfileUpdateMsg.getDefaultDashboardIdLSB()); |
|||
deviceProfile.setDefaultDashboardId(defaultDashboardUUID != null ? new DashboardId(defaultDashboardUUID) : null); |
|||
|
|||
String defaultQueueName = StringUtils.isNotBlank(deviceProfileUpdateMsg.getDefaultQueueName()) |
|||
? deviceProfileUpdateMsg.getDefaultQueueName() : null; |
|||
deviceProfile.setDefaultQueueName(defaultQueueName); |
|||
|
|||
UUID firmwareUUID = safeGetUUID(deviceProfileUpdateMsg.getFirmwareIdMSB(), deviceProfileUpdateMsg.getFirmwareIdLSB()); |
|||
deviceProfile.setFirmwareId(firmwareUUID != null ? new OtaPackageId(firmwareUUID) : null); |
|||
|
|||
UUID softwareUUID = safeGetUUID(deviceProfileUpdateMsg.getSoftwareIdMSB(), deviceProfileUpdateMsg.getSoftwareIdLSB()); |
|||
deviceProfile.setSoftwareId(softwareUUID != null ? new OtaPackageId(softwareUUID) : null); |
|||
|
|||
|
|||
deviceProfileValidator.validate(deviceProfile, DeviceProfile::getTenantId); |
|||
if (created) { |
|||
deviceProfile.setId(deviceProfileId); |
|||
} |
|||
deviceProfileService.saveDeviceProfile(deviceProfile, false); |
|||
} finally { |
|||
deviceCreationLock.unlock(); |
|||
} |
|||
return created; |
|||
} |
|||
} |
|||
@ -0,0 +1,76 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.edge.rpc.processor.entityview; |
|||
|
|||
import com.datastax.oss.driver.api.core.uuid.Uuids; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.util.Pair; |
|||
import org.thingsboard.common.util.JacksonUtil; |
|||
import org.thingsboard.server.common.data.EntityView; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
import org.thingsboard.server.common.data.id.AssetId; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EntityViewId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.gen.edge.v1.EdgeEntityType; |
|||
import org.thingsboard.server.gen.edge.v1.EntityViewUpdateMsg; |
|||
import org.thingsboard.server.service.edge.rpc.processor.BaseEdgeProcessor; |
|||
|
|||
import java.util.UUID; |
|||
|
|||
@Slf4j |
|||
public abstract class BaseEntityViewProcessor extends BaseEdgeProcessor { |
|||
|
|||
protected Pair<Boolean, Boolean> saveOrUpdateEntityView(TenantId tenantId, EntityViewId entityViewId, EntityViewUpdateMsg entityViewUpdateMsg, CustomerId customerId) { |
|||
boolean created = false; |
|||
boolean entityViewNameUpdated = false; |
|||
EntityView entityView = entityViewService.findEntityViewById(tenantId, entityViewId); |
|||
String entityViewName = entityViewUpdateMsg.getName(); |
|||
if (entityView == null) { |
|||
created = true; |
|||
entityView = new EntityView(); |
|||
entityView.setTenantId(tenantId); |
|||
entityView.setCreatedTime(Uuids.unixTimestamp(entityViewId.getId())); |
|||
} |
|||
EntityView entityViewByName = entityViewService.findEntityViewByTenantIdAndName(tenantId, entityViewName); |
|||
if (entityViewByName != null && !entityViewByName.getId().equals(entityViewId)) { |
|||
entityViewName = entityViewName + "_" + StringUtils.randomAlphanumeric(15); |
|||
log.warn("Entity view with name {} already exists. Renaming entity view name to {}", |
|||
entityViewUpdateMsg.getName(), entityViewName); |
|||
entityViewNameUpdated = true; |
|||
} |
|||
entityView.setName(entityViewName); |
|||
entityView.setType(entityViewUpdateMsg.getType()); |
|||
entityView.setCustomerId(customerId); |
|||
entityView.setAdditionalInfo(entityViewUpdateMsg.hasAdditionalInfo() ? |
|||
JacksonUtil.toJsonNode(entityViewUpdateMsg.getAdditionalInfo()) : null); |
|||
|
|||
UUID entityIdUUID = safeGetUUID(entityViewUpdateMsg.getEntityIdMSB(), entityViewUpdateMsg.getEntityIdLSB()); |
|||
if (EdgeEntityType.DEVICE.equals(entityViewUpdateMsg.getEntityType())) { |
|||
entityView.setEntityId(entityIdUUID != null ? new DeviceId(entityIdUUID) : null); |
|||
} else if (EdgeEntityType.ASSET.equals(entityViewUpdateMsg.getEntityType())) { |
|||
entityView.setEntityId(entityIdUUID != null ? new AssetId(entityIdUUID) : null); |
|||
} |
|||
|
|||
entityViewValidator.validate(entityView, EntityView::getTenantId); |
|||
if (created) { |
|||
entityView.setId(entityViewId); |
|||
} |
|||
entityViewService.saveEntityView(entityView, false); |
|||
return Pair.of(created, entityViewNameUpdated); |
|||
} |
|||
} |
|||
@ -0,0 +1,98 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.service.queue; |
|||
|
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.junit.jupiter.params.ParameterizedTest; |
|||
import org.junit.jupiter.params.provider.Arguments; |
|||
import org.junit.jupiter.params.provider.MethodSource; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.rule.RuleNode; |
|||
import org.thingsboard.server.common.msg.queue.RuleEngineException; |
|||
import org.thingsboard.server.common.msg.queue.RuleNodeException; |
|||
import org.thingsboard.server.common.msg.tools.TbRateLimitsException; |
|||
|
|||
import java.util.UUID; |
|||
import java.util.stream.Stream; |
|||
|
|||
import static org.mockito.ArgumentMatchers.any; |
|||
import static org.mockito.Mockito.mock; |
|||
import static org.mockito.Mockito.never; |
|||
import static org.mockito.Mockito.spy; |
|||
import static org.mockito.Mockito.verify; |
|||
|
|||
class TbMsgPackCallbackTest { |
|||
|
|||
TenantId tenantId; |
|||
UUID msgId; |
|||
TbMsgPackProcessingContext ctx; |
|||
TbMsgPackCallback callback; |
|||
|
|||
@BeforeEach |
|||
void setUp() { |
|||
tenantId = TenantId.fromUUID(UUID.randomUUID()); |
|||
msgId = UUID.randomUUID(); |
|||
ctx = mock(TbMsgPackProcessingContext.class); |
|||
callback = spy(new TbMsgPackCallback(msgId, tenantId, ctx)); |
|||
} |
|||
|
|||
private static Stream<Arguments> testOnFailure_NotRateLimitException() { |
|||
return Stream.of( |
|||
Arguments.of(new RuleEngineException("rule engine no cause")), |
|||
Arguments.of(new RuleEngineException("rule engine caused 1 lvl", new RuntimeException())), |
|||
Arguments.of(new RuleEngineException("rule engine caused 2 lvl", new RuntimeException(new Exception()))), |
|||
Arguments.of(new RuleEngineException("rule engine caused 2 lvl Throwable", new RuntimeException(new Throwable()))), |
|||
Arguments.of(new RuleNodeException("rule node no cause", "RuleChain", new RuleNode())) |
|||
); |
|||
} |
|||
|
|||
@ParameterizedTest |
|||
@MethodSource |
|||
void testOnFailure_NotRateLimitException(RuleEngineException ree) { |
|||
callback.onFailure(ree); |
|||
|
|||
verify(callback, never()).onRateLimit(any()); |
|||
verify(callback, never()).onSuccess(); |
|||
verify(ctx, never()).onSuccess(any()); |
|||
} |
|||
|
|||
private static Stream<Arguments> testOnFailure_RateLimitException() { |
|||
return Stream.of( |
|||
Arguments.of(new RuleEngineException("caused lvl 1", new TbRateLimitsException(EntityType.ASSET))), |
|||
Arguments.of(new RuleEngineException("caused lvl 2", new RuntimeException(new TbRateLimitsException(EntityType.ASSET)))), |
|||
Arguments.of( |
|||
new RuleEngineException("caused lvl 3", |
|||
new RuntimeException( |
|||
new Exception( |
|||
new TbRateLimitsException(EntityType.ASSET))))) |
|||
); |
|||
} |
|||
|
|||
@ParameterizedTest |
|||
@MethodSource |
|||
void testOnFailure_RateLimitException(RuleEngineException ree) { |
|||
callback.onFailure(ree); |
|||
|
|||
verify(callback).onRateLimit(any()); |
|||
verify(callback).onFailure(any()); |
|||
verify(callback, never()).onSuccess(); |
|||
verify(ctx).onSuccess(msgId); |
|||
verify(ctx).onSuccess(any()); |
|||
verify(ctx, never()).onFailure(any(), any(), any()); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
/** |
|||
* Copyright © 2016-2023 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.exception; |
|||
|
|||
public abstract class AbstractRateLimitException extends RuntimeException { |
|||
|
|||
public AbstractRateLimitException() { |
|||
super(); |
|||
} |
|||
|
|||
public AbstractRateLimitException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
public AbstractRateLimitException(String message, Throwable cause) { |
|||
super(message, cause); |
|||
} |
|||
|
|||
public AbstractRateLimitException(Throwable cause) { |
|||
super(cause); |
|||
} |
|||
|
|||
protected AbstractRateLimitException(String message, Throwable cause, |
|||
boolean enableSuppression, |
|||
boolean writableStackTrace) { |
|||
super(message, cause, enableSuppression, writableStackTrace); |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
/** |
|||
* Copyright © 2016-2023 The Thingsboard Authors |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|||
* you may not use this file except in compliance with the License. |
|||
* You may obtain a copy of the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, |
|||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
* See the License for the specific language governing permissions and |
|||
* limitations under the License. |
|||
*/ |
|||
package org.thingsboard.server.common.data.notification.settings; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonCreator; |
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.fasterxml.jackson.annotation.JsonProperty; |
|||
import lombok.Data; |
|||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod; |
|||
import org.thingsboard.server.common.data.notification.NotificationType; |
|||
import org.thingsboard.server.common.data.notification.targets.NotificationTargetType; |
|||
|
|||
import javax.validation.Valid; |
|||
import javax.validation.constraints.AssertTrue; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.util.Collections; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Data |
|||
public class UserNotificationSettings { |
|||
|
|||
@NotNull |
|||
@Valid |
|||
private final Map<NotificationType, NotificationPref> prefs; |
|||
|
|||
public static final UserNotificationSettings DEFAULT = new UserNotificationSettings(Collections.emptyMap()); |
|||
|
|||
public static final Set<NotificationDeliveryMethod> deliveryMethods = NotificationTargetType.PLATFORM_USERS.getSupportedDeliveryMethods(); |
|||
|
|||
@JsonCreator |
|||
public UserNotificationSettings(@JsonProperty("prefs") Map<NotificationType, NotificationPref> prefs) { |
|||
this.prefs = prefs; |
|||
} |
|||
|
|||
public boolean isEnabled(NotificationType notificationType, NotificationDeliveryMethod deliveryMethod) { |
|||
NotificationPref pref = prefs.get(notificationType); |
|||
if (pref == null) { |
|||
return true; |
|||
} |
|||
if (!pref.isEnabled()) { |
|||
return false; |
|||
} |
|||
return pref.getEnabledDeliveryMethods().getOrDefault(deliveryMethod, true); |
|||
} |
|||
|
|||
@Data |
|||
public static class NotificationPref { |
|||
private boolean enabled; |
|||
@NotNull |
|||
private Map<NotificationDeliveryMethod, Boolean> enabledDeliveryMethods; |
|||
|
|||
public static NotificationPref createDefault() { |
|||
NotificationPref pref = new NotificationPref(); |
|||
pref.setEnabled(true); |
|||
pref.setEnabledDeliveryMethods(deliveryMethods.stream().collect(Collectors.toMap(v -> v, v -> true))); |
|||
return pref; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@AssertTrue(message = "Only email, Web and SMS delivery methods are allowed") |
|||
public boolean isValid() { |
|||
return enabledDeliveryMethods.entrySet().stream() |
|||
.allMatch(entry -> deliveryMethods.contains(entry.getKey()) && entry.getValue() != null); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,54 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.queue.kafka; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.kafka.common.header.Header; |
|||
import org.junit.jupiter.api.BeforeEach; |
|||
import org.junit.jupiter.api.Test; |
|||
import org.thingsboard.server.queue.TbQueueMsg; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
import static org.mockito.ArgumentMatchers.any; |
|||
import static org.mockito.BDDMockito.willCallRealMethod; |
|||
import static org.mockito.BDDMockito.willReturn; |
|||
import static org.mockito.Mockito.mock; |
|||
|
|||
@Slf4j |
|||
class TbKafkaProducerTemplateTest { |
|||
|
|||
TbKafkaProducerTemplate<TbQueueMsg> producerTemplate; |
|||
|
|||
@BeforeEach |
|||
void setUp() { |
|||
producerTemplate = mock(TbKafkaProducerTemplate.class); |
|||
willCallRealMethod().given(producerTemplate).addAnalyticHeaders(any()); |
|||
willReturn("tb-core-to-core-notifications-tb-core-3").given(producerTemplate).getClientId(); |
|||
} |
|||
|
|||
@Test |
|||
void testAddAnalyticHeaders() { |
|||
List<Header> headers = new ArrayList<>(); |
|||
producerTemplate.addAnalyticHeaders(headers); |
|||
assertThat(headers).isNotEmpty(); |
|||
headers.forEach(r -> log.info("RecordHeader key [{}] value [{}]", r.key(), new String(r.value(), StandardCharsets.UTF_8))); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
|
|||
<configuration> |
|||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>%d{ISO8601} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<!-- TbKafkaProducerTemplate will add headers for each message when log level: |
|||
- DEBUG - producerId and thread name |
|||
- TRACE - will add stacktrace. |
|||
Kafka compression is highly recommended --> |
|||
<logger name="org.thingsboard.server.queue.kafka.TbKafkaProducerTemplate" level="TRACE"/> |
|||
|
|||
<root level="INFO"> |
|||
<appender-ref ref="console"/> |
|||
</root> |
|||
|
|||
</configuration> |
|||
@ -0,0 +1,161 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.coap; |
|||
|
|||
import org.eclipse.californium.core.coap.CoAP; |
|||
import org.eclipse.californium.core.coap.OptionSet; |
|||
import org.eclipse.californium.core.coap.Request; |
|||
import org.junit.jupiter.api.BeforeAll; |
|||
import org.junit.jupiter.params.ParameterizedTest; |
|||
import org.junit.jupiter.params.provider.Arguments; |
|||
import org.junit.jupiter.params.provider.MethodSource; |
|||
import org.thingsboard.server.coapserver.CoapServerService; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
import org.thingsboard.server.common.msg.session.FeatureType; |
|||
import org.thingsboard.server.common.transport.TransportService; |
|||
import org.thingsboard.server.queue.scheduler.SchedulerComponent; |
|||
import org.thingsboard.server.transport.coap.client.CoapClientContext; |
|||
|
|||
import java.util.Random; |
|||
import java.util.stream.Stream; |
|||
|
|||
import static org.junit.jupiter.api.Assertions.assertEquals; |
|||
import static org.junit.jupiter.api.Assertions.assertTrue; |
|||
import static org.mockito.Mockito.mock; |
|||
import static org.mockito.Mockito.when; |
|||
|
|||
class CoapTransportResourceTest { |
|||
|
|||
private static final String V1 = "v1"; |
|||
private static final String API = "api"; |
|||
private static final String TELEMETRY = "telemetry"; |
|||
private static final String ATTRIBUTES = "attributes"; |
|||
private static final String RPC = "rpc"; |
|||
private static final String CLAIM = "claim"; |
|||
private static final String PROVISION = "provision"; |
|||
private static final String GET_ATTRIBUTES_URI_QUERY = "clientKeys=attribute1,attribute2&sharedKeys=shared1,shared2"; |
|||
|
|||
private static final Random RANDOM = new Random(); |
|||
|
|||
private static CoapTransportResource coapTransportResource; |
|||
|
|||
@BeforeAll |
|||
static void setUp() { |
|||
|
|||
var ctxMock = mock(CoapTransportContext.class); |
|||
var coapServerServiceMock = mock(CoapServerService.class); |
|||
var transportServiceMock = mock(TransportService.class); |
|||
var clientContextMock = mock(CoapClientContext.class); |
|||
var schedulerComponentMock = mock(SchedulerComponent.class); |
|||
|
|||
when(ctxMock.getTransportService()).thenReturn(transportServiceMock); |
|||
when(ctxMock.getClientContext()).thenReturn(clientContextMock); |
|||
when(ctxMock.getSessionReportTimeout()).thenReturn(1L); |
|||
when(ctxMock.getScheduler()).thenReturn(schedulerComponentMock); |
|||
|
|||
coapTransportResource = new CoapTransportResource(ctxMock, coapServerServiceMock, V1); |
|||
} |
|||
|
|||
@ParameterizedTest |
|||
@MethodSource("provideRequestAndFeatureType") |
|||
void givenRequest_whenGetFeatureType_thenReturnedExpectedFeatureType(Request request, FeatureType expectedFeatureType) { |
|||
var featureTypeOptional = coapTransportResource.getFeatureType(request); |
|||
|
|||
assertTrue(featureTypeOptional.isPresent(), "Optional<FeatureType> is empty"); |
|||
assertEquals(expectedFeatureType, featureTypeOptional.get(), "Feature type is invalid"); |
|||
} |
|||
|
|||
static Stream<Arguments> provideRequestAndFeatureType() { |
|||
return Stream.of( |
|||
// accessToken based tests
|
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), |
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toGetAttributesAccessTokenRequest(), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.GET, RPC), FeatureType.RPC), |
|||
Arguments.of(toRpcResponseAccessTokenRequest(), FeatureType.RPC), |
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.POST, RPC), FeatureType.RPC), |
|||
Arguments.of(toAccessTokenRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), |
|||
// certificate based tests
|
|||
Arguments.of(toCertificateRequest(CoAP.Code.POST, TELEMETRY), FeatureType.TELEMETRY), |
|||
Arguments.of(toCertificateRequest(CoAP.Code.POST, ATTRIBUTES), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toGetAttributesCertificateRequest(), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toCertificateRequest(CoAP.Code.GET, ATTRIBUTES), FeatureType.ATTRIBUTES), |
|||
Arguments.of(toCertificateRequest(CoAP.Code.GET, RPC), FeatureType.RPC), |
|||
Arguments.of(toRpcResponseCertificateRequest(), FeatureType.RPC), |
|||
Arguments.of(toCertificateRequest(CoAP.Code.POST, RPC), FeatureType.RPC), |
|||
Arguments.of(toCertificateRequest(CoAP.Code.POST, CLAIM), FeatureType.CLAIM), |
|||
// provision request
|
|||
Arguments.of(toProvisionRequest(), FeatureType.PROVISION) |
|||
); |
|||
} |
|||
|
|||
private static Request toAccessTokenRequest(CoAP.Code method, String featureType) { |
|||
return getAccessTokenRequest(method, featureType, null, null); |
|||
} |
|||
|
|||
private static Request toGetAttributesAccessTokenRequest() { |
|||
return getAccessTokenRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); |
|||
} |
|||
|
|||
private static Request toRpcResponseAccessTokenRequest() { |
|||
return getAccessTokenRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); |
|||
} |
|||
|
|||
private static Request toCertificateRequest(CoAP.Code method, String featureType) { |
|||
return getCertificateRequest(method, featureType, null, null); |
|||
} |
|||
|
|||
private static Request toGetAttributesCertificateRequest() { |
|||
return getCertificateRequest(CoAP.Code.GET, CoapTransportResourceTest.ATTRIBUTES, null, CoapTransportResourceTest.GET_ATTRIBUTES_URI_QUERY); |
|||
} |
|||
|
|||
private static Request toRpcResponseCertificateRequest() { |
|||
return getCertificateRequest(CoAP.Code.POST, CoapTransportResourceTest.RPC, RANDOM.nextInt(100), null); |
|||
} |
|||
|
|||
private static Request getAccessTokenRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { |
|||
return getRequest(method, featureType, false, requestId, uriQuery); |
|||
} |
|||
|
|||
private static Request getCertificateRequest(CoAP.Code method, String featureType, Integer requestId, String uriQuery) { |
|||
return getRequest(method, featureType, true, requestId, uriQuery); |
|||
} |
|||
|
|||
private static Request toProvisionRequest() { |
|||
return getRequest(CoAP.Code.POST, PROVISION, true, null, null); |
|||
} |
|||
|
|||
private static Request getRequest(CoAP.Code method, String featureType, boolean dtls, Integer requestId, String uriQuery) { |
|||
var request = new Request(method); |
|||
var options = new OptionSet(); |
|||
options.addUriPath(API); |
|||
options.addUriPath(V1); |
|||
if (!dtls) { |
|||
options.addUriPath(StringUtils.randomAlphanumeric(20)); |
|||
} |
|||
options.addUriPath(featureType); |
|||
if (requestId != null) { |
|||
options.addUriPath(String.valueOf(requestId)); |
|||
} |
|||
if (uriQuery != null) { |
|||
options.setUriQuery(uriQuery); |
|||
} |
|||
request.setOptions(options); |
|||
return request; |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.common.util; |
|||
|
|||
import com.google.gson.JsonParseException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.thingsboard.server.common.data.StringUtils; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
|
|||
import javax.script.ScriptException; |
|||
import java.io.PrintWriter; |
|||
import java.io.StringWriter; |
|||
|
|||
@Slf4j |
|||
public class ExceptionUtil { |
|||
|
|||
@SuppressWarnings("unchecked") |
|||
public static <T extends Exception> T lookupException(Throwable source, Class<T> clazz) { |
|||
Exception e = lookupExceptionInCause(source, clazz); |
|||
if (e != null) { |
|||
return (T) e; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public static Exception lookupExceptionInCause(Throwable source, Class<? extends Exception>... clazzes) { |
|||
while (source != null) { |
|||
for (Class<? extends Exception> clazz : clazzes) { |
|||
if (clazz.isAssignableFrom(source.getClass())) { |
|||
return (Exception) source; |
|||
} |
|||
} |
|||
source = source.getCause(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public static String toString(Exception e, EntityId componentId, boolean stackTraceEnabled) { |
|||
Exception exception = lookupExceptionInCause(e, ScriptException.class, JsonParseException.class); |
|||
if (exception != null && StringUtils.isNotEmpty(exception.getMessage())) { |
|||
return exception.getMessage(); |
|||
} else { |
|||
if (stackTraceEnabled) { |
|||
StringWriter sw = new StringWriter(); |
|||
e.printStackTrace(new PrintWriter(sw)); |
|||
return sw.toString(); |
|||
} else { |
|||
log.debug("[{}] Unknown error during message processing", componentId, e); |
|||
return "Please contact system administrator"; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
/** |
|||
* Copyright © 2016-2023 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.common.util; |
|||
|
|||
import org.junit.jupiter.api.Test; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
import static org.assertj.core.api.Assertions.assertThat; |
|||
|
|||
class ExceptionUtilTest { |
|||
|
|||
final Exception cause = new RuntimeException(); |
|||
|
|||
@Test |
|||
void givenRootCause_whenLookupExceptionInCause_thenReturnRootCauseAndNoStackOverflow() { |
|||
Exception e = cause; |
|||
for (int i = 0; i <= 16384; i++) { |
|||
e = new Exception(e); |
|||
} |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(e, RuntimeException.class)).isSameAs(cause); |
|||
} |
|||
|
|||
@Test |
|||
void givenCause_whenLookupExceptionInCause_thenReturnCause() { |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(cause), RuntimeException.class)).isSameAs(cause); |
|||
} |
|||
|
|||
@Test |
|||
void givenNoCauseAndExceptionIsWantedCauseClass_whenLookupExceptionInCause_thenReturnSelf() { |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(cause, RuntimeException.class)).isSameAs(cause); |
|||
} |
|||
|
|||
@Test |
|||
void givenNoCause_whenLookupExceptionInCause_thenReturnNull() { |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(), RuntimeException.class)).isNull(); |
|||
} |
|||
|
|||
@Test |
|||
void givenNotWantedCause_whenLookupExceptionInCause_thenReturnNull() { |
|||
final Exception cause = new IOException(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(cause), RuntimeException.class)).isNull(); |
|||
} |
|||
|
|||
@Test |
|||
void givenCause_whenLookupExceptionInCauseByMany_thenReturnFirstCause() { |
|||
final Exception causeIAE = new IllegalAccessException(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE))).isNull(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IOException.class, NoSuchFieldException.class)).isNull(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IllegalAccessException.class, IOException.class, NoSuchFieldException.class)).isSameAs(causeIAE); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), IOException.class, NoSuchFieldException.class, IllegalAccessException.class)).isSameAs(causeIAE); |
|||
|
|||
final Exception causeIOE = new IOException(causeIAE); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE))).isNull(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIAE), ClassNotFoundException.class, NoSuchFieldException.class)).isNull(); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IOException.class, NoSuchFieldException.class)).isSameAs(causeIOE); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IllegalAccessException.class, IOException.class, NoSuchFieldException.class)).isSameAs(causeIOE); |
|||
assertThat(ExceptionUtil.lookupExceptionInCause(new Exception(causeIOE), IOException.class, NoSuchFieldException.class, IllegalAccessException.class)).isSameAs(causeIOE); |
|||
} |
|||
|
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue