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