diff --git a/application/pom.xml b/application/pom.xml
index 1b89752925..98a65bc5bb 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -249,6 +249,10 @@
io.grpc
grpc-stub
+
+ org.opensmpp
+ opensmpp-core
+
org.thingsboard
springfox-boot-starter
diff --git a/application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json b/application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json
index a065279cce..88f8232328 100644
--- a/application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json
+++ b/application/src/main/data/json/tenant/edge_management/rule_chains/edge_root_rule_chain.json
@@ -156,6 +156,21 @@
"toIndex": 7,
"type": "Attributes Updated"
},
+ {
+ "fromIndex": 3,
+ "toIndex": 7,
+ "type": "Attributes Deleted"
+ },
+ {
+ "fromIndex": 3,
+ "toIndex": 7,
+ "type": "Timeseries Deleted"
+ },
+ {
+ "fromIndex": 3,
+ "toIndex": 7,
+ "type": "Timeseries Updated"
+ },
{
"fromIndex": 4,
"toIndex": 7,
diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
index 95125b331a..0b28aca7b0 100644
--- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java
@@ -35,6 +35,7 @@ import org.thingsboard.server.actors.TbActorCtx;
import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.StringUtils;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -97,7 +98,6 @@ import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
@@ -107,6 +107,7 @@ import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
+import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -200,8 +201,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
boolean sent = false;
if (systemContext.isEdgesEnabled() && edgeId != null) {
log.debug("[{}][{}] device is related to edge [{}]. Saving RPC request to edge queue", tenantId, deviceId, edgeId.getId());
- saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId());
- sent = true;
+ try {
+ saveRpcRequestToEdgeQueue(request, rpcRequest.getRequestId()).get();
+ sent = true;
+ } catch (InterruptedException | ExecutionException e) {
+ String errMsg = String.format("[%s][%s][%s] Failed to save rpc request to edge queue %s", tenantId, deviceId, edgeId.getId(), request);
+ log.error(errMsg, e);
+ }
} else if (isSendNewRpcAvailable()) {
sent = rpcSubscriptions.size() > 0;
Set syncSessionSet = new HashSet<>();
@@ -810,13 +816,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
systemContext.getTbCoreToTransportService().process(nodeId, msg);
}
- private void saveRpcRequestToEdgeQueue(ToDeviceRpcRequest msg, Integer requestId) {
- EdgeEvent edgeEvent = new EdgeEvent();
- edgeEvent.setTenantId(tenantId);
- edgeEvent.setAction(EdgeEventActionType.RPC_CALL);
- edgeEvent.setEntityId(deviceId.getId());
- edgeEvent.setType(EdgeEventType.DEVICE);
-
+ private ListenableFuture saveRpcRequestToEdgeQueue(ToDeviceRpcRequest msg, Integer requestId) {
ObjectNode body = mapper.createObjectNode();
body.put("requestId", requestId);
body.put("requestUUID", msg.getId().toString());
@@ -824,11 +824,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor {
body.put("expirationTime", msg.getExpirationTime());
body.put("method", msg.getBody().getMethod());
body.put("params", msg.getBody().getParams());
- edgeEvent.setBody(body);
- edgeEvent.setEdgeId(edgeId);
- systemContext.getEdgeEventService().save(edgeEvent);
- systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId);
+ EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, EdgeEventType.DEVICE, EdgeEventActionType.RPC_CALL, deviceId, body);
+
+ return Futures.transform(systemContext.getEdgeEventService().saveAsync(edgeEvent), unused -> {
+ systemContext.getClusterService().onEdgeEventUpdate(tenantId, edgeId);
+ return null;
+ }, systemContext.getDbCallbackExecutor());
}
private List toTsKvProtos(@Nullable List result) {
diff --git a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
index e71b881477..b6ba0088bb 100644
--- a/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/SwaggerConfiguration.java
@@ -22,6 +22,7 @@ import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
@@ -84,6 +85,7 @@ import static springfox.documentation.builders.PathSelectors.regex;
@Slf4j
@Configuration
@TbCoreComponent
+@Profile("!test")
public class SwaggerConfiguration {
@Value("${swagger.api_path_regex}")
diff --git a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
index 90703481cd..3e9597a72d 100644
--- a/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/ThingsboardSecurityConfiguration.java
@@ -176,16 +176,16 @@ public class ThingsboardSecurityConfiguration extends WebSecurityConfigurerAdapt
return new BCryptPasswordEncoder();
}
- @Override
- public void configure(WebSecurity web) throws Exception {
- web.ignoring().antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**");
- }
-
@Autowired
private OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver;
@Override
protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeHttpRequests((authorizeHttpRequests) ->
+ authorizeHttpRequests
+ .antMatchers("/*.js","/*.css","/*.ico","/assets/**","/static/**")
+ .permitAll()
+ );
http.headers().cacheControl().and().frameOptions().disable()
.and()
.cors()
diff --git a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
index 664e6c3181..13b13123e6 100644
--- a/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
+++ b/application/src/main/java/org/thingsboard/server/config/WebSocketConfiguration.java
@@ -55,7 +55,7 @@ public class WebSocketConfiguration implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
- registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOrigins("*")
+ registry.addHandler(wsHandler(), WS_PLUGIN_MAPPING).setAllowedOriginPatterns("*")
.addInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() {
@Override
diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
index bdeec8d0ae..939e9da8a0 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.controller;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
+import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
@@ -29,29 +30,24 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
-import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.alarm.Alarm;
import org.thingsboard.server.common.data.alarm.AlarmInfo;
import org.thingsboard.server.common.data.alarm.AlarmQuery;
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
import org.thingsboard.server.common.data.alarm.AlarmStatus;
-import org.thingsboard.server.common.data.audit.ActionType;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AlarmId;
-import org.thingsboard.server.common.data.id.EdgeId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.alarm.TbAlarmService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
-import java.util.List;
-
import static org.thingsboard.server.controller.ControllerConstants.ALARM_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.ALARM_SORT_PROPERTY_ALLOWABLE_VALUES;
@@ -70,9 +66,12 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@RestController
@TbCoreComponent
+@RequiredArgsConstructor
@RequestMapping("/api")
public class AlarmController extends BaseController {
+ private final TbAlarmService tbAlarmService;
+
public static final String ALARM_ID = "alarmId";
private static final String ALARM_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the originator of alarm is owned by the same tenant. " +
"If the user has the authority of 'Customer User', the server checks that the originator of alarm belongs to the customer. ";
@@ -133,24 +132,9 @@ public class AlarmController extends BaseController {
@RequestMapping(value = "/alarm", method = RequestMethod.POST)
@ResponseBody
public Alarm saveAlarm(@ApiParam(value = "A JSON value representing the alarm.") @RequestBody Alarm alarm) throws ThingsboardException {
- try {
- alarm.setTenantId(getCurrentUser().getTenantId());
-
- checkEntity(alarm.getId(), alarm, Resource.ALARM);
-
- Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm));
- logEntityAction(savedAlarm.getOriginator(), savedAlarm,
- getCurrentUser().getCustomerId(),
- alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
-
- sendEntityNotificationMsg(getTenantId(), savedAlarm.getId(), alarm.getId() == null ? EdgeEventActionType.ADDED : EdgeEventActionType.UPDATED);
-
- return savedAlarm;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.ALARM), alarm,
- null, alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
- throw handleException(e);
- }
+ alarm.setTenantId(getCurrentUser().getTenantId());
+ checkEntity(alarm.getId(), alarm, Resource.ALARM);
+ return tbAlarmService.save(alarm, getCurrentUser());
}
@ApiOperation(value = "Delete Alarm (deleteAlarm)",
@@ -163,16 +147,7 @@ public class AlarmController extends BaseController {
try {
AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
-
- List relatedEdgeIds = findRelatedEdgeIds(getTenantId(), alarm.getOriginator());
-
- logEntityAction(alarm.getOriginator(), alarm,
- getCurrentUser().getCustomerId(),
- ActionType.ALARM_DELETE, null);
-
- sendAlarmDeleteNotificationMsg(getTenantId(), alarmId, relatedEdgeIds, alarm);
-
- return alarmService.deleteAlarm(getTenantId(), alarmId);
+ return tbAlarmService.delete(alarm, getCurrentUser());
} catch (Exception e) {
throw handleException(e);
}
@@ -187,19 +162,9 @@ public class AlarmController extends BaseController {
@ResponseStatus(value = HttpStatus.OK)
public void ackAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
- try {
- AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
- Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
- long ackTs = System.currentTimeMillis();
- alarmService.ackAlarm(getCurrentUser().getTenantId(), alarmId, ackTs).get();
- alarm.setAckTs(ackTs);
- alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK);
- logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null);
-
- sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.ALARM_ACK);
- } catch (Exception e) {
- throw handleException(e);
- }
+ AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
+ Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
+ tbAlarmService.ack(alarm, getCurrentUser());
}
@ApiOperation(value = "Clear Alarm (clearAlarm)",
@@ -211,19 +176,9 @@ public class AlarmController extends BaseController {
@ResponseStatus(value = HttpStatus.OK)
public void clearAlarm(@ApiParam(value = ALARM_ID_PARAM_DESCRIPTION) @PathVariable(ALARM_ID) String strAlarmId) throws ThingsboardException {
checkParameter(ALARM_ID, strAlarmId);
- try {
- AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
- Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
- long clearTs = System.currentTimeMillis();
- alarmService.clearAlarm(getCurrentUser().getTenantId(), alarmId, null, clearTs).get();
- alarm.setClearTs(clearTs);
- alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK);
- logEntityAction(alarm.getOriginator(), alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null);
-
- sendEntityNotificationMsg(getTenantId(), alarmId, EdgeEventActionType.ALARM_CLEAR);
- } catch (Exception e) {
- throw handleException(e);
- }
+ AlarmId alarmId = new AlarmId(toUUID(strAlarmId));
+ Alarm alarm = checkAlarmId(alarmId, Operation.WRITE);
+ tbAlarmService.clear(alarm, getCurrentUser());
}
@ApiOperation(value = "Get Alarms (getAlarms)",
@@ -276,6 +231,7 @@ public class AlarmController extends BaseController {
throw handleException(e);
}
}
+
@ApiOperation(value = "Get All Alarms (getAllAlarms)",
notes = "Returns a page of alarms that belongs to the current user owner. " +
"If the user has the authority of 'Tenant Administrator', the server returns alarms that belongs to the tenant of current user. " +
diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index 7bd9cb065d..4718feb774 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -34,13 +34,10 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype;
-import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo;
import org.thingsboard.server.common.data.asset.AssetSearchQuery;
-import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.AssetId;
@@ -54,6 +51,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.asset.AssetBulkImportService;
+import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -95,6 +93,7 @@ import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE
@Slf4j
public class AssetController extends BaseController {
private final AssetBulkImportService assetBulkImportService;
+ private final TbAssetService tbAssetService;
public static final String ASSET_ID = "assetId";
@@ -145,39 +144,12 @@ public class AssetController extends BaseController {
@RequestMapping(value = "/asset", method = RequestMethod.POST)
@ResponseBody
public Asset saveAsset(@ApiParam(value = "A JSON value representing the asset.") @RequestBody Asset asset) throws ThingsboardException {
- try {
- if (TB_SERVICE_QUEUE.equals(asset.getType())) {
- throw new ThingsboardException("Unable to save asset with type " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
- }
-
- asset.setTenantId(getCurrentUser().getTenantId());
-
- checkEntity(asset.getId(), asset, Resource.ASSET);
-
- Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
-
- onAssetCreatedOrUpdated(savedAsset, asset.getId() != null, getCurrentUser());
-
- return savedAsset;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.ASSET), asset,
- null, asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
- throw handleException(e);
- }
- }
-
- private void onAssetCreatedOrUpdated(Asset asset, boolean updated, SecurityUser user) {
- try {
- logEntityAction(user, asset.getId(), asset,
- asset.getCustomerId(),
- updated ? ActionType.UPDATED : ActionType.ADDED, null);
- } catch (ThingsboardException e) {
- log.error("Failed to log entity action", e);
- }
-
- if (updated) {
- sendEntityNotificationMsg(asset.getTenantId(), asset.getId(), EdgeEventActionType.UPDATED);
+ if (TB_SERVICE_QUEUE.equals(asset.getType())) {
+ throw new ThingsboardException("Unable to save asset with type " + TB_SERVICE_QUEUE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
+ asset.setTenantId(getCurrentUser().getTenantId());
+ checkEntity(asset.getId(), asset, Resource.ASSET);
+ return tbAssetService.save(asset, getCurrentUser());
}
@ApiOperation(value = "Delete asset (deleteAsset)",
@@ -190,21 +162,8 @@ public class AssetController extends BaseController {
try {
AssetId assetId = new AssetId(toUUID(strAssetId));
Asset asset = checkAssetId(assetId, Operation.DELETE);
-
- List relatedEdgeIds = findRelatedEdgeIds(getTenantId(), assetId);
-
- assetService.deleteAsset(getTenantId(), assetId);
-
- logEntityAction(assetId, asset,
- asset.getCustomerId(),
- ActionType.DELETED, null, strAssetId);
-
- sendDeleteNotificationMsg(getTenantId(), assetId, relatedEdgeIds);
+ tbAssetService.delete(asset, getCurrentUser()).get();
} catch (Exception e) {
- logEntityAction(emptyId(EntityType.ASSET),
- null,
- null,
- ActionType.DELETED, e, strAssetId);
throw handleException(e);
}
}
@@ -218,31 +177,11 @@ public class AssetController extends BaseController {
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(ASSET_ID, strAssetId);
- try {
- CustomerId customerId = new CustomerId(toUUID(strCustomerId));
- Customer customer = checkCustomerId(customerId, Operation.READ);
-
- AssetId assetId = new AssetId(toUUID(strAssetId));
- checkAssetId(assetId, Operation.ASSIGN_TO_CUSTOMER);
-
- Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(getTenantId(), assetId, customerId));
-
- logEntityAction(assetId, savedAsset,
- savedAsset.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, strCustomerId, customer.getName());
-
- sendEntityAssignToCustomerNotificationMsg(savedAsset.getTenantId(), savedAsset.getId(),
- customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER);
-
- return savedAsset;
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.ASSET), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strAssetId, strCustomerId);
-
- throw handleException(e);
- }
+ CustomerId customerId = new CustomerId(toUUID(strCustomerId));
+ Customer customer = checkCustomerId(customerId, Operation.READ);
+ AssetId assetId = new AssetId(toUUID(strAssetId));
+ checkAssetId(assetId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbAssetService.assignAssetToCustomer(getTenantId(), assetId, customer, getCurrentUser());
}
@ApiOperation(value = "Unassign asset from customer (unassignAssetFromCustomer)",
@@ -252,33 +191,13 @@ public class AssetController extends BaseController {
@ResponseBody
public Asset unassignAssetFromCustomer(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
- try {
- AssetId assetId = new AssetId(toUUID(strAssetId));
- Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_CUSTOMER);
- if (asset.getCustomerId() == null || asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
- throw new IncorrectParameterException("Asset isn't assigned to any customer!");
- }
-
- Customer customer = checkCustomerId(asset.getCustomerId(), Operation.READ);
-
- Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(getTenantId(), assetId));
-
- logEntityAction(assetId, asset,
- asset.getCustomerId(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, null, strAssetId, customer.getId().toString(), customer.getName());
-
- sendEntityAssignToCustomerNotificationMsg(savedAsset.getTenantId(), savedAsset.getId(),
- customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER);
-
- return savedAsset;
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.ASSET), null,
- null,
- ActionType.UNASSIGNED_FROM_CUSTOMER, e, strAssetId);
-
- throw handleException(e);
+ AssetId assetId = new AssetId(toUUID(strAssetId));
+ Asset asset = checkAssetId(assetId, Operation.UNASSIGN_FROM_CUSTOMER);
+ if (asset.getCustomerId() == null || asset.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
+ throw new IncorrectParameterException("Asset isn't assigned to any customer!");
}
+ Customer customer = checkCustomerId(asset.getCustomerId(), Operation.READ);
+ return tbAssetService.unassignAssetToCustomer(getTenantId(), assetId, customer, getCurrentUser());
}
@ApiOperation(value = "Make asset publicly available (assignAssetToPublicCustomer)",
@@ -290,25 +209,9 @@ public class AssetController extends BaseController {
@ResponseBody
public Asset assignAssetToPublicCustomer(@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(ASSET_ID, strAssetId);
- try {
- AssetId assetId = new AssetId(toUUID(strAssetId));
- Asset asset = checkAssetId(assetId, Operation.ASSIGN_TO_CUSTOMER);
- Customer publicCustomer = customerService.findOrCreatePublicCustomer(asset.getTenantId());
- Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(getTenantId(), assetId, publicCustomer.getId()));
-
- logEntityAction(assetId, savedAsset,
- savedAsset.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strAssetId, publicCustomer.getId().toString(), publicCustomer.getName());
-
- return savedAsset;
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.ASSET), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strAssetId);
-
- throw handleException(e);
- }
+ AssetId assetId = new AssetId(toUUID(strAssetId));
+ checkAssetId(assetId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbAssetService.assignAssetToPublicCustomer(getTenantId(), assetId, getCurrentUser());
}
@ApiOperation(value = "Get Tenant Assets (getTenantAssets)",
@@ -553,30 +456,14 @@ public class AssetController extends BaseController {
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(ASSET_ID, strAssetId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.READ);
- AssetId assetId = new AssetId(toUUID(strAssetId));
- checkAssetId(assetId, Operation.READ);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.READ);
- Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(getTenantId(), assetId, edgeId));
+ AssetId assetId = new AssetId(toUUID(strAssetId));
+ checkAssetId(assetId, Operation.READ);
- logEntityAction(assetId, savedAsset,
- savedAsset.getCustomerId(),
- ActionType.ASSIGNED_TO_EDGE, null, strAssetId, strEdgeId, edge.getName());
-
- sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedAsset.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE);
-
- return savedAsset;
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.ASSET), null,
- null,
- ActionType.ASSIGNED_TO_EDGE, e, strAssetId, strEdgeId);
-
- throw handleException(e);
- }
+ return tbAssetService.assignAssetToEdge(getTenantId(), assetId, edge, getCurrentUser());
}
@ApiOperation(value = "Unassign asset from edge (unassignAssetFromEdge)",
@@ -593,30 +480,13 @@ public class AssetController extends BaseController {
@ApiParam(value = ASSET_ID_PARAM_DESCRIPTION) @PathVariable(ASSET_ID) String strAssetId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(ASSET_ID, strAssetId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.READ);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.READ);
- AssetId assetId = new AssetId(toUUID(strAssetId));
- Asset asset = checkAssetId(assetId, Operation.READ);
-
- Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(getTenantId(), assetId, edgeId));
-
- logEntityAction(assetId, asset,
- asset.getCustomerId(),
- ActionType.UNASSIGNED_FROM_EDGE, null, strAssetId, strEdgeId, edge.getName());
+ AssetId assetId = new AssetId(toUUID(strAssetId));
+ Asset asset = checkAssetId(assetId, Operation.READ);
- sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedAsset.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE);
-
- return savedAsset;
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.ASSET), null,
- null,
- ActionType.UNASSIGNED_FROM_EDGE, e, strAssetId, strEdgeId);
-
- throw handleException(e);
- }
+ return tbAssetService.unassignAssetFromEdge(getTenantId(), asset, edge, getCurrentUser());
}
@ApiOperation(value = "Get assets assigned to edge (getEdgeAssets)",
@@ -680,9 +550,7 @@ public class AssetController extends BaseController {
@PostMapping("/asset/bulk_import")
public BulkImportResult processAssetsBulkImport(@RequestBody BulkImportRequest request) throws Exception {
SecurityUser user = getCurrentUser();
- return assetBulkImportService.processBulkImport(request, user, importedAssetInfo -> {
- onAssetCreatedOrUpdated(importedAssetInfo.getEntity(), importedAssetInfo.isUpdated(), user);
- });
+ return assetBulkImportService.processBulkImport(request, user);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
index f945cc30b7..1daefb7a39 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -349,8 +349,12 @@ public abstract class BaseController {
}
}
- UUID toUUID(String id) {
- return UUID.fromString(id);
+ UUID toUUID(String id) throws ThingsboardException {
+ try {
+ return UUID.fromString(id);
+ } catch (IllegalArgumentException e) {
+ throw handleException(e, false);
+ }
}
PageLink createPageLink(int pageSize, int page, String textSearch, String sortProperty, String sortOrder) throws ThingsboardException {
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index 85a21e912c..f7b3908010 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -37,20 +37,16 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;
-import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
import org.thingsboard.server.common.data.ClaimRequest;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.DataConstants;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceInfo;
import org.thingsboard.server.common.data.EntitySubtype;
-import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.SaveDeviceWithCredentialsRequest;
import org.thingsboard.server.common.data.Tenant;
-import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.device.DeviceSearchQuery;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CustomerId;
@@ -63,9 +59,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
import org.thingsboard.server.common.data.security.DeviceCredentials;
-import org.thingsboard.server.common.msg.TbMsg;
-import org.thingsboard.server.common.msg.TbMsgDataType;
-import org.thingsboard.server.common.msg.TbMsgMetaData;
import org.thingsboard.server.dao.device.claim.ClaimResponse;
import org.thingsboard.server.dao.device.claim.ClaimResult;
import org.thingsboard.server.dao.device.claim.ReclaimResult;
@@ -73,7 +66,7 @@ import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.device.DeviceBulkImportService;
-import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
+import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -81,7 +74,6 @@ import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import javax.annotation.Nullable;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -90,6 +82,7 @@ import java.util.stream.Collectors;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID;
import static org.thingsboard.server.controller.ControllerConstants.CUSTOMER_ID_PARAM_DESCRIPTION;
+import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_INFO_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_NAME_DESCRIPTION;
@@ -110,6 +103,7 @@ import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_A
import static org.thingsboard.server.controller.ControllerConstants.SORT_ORDER_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.SORT_PROPERTY_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_AUTHORITY_PARAGRAPH;
+import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@@ -122,13 +116,11 @@ import static org.thingsboard.server.controller.EdgeController.EDGE_ID;
@Slf4j
public class DeviceController extends BaseController {
- protected static final String DEVICE_ID = "deviceId";
protected static final String DEVICE_NAME = "deviceName";
- protected static final String TENANT_ID = "tenantId";
private final DeviceBulkImportService deviceBulkImportService;
- private final GatewayNotificationsService gatewayNotificationsService;
+ private final TbDeviceService tbDeviceService;
@ApiOperation(value = "Get Device (getDeviceById)",
notes = "Fetch the Device object based on the provided Device Id. " +
@@ -141,12 +133,8 @@ public class DeviceController extends BaseController {
public Device getDeviceById(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
- try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- return checkDeviceId(deviceId, Operation.READ);
- } catch (Exception e) {
- throw handleException(e);
- }
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ return checkDeviceId(deviceId, Operation.READ);
}
@ApiOperation(value = "Get Device Info (getDeviceInfoById)",
@@ -160,12 +148,8 @@ public class DeviceController extends BaseController {
public DeviceInfo getDeviceInfoById(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
- try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- return checkDeviceInfoId(deviceId, Operation.READ);
- } catch (Exception e) {
- throw handleException(e);
- }
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ return checkDeviceInfoId(deviceId, Operation.READ);
}
@ApiOperation(value = "Create Or Update Device (saveDevice)",
@@ -182,27 +166,14 @@ public class DeviceController extends BaseController {
public Device saveDevice(@ApiParam(value = "A JSON value representing the device.") @RequestBody Device device,
@ApiParam(value = "Optional value of the device credentials to be used during device creation. " +
"If omitted, access token will be auto-generated.") @RequestParam(name = "accessToken", required = false) String accessToken) throws ThingsboardException {
- boolean created = device.getId() == null;
- try {
- device.setTenantId(getCurrentUser().getTenantId());
-
- Device oldDevice = null;
- if (!created) {
- oldDevice = checkDeviceId(device.getId(), Operation.WRITE);
- } else {
- checkEntity(null, device, Resource.DEVICE);
- }
-
- Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
-
- onDeviceCreatedOrUpdated(savedDevice, oldDevice, !created, getCurrentUser());
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), device,
- null, created ? ActionType.ADDED : ActionType.UPDATED, e);
- throw handleException(e);
+ device.setTenantId(getCurrentUser().getTenantId());
+ Device oldDevice = null;
+ if (device.getId() != null) {
+ oldDevice = checkDeviceId(device.getId(), Operation.WRITE);
+ } else {
+ checkEntity(null, device, Resource.DEVICE);
}
+ return tbDeviceService.save(getTenantId(), device, oldDevice, accessToken, getCurrentUser());
}
@ApiOperation(value = "Create Device (saveDevice) with credentials ",
@@ -218,36 +189,11 @@ public class DeviceController extends BaseController {
@RequestBody SaveDeviceWithCredentialsRequest deviceAndCredentials) throws ThingsboardException {
Device device = checkNotNull(deviceAndCredentials.getDevice());
DeviceCredentials credentials = checkNotNull(deviceAndCredentials.getCredentials());
- boolean created = device.getId() == null;
- try {
- device.setTenantId(getCurrentUser().getTenantId());
- checkEntity(device.getId(), device, Resource.DEVICE);
- Device savedDevice = deviceService.saveDeviceWithCredentials(device, credentials);
- checkNotNull(savedDevice);
- tbClusterService.onDeviceUpdated(savedDevice, device);
- logEntityAction(savedDevice.getId(), savedDevice,
- savedDevice.getCustomerId(),
- device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null);
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), device,
- null, created ? ActionType.ADDED : ActionType.UPDATED, e);
- throw handleException(e);
- }
+ device.setTenantId(getCurrentUser().getTenantId());
+ checkEntity(device.getId(), device, Resource.DEVICE);
+ return tbDeviceService.saveDeviceWithCredentials(getTenantId(), device, credentials, getCurrentUser());
}
- private void onDeviceCreatedOrUpdated(Device savedDevice, Device oldDevice, boolean updated, SecurityUser user) {
- tbClusterService.onDeviceUpdated(savedDevice, oldDevice);
-
- try {
- logEntityAction(user, savedDevice.getId(), savedDevice,
- savedDevice.getCustomerId(),
- updated ? ActionType.UPDATED : ActionType.ADDED, null);
- } catch (ThingsboardException e) {
- log.error("Failed to log entity action", e);
- }
- }
@ApiOperation(value = "Delete device (deleteDevice)",
notes = "Deletes the device, it's credentials and all the relations (from and to the device). Referencing non-existing device Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH)
@@ -257,27 +203,11 @@ public class DeviceController extends BaseController {
public void deleteDevice(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ Device device = checkDeviceId(deviceId, Operation.DELETE);
try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- Device device = checkDeviceId(deviceId, Operation.DELETE);
-
- List relatedEdgeIds = findRelatedEdgeIds(getTenantId(), deviceId);
-
- deviceService.deleteDevice(getCurrentUser().getTenantId(), deviceId);
-
- gatewayNotificationsService.onDeviceDeleted(device);
- tbClusterService.onDeviceDeleted(device, null);
-
- logEntityAction(deviceId, device,
- device.getCustomerId(),
- ActionType.DELETED, null, strDeviceId);
-
- sendDeleteNotificationMsg(getTenantId(), deviceId, relatedEdgeIds);
+ tbDeviceService.deleteDevice(device, getCurrentUser()).get();
} catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE),
- null,
- null,
- ActionType.DELETED, e, strDeviceId);
throw handleException(e);
}
}
@@ -293,29 +223,11 @@ public class DeviceController extends BaseController {
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(DEVICE_ID, strDeviceId);
- try {
- CustomerId customerId = new CustomerId(toUUID(strCustomerId));
- Customer customer = checkCustomerId(customerId, Operation.READ);
-
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- checkDeviceId(deviceId, Operation.ASSIGN_TO_CUSTOMER);
-
- Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(getCurrentUser().getTenantId(), deviceId, customerId));
-
- logEntityAction(deviceId, savedDevice,
- savedDevice.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, strCustomerId, customer.getName());
-
- sendEntityAssignToCustomerNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(),
- customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER);
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strDeviceId, strCustomerId);
- throw handleException(e);
- }
+ CustomerId customerId = new CustomerId(toUUID(strCustomerId));
+ Customer customer = checkCustomerId(customerId, Operation.READ);
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ checkDeviceId(deviceId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbDeviceService.assignDeviceToCustomer(getTenantId(), deviceId, customer, getCurrentUser());
}
@ApiOperation(value = "Unassign device from customer (unassignDeviceFromCustomer)",
@@ -332,22 +244,11 @@ public class DeviceController extends BaseController {
if (device.getCustomerId() == null || device.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
throw new IncorrectParameterException("Device isn't assigned to any customer!");
}
- Customer customer = checkCustomerId(device.getCustomerId(), Operation.READ);
-
- Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(getCurrentUser().getTenantId(), deviceId));
-
- logEntityAction(deviceId, device,
- device.getCustomerId(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, null, strDeviceId, customer.getId().toString(), customer.getName());
- sendEntityAssignToCustomerNotificationMsg(savedDevice.getTenantId(), savedDevice.getId(),
- customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER);
+ Customer customer = checkCustomerId(device.getCustomerId(), Operation.READ);
- return savedDevice;
+ return tbDeviceService.unassignDeviceFromCustomer(device, customer, getCurrentUser());
} catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.UNASSIGNED_FROM_CUSTOMER, e, strDeviceId);
throw handleException(e);
}
}
@@ -362,23 +263,9 @@ public class DeviceController extends BaseController {
public Device assignDeviceToPublicCustomer(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
- try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_CUSTOMER);
- Customer publicCustomer = customerService.findOrCreatePublicCustomer(device.getTenantId());
- Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(getCurrentUser().getTenantId(), deviceId, publicCustomer.getId()));
-
- logEntityAction(deviceId, savedDevice,
- savedDevice.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strDeviceId, publicCustomer.getId().toString(), publicCustomer.getName());
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strDeviceId);
- throw handleException(e);
- }
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ checkDeviceId(deviceId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbDeviceService.assignDeviceToPublicCustomer(getTenantId(), deviceId, getCurrentUser());
}
@ApiOperation(value = "Get Device Credentials (getDeviceCredentialsByDeviceId)",
@@ -389,20 +276,9 @@ public class DeviceController extends BaseController {
public DeviceCredentials getDeviceCredentialsByDeviceId(@ApiParam(value = DEVICE_ID_PARAM_DESCRIPTION)
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(DEVICE_ID, strDeviceId);
- try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS);
- DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(getCurrentUser().getTenantId(), deviceId));
- logEntityAction(deviceId, device,
- device.getCustomerId(),
- ActionType.CREDENTIALS_READ, null, strDeviceId);
- return deviceCredentials;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.CREDENTIALS_READ, e, strDeviceId);
- throw handleException(e);
- }
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ Device device = checkDeviceId(deviceId, Operation.READ_CREDENTIALS);
+ return tbDeviceService.getDeviceCredentialsByDeviceId(device, getCurrentUser());
}
@ApiOperation(value = "Update device credentials (updateDeviceCredentials)", notes = "During device creation, platform generates random 'ACCESS_TOKEN' credentials. " +
@@ -416,23 +292,8 @@ public class DeviceController extends BaseController {
@ApiParam(value = "A JSON value representing the device credentials.")
@RequestBody DeviceCredentials deviceCredentials) throws ThingsboardException {
checkNotNull(deviceCredentials);
- try {
- Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS);
- DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(getCurrentUser().getTenantId(), deviceCredentials));
- tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId(), result), null);
-
- sendEntityNotificationMsg(getTenantId(), device.getId(), EdgeEventActionType.CREDENTIALS_UPDATED);
-
- logEntityAction(device.getId(), device,
- device.getCustomerId(),
- ActionType.CREDENTIALS_UPDATED, null, deviceCredentials);
- return result;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.CREDENTIALS_UPDATED, e, deviceCredentials);
- throw handleException(e);
- }
+ Device device = checkDeviceId(deviceCredentials.getDeviceId(), Operation.WRITE_CREDENTIALS);
+ return tbDeviceService.updateDeviceCredentials(device, deviceCredentials, getCurrentUser());
}
@ApiOperation(value = "Get Tenant Devices (getTenantDevices)",
@@ -692,52 +553,42 @@ public class DeviceController extends BaseController {
@ApiParam(value = "Claiming request which can optionally contain secret key")
@RequestBody(required = false) ClaimRequest claimRequest) throws ThingsboardException {
checkParameter(DEVICE_NAME, deviceName);
- try {
- final DeferredResult deferredResult = new DeferredResult<>();
-
- SecurityUser user = getCurrentUser();
- TenantId tenantId = user.getTenantId();
- CustomerId customerId = user.getCustomerId();
-
- Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
- accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
- device.getId(), device);
- String secretKey = getSecretKey(claimRequest);
+ final DeferredResult deferredResult = new DeferredResult<>();
- ListenableFuture future = claimDevicesService.claimDevice(device, customerId, secretKey);
- Futures.addCallback(future, new FutureCallback() {
- @Override
- public void onSuccess(@Nullable ClaimResult result) {
- HttpStatus status;
- if (result != null) {
- if (result.getResponse().equals(ClaimResponse.SUCCESS)) {
- status = HttpStatus.OK;
- deferredResult.setResult(new ResponseEntity<>(result, status));
-
- try {
- logEntityAction(user, device.getId(), result.getDevice(), customerId, ActionType.ASSIGNED_TO_CUSTOMER, null,
- device.getId().toString(), customerId.toString(), customerService.findCustomerById(tenantId, customerId).getName());
- } catch (ThingsboardException e) {
- throw new RuntimeException(e);
- }
- } else {
- status = HttpStatus.BAD_REQUEST;
- deferredResult.setResult(new ResponseEntity<>(result.getResponse(), status));
- }
+ SecurityUser user = getCurrentUser();
+ TenantId tenantId = user.getTenantId();
+ CustomerId customerId = user.getCustomerId();
+
+ Device device = checkNotNull(deviceService.findDeviceByTenantIdAndName(tenantId, deviceName));
+ accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
+ device.getId(), device);
+ String secretKey = getSecretKey(claimRequest);
+
+ ListenableFuture future = tbDeviceService.claimDevice(tenantId, device, customerId, secretKey, user);
+
+ Futures.addCallback(future, new FutureCallback() {
+ @Override
+ public void onSuccess(@Nullable ClaimResult result) {
+ HttpStatus status;
+ if (result != null) {
+ if (result.getResponse().equals(ClaimResponse.SUCCESS)) {
+ status = HttpStatus.OK;
+ deferredResult.setResult(new ResponseEntity<>(result, status));
} else {
- deferredResult.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
+ status = HttpStatus.BAD_REQUEST;
+ deferredResult.setResult(new ResponseEntity<>(result.getResponse(), status));
}
+ } else {
+ deferredResult.setResult(new ResponseEntity<>(HttpStatus.BAD_REQUEST));
}
+ }
- @Override
- public void onFailure(Throwable t) {
- deferredResult.setErrorResult(t);
- }
- }, MoreExecutors.directExecutor());
- return deferredResult;
- } catch (Exception e) {
- throw handleException(e);
- }
+ @Override
+ public void onFailure(Throwable t) {
+ deferredResult.setErrorResult(t);
+ }
+ }, MoreExecutors.directExecutor());
+ return deferredResult;
}
@ApiOperation(value = "Reclaim device (reClaimDevice)",
@@ -759,21 +610,11 @@ public class DeviceController extends BaseController {
accessControlService.checkPermission(user, Resource.DEVICE, Operation.CLAIM_DEVICES,
device.getId(), device);
- ListenableFuture result = claimDevicesService.reClaimDevice(tenantId, device);
+ ListenableFuture result = tbDeviceService.reclaimDevice(tenantId, device, user);
Futures.addCallback(result, new FutureCallback<>() {
@Override
public void onSuccess(ReclaimResult reclaimResult) {
deferredResult.setResult(new ResponseEntity(HttpStatus.OK));
-
- Customer unassignedCustomer = reclaimResult.getUnassignedCustomer();
- if (unassignedCustomer != null) {
- try {
- logEntityAction(user, device.getId(), device, device.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, null,
- device.getId().toString(), unassignedCustomer.getId().toString(), unassignedCustomer.getName());
- } catch (ThingsboardException e) {
- throw new RuntimeException(e);
- }
- }
}
@Override
@@ -787,7 +628,7 @@ public class DeviceController extends BaseController {
}
}
- private String getSecretKey(ClaimRequest claimRequest) throws IOException {
+ private String getSecretKey(ClaimRequest claimRequest) {
String secretKey = claimRequest.getSecretKey();
if (secretKey != null) {
return secretKey;
@@ -806,47 +647,15 @@ public class DeviceController extends BaseController {
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
checkParameter(DEVICE_ID, strDeviceId);
- try {
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_TENANT);
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_TENANT);
- TenantId newTenantId = TenantId.fromUUID(toUUID(strTenantId));
- Tenant newTenant = tenantService.findTenantById(newTenantId);
- if (newTenant == null) {
- throw new ThingsboardException("Could not find the specified Tenant!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
- }
-
- Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device);
-
- logEntityAction(getCurrentUser(), deviceId, assignedDevice,
- assignedDevice.getCustomerId(),
- ActionType.ASSIGNED_TO_TENANT, null, strTenantId, newTenant.getName());
-
- Tenant currentTenant = tenantService.findTenantById(getTenantId());
- pushAssignedFromNotification(currentTenant, newTenantId, assignedDevice);
-
- return assignedDevice;
- } catch (Exception e) {
- logEntityAction(getCurrentUser(), emptyId(EntityType.DEVICE), null,
- null,
- ActionType.ASSIGNED_TO_TENANT, e, strTenantId);
- throw handleException(e);
- }
- }
-
- private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
- String data = entityToStr(assignedDevice);
- if (data != null) {
- TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
- tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
+ TenantId newTenantId = TenantId.fromUUID(toUUID(strTenantId));
+ Tenant newTenant = tenantService.findTenantById(newTenantId);
+ if (newTenant == null) {
+ throw new ThingsboardException("Could not find the specified Tenant!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
}
- }
-
- private TbMsgMetaData getMetaDataForAssignedFrom(Tenant tenant) {
- TbMsgMetaData metaData = new TbMsgMetaData();
- metaData.putValue("assignedFromTenantId", tenant.getId().getId().toString());
- metaData.putValue("assignedFromTenantName", tenant.getName());
- return metaData;
+ return tbDeviceService.assignDeviceToTenant(device, newTenant, getCurrentUser());
}
@ApiOperation(value = "Assign device to edge (assignDeviceToEdge)",
@@ -865,28 +674,13 @@ public class DeviceController extends BaseController {
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(DEVICE_ID, strDeviceId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.READ);
-
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- checkDeviceId(deviceId, Operation.READ);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.READ);
- Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(getCurrentUser().getTenantId(), deviceId, edgeId));
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ checkDeviceId(deviceId, Operation.READ);
- logEntityAction(deviceId, savedDevice,
- savedDevice.getCustomerId(),
- ActionType.ASSIGNED_TO_EDGE, null, strDeviceId, strEdgeId, edge.getName());
-
- sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDevice.getId(), EdgeEventActionType.ASSIGNED_TO_EDGE);
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.ASSIGNED_TO_EDGE, e, strDeviceId, strEdgeId);
- throw handleException(e);
- }
+ return tbDeviceService.assignDeviceToEdge(getTenantId(), deviceId, edge, getCurrentUser());
}
@ApiOperation(value = "Unassign device from edge (unassignDeviceFromEdge)",
@@ -905,28 +699,12 @@ public class DeviceController extends BaseController {
@PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter(DEVICE_ID, strDeviceId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.READ);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.READ);
- DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
- Device device = checkDeviceId(deviceId, Operation.READ);
-
- Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(getCurrentUser().getTenantId(), deviceId, edgeId));
-
- logEntityAction(deviceId, device,
- device.getCustomerId(),
- ActionType.UNASSIGNED_FROM_EDGE, null, strDeviceId, strEdgeId, edge.getName());
-
- sendEntityAssignToEdgeNotificationMsg(getTenantId(), edgeId, savedDevice.getId(), EdgeEventActionType.UNASSIGNED_FROM_EDGE);
-
- return savedDevice;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.DEVICE), null,
- null,
- ActionType.UNASSIGNED_FROM_EDGE, e, strDeviceId, strEdgeId);
- throw handleException(e);
- }
+ DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
+ Device device = checkDeviceId(deviceId, Operation.READ);
+ return tbDeviceService.unassignDeviceFromEdge(device, edge, getCurrentUser());
}
@ApiOperation(value = "Get devices assigned to edge (getEdgeDevices)",
@@ -992,10 +770,11 @@ public class DeviceController extends BaseController {
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/devices/count/{otaPackageType}/{deviceProfileId}", method = RequestMethod.GET)
@ResponseBody
- public Long countByDeviceProfileAndEmptyOtaPackage(@ApiParam(value = "OTA package type", allowableValues = "FIRMWARE, SOFTWARE")
- @PathVariable("otaPackageType") String otaPackageType,
- @ApiParam(value = "Device Profile Id. I.g. '784f394c-42b6-435a-983c-b7beff2784f9'")
- @PathVariable("deviceProfileId") String deviceProfileId) throws ThingsboardException {
+ public Long countByDeviceProfileAndEmptyOtaPackage
+ (@ApiParam(value = "OTA package type", allowableValues = "FIRMWARE, SOFTWARE")
+ @PathVariable("otaPackageType") String otaPackageType,
+ @ApiParam(value = "Device Profile Id. I.g. '784f394c-42b6-435a-983c-b7beff2784f9'")
+ @PathVariable("deviceProfileId") String deviceProfileId) throws ThingsboardException {
checkParameter("OtaPackageType", otaPackageType);
checkParameter("DeviceProfileId", deviceProfileId);
try {
@@ -1012,11 +791,10 @@ public class DeviceController extends BaseController {
notes = "There's an ability to import the bulk of devices using the only .csv file." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@PostMapping("/device/bulk_import")
- public BulkImportResult processDevicesBulkImport(@RequestBody BulkImportRequest request) throws Exception {
+ public BulkImportResult processDevicesBulkImport(@RequestBody BulkImportRequest request) throws
+ Exception {
SecurityUser user = getCurrentUser();
- return deviceBulkImportService.processBulkImport(request, user, importedDeviceInfo -> {
- onDeviceCreatedOrUpdated(importedDeviceInfo.getEntity(), importedDeviceInfo.getOldEntity(), importedDeviceInfo.isUpdated(), user);
- });
+ return deviceBulkImportService.processBulkImport(request, user);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
index f3d73f13e5..8a01e9ef02 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java
@@ -34,10 +34,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype;
-import org.thingsboard.server.common.data.EntityType;
-import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.edge.Edge;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
import org.thingsboard.server.common.data.edge.EdgeInfo;
import org.thingsboard.server.common.data.edge.EdgeSearchQuery;
import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
@@ -48,20 +45,19 @@ import org.thingsboard.server.common.data.id.RuleChainId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
-import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.exception.DataValidationException;
import org.thingsboard.server.dao.exception.IncorrectParameterException;
import org.thingsboard.server.dao.model.ModelConstants;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.edge.EdgeBulkImportService;
+import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.importing.BulkImportRequest;
import org.thingsboard.server.service.importing.BulkImportResult;
import org.thingsboard.server.service.security.model.SecurityUser;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -90,6 +86,7 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@RequiredArgsConstructor
public class EdgeController extends BaseController {
private final EdgeBulkImportService edgeBulkImportService;
+ private final TbEdgeService tbEdgeService;
public static final String EDGE_ID = "edgeId";
public static final String EDGE_SECURITY_CHECK = "If the user has the authority of 'Tenant Administrator', the server checks that the edge is owned by the same tenant. " +
@@ -144,84 +141,43 @@ public class EdgeController extends BaseController {
"Specify existing Edge id to update the edge. " +
"Referencing non-existing Edge Id will cause 'Not Found' error." +
"\n\nEdge name is unique in the scope of tenant. Use unique identifiers like MAC or IMEI for the edge names and non-unique 'label' field for user-friendly visualization purposes."
- + TENANT_AUTHORITY_PARAGRAPH,
+ + TENANT_AUTHORITY_PARAGRAPH,
produces = MediaType.APPLICATION_JSON_VALUE)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge", method = RequestMethod.POST)
@ResponseBody
public Edge saveEdge(@ApiParam(value = "A JSON value representing the edge.", required = true)
@RequestBody Edge edge) throws ThingsboardException {
- try {
- TenantId tenantId = getCurrentUser().getTenantId();
- edge.setTenantId(tenantId);
- boolean created = edge.getId() == null;
-
- RuleChain edgeTemplateRootRuleChain = null;
- if (created) {
- edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(tenantId);
- if (edgeTemplateRootRuleChain == null) {
- throw new DataValidationException("Root edge rule chain is not available!");
- }
+ TenantId tenantId = getCurrentUser().getTenantId();
+ edge.setTenantId(tenantId);
+ boolean created = edge.getId() == null;
+
+ RuleChain edgeTemplateRootRuleChain = null;
+ if (created) {
+ edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(tenantId);
+ if (edgeTemplateRootRuleChain == null) {
+ throw new DataValidationException("Root edge rule chain is not available!");
}
-
- Operation operation = created ? Operation.CREATE : Operation.WRITE;
-
- accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation,
- edge.getId(), edge);
-
- Edge savedEdge = checkNotNull(edgeService.saveEdge(edge));
- onEdgeCreatedOrUpdated(tenantId, savedEdge, edgeTemplateRootRuleChain, !created, getCurrentUser());
-
- return savedEdge;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.EDGE), edge,
- null, edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e);
- throw handleException(e);
}
- }
- private void onEdgeCreatedOrUpdated(TenantId tenantId, Edge edge, RuleChain edgeTemplateRootRuleChain, boolean updated, SecurityUser user) throws IOException, ThingsboardException {
- if (!updated) {
- ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edge.getId());
- edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, edgeTemplateRootRuleChain.getId());
- edgeService.assignDefaultRuleChainsToEdge(tenantId, edge.getId());
- }
+ Operation operation = created ? Operation.CREATE : Operation.WRITE;
- tbClusterService.broadcastEntityStateChangeEvent(edge.getTenantId(), edge.getId(),
- updated ? ComponentLifecycleEvent.UPDATED : ComponentLifecycleEvent.CREATED);
+ accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edge.getId(), edge);
- logEntityAction(user, edge.getId(), edge, null, updated ? ActionType.UPDATED : ActionType.ADDED, null);
+ return tbEdgeService.saveEdge(edge, edgeTemplateRootRuleChain, getCurrentUser());
}
@ApiOperation(value = "Delete edge (deleteEdge)",
- notes = "Deletes the edge. Referencing non-existing edge Id will cause an error."+ TENANT_AUTHORITY_PARAGRAPH)
+ notes = "Deletes the edge. Referencing non-existing edge Id will cause an error." + TENANT_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/edge/{edgeId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteEdge(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.DELETE);
- edgeService.deleteEdge(getTenantId(), edgeId);
-
- tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
- ComponentLifecycleEvent.DELETED);
-
- logEntityAction(edgeId, edge,
- null,
- ActionType.DELETED, null, strEdgeId);
-
- } catch (Exception e) {
-
- logEntityAction(emptyId(EntityType.EDGE),
- null,
- null,
- ActionType.DELETED, e, strEdgeId);
-
- throw handleException(e);
- }
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.DELETE);
+ tbEdgeService.deleteEdge(edge, getCurrentUser());
}
@ApiOperation(value = "Get Tenant Edges (getEdges)",
@@ -261,32 +217,11 @@ public class EdgeController extends BaseController {
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter("customerId", strCustomerId);
checkParameter(EDGE_ID, strEdgeId);
- try {
- CustomerId customerId = new CustomerId(toUUID(strCustomerId));
- Customer customer = checkCustomerId(customerId, Operation.READ);
-
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
-
- Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, customerId));
-
- tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
- ComponentLifecycleEvent.UPDATED);
-
- logEntityAction(edgeId, savedEdge,
- savedEdge.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, strCustomerId, customer.getName());
-
- sendEntityAssignToCustomerNotificationMsg(savedEdge.getTenantId(), savedEdge.getId(),
- customerId, EdgeEventActionType.ASSIGNED_TO_CUSTOMER);
-
- return savedEdge;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.EDGE), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId, strCustomerId);
- throw handleException(e);
- }
+ CustomerId customerId = new CustomerId(toUUID(strCustomerId));
+ Customer customer = checkCustomerId(customerId, Operation.READ);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbEdgeService.assignEdgeToCustomer(getTenantId(), edgeId, customer, getCurrentUser());
}
@ApiOperation(value = "Unassign edge from customer (unassignEdgeFromCustomer)",
@@ -298,33 +233,14 @@ public class EdgeController extends BaseController {
public Edge unassignEdgeFromCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.UNASSIGN_FROM_CUSTOMER);
- if (edge.getCustomerId() == null || edge.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
- throw new IncorrectParameterException("Edge isn't assigned to any customer!");
- }
- Customer customer = checkCustomerId(edge.getCustomerId(), Operation.READ);
-
- Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(getCurrentUser().getTenantId(), edgeId));
-
- tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
- ComponentLifecycleEvent.UPDATED);
-
- logEntityAction(edgeId, edge,
- edge.getCustomerId(),
- ActionType.UNASSIGNED_FROM_CUSTOMER, null, strEdgeId, customer.getId().toString(), customer.getName());
-
- sendEntityAssignToCustomerNotificationMsg(savedEdge.getTenantId(), savedEdge.getId(),
- customer.getId(), EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER);
-
- return savedEdge;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.EDGE), null,
- null,
- ActionType.UNASSIGNED_FROM_CUSTOMER, e, strEdgeId);
- throw handleException(e);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.UNASSIGN_FROM_CUSTOMER);
+ if (edge.getCustomerId() == null || edge.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
+ throw new IncorrectParameterException("Edge isn't assigned to any customer!");
}
+ Customer customer = checkCustomerId(edge.getCustomerId(), Operation.READ);
+
+ return tbEdgeService.unassignEdgeFromCustomer(edge, customer, getCurrentUser());
}
@ApiOperation(value = "Make edge publicly available (assignEdgeToPublicCustomer)",
@@ -338,26 +254,9 @@ public class EdgeController extends BaseController {
public Edge assignEdgeToPublicCustomer(@ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true)
@PathVariable(EDGE_ID) String strEdgeId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
- try {
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
- Customer publicCustomer = customerService.findOrCreatePublicCustomer(edge.getTenantId());
- Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(getCurrentUser().getTenantId(), edgeId, publicCustomer.getId()));
-
- tbClusterService.broadcastEntityStateChangeEvent(getTenantId(), edgeId,
- ComponentLifecycleEvent.UPDATED);
-
- logEntityAction(edgeId, savedEdge,
- savedEdge.getCustomerId(),
- ActionType.ASSIGNED_TO_CUSTOMER, null, strEdgeId, publicCustomer.getId().toString(), publicCustomer.getName());
-
- return savedEdge;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.EDGE), null,
- null,
- ActionType.ASSIGNED_TO_CUSTOMER, e, strEdgeId);
- throw handleException(e);
- }
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ checkEdgeId(edgeId, Operation.ASSIGN_TO_CUSTOMER);
+ return tbEdgeService.assignEdgeToPublicCustomer(getTenantId(), edgeId, getCurrentUser());
}
@ApiOperation(value = "Get Tenant Edges (getTenantEdges)",
@@ -455,29 +354,12 @@ public class EdgeController extends BaseController {
@PathVariable("ruleChainId") String strRuleChainId) throws ThingsboardException {
checkParameter(EDGE_ID, strEdgeId);
checkParameter("ruleChainId", strRuleChainId);
- try {
- RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
- checkRuleChain(ruleChainId, Operation.WRITE);
-
- EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
- Edge edge = checkEdgeId(edgeId, Operation.WRITE);
- accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.WRITE,
- edge.getId(), edge);
-
- Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(getTenantId(), edge, ruleChainId);
-
- tbClusterService.broadcastEntityStateChangeEvent(updatedEdge.getTenantId(), updatedEdge.getId(), ComponentLifecycleEvent.UPDATED);
-
- logEntityAction(updatedEdge.getId(), updatedEdge, null, ActionType.UPDATED, null);
-
- return updatedEdge;
- } catch (Exception e) {
- logEntityAction(emptyId(EntityType.EDGE),
- null,
- null,
- ActionType.UPDATED, e, strEdgeId);
- throw handleException(e);
- }
+ RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
+ checkRuleChain(ruleChainId, Operation.WRITE);
+ EdgeId edgeId = new EdgeId(toUUID(strEdgeId));
+ Edge edge = checkEdgeId(edgeId, Operation.WRITE);
+ accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, Operation.WRITE, edge.getId(), edge);
+ return tbEdgeService.setEdgeRootRuleChain(edge, ruleChainId, getCurrentUser());
}
@ApiOperation(value = "Get Customer Edges (getCustomerEdges)",
@@ -693,12 +575,6 @@ public class EdgeController extends BaseController {
throw new DataValidationException("Root edge rule chain is not available!");
}
- return edgeBulkImportService.processBulkImport(request, user, importedAssetInfo -> {
- try {
- onEdgeCreatedOrUpdated(user.getTenantId(), importedAssetInfo.getEntity(), edgeTemplateRootRuleChain, importedAssetInfo.isUpdated(), user);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
+ return edgeBulkImportService.processBulkImport(request, user);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
index 002956924d..281a13a6a0 100644
--- a/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/OtaPackageController.java
@@ -28,6 +28,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@@ -49,6 +50,8 @@ import org.thingsboard.server.service.security.permission.Resource;
import java.nio.ByteBuffer;
+import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
+import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
import static org.thingsboard.server.controller.ControllerConstants.DEVICE_PROFILE_ID_PARAM_DESCRIPTION;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES;
import static org.thingsboard.server.controller.ControllerConstants.OTA_PACKAGE_DESCRIPTION;
@@ -105,7 +108,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Info (getOtaPackageInfoById)",
notes = "Fetch the OTA Package Info object based on the provided OTA Package Id. " +
OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackage/info/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
@@ -123,7 +126,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package (getOtaPackageById)",
notes = "Fetch the OTA Package object based on the provided OTA Package Id. " +
"The server checks that the OTA Package is owned by the same tenant. " + OTA_PACKAGE_DESCRIPTION + TENANT_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.GET)
@ResponseBody
@@ -144,8 +147,8 @@ public class OtaPackageController extends BaseController {
"Specify existing OTA Package id to update the OTA Package Info. " +
"Referencing non-existing OTA Package Id will cause 'Not Found' error. " +
"\n\nOTA Package combination of the title with the version is unique in the scope of tenant. " + TENANT_AUTHORITY_PARAGRAPH,
- produces = "application/json",
- consumes = "application/json")
+ produces = APPLICATION_JSON_VALUE,
+ consumes = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage", method = RequestMethod.POST)
@ResponseBody
@@ -168,9 +171,10 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Save OTA Package data (saveOtaPackageData)",
notes = "Update the OTA Package. Adds the date to the existing OTA Package Info" + TENANT_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE,
+ consumes = MULTIPART_FORM_DATA_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
- @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST)
+ @RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.POST, consumes = MULTIPART_FORM_DATA_VALUE)
@ResponseBody
public OtaPackageInfo saveOtaPackageData(@ApiParam(value = OTA_PACKAGE_ID_PARAM_DESCRIPTION)
@PathVariable(OTA_PACKAGE_ID) String strOtaPackageId,
@@ -179,7 +183,7 @@ public class OtaPackageController extends BaseController {
@ApiParam(value = "OTA Package checksum algorithm.", allowableValues = OTA_PACKAGE_CHECKSUM_ALGORITHM_ALLOWABLE_VALUES)
@RequestParam(CHECKSUM_ALGORITHM) String checksumAlgorithmStr,
@ApiParam(value = "OTA Package data.")
- @RequestBody MultipartFile file) throws ThingsboardException {
+ @RequestPart MultipartFile file) throws ThingsboardException {
checkParameter(OTA_PACKAGE_ID, strOtaPackageId);
checkParameter(CHECKSUM_ALGORITHM, checksumAlgorithmStr);
try {
@@ -221,7 +225,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages", method = RequestMethod.GET)
@ResponseBody
@@ -246,7 +250,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Get OTA Package Infos (getOtaPackages)",
notes = "Returns a page of OTA Package Info objects owned by tenant. " +
PAGE_DATA_PARAMETERS + OTA_PACKAGE_INFO_DESCRIPTION + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/otaPackages/{deviceProfileId}/{type}", method = RequestMethod.GET)
@ResponseBody
@@ -278,7 +282,7 @@ public class OtaPackageController extends BaseController {
@ApiOperation(value = "Delete OTA Package (deleteOtaPackage)",
notes = "Deletes the OTA Package. Referencing non-existing OTA Package Id will cause an error. " +
"Can't delete the OTA Package if it is referenced by existing devices or device profile." + TENANT_AUTHORITY_PARAGRAPH,
- produces = "application/json")
+ produces = APPLICATION_JSON_VALUE)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/otaPackage/{otaPackageId}", method = RequestMethod.DELETE)
@ResponseBody
diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
index 496cd60e81..6d6e99cbba 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
@@ -18,8 +18,9 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.databind.node.ObjectNode;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
@@ -36,10 +37,9 @@ import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
-import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
import org.thingsboard.server.dao.tenant.TenantService;
import org.thingsboard.server.queue.util.TbCoreComponent;
-import org.thingsboard.server.service.install.InstallScripts;
+import org.thingsboard.server.service.entitiy.tenant.TbTenantService;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
@@ -63,14 +63,13 @@ import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LI
@TbCoreComponent
@RequestMapping("/api")
@Slf4j
+@RequiredArgsConstructor
public class TenantController extends BaseController {
private static final String TENANT_INFO_DESCRIPTION = "The Tenant Info object extends regular Tenant object and includes Tenant Profile name. ";
- @Autowired
- private InstallScripts installScripts;
- @Autowired
- private TenantService tenantService;
+ private final TenantService tenantService;
+ private final TbTenantService tbTenantService;
@ApiOperation(value = "Get Tenant (getTenantById)",
notes = "Fetch the Tenant object based on the provided Tenant Id. " + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH)
@@ -121,27 +120,10 @@ public class TenantController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant", method = RequestMethod.POST)
@ResponseBody
- public Tenant saveTenant(
- @ApiParam(value = "A JSON value representing the tenant.")
- @RequestBody Tenant tenant) throws ThingsboardException {
- try {
- boolean newTenant = tenant.getId() == null;
-
- checkEntity(tenant.getId(), tenant, Resource.TENANT);
-
- tenant = checkNotNull(tenantService.saveTenant(tenant));
- if (newTenant) {
- installScripts.createDefaultRuleChains(tenant.getId());
- installScripts.createDefaultEdgeRuleChains(tenant.getId());
- }
- tenantProfileCache.evict(tenant.getId());
- tbClusterService.onTenantChange(tenant, null);
- tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(),
- newTenant ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
- return tenant;
- } catch (Exception e) {
- throw handleException(e);
- }
+ public Tenant saveTenant(@ApiParam(value = "A JSON value representing the tenant.")
+ @RequestBody Tenant tenant) throws ThingsboardException {
+ checkEntity(tenant.getId(), tenant, Resource.TENANT);
+ return tbTenantService.save(tenant);
}
@ApiOperation(value = "Delete Tenant (deleteTenant)",
@@ -149,20 +131,12 @@ public class TenantController extends BaseController {
@PreAuthorize("hasAuthority('SYS_ADMIN')")
@RequestMapping(value = "/tenant/{tenantId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
- public void deleteTenant(
- @ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
- @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
+ public void deleteTenant(@ApiParam(value = TENANT_ID_PARAM_DESCRIPTION)
+ @PathVariable(TENANT_ID) String strTenantId) throws ThingsboardException {
checkParameter(TENANT_ID, strTenantId);
- try {
- TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
- Tenant tenant = checkTenantId(tenantId, Operation.DELETE);
- tenantService.deleteTenant(tenantId);
- tenantProfileCache.evict(tenantId);
- tbClusterService.onTenantDelete(tenant, null);
- tbClusterService.broadcastEntityStateChangeEvent(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
- } catch (Exception e) {
- throw handleException(e);
- }
+ TenantId tenantId = TenantId.fromUUID(toUUID(strTenantId));
+ Tenant tenant = checkTenantId(tenantId, Operation.DELETE);
+ tbTenantService.delete(tenant);
}
@ApiOperation(value = "Get Tenants (getTenants)", notes = "Returns a page of tenants registered in the platform. " + PAGE_DATA_PARAMETERS + SYSTEM_AUTHORITY_PARAGRAPH)
diff --git a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
index 4c75f7d45d..e9999d2dc1 100644
--- a/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/asset/AssetBulkImportService.java
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.asset;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
@@ -25,6 +26,7 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.asset.TbAssetService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -37,6 +39,7 @@ import java.util.Optional;
@RequiredArgsConstructor
public class AssetBulkImportService extends AbstractBulkImportService {
private final AssetService assetService;
+ private final TbAssetService tbAssetService;
@Override
protected void setEntityFields(Asset entity, Map fields) {
@@ -61,8 +64,9 @@ public class AssetBulkImportService extends AbstractBulkImportService {
}
@Override
- protected Asset saveEntity(Asset entity, Map fields) {
- return assetService.saveAsset(entity);
+ @SneakyThrows
+ protected Asset saveEntity(SecurityUser user, Asset entity, Map fields) {
+ return tbAssetService.save(entity, user);
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
index cd655a2467..34c30d5225 100644
--- a/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/device/DeviceBulkImportService.java
@@ -49,6 +49,7 @@ import org.thingsboard.server.dao.device.DeviceProfileService;
import org.thingsboard.server.dao.device.DeviceService;
import org.thingsboard.server.dao.exception.DeviceCredentialsValidationException;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.device.TbDeviceService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -68,6 +69,7 @@ import java.util.concurrent.locks.ReentrantLock;
@RequiredArgsConstructor
public class DeviceBulkImportService extends AbstractBulkImportService {
protected final DeviceService deviceService;
+ protected final TbDeviceService tbDeviceService;
protected final DeviceCredentialsService deviceCredentialsService;
protected final DeviceProfileService deviceProfileService;
@@ -99,7 +101,8 @@ public class DeviceBulkImportService extends AbstractBulkImportService {
}
@Override
- protected Device saveEntity(Device entity, Map fields) {
+ @SneakyThrows
+ protected Device saveEntity(SecurityUser user, Device entity, Map fields) {
DeviceCredentials deviceCredentials;
try {
deviceCredentials = createDeviceCredentials(fields);
@@ -118,7 +121,7 @@ public class DeviceBulkImportService extends AbstractBulkImportService {
}
entity.setDeviceProfileId(deviceProfile.getId());
- return deviceService.saveDeviceWithCredentials(entity, deviceCredentials);
+ return tbDeviceService.saveDeviceWithCredentials(user.getTenantId(), entity, deviceCredentials, user);
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
index 55779f19ef..6b5e519f80 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/DefaultEdgeNotificationService.java
@@ -16,11 +16,16 @@
package org.thingsboard.server.service.edge;
import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.ThingsBoardThreadFactory;
import org.thingsboard.server.cluster.TbClusterService;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -42,7 +47,6 @@ import org.thingsboard.server.service.edge.rpc.processor.RelationEdgeProcessor;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
-import java.io.IOException;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -76,29 +80,29 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
@Autowired
private CustomerEdgeProcessor customerProcessor;
- private ExecutorService tsCallBackExecutor;
+ private ExecutorService dbCallBackExecutor;
@PostConstruct
public void initExecutor() {
- tsCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications"));
+ dbCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications"));
}
@PreDestroy
public void shutdownExecutor() {
- if (tsCallBackExecutor != null) {
- tsCallBackExecutor.shutdownNow();
+ if (dbCallBackExecutor != null) {
+ dbCallBackExecutor.shutdownNow();
}
}
@Override
- public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException {
+ public Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws Exception {
edge.setRootRuleChainId(ruleChainId);
Edge savedEdge = edgeService.saveEdge(edge);
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, null);
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.RULE_CHAIN, EdgeEventActionType.UPDATED, ruleChainId, null).get();
return savedEdge;
}
- private void saveEdgeEvent(TenantId tenantId,
+ private ListenableFuture saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
@@ -107,17 +111,12 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
log.debug("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
- EdgeEvent edgeEvent = new EdgeEvent();
- edgeEvent.setEdgeId(edgeId);
- edgeEvent.setTenantId(tenantId);
- edgeEvent.setType(type);
- edgeEvent.setAction(action);
- if (entityId != null) {
- edgeEvent.setEntityId(entityId.getId());
- }
- edgeEvent.setBody(body);
- edgeEventService.save(edgeEvent);
- clusterService.onEdgeEventUpdate(tenantId, edgeId);
+ EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
+
+ return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
+ clusterService.onEdgeEventUpdate(tenantId, edgeId);
+ return null;
+ }, dbCallBackExecutor);
}
@Override
@@ -126,9 +125,10 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
try {
TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB()));
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
+ ListenableFuture future;
switch (type) {
case EDGE:
- edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg);
+ future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg);
break;
case USER:
case ASSET:
@@ -137,33 +137,47 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService {
case ENTITY_VIEW:
case DASHBOARD:
case RULE_CHAIN:
- entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
+ future = entityProcessor.processEntityNotification(tenantId, edgeNotificationMsg);
break;
case CUSTOMER:
- customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg);
+ future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg);
break;
case WIDGETS_BUNDLE:
case WIDGET_TYPE:
- entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
+ future = entityProcessor.processEntityNotificationForAllEdges(tenantId, edgeNotificationMsg);
break;
case ALARM:
- alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg);
+ future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg);
break;
case RELATION:
- relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg);
+ future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg);
break;
default:
log.warn("Edge event type [{}] is not designed to be pushed to edge", type);
+ future = Futures.immediateFuture(null);
}
+ Futures.addCallback(future, new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable Void unused) {
+ callback.onSuccess();
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ callBackFailure(edgeNotificationMsg, callback, throwable);
+ }
+ }, dbCallBackExecutor);
} catch (Exception e) {
- callback.onFailure(e);
- String errMsg = String.format("Can't push to edge updates, edgeNotificationMsg [%s]", edgeNotificationMsg);
- log.error(errMsg, e);
- } finally {
- callback.onSuccess();
+ callBackFailure(edgeNotificationMsg, callback, e);
}
}
+ private void callBackFailure(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) {
+ String errMsg = String.format("Can't push to edge updates, edgeNotificationMsg [%s]", edgeNotificationMsg);
+ log.error(errMsg, throwable);
+ callback.onFailure(throwable);
+ }
+
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
index 615a7cddd2..038dcadfc8 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeBulkImportService.java
@@ -18,13 +18,17 @@ package org.thingsboard.server.service.edge;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
import org.springframework.stereotype.Service;
import org.thingsboard.common.util.JacksonUtil;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleChain;
import org.thingsboard.server.dao.edge.EdgeService;
+import org.thingsboard.server.dao.rule.RuleChainService;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.edge.TbEdgeService;
import org.thingsboard.server.service.importing.AbstractBulkImportService;
import org.thingsboard.server.service.importing.BulkImportColumnType;
import org.thingsboard.server.service.security.model.SecurityUser;
@@ -37,6 +41,8 @@ import java.util.Optional;
@RequiredArgsConstructor
public class EdgeBulkImportService extends AbstractBulkImportService {
private final EdgeService edgeService;
+ private final TbEdgeService tbEdgeService;
+ private final RuleChainService ruleChainService;
@Override
protected void setEntityFields(Edge entity, Map fields) {
@@ -66,9 +72,11 @@ public class EdgeBulkImportService extends AbstractBulkImportService {
entity.setAdditionalInfo(additionalInfo);
}
+ @SneakyThrows
@Override
- protected Edge saveEntity(Edge entity, Map fields) {
- return edgeService.saveEdge(entity);
+ protected Edge saveEntity(SecurityUser user, Edge entity, Map fields) {
+ RuleChain edgeTemplateRootRuleChain = ruleChainService.getEdgeTemplateRootRuleChain(user.getTenantId());
+ return tbEdgeService.saveEdge(entity, edgeTemplateRootRuleChain, user);
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
index be6741cef6..ee36c80454 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeNotificationService.java
@@ -21,11 +21,9 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.msg.queue.TbCallback;
import org.thingsboard.server.gen.transport.TransportProtos;
-import java.io.IOException;
-
public interface EdgeNotificationService {
- Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws IOException;
+ Edge setEdgeRootRuleChain(TenantId tenantId, Edge edge, RuleChainId ruleChainId) throws Exception;
void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventUtils.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventUtils.java
deleted file mode 100644
index 0aeac4c16a..0000000000
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeEventUtils.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Copyright © 2016-2022 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.service.edge.rpc;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import org.thingsboard.server.common.data.edge.EdgeEvent;
-import org.thingsboard.server.common.data.edge.EdgeEventActionType;
-import org.thingsboard.server.common.data.edge.EdgeEventType;
-import org.thingsboard.server.common.data.id.EdgeId;
-import org.thingsboard.server.common.data.id.EntityId;
-import org.thingsboard.server.common.data.id.TenantId;
-
-public final class EdgeEventUtils {
-
- private EdgeEventUtils() {
- }
-
- public static EdgeEvent constructEdgeEvent(TenantId tenantId,
- EdgeId edgeId,
- EdgeEventType type,
- EdgeEventActionType action,
- EntityId entityId,
- JsonNode body) {
- EdgeEvent edgeEvent = new EdgeEvent();
- edgeEvent.setTenantId(tenantId);
- edgeEvent.setEdgeId(edgeId);
- edgeEvent.setType(type);
- edgeEvent.setAction(action);
- if (entityId != null) {
- edgeEvent.setEntityId(entityId.getId());
- }
- edgeEvent.setBody(body);
- return edgeEvent;
- }
-}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
index 65ca6b4ea6..c56fcd4ed9 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcService.java
@@ -15,7 +15,6 @@
*/
package org.thingsboard.server.service.edge.rpc;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import io.grpc.Server;
@@ -71,7 +70,6 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
private final ConcurrentMap sessionNewEventsLocks = new ConcurrentHashMap<>();
private final Map sessionNewEvents = new HashMap<>();
private final ConcurrentMap> sessionEdgeEventChecks = new ConcurrentHashMap<>();
- private static final ObjectMapper mapper = new ObjectMapper();
@Value("${edges.rpc.port}")
private int rpcPort;
@@ -159,7 +157,7 @@ public class EdgeGrpcService extends EdgeRpcServiceGrpc.EdgeRpcServiceImplBase i
@Override
public StreamObserver handleMsgs(StreamObserver outputStream) {
- return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, mapper, sendDownlinkExecutorService).getInputStream();
+ return new EdgeGrpcSession(ctx, outputStream, this::onEdgeConnect, this::onEdgeDisconnect, sendDownlinkExecutorService).getInputStream();
}
@Override
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
index e4f32f6a89..de0cea14d6 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/EdgeGrpcSession.java
@@ -16,7 +16,6 @@
package org.thingsboard.server.service.edge.rpc;
import com.datastax.oss.driver.api.core.uuid.Uuids;
-import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
@@ -96,7 +95,6 @@ public final class EdgeGrpcSession implements Closeable {
private final UUID sessionId;
private final BiConsumer sessionOpenListener;
private final Consumer sessionCloseListener;
- private final ObjectMapper mapper;
private final EdgeSessionState sessionState = new EdgeSessionState();
@@ -112,13 +110,12 @@ public final class EdgeGrpcSession implements Closeable {
private ScheduledExecutorService sendDownlinkExecutorService;
EdgeGrpcSession(EdgeContextComponent ctx, StreamObserver outputStream, BiConsumer sessionOpenListener,
- Consumer sessionCloseListener, ObjectMapper mapper, ScheduledExecutorService sendDownlinkExecutorService) {
+ Consumer sessionCloseListener, ScheduledExecutorService sendDownlinkExecutorService) {
this.sessionId = UUID.randomUUID();
this.ctx = ctx;
this.outputStream = outputStream;
this.sessionOpenListener = sessionOpenListener;
this.sessionCloseListener = sessionCloseListener;
- this.mapper = mapper;
this.sendDownlinkExecutorService = sendDownlinkExecutorService;
initInputStream();
}
@@ -402,11 +399,11 @@ public final class EdgeGrpcSession implements Closeable {
Runnable sendDownlinkMsgsTask = () -> {
try {
if (isConnected() && sessionState.getPendingMsgsMap().values().size() > 0) {
+ List copy = new ArrayList<>(sessionState.getPendingMsgsMap().values());
if (!firstRun) {
- log.warn("[{}] Failed to deliver the batch: {}", this.sessionId, sessionState.getPendingMsgsMap().values());
+ log.warn("[{}] Failed to deliver the batch: {}", this.sessionId, copy);
}
- log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, sessionState.getPendingMsgsMap().values().size());
- List copy = new ArrayList<>(sessionState.getPendingMsgsMap().values());
+ log.trace("[{}] [{}] downlink msg(s) are going to be send.", this.sessionId, copy.size());
for (DownlinkMsg downlinkMsg : copy) {
sendDownlinkMsg(ResponseMsg.newBuilder()
.setDownlinkMsg(downlinkMsg)
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
index 51b84d6a94..0f4ecf7e30 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AdminSettingsEdgeEventFetcher.java
@@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.thingsboard.server.common.data.AdminSettings;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -35,7 +36,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.settings.AdminSettingsService;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -80,19 +80,19 @@ public class AdminSettingsEdgeEventFetcher implements EdgeEventFetcher {
List result = new ArrayList<>();
AdminSettings systemMailSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "mail");
- result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailSettings)));
AdminSettings tenantMailSettings = convertToTenantAdminSettings(systemMailSettings.getKey(), (ObjectNode) systemMailSettings.getJsonValue());
- result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailSettings)));
AdminSettings systemMailTemplates = loadMailTemplates();
- result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(systemMailTemplates)));
AdminSettings tenantMailTemplates = convertToTenantAdminSettings(systemMailTemplates.getKey(), (ObjectNode) systemMailTemplates.getJsonValue());
- result.add(EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
+ result.add(EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ADMIN_SETTINGS,
EdgeEventActionType.UPDATED, null, mapper.valueToTree(tenantMailTemplates)));
// @voba - returns PageData object to be in sync with other fetchers
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java
index e66cafda56..ead87638fb 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/AssetsEdgeEventFetcher.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.asset.AssetService;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@AllArgsConstructor
@Slf4j
@@ -41,7 +41,7 @@ public class AssetsEdgeEventFetcher extends BasePageableEdgeEventFetcher
@Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, Asset asset) {
- return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET,
+ return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.ASSET,
EdgeEventActionType.ADDED, asset.getId(), null);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java
index 606cd6eaca..6791ba69a6 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseUsersEdgeEventFetcher.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.user.UserService;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@Slf4j
@AllArgsConstructor
@@ -41,7 +41,7 @@ public abstract class BaseUsersEdgeEventFetcher extends BasePageableEdgeEventFet
@Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, User user) {
- return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
+ return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
EdgeEventActionType.ADDED, user.getId(), null);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java
index 3f8beb861d..709c438739 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/BaseWidgetsBundlesEdgeEventFetcher.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.widget.WidgetsBundle;
import org.thingsboard.server.dao.widget.WidgetsBundleService;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@Slf4j
@AllArgsConstructor
@@ -41,7 +41,7 @@ public abstract class BaseWidgetsBundlesEdgeEventFetcher extends BasePageableEdg
@Override
EdgeEvent constructEdgeEvent(TenantId tenantId, Edge edge, WidgetsBundle widgetsBundle) {
- return EdgeEventUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE,
+ return EdgeUtils.constructEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGETS_BUNDLE,
EdgeEventActionType.ADDED, widgetsBundle.getId(), null);
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java
index adaac874a0..1d5c618a0a 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/CustomerEdgeEventFetcher.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -24,7 +25,6 @@ import org.thingsboard.server.common.data.edge.EdgeEventType;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import java.util.ArrayList;
import java.util.List;
@@ -41,7 +41,7 @@ public class CustomerEdgeEventFetcher implements EdgeEventFetcher {
@Override
public PageData fetchEdgeEvents(TenantId tenantId, Edge edge, PageLink pageLink) {
List result = new ArrayList<>();
- result.add(EdgeEventUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(),
+ result.add(EdgeUtils.constructEdgeEvent(edge.getTenantId(), edge.getId(),
EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, edge.getCustomerId(), null));
// @voba - returns PageData object to be in sync with other fetchers
return new PageData<>(result, 1, result.size(), false);
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java
index f46ab01ee5..a6e7b3307c 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/DashboardsEdgeEventFetcher.java
@@ -18,6 +18,7 @@ package org.thingsboard.server.service.edge.rpc.fetch;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.thingsboard.server.common.data.DashboardInfo;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
import org.thingsboard.server.common.data.edge.EdgeEventActionType;
@@ -26,7 +27,6 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.dao.dashboard.DashboardService;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
@AllArgsConstructor
@Slf4j
@@ -41,7 +41,7 @@ public class DashboardsEdgeEventFetcher extends BasePageableEdgeEventFetcher processAlarmNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
AlarmId alarmId = new AlarmId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
switch (actionType) {
case DELETED:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
- Alarm alarm = mapper.readValue(edgeNotificationMsg.getBody(), Alarm.class);
- saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, mapper.valueToTree(alarm));
- break;
+ Alarm deletedAlarm = mapper.readValue(edgeNotificationMsg.getBody(), Alarm.class);
+ return saveEdgeEvent(tenantId, edgeId, EdgeEventType.ALARM, actionType, alarmId, mapper.valueToTree(deletedAlarm));
default:
ListenableFuture alarmFuture = alarmService.findAlarmByIdAsync(tenantId, alarmId);
- Futures.addCallback(alarmFuture, new FutureCallback() {
- @Override
- public void onSuccess(@Nullable Alarm alarm) {
- if (alarm != null) {
- EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());
- if (type != null) {
- PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
- PageData pageData;
- do {
- pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
- if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
- for (EdgeId edgeId : pageData.getData()) {
- saveEdgeEvent(tenantId,
- edgeId,
- EdgeEventType.ALARM,
- EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
- alarmId,
- null);
- }
- if (pageData.hasNext()) {
- pageLink = pageLink.nextPageLink();
- }
- }
- } while (pageData != null && pageData.hasNext());
- }
- }
+ return Futures.transformAsync(alarmFuture, alarm -> {
+ if (alarm == null) {
+ return Futures.immediateFuture(null);
}
-
- @Override
- public void onFailure(Throwable t) {
- log.warn("[{}] can't find alarm by id [{}] {}", tenantId.getId(), alarmId.getId(), t);
+ EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(alarm.getOriginator().getEntityType());
+ if (type == null) {
+ return Futures.immediateFuture(null);
}
+ PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
+ PageData pageData;
+ List> futures = new ArrayList<>();
+ do {
+ pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, alarm.getOriginator(), pageLink);
+ if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
+ for (EdgeId relatedEdgeId : pageData.getData()) {
+ futures.add(saveEdgeEvent(tenantId,
+ relatedEdgeId,
+ EdgeEventType.ALARM,
+ EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
+ alarmId,
+ null));
+ }
+ if (pageData.hasNext()) {
+ pageLink = pageLink.nextPageLink();
+ }
+ }
+ } while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}, dbCallbackExecutorService);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
index 10d1ae88c5..09bef32af9 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java
@@ -17,10 +17,13 @@ package org.thingsboard.server.service.edge.rpc.processor;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EdgeUtils;
import org.thingsboard.server.common.data.HasCustomerId;
import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeEvent;
@@ -67,6 +70,9 @@ import org.thingsboard.server.service.executors.DbCallbackExecutorService;
import org.thingsboard.server.service.profile.TbDeviceProfileCache;
import org.thingsboard.server.service.state.DeviceStateService;
+import java.util.ArrayList;
+import java.util.List;
+
@Slf4j
public abstract class BaseEdgeProcessor {
@@ -179,27 +185,22 @@ public abstract class BaseEdgeProcessor {
@Autowired
protected DbCallbackExecutorService dbCallbackExecutorService;
- protected void saveEdgeEvent(TenantId tenantId,
- EdgeId edgeId,
- EdgeEventType type,
- EdgeEventActionType action,
- EntityId entityId,
- JsonNode body) {
+ protected ListenableFuture saveEdgeEvent(TenantId tenantId,
+ EdgeId edgeId,
+ EdgeEventType type,
+ EdgeEventActionType action,
+ EntityId entityId,
+ JsonNode body) {
log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " +
"action [{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
- EdgeEvent edgeEvent = new EdgeEvent();
- edgeEvent.setTenantId(tenantId);
- edgeEvent.setEdgeId(edgeId);
- edgeEvent.setType(type);
- edgeEvent.setAction(action);
- if (entityId != null) {
- edgeEvent.setEntityId(entityId.getId());
- }
- edgeEvent.setBody(body);
- edgeEventService.save(edgeEvent);
- tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
+ EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
+
+ return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
+ tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
+ return null;
+ }, dbCallbackExecutorService);
}
protected CustomerId getCustomerIdIfEdgeAssignedToCustomer(HasCustomerId hasCustomerIdEntity, Edge edge) {
@@ -210,19 +211,21 @@ public abstract class BaseEdgeProcessor {
}
}
- protected void processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
+ protected ListenableFuture processActionForAllEdges(TenantId tenantId, EdgeEventType type, EdgeEventActionType actionType, EntityId entityId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
+ List> futures = new ArrayList<>();
do {
pageData = edgeService.findEdgesByTenantId(tenantId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (Edge edge : pageData.getData()) {
- saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null);
+ futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, entityId, null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java
index 6c670e47ce..3554057482 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/CustomerEdgeProcessor.java
@@ -15,6 +15,8 @@
*/
package org.thingsboard.server.service.edge.rpc.processor;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Customer;
@@ -35,6 +37,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
@Component
@@ -70,7 +74,7 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public void processCustomerNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
+ public ListenableFuture processCustomerNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
UUID uuid = new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB());
@@ -79,22 +83,24 @@ public class CustomerEdgeProcessor extends BaseEdgeProcessor {
case UPDATED:
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
+ List> futures = new ArrayList<>();
do {
pageData = edgeService.findEdgesByTenantIdAndCustomerId(tenantId, customerId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (Edge edge : pageData.getData()) {
- saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null);
+ futures.add(saveEdgeEvent(tenantId, edge.getId(), type, actionType, customerId, null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
- break;
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
case DELETED:
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
- saveEdgeEvent(tenantId, edgeId, type, actionType, customerId, null);
- break;
+ return saveEdgeEvent(tenantId, edgeId, type, actionType, customerId, null);
+ default:
+ return Futures.immediateFuture(null);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java
index f19ec25b27..0e1dee7132 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/DeviceEdgeProcessor.java
@@ -84,7 +84,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
if (deviceAlreadyExistsForThisEdge) {
log.info("[{}] Device with name '{}' already exists on the cloud, and related to this edge [{}]. " +
"deviceUpdateMsg [{}], Updating device", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
- updateDevice(tenantId, edge, deviceUpdateMsg);
+ return updateDevice(tenantId, edge, deviceUpdateMsg);
} else {
log.info("[{}] Device with name '{}' already exists on the cloud, but not related to this edge [{}]. deviceUpdateMsg [{}]." +
"Creating a new device with random prefix and relate to this edge", tenantId, deviceName, edge.getId(), deviceUpdateMsg);
@@ -99,8 +99,10 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
}
ObjectNode body = mapper.createObjectNode();
body.put("conflictName", deviceName);
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body);
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null);
+ ListenableFuture input = saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ENTITY_MERGE_REQUEST, newDevice.getId(), body);
+ return Futures.transformAsync(input, unused ->
+ saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, newDevice.getId(), null),
+ dbCallbackExecutorService);
}
} else {
log.info("[{}] Creating new device and replacing device entity on the edge [{}]", tenantId, deviceUpdateMsg);
@@ -111,24 +113,22 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
log.error(errMsg, e);
return Futures.immediateFuture(null);
}
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, device.getId(), null);
+ return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, device.getId(), null);
}
- break;
case ENTITY_UPDATED_RPC_MESSAGE:
- updateDevice(tenantId, edge, deviceUpdateMsg);
- break;
+ return updateDevice(tenantId, edge, deviceUpdateMsg);
case ENTITY_DELETED_RPC_MESSAGE:
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
Device deviceToDelete = deviceService.findDeviceById(tenantId, deviceId);
if (deviceToDelete != null) {
deviceService.unassignDeviceFromEdge(tenantId, deviceId, edge.getId());
}
- break;
+ return Futures.immediateFuture(null);
case UNRECOGNIZED:
+ default:
log.error("Unsupported msg type {}", deviceUpdateMsg.getMsgType());
return Futures.immediateFailedFuture(new RuntimeException("Unsupported msg type " + deviceUpdateMsg.getMsgType()));
}
- return Futures.immediateFuture(null);
}
private boolean isDeviceAlreadyExistsOnCloudForThisEdge(TenantId tenantId, Edge edge, Device device) {
@@ -174,7 +174,7 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
}
- private void updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
+ private ListenableFuture updateDevice(TenantId tenantId, Edge edge, DeviceUpdateMsg deviceUpdateMsg) {
DeviceId deviceId = new DeviceId(new UUID(deviceUpdateMsg.getIdMSB(), deviceUpdateMsg.getIdLSB()));
Device device = deviceService.findDeviceById(tenantId, deviceId);
if (device != null) {
@@ -194,9 +194,11 @@ public class DeviceEdgeProcessor extends BaseEdgeProcessor {
}
Device savedDevice = deviceService.saveDevice(device);
tbClusterService.onDeviceUpdated(savedDevice, device);
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
+ return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.CREDENTIALS_REQUEST, deviceId, null);
} else {
- log.warn("[{}] can't find device [{}], edge [{}]", tenantId, deviceUpdateMsg, edge.getId());
+ String errMsg = String.format("[%s] can't find device [%s], edge [%s]", tenantId, deviceUpdateMsg, edge.getId());
+ log.warn(errMsg);
+ return Futures.immediateFailedFuture(new RuntimeException(errMsg));
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java
index 3d662da232..fdbebafc98 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EdgeProcessor.java
@@ -15,11 +15,9 @@
*/
package org.thingsboard.server.service.edge.rpc.processor;
-import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
-import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.edge.Edge;
@@ -33,6 +31,8 @@ import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import java.util.ArrayList;
+import java.util.List;
import java.util.UUID;
@Component
@@ -40,7 +40,7 @@ import java.util.UUID;
@TbCoreComponent
public class EdgeProcessor extends BaseEdgeProcessor {
- public void processEdgeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
+ public ListenableFuture processEdgeNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
try {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeId edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
@@ -49,54 +49,43 @@ public class EdgeProcessor extends BaseEdgeProcessor {
case ASSIGNED_TO_CUSTOMER:
CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
- Futures.addCallback(edgeFuture, new FutureCallback() {
- @Override
- public void onSuccess(@Nullable Edge edge) {
- if (edge != null && !customerId.isNullUid()) {
- saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null);
- PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
- PageData pageData;
- do {
- pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
- if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
- log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
- for (User user : pageData.getData()) {
- saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null);
- }
- if (pageData.hasNext()) {
- pageLink = pageLink.nextPageLink();
- }
- }
- } while (pageData != null && pageData.hasNext());
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
+ return Futures.transformAsync(edgeFuture, edge -> {
+ if (edge == null || customerId.isNullUid()) {
+ return Futures.immediateFuture(null);
}
+ List> futures = new ArrayList<>();
+ futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.ADDED, customerId, null));
+ PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
+ PageData pageData;
+ do {
+ pageData = userService.findCustomerUsers(tenantId, customerId, pageLink);
+ if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
+ log.trace("[{}] [{}] user(s) are going to be added to edge.", edge.getId(), pageData.getData().size());
+ for (User user : pageData.getData()) {
+ futures.add(saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.USER, EdgeEventActionType.ADDED, user.getId(), null));
+ }
+ if (pageData.hasNext()) {
+ pageLink = pageLink.nextPageLink();
+ }
+ }
+ } while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}, dbCallbackExecutorService);
- break;
case UNASSIGNED_FROM_CUSTOMER:
CustomerId customerIdToDelete = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
edgeFuture = edgeService.findEdgeByIdAsync(tenantId, edgeId);
- Futures.addCallback(edgeFuture, new FutureCallback() {
- @Override
- public void onSuccess(@Nullable Edge edge) {
- if (edge != null && !customerIdToDelete.isNullUid()) {
- saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null);
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- log.error("Can't find edge by id [{}]", edgeNotificationMsg, t);
+ return Futures.transformAsync(edgeFuture, edge -> {
+ if (edge == null || customerIdToDelete.isNullUid()) {
+ return Futures.immediateFuture(null);
}
+ return saveEdgeEvent(edge.getTenantId(), edge.getId(), EdgeEventType.CUSTOMER, EdgeEventActionType.DELETED, customerIdToDelete, null);
}, dbCallbackExecutorService);
- break;
+ default:
+ return Futures.immediateFuture(null);
}
} catch (Exception e) {
log.error("Exception during processing edge event", e);
+ return Futures.immediateFailedFuture(e);
}
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java
index 89ce662467..195f932b93 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/EntityEdgeProcessor.java
@@ -15,11 +15,9 @@
*/
package org.thingsboard.server.service.edge.rpc.processor;
-import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import lombok.extern.slf4j.Slf4j;
-import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EdgeUtils;
@@ -45,6 +43,7 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType;
import org.thingsboard.server.gen.transport.TransportProtos;
import org.thingsboard.server.queue.util.TbCoreComponent;
+import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -89,92 +88,107 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
return downlinkMsg;
}
- public void processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
+ public ListenableFuture processEntityNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type,
new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
- EdgeId edgeId = null;
- if (edgeNotificationMsg.getEdgeIdMSB() != 0 && edgeNotificationMsg.getEdgeIdLSB() != 0) {
- edgeId = new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
- }
+ EdgeId edgeId = safeGetEdgeId(edgeNotificationMsg);
switch (actionType) {
case ADDED: // used only for USER entity
case UPDATED:
case CREDENTIALS_UPDATED:
- pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
- break;
+ return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
case ASSIGNED_TO_CUSTOMER:
case UNASSIGNED_FROM_CUSTOMER:
- PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
- PageData pageData;
- do {
- pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
- if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
- for (EdgeId relatedEdgeId : pageData.getData()) {
- try {
- CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
- ListenableFuture future = edgeService.findEdgeByIdAsync(tenantId, relatedEdgeId);
- Futures.addCallback(future, new FutureCallback<>() {
- @Override
- public void onSuccess(@Nullable Edge edge) {
- if (edge != null && edge.getCustomerId() != null &&
- !edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) {
- saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null);
- }
- }
-
- @Override
- public void onFailure(Throwable t) {
- log.error("Failed to find edge by id [{}] {}", edgeNotificationMsg, t);
- }
- }, dbCallbackExecutorService);
- } catch (Exception e) {
- log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e);
- }
- }
- if (pageData.hasNext()) {
- pageLink = pageLink.nextPageLink();
- }
- }
- } while (pageData != null && pageData.hasNext());
- break;
+ return pushNotificationToAllRelatedCustomerEdges(tenantId, edgeNotificationMsg, entityId, actionType, type);
case DELETED:
if (edgeId != null) {
- saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
+ return saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
} else {
- pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
+ return pushNotificationToAllRelatedEdges(tenantId, entityId, type, actionType);
}
- break;
case ASSIGNED_TO_EDGE:
case UNASSIGNED_FROM_EDGE:
- saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
- if (type.equals(EdgeEventType.RULE_CHAIN)) {
- updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
+ ListenableFuture future = saveEdgeEvent(tenantId, edgeId, type, actionType, entityId, null);
+ return Futures.transformAsync(future, unused -> {
+ if (type.equals(EdgeEventType.RULE_CHAIN)) {
+ return updateDependentRuleChains(tenantId, new RuleChainId(entityId.getId()), edgeId);
+ } else {
+ return Futures.immediateFuture(null);
+ }
+ }, dbCallbackExecutorService);
+ default:
+ return Futures.immediateFuture(null);
+ }
+ }
+
+ private ListenableFuture pushNotificationToAllRelatedCustomerEdges(TenantId tenantId,
+ TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg,
+ EntityId entityId,
+ EdgeEventActionType actionType,
+ EdgeEventType type) {
+ PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
+ PageData pageData;
+ List> futures = new ArrayList<>();
+ do {
+ pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
+ if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
+ for (EdgeId relatedEdgeId : pageData.getData()) {
+ try {
+ CustomerId customerId = mapper.readValue(edgeNotificationMsg.getBody(), CustomerId.class);
+ ListenableFuture future = edgeService.findEdgeByIdAsync(tenantId, relatedEdgeId);
+ futures.add(Futures.transformAsync(future, edge -> {
+ if (edge != null && edge.getCustomerId() != null &&
+ !edge.getCustomerId().isNullUid() && edge.getCustomerId().equals(customerId)) {
+ return saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null);
+ } else {
+ return Futures.immediateFuture(null);
+ }
+ }, dbCallbackExecutorService));
+ } catch (Exception e) {
+ log.error("Can't parse customer id from entity body [{}]", edgeNotificationMsg, e);
+ return Futures.immediateFailedFuture(e);
+ }
}
- break;
+ if (pageData.hasNext()) {
+ pageLink = pageLink.nextPageLink();
+ }
+ }
+ } while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
+ }
+
+ private EdgeId safeGetEdgeId(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
+ if (edgeNotificationMsg.getEdgeIdMSB() != 0 && edgeNotificationMsg.getEdgeIdLSB() != 0) {
+ return new EdgeId(new UUID(edgeNotificationMsg.getEdgeIdMSB(), edgeNotificationMsg.getEdgeIdLSB()));
+ } else {
+ return null;
}
}
- private void pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) {
+ private ListenableFuture pushNotificationToAllRelatedEdges(TenantId tenantId, EntityId entityId, EdgeEventType type, EdgeEventActionType actionType) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
+ List> futures = new ArrayList<>();
do {
pageData = edgeService.findRelatedEdgeIdsByEntityId(tenantId, entityId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
for (EdgeId relatedEdgeId : pageData.getData()) {
- saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null);
+ futures.add(saveEdgeEvent(tenantId, relatedEdgeId, type, actionType, entityId, null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
}
} while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
- private void updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
+ private ListenableFuture updateDependentRuleChains(TenantId tenantId, RuleChainId processingRuleChainId, EdgeId edgeId) {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
+ List> futures = new ArrayList<>();
do {
pageData = ruleChainService.findRuleChainsByTenantIdAndEdgeId(tenantId, edgeId, pageLink);
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
@@ -185,12 +199,12 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
if (connectionInfos != null && !connectionInfos.isEmpty()) {
for (RuleChainConnectionInfo connectionInfo : connectionInfos) {
if (connectionInfo.getTargetRuleChainId().equals(processingRuleChainId)) {
- saveEdgeEvent(tenantId,
+ futures.add(saveEdgeEvent(tenantId,
edgeId,
EdgeEventType.RULE_CHAIN_METADATA,
EdgeEventActionType.UPDATED,
ruleChain.getId(),
- null);
+ null));
}
}
}
@@ -201,9 +215,10 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
}
}
} while (pageData != null && pageData.hasNext());
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
- public void processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
+ public ListenableFuture processEntityNotificationForAllEdges(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) {
EdgeEventActionType actionType = EdgeEventActionType.valueOf(edgeNotificationMsg.getAction());
EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType());
EntityId entityId = EntityIdFactory.getByEdgeEventTypeAndUuid(type, new UUID(edgeNotificationMsg.getEntityIdMSB(), edgeNotificationMsg.getEntityIdLSB()));
@@ -211,8 +226,9 @@ public class EntityEdgeProcessor extends BaseEdgeProcessor {
case ADDED:
case UPDATED:
case DELETED:
- processActionForAllEdges(tenantId, type, actionType, entityId);
- break;
+ return processActionForAllEdges(tenantId, type, actionType, entityId);
+ default:
+ return Futures.immediateFuture(null);
}
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java
index d49ac7094c..f86ea8aad2 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/RelationEdgeProcessor.java
@@ -126,24 +126,29 @@ public class RelationEdgeProcessor extends BaseEdgeProcessor {
.build();
}
- public void processRelationNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
+ public ListenableFuture processRelationNotification(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg) throws JsonProcessingException {
EntityRelation relation = mapper.readValue(edgeNotificationMsg.getBody(), EntityRelation.class);
- if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
- !relation.getTo().getEntityType().equals(EntityType.EDGE)) {
- Set uniqueEdgeIds = new HashSet<>();
- uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getTo()));
- uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getFrom()));
- if (!uniqueEdgeIds.isEmpty()) {
- for (EdgeId edgeId : uniqueEdgeIds) {
- saveEdgeEvent(tenantId,
- edgeId,
- EdgeEventType.RELATION,
- EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
- null,
- mapper.valueToTree(relation));
- }
- }
+ if (relation.getFrom().getEntityType().equals(EntityType.EDGE) ||
+ relation.getTo().getEntityType().equals(EntityType.EDGE)) {
+ return Futures.immediateFuture(null);
+ }
+
+ Set uniqueEdgeIds = new HashSet<>();
+ uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getTo()));
+ uniqueEdgeIds.addAll(findRelatedEdgeIds(tenantId, relation.getFrom()));
+ if (uniqueEdgeIds.isEmpty()) {
+ return Futures.immediateFuture(null);
+ }
+ List> futures = new ArrayList<>();
+ for (EdgeId edgeId : uniqueEdgeIds) {
+ futures.add(saveEdgeEvent(tenantId,
+ edgeId,
+ EdgeEventType.RELATION,
+ EdgeEventActionType.valueOf(edgeNotificationMsg.getAction()),
+ null,
+ mapper.valueToTree(relation)));
}
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
private List findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
index d69133434a..9d87cabb2c 100644
--- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
+++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/sync/DefaultEdgeRequestsService.java
@@ -26,6 +26,7 @@ import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import org.thingsboard.server.cluster.TbClusterService;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.DeviceProfile;
import org.thingsboard.server.common.data.EdgeUtils;
@@ -71,9 +72,7 @@ import org.thingsboard.server.gen.edge.v1.RelationRequestMsg;
import org.thingsboard.server.gen.edge.v1.RuleChainMetadataRequestMsg;
import org.thingsboard.server.gen.edge.v1.UserCredentialsRequestMsg;
import org.thingsboard.server.gen.edge.v1.WidgetBundleTypesRequestMsg;
-import org.thingsboard.server.service.edge.rpc.EdgeEventUtils;
import org.thingsboard.server.service.executors.DbCallbackExecutorService;
-import org.thingsboard.server.cluster.TbClusterService;
import java.util.ArrayList;
import java.util.HashMap;
@@ -122,13 +121,13 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override
public ListenableFuture processRuleChainMetadataRequestMsg(TenantId tenantId, Edge edge, RuleChainMetadataRequestMsg ruleChainMetadataRequestMsg) {
log.trace("[{}] processRuleChainMetadataRequestMsg [{}][{}]", tenantId, edge.getName(), ruleChainMetadataRequestMsg);
- if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() != 0 && ruleChainMetadataRequestMsg.getRuleChainIdLSB() != 0) {
- RuleChainId ruleChainId =
- new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
- saveEdgeEvent(tenantId, edge.getId(),
- EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null);
+ if (ruleChainMetadataRequestMsg.getRuleChainIdMSB() == 0 || ruleChainMetadataRequestMsg.getRuleChainIdLSB() == 0) {
+ return Futures.immediateFuture(null);
}
- return Futures.immediateFuture(null);
+ RuleChainId ruleChainId =
+ new RuleChainId(new UUID(ruleChainMetadataRequestMsg.getRuleChainIdMSB(), ruleChainMetadataRequestMsg.getRuleChainIdLSB()));
+ return saveEdgeEvent(tenantId, edge.getId(),
+ EdgeEventType.RULE_CHAIN_METADATA, EdgeEventActionType.ADDED, ruleChainId, null);
}
@Override
@@ -138,63 +137,72 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
EntityType.valueOf(attributesRequestMsg.getEntityType()),
new UUID(attributesRequestMsg.getEntityIdMSB(), attributesRequestMsg.getEntityIdLSB()));
final EdgeEventType type = EdgeUtils.getEdgeEventTypeByEntityType(entityId.getEntityType());
- if (type != null) {
- SettableFuture futureToSet = SettableFuture.create();
- String scope = attributesRequestMsg.getScope();
- ListenableFuture> findAttrFuture = attributesService.findAll(tenantId, entityId, scope);
- Futures.addCallback(findAttrFuture, new FutureCallback>() {
- @Override
- public void onSuccess(@Nullable List ssAttributes) {
- if (ssAttributes != null && !ssAttributes.isEmpty()) {
- try {
- Map entityData = new HashMap<>();
- ObjectNode attributes = mapper.createObjectNode();
- for (AttributeKvEntry attr : ssAttributes) {
- if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
- attributes.put(attr.getKey(), attr.getBooleanValue().get());
- } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
- attributes.put(attr.getKey(), attr.getDoubleValue().get());
- } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
- attributes.put(attr.getKey(), attr.getLongValue().get());
- } else {
- attributes.put(attr.getKey(), attr.getValueAsString());
- }
- }
- entityData.put("kv", attributes);
- entityData.put("scope", scope);
- JsonNode body = mapper.valueToTree(entityData);
- log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
- saveEdgeEvent(tenantId,
- edge.getId(),
- type,
- EdgeEventActionType.ATTRIBUTES_UPDATED,
- entityId,
- body);
- } catch (Exception e) {
- log.error("[{}] Failed to save attribute updates to the edge", edge.getName(), e);
- futureToSet.setException(new RuntimeException("[" + edge.getName() + "] Failed to send attribute updates to the edge", e));
- return;
- }
- } else {
- log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId,
- edge.getName(),
- entityId.getEntityType(),
- entityId.getId());
- }
+ if (type == null) {
+ log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType());
+ return Futures.immediateFuture(null);
+ }
+ SettableFuture futureToSet = SettableFuture.create();
+ String scope = attributesRequestMsg.getScope();
+ ListenableFuture> findAttrFuture = attributesService.findAll(tenantId, entityId, scope);
+ Futures.addCallback(findAttrFuture, new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable List ssAttributes) {
+ if (ssAttributes == null || ssAttributes.isEmpty()) {
+ log.trace("[{}][{}] No attributes found for entity {} [{}]", tenantId,
+ edge.getName(),
+ entityId.getEntityType(),
+ entityId.getId());
futureToSet.set(null);
+ return;
}
- @Override
- public void onFailure(Throwable t) {
- log.error("Can't find attributes [{}]", attributesRequestMsg, t);
- futureToSet.setException(t);
+ try {
+ Map entityData = new HashMap<>();
+ ObjectNode attributes = mapper.createObjectNode();
+ for (AttributeKvEntry attr : ssAttributes) {
+ if (attr.getDataType() == DataType.BOOLEAN && attr.getBooleanValue().isPresent()) {
+ attributes.put(attr.getKey(), attr.getBooleanValue().get());
+ } else if (attr.getDataType() == DataType.DOUBLE && attr.getDoubleValue().isPresent()) {
+ attributes.put(attr.getKey(), attr.getDoubleValue().get());
+ } else if (attr.getDataType() == DataType.LONG && attr.getLongValue().isPresent()) {
+ attributes.put(attr.getKey(), attr.getLongValue().get());
+ } else {
+ attributes.put(attr.getKey(), attr.getValueAsString());
+ }
+ }
+ entityData.put("kv", attributes);
+ entityData.put("scope", scope);
+ JsonNode body = mapper.valueToTree(entityData);
+ log.debug("Sending attributes data msg, entityId [{}], attributes [{}]", entityId, body);
+ ListenableFuture future = saveEdgeEvent(tenantId, edge.getId(), type, EdgeEventActionType.ATTRIBUTES_UPDATED, entityId, body);
+ Futures.addCallback(future, new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable Void unused) {
+ futureToSet.set(null);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ String errMsg = String.format("[%s] Failed to save edge event [%s]", edge.getId(), attributesRequestMsg);
+ log.error(errMsg, throwable);
+ futureToSet.setException(new RuntimeException(errMsg, throwable));
+ }
+ }, dbCallbackExecutorService);
+ } catch (Exception e) {
+ String errMsg = String.format("[%s] Failed to save attribute updates to the edge [%s]", edge.getId(), attributesRequestMsg);
+ log.error(errMsg, e);
+ futureToSet.setException(new RuntimeException(errMsg, e));
}
- }, dbCallbackExecutorService);
- return futureToSet;
- } else {
- log.warn("[{}] Type doesn't supported {}", tenantId, entityId.getEntityType());
- return Futures.immediateFuture(null);
- }
+ }
+
+ @Override
+ public void onFailure(Throwable t) {
+ String errMsg = String.format("[%s] Can't find attributes [%s]", edge.getId(), attributesRequestMsg);
+ log.error(errMsg, t);
+ futureToSet.setException(new RuntimeException(errMsg, t));
+ }
+ }, dbCallbackExecutorService);
+ return futureToSet;
}
@Override
@@ -209,33 +217,49 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
futures.add(findRelationByQuery(tenantId, edge, entityId, EntitySearchDirection.TO));
ListenableFuture>> relationsListFuture = Futures.allAsList(futures);
SettableFuture futureToSet = SettableFuture.create();
- Futures.addCallback(relationsListFuture, new FutureCallback>>() {
+ Futures.addCallback(relationsListFuture, new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List> relationsList) {
try {
if (relationsList != null && !relationsList.isEmpty()) {
+ List> futures = new ArrayList<>();
for (List entityRelations : relationsList) {
log.trace("[{}] [{}] [{}] relation(s) are going to be pushed to edge.", edge.getId(), entityId, entityRelations.size());
for (EntityRelation relation : entityRelations) {
try {
if (!relation.getFrom().getEntityType().equals(EntityType.EDGE) &&
!relation.getTo().getEntityType().equals(EntityType.EDGE)) {
- saveEdgeEvent(tenantId,
+ futures.add(saveEdgeEvent(tenantId,
edge.getId(),
EdgeEventType.RELATION,
EdgeEventActionType.ADDED,
null,
- mapper.valueToTree(relation));
+ mapper.valueToTree(relation)));
}
} catch (Exception e) {
- log.error("Exception during loading relation [{}] to edge on sync!", relation, e);
- futureToSet.setException(e);
+ String errMsg = String.format("[%s] Exception during loading relation [%s] to edge on sync!", edge.getId(), relation);
+ log.error(errMsg, e);
+ futureToSet.setException(new RuntimeException(errMsg, e));
return;
}
}
}
+ Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable List voids) {
+ futureToSet.set(null);
+ }
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ String errMsg = String.format("[%s] Exception during saving edge events [%s]!", edge.getId(), relationRequestMsg);
+ log.error(errMsg, throwable);
+ futureToSet.setException(new RuntimeException(errMsg, throwable));
+ }
+ }, dbCallbackExecutorService);
+ } else {
+ futureToSet.set(null);
}
- futureToSet.set(null);
} catch (Exception e) {
log.error("Exception during loading relation(s) to edge on sync!", e);
futureToSet.setException(e);
@@ -244,8 +268,9 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override
public void onFailure(Throwable t) {
- log.error("[{}] Can't find relation by query. Entity id [{}]", tenantId, entityId, t);
- futureToSet.setException(t);
+ String errMsg = String.format("[%s] Can't find relation by query. Entity id [%s]!", tenantId, entityId);
+ log.error(errMsg, t);
+ futureToSet.setException(new RuntimeException(errMsg, t));
}
}, dbCallbackExecutorService);
return futureToSet;
@@ -261,40 +286,42 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
@Override
public ListenableFuture processDeviceCredentialsRequestMsg(TenantId tenantId, Edge edge, DeviceCredentialsRequestMsg deviceCredentialsRequestMsg) {
log.trace("[{}] processDeviceCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), deviceCredentialsRequestMsg);
- if (deviceCredentialsRequestMsg.getDeviceIdMSB() != 0 && deviceCredentialsRequestMsg.getDeviceIdLSB() != 0) {
- DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE,
- EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null);
+ if (deviceCredentialsRequestMsg.getDeviceIdMSB() == 0 || deviceCredentialsRequestMsg.getDeviceIdLSB() == 0) {
+ return Futures.immediateFuture(null);
}
- return Futures.immediateFuture(null);
+ DeviceId deviceId = new DeviceId(new UUID(deviceCredentialsRequestMsg.getDeviceIdMSB(), deviceCredentialsRequestMsg.getDeviceIdLSB()));
+ return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE,
+ EdgeEventActionType.CREDENTIALS_UPDATED, deviceId, null);
}
@Override
public ListenableFuture processUserCredentialsRequestMsg(TenantId tenantId, Edge edge, UserCredentialsRequestMsg userCredentialsRequestMsg) {
log.trace("[{}] processUserCredentialsRequestMsg [{}][{}]", tenantId, edge.getName(), userCredentialsRequestMsg);
- if (userCredentialsRequestMsg.getUserIdMSB() != 0 && userCredentialsRequestMsg.getUserIdLSB() != 0) {
- UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
- EdgeEventActionType.CREDENTIALS_UPDATED, userId, null);
+ if (userCredentialsRequestMsg.getUserIdMSB() == 0 || userCredentialsRequestMsg.getUserIdLSB() == 0) {
+ return Futures.immediateFuture(null);
}
- return Futures.immediateFuture(null);
+ UserId userId = new UserId(new UUID(userCredentialsRequestMsg.getUserIdMSB(), userCredentialsRequestMsg.getUserIdLSB()));
+ return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.USER,
+ EdgeEventActionType.CREDENTIALS_UPDATED, userId, null);
}
@Override
public ListenableFuture processDeviceProfileDevicesRequestMsg(TenantId tenantId, Edge edge, DeviceProfileDevicesRequestMsg deviceProfileDevicesRequestMsg) {
log.trace("[{}] processDeviceProfileDevicesRequestMsg [{}][{}]", tenantId, edge.getName(), deviceProfileDevicesRequestMsg);
- if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() != 0 && deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() != 0) {
- DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB()));
- DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
- if (deviceProfileById != null) {
- syncDevices(tenantId, edge, deviceProfileById.getName());
- }
+ if (deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB() == 0 || deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB() == 0) {
+ return Futures.immediateFuture(null);
+ }
+ DeviceProfileId deviceProfileId = new DeviceProfileId(new UUID(deviceProfileDevicesRequestMsg.getDeviceProfileIdMSB(), deviceProfileDevicesRequestMsg.getDeviceProfileIdLSB()));
+ DeviceProfile deviceProfileById = deviceProfileService.findDeviceProfileById(tenantId, deviceProfileId);
+ if (deviceProfileById == null) {
+ return Futures.immediateFuture(null);
}
- return Futures.immediateFuture(null);
+ return syncDevices(tenantId, edge, deviceProfileById.getName());
}
- private void syncDevices(TenantId tenantId, Edge edge, String deviceType) {
+ private ListenableFuture syncDevices(TenantId tenantId, Edge edge, String deviceType) {
log.trace("[{}] syncDevices [{}][{}]", tenantId, edge.getName(), deviceType);
+ List> futures = new ArrayList<>();
try {
PageLink pageLink = new PageLink(DEFAULT_PAGE_SIZE);
PageData pageData;
@@ -303,7 +330,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
if (pageData != null && pageData.getData() != null && !pageData.getData().isEmpty()) {
log.trace("[{}] [{}] device(s) are going to be pushed to edge.", edge.getId(), pageData.getData().size());
for (Device device : pageData.getData()) {
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null);
+ futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.DEVICE, EdgeEventActionType.ADDED, device.getId(), null));
}
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
@@ -313,25 +340,26 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
} catch (Exception e) {
log.error("Exception during loading edge device(s) on sync!", e);
}
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
@Override
public ListenableFuture processWidgetBundleTypesRequestMsg(TenantId tenantId, Edge edge,
WidgetBundleTypesRequestMsg widgetBundleTypesRequestMsg) {
log.trace("[{}] processWidgetBundleTypesRequestMsg [{}][{}]", tenantId, edge.getName(), widgetBundleTypesRequestMsg);
+ List> futures = new ArrayList<>();
if (widgetBundleTypesRequestMsg.getWidgetBundleIdMSB() != 0 && widgetBundleTypesRequestMsg.getWidgetBundleIdLSB() != 0) {
WidgetsBundleId widgetsBundleId = new WidgetsBundleId(new UUID(widgetBundleTypesRequestMsg.getWidgetBundleIdMSB(), widgetBundleTypesRequestMsg.getWidgetBundleIdLSB()));
WidgetsBundle widgetsBundleById = widgetsBundleService.findWidgetsBundleById(tenantId, widgetsBundleId);
if (widgetsBundleById != null) {
List widgetTypesToPush =
widgetTypeService.findWidgetTypesByTenantIdAndBundleAlias(widgetsBundleById.getTenantId(), widgetsBundleById.getAlias());
-
for (WidgetType widgetType : widgetTypesToPush) {
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null);
+ futures.add(saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.WIDGET_TYPE, EdgeEventActionType.ADDED, widgetType.getId(), null));
}
}
}
- return Futures.immediateFuture(null);
+ return Futures.transform(Futures.allAsList(futures), voids -> null, dbCallbackExecutorService);
}
@Override
@@ -344,46 +372,35 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
Futures.addCallback(entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), new FutureCallback<>() {
@Override
public void onSuccess(@Nullable List entityViews) {
- try {
- if (entityViews != null && !entityViews.isEmpty()) {
- List> futures = new ArrayList<>();
- for (EntityView entityView : entityViews) {
- ListenableFuture future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
- EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
- futures.add(future);
- Futures.addCallback(future, new FutureCallback<>() {
- @Override
- public void onSuccess(@Nullable Boolean result) {
- if (Boolean.TRUE.equals(result)) {
- saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW,
- EdgeEventActionType.ADDED, entityView.getId(), null);
- }
- }
- @Override
- public void onFailure(Throwable t) {
- // Do nothing - error handles in allAsList
- }
- }, dbCallbackExecutorService);
+ if (entityViews == null || entityViews.isEmpty()) {
+ futureToSet.set(null);
+ return;
+ }
+ List> futures = new ArrayList<>();
+ for (EntityView entityView : entityViews) {
+ ListenableFuture future = relationService.checkRelation(tenantId, edge.getId(), entityView.getId(),
+ EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE);
+ futures.add(Futures.transformAsync(future, result -> {
+ if (Boolean.TRUE.equals(result)) {
+ return saveEdgeEvent(tenantId, edge.getId(), EdgeEventType.ENTITY_VIEW,
+ EdgeEventActionType.ADDED, entityView.getId(), null);
+ } else {
+ return Futures.immediateFuture(null);
}
- Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
- @Override
- public void onSuccess(@Nullable List result) {
- futureToSet.set(null);
- }
-
- @Override
- public void onFailure(Throwable t) {
- log.error("Exception during loading relation [{}] to edge on sync!", t, t);
- futureToSet.setException(t);
- }
- }, dbCallbackExecutorService);
- } else {
+ }, dbCallbackExecutorService));
+ }
+ Futures.addCallback(Futures.allAsList(futures), new FutureCallback<>() {
+ @Override
+ public void onSuccess(@Nullable List result) {
futureToSet.set(null);
}
- } catch (Exception e) {
- log.error("Exception during loading relation(s) to edge on sync!", e);
- futureToSet.setException(e);
- }
+
+ @Override
+ public void onFailure(Throwable t) {
+ log.error("Exception during loading relation to edge on sync!", t);
+ futureToSet.setException(t);
+ }
+ }, dbCallbackExecutorService);
}
@Override
@@ -395,7 +412,7 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
return futureToSet;
}
- private void saveEdgeEvent(TenantId tenantId,
+ private ListenableFuture saveEdgeEvent(TenantId tenantId,
EdgeId edgeId,
EdgeEventType type,
EdgeEventActionType action,
@@ -404,10 +421,12 @@ public class DefaultEdgeRequestsService implements EdgeRequestsService {
log.trace("Pushing edge event to edge queue. tenantId [{}], edgeId [{}], type [{}], action[{}], entityId [{}], body [{}]",
tenantId, edgeId, type, action, entityId, body);
- EdgeEvent edgeEvent = EdgeEventUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
+ EdgeEvent edgeEvent = EdgeUtils.constructEdgeEvent(tenantId, edgeId, type, action, entityId, body);
- edgeEventService.save(edgeEvent);
- tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
+ return Futures.transform(edgeEventService.saveAsync(edgeEvent), unused -> {
+ tbClusterService.onEdgeEventUpdate(tenantId, edgeId);
+ return null;
+ }, dbCallbackExecutorService);
}
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
new file mode 100644
index 0000000000..e2ccc1f3d2
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/AbstractTbEntityService.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.thingsboard.server.cluster.TbClusterService;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.HasName;
+import org.thingsboard.server.common.data.User;
+import org.thingsboard.server.common.data.alarm.AlarmInfo;
+import org.thingsboard.server.common.data.alarm.AlarmQuery;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.AlarmId;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.EntityIdFactory;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.page.PageData;
+import org.thingsboard.server.common.data.page.PageDataIterableByTenantIdEntityId;
+import org.thingsboard.server.common.data.page.TimePageLink;
+import org.thingsboard.server.dao.alarm.AlarmService;
+import org.thingsboard.server.dao.asset.AssetService;
+import org.thingsboard.server.dao.customer.CustomerService;
+import org.thingsboard.server.dao.device.ClaimDevicesService;
+import org.thingsboard.server.dao.device.DeviceCredentialsService;
+import org.thingsboard.server.dao.device.DeviceService;
+import org.thingsboard.server.dao.edge.EdgeService;
+import org.thingsboard.server.dao.exception.DataValidationException;
+import org.thingsboard.server.dao.exception.IncorrectParameterException;
+import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.dao.rule.RuleChainService;
+import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
+import org.thingsboard.server.dao.tenant.TenantService;
+import org.thingsboard.server.service.action.EntityActionService;
+import org.thingsboard.server.service.edge.EdgeNotificationService;
+import org.thingsboard.server.service.executors.DbCallbackExecutorService;
+
+import javax.mail.MessagingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+@Slf4j
+public abstract class AbstractTbEntityService {
+
+ protected static final int DEFAULT_PAGE_SIZE = 1000;
+
+ private static final ObjectMapper json = new ObjectMapper();
+
+ @Value("${server.log_controller_error_stack_trace}")
+ @Getter
+ private boolean logControllerErrorStackTrace;
+ @Value("${edges.enabled}")
+ @Getter
+ protected boolean edgesEnabled;
+
+ @Autowired
+ protected DbCallbackExecutorService dbExecutor;
+ @Autowired
+ protected TbNotificationEntityService notificationEntityService;
+ @Autowired(required = false)
+ protected EdgeService edgeService;
+ @Autowired
+ protected AlarmService alarmService;
+ @Autowired
+ protected EntityActionService entityActionService;
+ @Autowired
+ protected DeviceService deviceService;
+ @Autowired
+ protected AssetService assetService;
+ @Autowired
+ protected DeviceCredentialsService deviceCredentialsService;
+ @Autowired
+ protected TenantService tenantService;
+ @Autowired
+ protected CustomerService customerService;
+ @Autowired
+ protected ClaimDevicesService claimDevicesService;
+ @Autowired
+ protected TbTenantProfileCache tenantProfileCache;
+ @Autowired
+ protected RuleChainService ruleChainService;
+ @Autowired
+ protected EdgeNotificationService edgeNotificationService;
+
+ protected ListenableFuture removeAlarmsByEntityId(TenantId tenantId, EntityId entityId) {
+ ListenableFuture> alarmsFuture =
+ alarmService.findAlarms(tenantId, new AlarmQuery(entityId, new TimePageLink(Integer.MAX_VALUE), null, null, false));
+
+ ListenableFuture> alarmIdsFuture = Futures.transform(alarmsFuture, page ->
+ page.getData().stream().map(AlarmInfo::getId).collect(Collectors.toList()), dbExecutor);
+
+ return Futures.transform(alarmIdsFuture, ids -> {
+ ids.stream().map(alarmId -> alarmService.deleteAlarm(tenantId, alarmId)).collect(Collectors.toList());
+ return null;
+ }, dbExecutor);
+ }
+
+ protected void logEntityAction(User user, TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException {
+ if (user != null) {
+ entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
+ } else if (e == null) {
+ entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo);
+ }
+ }
+
+ protected T checkNotNull(T reference) throws ThingsboardException {
+ return checkNotNull(reference, "Requested item wasn't found!");
+ }
+
+ protected T checkNotNull(T reference, String notFoundMessage) throws ThingsboardException {
+ if (reference == null) {
+ throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND);
+ }
+ return reference;
+ }
+
+ protected T checkNotNull(Optional reference) throws ThingsboardException {
+ return checkNotNull(reference, "Requested item wasn't found!");
+ }
+
+ protected T checkNotNull(Optional reference, String notFoundMessage) throws ThingsboardException {
+ if (reference.isPresent()) {
+ return reference.get();
+ } else {
+ throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND);
+ }
+ }
+
+ protected ThingsboardException handleException(Exception exception) {
+ return handleException(exception, true);
+ }
+
+ protected ThingsboardException handleException(Exception exception, boolean logException) {
+ if (logException && logControllerErrorStackTrace) {
+ log.error("Error [{}]", exception.getMessage(), exception);
+ }
+
+ String cause = "";
+ if (exception.getCause() != null) {
+ cause = exception.getCause().getClass().getCanonicalName();
+ }
+
+ if (exception instanceof ThingsboardException) {
+ return (ThingsboardException) exception;
+ } else if (exception instanceof IllegalArgumentException || exception instanceof IncorrectParameterException
+ || exception instanceof DataValidationException || cause.contains("IncorrectParameterException")) {
+ return new ThingsboardException(exception.getMessage(), ThingsboardErrorCode.BAD_REQUEST_PARAMS);
+ } else if (exception instanceof MessagingException) {
+ return new ThingsboardException("Unable to send mail: " + exception.getMessage(), ThingsboardErrorCode.GENERAL);
+ } else {
+ return new ThingsboardException(exception.getMessage(), exception, ThingsboardErrorCode.GENERAL);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected I emptyId(EntityType entityType) {
+ return (I) EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID);
+ }
+
+ protected List findRelatedEdgeIds(TenantId tenantId, EntityId entityId) {
+ if (!edgesEnabled) {
+ return null;
+ }
+ if (EntityType.EDGE.equals(entityId.getEntityType())) {
+ return Collections.singletonList(new EdgeId(entityId.getId()));
+ }
+ PageDataIterableByTenantIdEntityId relatedEdgeIdsIterator =
+ new PageDataIterableByTenantIdEntityId<>(edgeService::findRelatedEdgeIdsByEntityId, tenantId, entityId, DEFAULT_PAGE_SIZE);
+ List result = new ArrayList<>();
+ for (EdgeId edgeId : relatedEdgeIdsIterator) {
+ result.add(edgeId);
+ }
+ return result;
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
new file mode 100644
index 0000000000..b6ab974988
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/DefaultTbNotificationEntityService.java
@@ -0,0 +1,299 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.thingsboard.rule.engine.api.msg.DeviceCredentialsUpdateNotificationMsg;
+import org.thingsboard.server.cluster.TbClusterService;
+import org.thingsboard.server.common.data.DataConstants;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.HasName;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.edge.EdgeEventType;
+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.EdgeId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.common.msg.TbMsg;
+import org.thingsboard.server.common.msg.TbMsgDataType;
+import org.thingsboard.server.common.msg.TbMsgMetaData;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.action.EntityActionService;
+import org.thingsboard.server.service.gateway_device.GatewayNotificationsService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.List;
+
+@Slf4j
+@Service
+@TbCoreComponent
+@RequiredArgsConstructor
+public class DefaultTbNotificationEntityService implements TbNotificationEntityService {
+ private static final ObjectMapper json = new ObjectMapper();
+
+ private final EntityActionService entityActionService;
+ private final TbClusterService tbClusterService;
+ private final GatewayNotificationsService gatewayNotificationsService;
+
+ @Override
+ public void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ ActionType actionType, SecurityUser user, Exception e,
+ Object... additionalInfo) {
+ logEntityAction(tenantId, entityId, entity, customerId, actionType, user, e, additionalInfo);
+ }
+
+ @Override
+ public void notifyDeleteEntity(TenantId tenantId, I entityId, E entity,
+ CustomerId customerId, List relatedEdgeIds,
+ SecurityUser user, Object... additionalInfo) {
+ logEntityAction(tenantId, entityId, entity, customerId, ActionType.DELETED, user, additionalInfo);
+ sendDeleteNotificationMsg(tenantId, entityId, relatedEdgeIds);
+ }
+
+ @Override
+ public void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
+ CustomerId customerId, E entity,
+ ActionType actionType,
+ EdgeEventActionType edgeActionType,
+ SecurityUser user, boolean sendToEdge,
+ Object... additionalInfo) {
+ logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
+
+ if (sendToEdge) {
+ sendEntityAssignToCustomerNotificationMsg(tenantId, entityId, customerId, edgeActionType);
+ }
+ }
+
+ @Override
+ public void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
+ CustomerId customerId, EdgeId edgeId,
+ E entity, ActionType actionType,
+ EdgeEventActionType edgeActionType,
+ SecurityUser user, Object... additionalInfo) {
+ logEntityAction(tenantId, entityId, entity, customerId, actionType, user, additionalInfo);
+ sendEntityAssignToEdgeNotificationMsg(tenantId, edgeId, entityId, edgeActionType);
+ }
+
+ @Override
+ public void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event) {
+ tbClusterService.onTenantChange(tenant, null);
+ tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), event);
+ }
+
+ @Override
+ public void notifyDeleteTenant(Tenant tenant) {
+ tbClusterService.onTenantDelete(tenant, null);
+ tbClusterService.broadcastEntityStateChangeEvent(tenant.getId(), tenant.getId(), ComponentLifecycleEvent.DELETED);
+ }
+
+ @Override
+ public void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId,
+ Device device, Device oldDevice, ActionType actionType,
+ SecurityUser user, Object... additionalInfo) {
+ tbClusterService.onDeviceUpdated(device, oldDevice);
+ logEntityAction(tenantId, deviceId, device, customerId, actionType, user, additionalInfo);
+ }
+
+ @Override
+ public void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
+ List relatedEdgeIds, SecurityUser user, Object... additionalInfo) {
+ gatewayNotificationsService.onDeviceDeleted(device);
+ tbClusterService.onDeviceDeleted(device, null);
+
+ notifyDeleteEntity(tenantId, deviceId, device, customerId, relatedEdgeIds, user, additionalInfo);
+ }
+
+ @Override
+ public void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
+ DeviceCredentials deviceCredentials, SecurityUser user) {
+ tbClusterService.pushMsgToCore(new DeviceCredentialsUpdateNotificationMsg(tenantId, deviceCredentials.getDeviceId(), deviceCredentials), null);
+ sendEntityNotificationMsg(tenantId, deviceId, EdgeEventActionType.CREDENTIALS_UPDATED);
+ logEntityAction(tenantId, deviceId, device, customerId, ActionType.CREDENTIALS_UPDATED, user, deviceCredentials);
+ }
+
+ @Override
+ public void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId,
+ Device device, Tenant tenant, SecurityUser user, Object... additionalInfo) {
+ logEntityAction(tenantId, deviceId, device, customerId, ActionType.ASSIGNED_TO_TENANT, user, additionalInfo);
+ pushAssignedFromNotification(tenant, newTenantId, device);
+ }
+
+ @Override
+ public void notifyCreateOrUpdateAsset(TenantId tenantId, AssetId assetId, CustomerId customerId, Asset asset,
+ ActionType actionType, SecurityUser user, Object... additionalInfo) {
+ logEntityAction(tenantId, assetId, asset, customerId, actionType, user, additionalInfo);
+
+ if (actionType == ActionType.UPDATED) {
+ sendEntityNotificationMsg(asset.getTenantId(), asset.getId(), EdgeEventActionType.UPDATED);
+ }
+ }
+
+ @Override
+ public void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType,
+ SecurityUser user, Object... additionalInfo) {
+ ComponentLifecycleEvent lifecycleEvent;
+ EdgeEventActionType edgeEventActionType = null;
+ switch (actionType) {
+ case ADDED:
+ lifecycleEvent = ComponentLifecycleEvent.CREATED;
+ break;
+ case UPDATED:
+ lifecycleEvent = ComponentLifecycleEvent.UPDATED;
+ break;
+ case ASSIGNED_TO_CUSTOMER:
+ lifecycleEvent = ComponentLifecycleEvent.UPDATED;
+ edgeEventActionType = EdgeEventActionType.ASSIGNED_TO_CUSTOMER;
+ break;
+ case UNASSIGNED_FROM_CUSTOMER:
+ lifecycleEvent = ComponentLifecycleEvent.UPDATED;
+ edgeEventActionType = EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER;
+ break;
+ case DELETED:
+ lifecycleEvent = ComponentLifecycleEvent.DELETED;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown actionType: " + actionType);
+ }
+
+ tbClusterService.broadcastEntityStateChangeEvent(tenantId, edgeId, lifecycleEvent);
+ logEntityAction(tenantId, edgeId, edge, customerId, actionType, user, additionalInfo);
+
+ //Send notification to edge
+ if (edgeEventActionType != null) {
+ sendEntityAssignToCustomerNotificationMsg(tenantId, edgeId, customerId, edgeEventActionType);
+ }
+ }
+
+ @Override
+ public void notifyCreateOrUpdateAlarm(Alarm alarm, ActionType actionType, SecurityUser user, Object... additionalInfo) {
+ logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), actionType, user, additionalInfo);
+ sendEntityNotificationMsg(alarm.getTenantId(), alarm.getId(), edgeTypeByActionType (actionType));
+ }
+
+ @Override
+ public void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List relatedEdgeIds) {
+ logEntityAction(alarm.getTenantId(), alarm.getOriginator(), alarm, alarm.getCustomerId(), ActionType.ALARM_DELETE, user, null);
+ sendAlarmDeleteNotificationMsg(alarm, relatedEdgeIds);
+ }
+
+ private void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ ActionType actionType, SecurityUser user, Object... additionalInfo) {
+ logEntityAction(tenantId, entityId, entity, customerId, actionType, user, null, additionalInfo);
+ }
+
+ private void logEntityAction(TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ ActionType actionType, SecurityUser user, Exception e, Object... additionalInfo) {
+ if (user != null) {
+ entityActionService.logEntityAction(user, entityId, entity, customerId, actionType, e, additionalInfo);
+ } else if (e == null) {
+ entityActionService.pushEntityActionToRuleEngine(entityId, entity, tenantId, customerId, actionType, null, additionalInfo);
+ }
+ }
+
+ private void sendEntityNotificationMsg(TenantId tenantId, EntityId entityId, EdgeEventActionType action) {
+ sendNotificationMsgToEdgeService(tenantId, null, entityId, null, null, action);
+ }
+
+ private void sendEntityAssignToCustomerNotificationMsg(TenantId tenantId, EntityId entityId, CustomerId customerId, EdgeEventActionType action) {
+ try {
+ sendNotificationMsgToEdgeService(tenantId, null, entityId, json.writeValueAsString(customerId), null, action);
+ } catch (Exception e) {
+ log.warn("Failed to push assign/unassign to/from customer to core: {}", customerId, e);
+ }
+ }
+
+ private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds) {
+ sendDeleteNotificationMsg(tenantId, entityId, edgeIds, null);
+ }
+
+ protected void sendAlarmDeleteNotificationMsg(Alarm alarm, List relatedEdgeIds) {
+ try {
+ sendDeleteNotificationMsg(alarm.getTenantId(), alarm.getId(), relatedEdgeIds, json.writeValueAsString(alarm));
+ } catch (Exception e) {
+ log.warn("Failed to push delete alarm msg to core: {}", alarm, e);
+ }
+ }
+ private void sendDeleteNotificationMsg(TenantId tenantId, EntityId entityId, List edgeIds, String body) {
+ if (edgeIds != null && !edgeIds.isEmpty()) {
+ for (EdgeId edgeId : edgeIds) {
+ sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, null, EdgeEventActionType.DELETED);
+ }
+ }
+ }
+
+ private void sendEntityAssignToEdgeNotificationMsg(TenantId tenantId, EdgeId edgeId, EntityId entityId, EdgeEventActionType action) {
+ sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, null, null, action);
+ }
+
+ private void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, EntityId entityId, String body, EdgeEventType type, EdgeEventActionType action) {
+ tbClusterService.sendNotificationMsgToEdgeService(tenantId, edgeId, entityId, body, type, action);
+ }
+
+ private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) {
+ String data = entityToStr(assignedDevice);
+ if (data != null) {
+ TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), assignedDevice.getCustomerId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data);
+ tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null);
+ }
+ }
+
+ private TbMsgMetaData getMetaDataForAssignedFrom(Tenant tenant) {
+ TbMsgMetaData metaData = new TbMsgMetaData();
+ metaData.putValue("assignedFromTenantId", tenant.getId().getId().toString());
+ metaData.putValue("assignedFromTenantName", tenant.getName());
+ return metaData;
+ }
+
+ private String entityToStr(E entity) {
+ try {
+ return json.writeValueAsString(json.valueToTree(entity));
+ } catch (JsonProcessingException e) {
+ log.warn("[{}] Failed to convert entity to string!", entity, e);
+ }
+ return null;
+ }
+
+ private EdgeEventActionType edgeTypeByActionType (ActionType actionType) {
+ switch (actionType) {
+ case ADDED:
+ return EdgeEventActionType.ADDED;
+ case UPDATED:
+ return EdgeEventActionType.UPDATED;
+ case ALARM_ACK:
+ return EdgeEventActionType.ALARM_ACK;
+ case ALARM_CLEAR:
+ return EdgeEventActionType.ALARM_CLEAR;
+ case DELETED:
+ return EdgeEventActionType.DELETED;
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
new file mode 100644
index 0000000000..181a1f41eb
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/TbNotificationEntityService.java
@@ -0,0 +1,86 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy;
+
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.HasName;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+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.EdgeId;
+import org.thingsboard.server.common.data.id.EntityId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.List;
+
+public interface TbNotificationEntityService {
+
+ void notifyEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ ActionType actionType, SecurityUser user, Exception e,
+ Object... additionalInfo);
+
+ void notifyDeleteEntity(TenantId tenantId, I entityId, E entity, CustomerId customerId,
+ List relatedEdgeIds, SecurityUser user,
+ Object... additionalInfo);
+
+ void notifyAssignOrUnassignEntityToCustomer(TenantId tenantId, I entityId,
+ CustomerId customerId, E entity,
+ ActionType actionType,
+ EdgeEventActionType edgeActionType,
+ SecurityUser user, boolean sendToEdge,
+ Object... additionalInfo);
+
+ void notifyAssignOrUnassignEntityToEdge(TenantId tenantId, I entityId,
+ CustomerId customerId, EdgeId edgeId,
+ E entity, ActionType actionType,
+ EdgeEventActionType edgeActionType,
+ SecurityUser user, Object... additionalInfo);
+
+ void notifyCreateOruUpdateTenant(Tenant tenant, ComponentLifecycleEvent event);
+
+ void notifyDeleteTenant(Tenant tenant);
+
+ void notifyCreateOrUpdateDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
+ Device oldDevice, ActionType actionType, SecurityUser user, Object... additionalInfo);
+
+ void notifyDeleteDevice(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
+ List relatedEdgeIds, SecurityUser user, Object... additionalInfo);
+
+ void notifyUpdateDeviceCredentials(TenantId tenantId, DeviceId deviceId, CustomerId customerId, Device device,
+ DeviceCredentials deviceCredentials, SecurityUser user);
+
+ void notifyAssignDeviceToTenant(TenantId tenantId, TenantId newTenantId, DeviceId deviceId, CustomerId customerId,
+ Device device, Tenant tenant, SecurityUser user, Object... additionalInfo);
+
+ void notifyCreateOrUpdateAsset(TenantId tenantId, AssetId assetId, CustomerId customerId, Asset asset,
+ ActionType actionType, SecurityUser user, Object... additionalInfo);
+
+ void notifyEdge(TenantId tenantId, EdgeId edgeId, CustomerId customerId, Edge edge, ActionType actionType, SecurityUser user, Object... additionalInfo);
+
+ void notifyCreateOrUpdateAlarm(Alarm alarm,
+ ActionType actionType, SecurityUser user, Object... additionalInfo);
+
+ void notifyDeleteAlarm(Alarm alarm, SecurityUser user, List relatedEdgeIds);
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
new file mode 100644
index 0000000000..f0ac516393
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/DefaultTbAlarmService.java
@@ -0,0 +1,85 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.alarm;
+
+
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.alarm.AlarmStatus;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.List;
+
+@Service
+@TbCoreComponent
+@AllArgsConstructor
+public class DefaultTbAlarmService extends AbstractTbEntityService implements TbAlarmService {
+
+ @Override
+ public Alarm save(Alarm alarm, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ TenantId tenantId = alarm.getTenantId();
+ try {
+ Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm).getAlarm());
+ notificationEntityService.notifyCreateOrUpdateAlarm(savedAlarm, actionType, user);
+ return savedAlarm;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ALARM), alarm, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public void ack(Alarm alarm, SecurityUser user) throws ThingsboardException {
+ try {
+ long ackTs = System.currentTimeMillis();
+ alarmService.ackAlarm(user.getTenantId(), alarm.getId(), ackTs).get();
+ alarm.setAckTs(ackTs);
+ alarm.setStatus(alarm.getStatus().isCleared() ? AlarmStatus.CLEARED_ACK : AlarmStatus.ACTIVE_ACK);
+ notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_ACK, user);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public void clear(Alarm alarm, SecurityUser user) throws ThingsboardException {
+ try {
+ long clearTs = System.currentTimeMillis();
+ alarmService.clearAlarm(user.getTenantId(), alarm.getId(), null, clearTs).get();
+ alarm.setClearTs(clearTs);
+ alarm.setStatus(alarm.getStatus().isAck() ? AlarmStatus.CLEARED_ACK : AlarmStatus.CLEARED_UNACK);
+ notificationEntityService.notifyCreateOrUpdateAlarm(alarm, ActionType.ALARM_CLEAR, user);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Boolean delete(Alarm alarm, SecurityUser user) throws ThingsboardException {
+ List relatedEdgeIds = findRelatedEdgeIds(alarm.getTenantId(), alarm.getOriginator());
+ notificationEntityService.notifyDeleteAlarm(alarm, user, relatedEdgeIds);
+ return alarmService.deleteAlarm(alarm.getTenantId(), alarm.getId()).isSuccessful();
+ }
+}
diff --git a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
similarity index 50%
rename from application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java
rename to application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
index 9252e3c4c4..7c3613d730 100644
--- a/application/src/test/java/org/thingsboard/server/transport/mqtt/rpc/sql/MqttServerSideRpcProtoIntegrationTest.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/alarm/TbAlarmService.java
@@ -13,12 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.transport.mqtt.rpc.sql;
+package org.thingsboard.server.service.entitiy.alarm;
-import org.thingsboard.server.dao.service.DaoSqlTest;
-import org.thingsboard.server.transport.mqtt.rpc.AbstractMqttServerSideRpcProtoIntegrationTest;
+import org.thingsboard.server.common.data.alarm.Alarm;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.service.security.model.SecurityUser;
+public interface TbAlarmService {
-@DaoSqlTest
-public class MqttServerSideRpcProtoIntegrationTest extends AbstractMqttServerSideRpcProtoIntegrationTest {
+ Alarm save (Alarm alarm, SecurityUser user) throws ThingsboardException;
+
+ void ack (Alarm alarm, SecurityUser user) throws ThingsboardException;
+
+ void clear (Alarm alarm, SecurityUser user) throws ThingsboardException;
+
+ Boolean delete (Alarm alarm, SecurityUser user) throws ThingsboardException;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
new file mode 100644
index 0000000000..84b9c707d0
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/DefaultTbAssetService.java
@@ -0,0 +1,163 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.asset;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import lombok.AllArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.List;
+
+@Service
+@TbCoreComponent
+@AllArgsConstructor
+public class DefaultTbAssetService extends AbstractTbEntityService implements TbAssetService {
+ @Override
+ public Asset save(Asset asset, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = asset.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ TenantId tenantId = asset.getTenantId();
+ try {
+ Asset savedAsset = checkNotNull(assetService.saveAsset(asset));
+ notificationEntityService.notifyCreateOrUpdateAsset(tenantId, savedAsset.getId(), savedAsset.getCustomerId(), asset, actionType, user);
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), asset, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException {
+ TenantId tenantId = asset.getTenantId();
+ AssetId assetId = asset.getId();
+ try {
+ List relatedEdgeIds = findRelatedEdgeIds(tenantId, assetId);
+ assetService.deleteAsset(tenantId, assetId);
+ notificationEntityService.notifyDeleteEntity(tenantId, assetId, asset, asset.getCustomerId(), relatedEdgeIds, user, asset.toString());
+
+ return removeAlarmsByEntityId(tenantId, assetId);
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ ActionType.DELETED, user, e, asset.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ CustomerId customerId = customer.getId();
+ try {
+ Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, customerId));
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
+ actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
+
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ actionType, user, e, assetId.toString(), customerId.toString());
+
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
+ try {
+ Asset savedAsset = checkNotNull(assetService.unassignAssetFromCustomer(tenantId, assetId));
+ CustomerId customerId = customer.getId();
+
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, customerId, savedAsset,
+ actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user,
+ true, customerId.toString(), customer.getName());
+
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ actionType, user, e, assetId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ try {
+ Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
+ Asset savedAsset = checkNotNull(assetService.assignAssetToCustomer(tenantId, assetId, publicCustomer.getId()));
+
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, assetId, savedAsset.getCustomerId(), savedAsset,
+ actionType, null, user, false, actionType.toString(),
+ publicCustomer.getId().toString(), publicCustomer.getName());
+
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ actionType, user, e, assetId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
+ EdgeId edgeId = edge.getId();
+ try {
+ Asset savedAsset = checkNotNull(assetService.assignAssetToEdge(tenantId, assetId, edgeId));
+ notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, savedAsset.getCustomerId(),
+ edgeId, savedAsset, actionType, EdgeEventActionType.ASSIGNED_TO_EDGE, user, assetId.toString(), edgeId.toString(), edge.getName());
+
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ actionType, user, e, assetId.toString(), edgeId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
+ AssetId assetId = asset.getId();
+ EdgeId edgeId = edge.getId();
+ try {
+ Asset savedAsset = checkNotNull(assetService.unassignAssetFromEdge(tenantId, assetId, edgeId));
+
+ notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, assetId, asset.getCustomerId(),
+ edgeId, asset, actionType, EdgeEventActionType.UNASSIGNED_FROM_EDGE, user, assetId.toString(), edgeId.toString(), edge.getName());
+ return savedAsset;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.ASSET), null, null,
+ actionType, user, e, assetId.toString(), edgeId.toString());
+ throw handleException(e);
+ }
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java
new file mode 100644
index 0000000000..c6e1c29940
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/asset/TbAssetService.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.asset;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.asset.Asset;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.AssetId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+public interface TbAssetService {
+ Asset save(Asset asset, SecurityUser user) throws ThingsboardException;
+
+ ListenableFuture delete(Asset asset, SecurityUser user) throws ThingsboardException;
+
+ Asset assignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Asset unassignAssetToCustomer(TenantId tenantId, AssetId assetId, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Asset assignAssetToPublicCustomer(TenantId tenantId, AssetId assetId, SecurityUser user) throws ThingsboardException;
+
+ Asset assignAssetToEdge(TenantId tenantId, AssetId assetId, Edge edge, SecurityUser user) throws ThingsboardException;
+
+ Asset unassignAssetFromEdge(TenantId tenantId, Asset asset, Edge edge, SecurityUser user) throws ThingsboardException;
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
new file mode 100644
index 0000000000..1bed17f941
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/DefaultTbDeviceService.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.device;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.edge.EdgeEventActionType;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.dao.device.claim.ClaimResponse;
+import org.thingsboard.server.dao.device.claim.ClaimResult;
+import org.thingsboard.server.dao.device.claim.ReclaimResult;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+import java.util.List;
+
+@AllArgsConstructor
+@TbCoreComponent
+@Service
+@Slf4j
+public class DefaultTbDeviceService extends AbstractTbEntityService implements TbDeviceService {
+
+ @Override
+ public Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ try {
+ Device savedDevice = checkNotNull(deviceService.saveDeviceWithAccessToken(device, accessToken));
+ notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
+ savedDevice, oldDevice, actionType, user);
+
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials credentials, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = device.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ try {
+ Device savedDevice = checkNotNull(deviceService.saveDeviceWithCredentials(device, credentials));
+ notificationEntityService.notifyCreateOrUpdateDevice(tenantId, savedDevice.getId(), savedDevice.getCustomerId(),
+ savedDevice, device, actionType, user);
+
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), device, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture deleteDevice(Device device, SecurityUser user) throws ThingsboardException {
+ TenantId tenantId = device.getTenantId();
+ DeviceId deviceId = device.getId();
+ try {
+ List relatedEdgeIds = findRelatedEdgeIds(tenantId, deviceId);
+ deviceService.deleteDevice(tenantId, deviceId);
+ notificationEntityService.notifyDeleteDevice(tenantId, deviceId, device.getCustomerId(), device,
+ relatedEdgeIds, user, deviceId.toString());
+
+ return removeAlarmsByEntityId(tenantId, deviceId);
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ ActionType.DELETED, user, e, deviceId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ CustomerId customerId = customer.getId();
+ try {
+ Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(user.getTenantId(), deviceId, customerId));
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
+ actionType, EdgeEventActionType.ASSIGNED_TO_CUSTOMER, user, true, customerId.toString(), customer.getName());
+
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString(), customerId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
+ TenantId tenantId = device.getTenantId();
+ DeviceId deviceId = device.getId();
+ try {
+ Device savedDevice = checkNotNull(deviceService.unassignDeviceFromCustomer(tenantId, deviceId));
+ CustomerId customerId = customer.getId();
+
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, customerId, savedDevice,
+ actionType, EdgeEventActionType.UNASSIGNED_FROM_CUSTOMER, user,
+ true, customerId.toString(), customer.getName());
+
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ try {
+ Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
+ Device savedDevice = checkNotNull(deviceService.assignDeviceToCustomer(tenantId, deviceId, publicCustomer.getId()));
+
+ notificationEntityService.notifyAssignOrUnassignEntityToCustomer(tenantId, deviceId, savedDevice.getCustomerId(), savedDevice,
+ actionType, null, user, false, deviceId.toString(),
+ publicCustomer.getId().toString(), publicCustomer.getName());
+
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.CREDENTIALS_READ;
+ TenantId tenantId = device.getTenantId();
+ DeviceId deviceId = device.getId();
+ try {
+ DeviceCredentials deviceCredentials = checkNotNull(deviceCredentialsService.findDeviceCredentialsByDeviceId(tenantId, deviceId));
+ notificationEntityService.notifyEntity(tenantId, deviceId, device, device.getCustomerId(),
+ actionType, user, null, deviceId.toString());
+ return deviceCredentials;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException {
+ TenantId tenantId = device.getTenantId();
+ DeviceId deviceId = device.getId();
+ try {
+ DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(tenantId, deviceCredentials));
+ notificationEntityService.notifyUpdateDeviceCredentials(tenantId, deviceId, device.getCustomerId(), device, result, user);
+ return result;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ ActionType.CREDENTIALS_UPDATED, user, e, deviceCredentials);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException {
+ try {
+ ListenableFuture future = claimDevicesService.claimDevice(device, customerId, secretKey);
+
+ return Futures.transform(future, result -> {
+ if (result != null && result.getResponse().equals(ClaimResponse.SUCCESS)) {
+ notificationEntityService.notifyEntity(tenantId, device.getId(), result.getDevice(), customerId,
+ ActionType.ASSIGNED_TO_CUSTOMER, user, null, device.getId().toString(), customerId.toString(),
+ customerService.findCustomerById(tenantId, customerId).getName());
+ }
+ return result;
+ }, MoreExecutors.directExecutor());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public ListenableFuture reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException {
+ try {
+ ListenableFuture future = claimDevicesService.reClaimDevice(tenantId, device);
+
+ return Futures.transform(future, result -> {
+ Customer unassignedCustomer = result.getUnassignedCustomer();
+ if (unassignedCustomer != null) {
+ notificationEntityService.notifyEntity(tenantId, device.getId(), device, device.getCustomerId(), ActionType.UNASSIGNED_FROM_CUSTOMER, user, null,
+ device.getId().toString(), unassignedCustomer.getId().toString(), unassignedCustomer.getName());
+ }
+ return result;
+ }, MoreExecutors.directExecutor());
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException {
+ TenantId tenantId = device.getTenantId();
+ TenantId newTenantId = newTenant.getId();
+ try {
+ Tenant tenant = tenantService.findTenantById(tenantId);
+ Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device);
+
+ notificationEntityService.notifyAssignDeviceToTenant(tenantId, newTenantId, device.getId(),
+ assignedDevice.getCustomerId(), assignedDevice, tenant, user, newTenantId.toString(), newTenant.getName());
+
+ return assignedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ ActionType.ASSIGNED_TO_TENANT, user, e, newTenantId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_EDGE;
+ EdgeId edgeId = edge.getId();
+ try {
+ Device savedDevice = checkNotNull(deviceService.assignDeviceToEdge(tenantId, deviceId, edgeId));
+ notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, savedDevice.getCustomerId(),
+ edgeId, savedDevice, actionType, EdgeEventActionType.ASSIGNED_TO_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName());
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString(), edgeId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_EDGE;
+ TenantId tenantId = device.getTenantId();
+ DeviceId deviceId = device.getId();
+ EdgeId edgeId = edge.getId();
+ try {
+ Device savedDevice = checkNotNull(deviceService.unassignDeviceFromEdge(tenantId, deviceId, edgeId));
+
+ notificationEntityService.notifyAssignOrUnassignEntityToEdge(tenantId, deviceId, device.getCustomerId(),
+ edgeId, device, actionType, EdgeEventActionType.UNASSIGNED_FROM_EDGE, user, deviceId.toString(), edgeId.toString(), edge.getName());
+ return savedDevice;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.DEVICE), null, null,
+ actionType, user, e, deviceId.toString(), edgeId.toString());
+ throw handleException(e);
+ }
+ }
+
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java
new file mode 100644
index 0000000000..16fd0c7448
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/device/TbDeviceService.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.device;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.Device;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.DeviceId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.security.DeviceCredentials;
+import org.thingsboard.server.dao.device.claim.ClaimResult;
+import org.thingsboard.server.dao.device.claim.ReclaimResult;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+public interface TbDeviceService {
+
+ Device save(TenantId tenantId, Device device, Device oldDevice, String accessToken, SecurityUser user) throws ThingsboardException;
+
+ Device saveDeviceWithCredentials(TenantId tenantId, Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException;
+
+ ListenableFuture deleteDevice(Device device, SecurityUser user) throws ThingsboardException;
+
+ Device assignDeviceToCustomer(TenantId tenantId, DeviceId deviceId, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Device unassignDeviceFromCustomer(Device device, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Device assignDeviceToPublicCustomer(TenantId tenantId, DeviceId deviceId, SecurityUser user) throws ThingsboardException;
+
+ DeviceCredentials getDeviceCredentialsByDeviceId(Device device, SecurityUser user) throws ThingsboardException;
+
+ DeviceCredentials updateDeviceCredentials(Device device, DeviceCredentials deviceCredentials, SecurityUser user) throws ThingsboardException;
+
+ ListenableFuture claimDevice(TenantId tenantId, Device device, CustomerId customerId, String secretKey, SecurityUser user) throws ThingsboardException;
+
+ ListenableFuture reclaimDevice(TenantId tenantId, Device device, SecurityUser user) throws ThingsboardException;
+
+ Device assignDeviceToTenant(Device device, Tenant newTenant, SecurityUser user) throws ThingsboardException;
+
+ Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, Edge edge, SecurityUser user) throws ThingsboardException;
+
+ Device unassignDeviceFromEdge(Device device, Edge edge, SecurityUser user) throws ThingsboardException;
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
new file mode 100644
index 0000000000..93487ac5cd
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/DefaultTbEdgeService.java
@@ -0,0 +1,150 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.edge;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.EntityType;
+import org.thingsboard.server.common.data.audit.ActionType;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.CustomerId;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+@AllArgsConstructor
+@TbCoreComponent
+@Service
+@Slf4j
+public class DefaultTbEdgeService extends AbstractTbEntityService implements TbEdgeService {
+
+ @Override
+ public Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = edge.getId() == null ? ActionType.ADDED : ActionType.UPDATED;
+ TenantId tenantId = edge.getTenantId();
+ try {
+ Edge savedEdge = checkNotNull(edgeService.saveEdge(edge));
+ EdgeId edgeId = savedEdge.getId();
+
+ if (actionType == ActionType.ADDED) {
+ ruleChainService.assignRuleChainToEdge(tenantId, edgeTemplateRootRuleChain.getId(), edgeId);
+ edgeNotificationService.setEdgeRootRuleChain(tenantId, savedEdge, edgeTemplateRootRuleChain.getId());
+ edgeService.assignDefaultRuleChainsToEdge(tenantId, edgeId);
+ }
+
+ notificationEntityService.notifyEdge(tenantId, edgeId, savedEdge.getCustomerId(), savedEdge, actionType, user);
+
+ return savedEdge;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.DELETED;
+ EdgeId edgeId = edge.getId();
+ TenantId tenantId = edge.getTenantId();
+ try {
+ edgeService.deleteEdge(tenantId, edgeId);
+ notificationEntityService.notifyEdge(tenantId, edgeId, edge.getCustomerId(), edge, actionType, user, edgeId.toString());
+
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), edge, null, actionType, user, e);
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ CustomerId customerId = customer.getId();
+ try {
+ Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
+
+ notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
+ edgeId.toString(), customerId.toString(), customer.getName());
+
+ return savedEdge;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
+ actionType, user, e, edgeId.toString(), customerId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UNASSIGNED_FROM_CUSTOMER;
+ TenantId tenantId = edge.getTenantId();
+ EdgeId edgeId = edge.getId();
+ CustomerId customerId = customer.getId();
+ try {
+ Edge savedEdge = checkNotNull(edgeService.unassignEdgeFromCustomer(tenantId, edgeId));
+
+ notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
+ edgeId.toString(), customerId.toString(), customer.getName());
+ return savedEdge;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
+ actionType, user, e, edgeId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.ASSIGNED_TO_CUSTOMER;
+ try {
+ Customer publicCustomer = customerService.findOrCreatePublicCustomer(tenantId);
+ CustomerId customerId = publicCustomer.getId();
+ Edge savedEdge = checkNotNull(edgeService.assignEdgeToCustomer(tenantId, edgeId, customerId));
+
+ notificationEntityService.notifyEdge(tenantId, edgeId, customerId, savedEdge, actionType, user,
+ edgeId.toString(), customerId.toString(), publicCustomer.getName());
+
+ return savedEdge;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
+ actionType, user, e, edgeId.toString());
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException {
+ ActionType actionType = ActionType.UPDATED;
+ TenantId tenantId = edge.getTenantId();
+ EdgeId edgeId = edge.getId();
+ try {
+ Edge updatedEdge = edgeNotificationService.setEdgeRootRuleChain(tenantId, edge, ruleChainId);
+ notificationEntityService.notifyEdge(tenantId, edgeId, null, updatedEdge, actionType, user);
+ return updatedEdge;
+ } catch (Exception e) {
+ notificationEntityService.notifyEntity(tenantId, emptyId(EntityType.EDGE), null, null,
+ actionType, user, e, edgeId.toString());
+ throw handleException(e);
+ }
+ }
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java
new file mode 100644
index 0000000000..5ed27fbbb3
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/edge/TbEdgeService.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.edge;
+
+import org.thingsboard.server.common.data.Customer;
+import org.thingsboard.server.common.data.edge.Edge;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.EdgeId;
+import org.thingsboard.server.common.data.id.RuleChainId;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.service.security.model.SecurityUser;
+
+public interface TbEdgeService {
+ Edge saveEdge(Edge edge, RuleChain edgeTemplateRootRuleChain, SecurityUser user) throws ThingsboardException;
+
+ void deleteEdge(Edge edge, SecurityUser user) throws ThingsboardException;
+
+ Edge assignEdgeToCustomer(TenantId tenantId, EdgeId edgeId, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Edge unassignEdgeFromCustomer(Edge edge, Customer customer, SecurityUser user) throws ThingsboardException;
+
+ Edge assignEdgeToPublicCustomer(TenantId tenantId, EdgeId edgeId, SecurityUser user) throws ThingsboardException;
+
+ Edge setEdgeRootRuleChain(Edge edge, RuleChainId ruleChainId, SecurityUser user) throws ThingsboardException;
+}
diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java
new file mode 100644
index 0000000000..ac3d651b6b
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/DefaultTbTenantService.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.entitiy.tenant;
+
+import lombok.AllArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
+import org.thingsboard.server.queue.util.TbCoreComponent;
+import org.thingsboard.server.service.entitiy.AbstractTbEntityService;
+import org.thingsboard.server.service.install.InstallScripts;
+
+@Service
+@TbCoreComponent
+@AllArgsConstructor
+public class DefaultTbTenantService extends AbstractTbEntityService implements TbTenantService {
+
+ @Autowired
+ private InstallScripts installScripts;
+
+ @Override
+ public Tenant save(Tenant tenant) throws ThingsboardException {
+ try {
+ boolean newTenant = tenant.getId() == null;
+ Tenant savedTenant = checkNotNull(tenantService.saveTenant(tenant));
+ if (newTenant) {
+ installScripts.createDefaultRuleChains(savedTenant.getId());
+ installScripts.createDefaultEdgeRuleChains(savedTenant.getId());
+ }
+ tenantProfileCache.evict(savedTenant.getId());
+ notificationEntityService.notifyCreateOruUpdateTenant(savedTenant, newTenant ?
+ ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED);
+ return savedTenant;
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+
+ @Override
+ public void delete(Tenant tenant) throws ThingsboardException {
+ try {
+ TenantId tenantId = tenant.getId();
+ tenantService.deleteTenant(tenantId);
+ tenantProfileCache.evict(tenantId);
+ notificationEntityService.notifyDeleteTenant(tenant);
+ } catch (Exception e) {
+ throw handleException(e);
+ }
+ }
+}
diff --git a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcProtoSqlIntegrationTest.java b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/TbTenantService.java
similarity index 65%
rename from application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcProtoSqlIntegrationTest.java
rename to application/src/main/java/org/thingsboard/server/service/entitiy/tenant/TbTenantService.java
index 169d4d51e5..0ff7bc749c 100644
--- a/application/src/test/java/org/thingsboard/server/transport/coap/rpc/sql/CoapServerSideRpcProtoSqlIntegrationTest.java
+++ b/application/src/main/java/org/thingsboard/server/service/entitiy/tenant/TbTenantService.java
@@ -13,12 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.thingsboard.server.transport.coap.rpc.sql;
+package org.thingsboard.server.service.entitiy.tenant;
-import org.thingsboard.server.transport.coap.rpc.AbstractCoapServerSideRpcProtoIntegrationTest;
-import org.thingsboard.server.dao.service.DaoSqlTest;
+import org.thingsboard.server.common.data.Tenant;
+import org.thingsboard.server.common.data.exception.ThingsboardException;
+public interface TbTenantService {
+ Tenant save(Tenant tenant) throws ThingsboardException;
-@DaoSqlTest
-public class CoapServerSideRpcProtoSqlIntegrationTest extends AbstractCoapServerSideRpcProtoIntegrationTest {
+ void delete(Tenant tenant) throws ThingsboardException;
}
diff --git a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java
index b7b740f190..81a0068a4d 100644
--- a/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java
+++ b/application/src/main/java/org/thingsboard/server/service/importing/AbstractBulkImportService.java
@@ -95,7 +95,7 @@ public abstract class AbstractBulkImportService processBulkImport(BulkImportRequest request, SecurityUser user, Consumer> onEntityImported) throws Exception {
+ public final BulkImportResult processBulkImport(BulkImportRequest request, SecurityUser user) throws Exception {
List entitiesData = parseData(request);
BulkImportResult result = new BulkImportResult<>();
@@ -106,10 +106,9 @@ public abstract class AbstractBulkImportService DonAsynchron.submit(() -> {
SecurityContextHolder.setContext(securityContext);
- ImportedEntityInfo importedEntityInfo = saveEntity(entityData.getFields(), user);
+ ImportedEntityInfo importedEntityInfo = saveEntity(entityData.getFields(), user);
E entity = importedEntityInfo.getEntity();
- onEntityImported.accept(importedEntityInfo);
saveKvs(user, entity, entityData.getKvs());
return importedEntityInfo;
@@ -148,7 +147,7 @@ public abstract class AbstractBulkImportService fields);
- protected abstract E saveEntity(E entity, Map fields);
+ protected abstract E saveEntity(SecurityUser user, E entity, Map fields);
protected abstract EntityType getEntityType();
diff --git a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java
index 2591790137..b42dcb6b83 100644
--- a/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java
+++ b/application/src/main/java/org/thingsboard/server/service/sms/DefaultSmsSenderFactory.java
@@ -19,9 +19,11 @@ import org.springframework.stereotype.Component;
import org.thingsboard.rule.engine.api.sms.SmsSender;
import org.thingsboard.rule.engine.api.sms.SmsSenderFactory;
import org.thingsboard.server.common.data.sms.config.AwsSnsSmsProviderConfiguration;
+import org.thingsboard.server.common.data.sms.config.SmppSmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.SmsProviderConfiguration;
import org.thingsboard.server.common.data.sms.config.TwilioSmsProviderConfiguration;
import org.thingsboard.server.service.sms.aws.AwsSmsSender;
+import org.thingsboard.server.service.sms.smpp.SmppSmsSender;
import org.thingsboard.server.service.sms.twilio.TwilioSmsSender;
@Component
@@ -34,6 +36,8 @@ public class DefaultSmsSenderFactory implements SmsSenderFactory {
return new AwsSmsSender((AwsSnsSmsProviderConfiguration)config);
case TWILIO:
return new TwilioSmsSender((TwilioSmsProviderConfiguration)config);
+ case SMPP:
+ return new SmppSmsSender((SmppSmsProviderConfiguration) config);
default:
throw new RuntimeException("Unknown SMS provider type " + config.getType());
}
diff --git a/application/src/main/java/org/thingsboard/server/service/sms/smpp/SmppSmsSender.java b/application/src/main/java/org/thingsboard/server/service/sms/smpp/SmppSmsSender.java
new file mode 100644
index 0000000000..57c5c5d25c
--- /dev/null
+++ b/application/src/main/java/org/thingsboard/server/service/sms/smpp/SmppSmsSender.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright © 2016-2022 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.thingsboard.server.service.sms.smpp;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.smpp.Connection;
+import org.smpp.Data;
+import org.smpp.Session;
+import org.smpp.TCPIPConnection;
+import org.smpp.TimeoutException;
+import org.smpp.WrongSessionStateException;
+import org.smpp.pdu.Address;
+import org.smpp.pdu.BindReceiver;
+import org.smpp.pdu.BindRequest;
+import org.smpp.pdu.BindResponse;
+import org.smpp.pdu.BindTransciever;
+import org.smpp.pdu.BindTransmitter;
+import org.smpp.pdu.PDUException;
+import org.smpp.pdu.SubmitSM;
+import org.smpp.pdu.SubmitSMResp;
+import org.thingsboard.rule.engine.api.sms.exception.SmsException;
+import org.thingsboard.server.common.data.sms.config.SmppSmsProviderConfiguration;
+import org.thingsboard.server.service.sms.AbstractSmsSender;
+
+import java.io.IOException;
+import java.util.Optional;
+
+@Slf4j
+public class SmppSmsSender extends AbstractSmsSender {
+ protected SmppSmsProviderConfiguration config;
+
+ protected Session smppSession;
+
+ public SmppSmsSender(SmppSmsProviderConfiguration config) {
+ if (config.getBindType() == null) {
+ config.setBindType(SmppSmsProviderConfiguration.SmppBindType.TX);
+ }
+ if (StringUtils.isNotEmpty(config.getSourceAddress())) {
+ if (config.getSourceTon() == null) {
+ config.setSourceTon((byte) 5);
+ }
+ if (config.getSourceNpi() == null) {
+ config.setSourceNpi((byte) 0);
+ }
+ }
+ if (config.getDestinationTon() == null) {
+ config.setDestinationTon((byte) 5);
+ }
+ if (config.getDestinationNpi() == null) {
+ config.setDestinationNpi((byte) 0);
+ }
+
+ this.config = config;
+ this.smppSession = initSmppSession();
+ }
+
+ private SmppSmsSender() {} // for testing purposes
+
+
+ @Override
+ public int sendSms(String numberTo, String message) throws SmsException {
+ try {
+ checkSmppSession();
+
+ SubmitSM request = new SubmitSM();
+ if (StringUtils.isNotEmpty(config.getServiceType())) {
+ request.setServiceType(config.getServiceType());
+ }
+ if (StringUtils.isNotEmpty(config.getSourceAddress())) {
+ request.setSourceAddr(new Address(config.getSourceTon(), config.getSourceNpi(), config.getSourceAddress()));
+ }
+ request.setDestAddr(new Address(config.getDestinationTon(), config.getDestinationNpi(), prepareNumber(numberTo)));
+ request.setShortMessage(message);
+ request.setDataCoding(Optional.ofNullable(config.getCodingScheme()).orElse((byte) 0));
+ request.setReplaceIfPresentFlag((byte) 0);
+ request.setEsmClass((byte) 0);
+ request.setProtocolId((byte) 0);
+ request.setPriorityFlag((byte) 0);
+ request.setRegisteredDelivery((byte) 0);
+ request.setSmDefaultMsgId((byte) 0);
+
+ SubmitSMResp response = smppSession.submit(request);
+
+ log.debug("SMPP submit command status: {}", response.getCommandStatus());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ return countMessageSegments(message);
+ }
+
+ private synchronized void checkSmppSession() {
+ if (smppSession == null || !smppSession.isOpened()) {
+ smppSession = initSmppSession();
+ }
+ }
+
+ protected Session initSmppSession() {
+ try {
+ Connection connection = new TCPIPConnection(config.getHost(), config.getPort());
+ Session session = new Session(connection);
+
+ BindRequest bindRequest;
+ switch (config.getBindType()) {
+ case TX:
+ bindRequest = new BindTransmitter();
+ break;
+ case RX:
+ bindRequest = new BindReceiver();
+ break;
+ case TRX:
+ bindRequest = new BindTransciever();
+ break;
+ default:
+ throw new UnsupportedOperationException("Unsupported bind type " + config.getBindType());
+ }
+
+ bindRequest.setSystemId(config.getSystemId());
+ bindRequest.setPassword(config.getPassword());
+
+ byte interfaceVersion;
+ switch (config.getProtocolVersion()) {
+ case "3.3":
+ interfaceVersion = Data.SMPP_V33;
+ break;
+ case "3.4":
+ interfaceVersion = Data.SMPP_V34;
+ break;
+ default:
+ throw new UnsupportedOperationException("Unsupported SMPP version: " + config.getProtocolVersion());
+ }
+ bindRequest.setInterfaceVersion(interfaceVersion);
+
+ if (StringUtils.isNotEmpty(config.getSystemType())) {
+ bindRequest.setSystemType(config.getSystemType());
+ }
+ if (StringUtils.isNotEmpty(config.getAddressRange())) {
+ bindRequest.setAddressRange(config.getDestinationTon(), config.getDestinationNpi(), config.getAddressRange());
+ }
+
+ BindResponse bindResponse = session.bind(bindRequest);
+ log.debug("SMPP bind response: {}", bindResponse.debugString());
+
+ if (bindResponse.getCommandStatus() != 0) {
+ throw new IllegalStateException("Error status when binding: " + bindResponse.getCommandStatus());
+ }
+
+ return session;
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to establish SMPP session: " + ExceptionUtils.getRootCauseMessage(e), e);
+ }
+ }
+
+ private String prepareNumber(String number) {
+ if (config.getDestinationTon() == Data.GSM_TON_INTERNATIONAL) {
+ return StringUtils.removeStart(number, "+");
+ }
+ return number;
+ }
+
+ @Override
+ public void destroy() {
+ try {
+ smppSession.unbind();
+ smppSession.close();
+ } catch (TimeoutException | PDUException | IOException | WrongSessionStateException e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+}
diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml
index 03c3bbd9f9..0aa7b3bb66 100644
--- a/application/src/main/resources/thingsboard.yml
+++ b/application/src/main/resources/thingsboard.yml
@@ -283,6 +283,11 @@ sql:
batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}"
stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}"
batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
+ edge_events:
+ batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}"
+ batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}"
+ stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}"
+ batch_threads: "${SQL_EDGE_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution
# Specify whether to sort entities before batch update. Should be enabled for cluster mode to avoid deadlocks
batch_sort: "${SQL_BATCH_SORT:false}"
# Specify whether to remove null characters from strValue of attributes and timeseries before insert
@@ -476,6 +481,8 @@ updates:
# Enable/disable updates checking.
enabled: "${UPDATES_ENABLED:true}"
+spring.main.allow-circular-references: "true"
+
# spring freemarker configuration
spring.freemarker.checkTemplateLocation: "false"
@@ -485,7 +492,7 @@ spring.mvc.cors:
# Intercept path
"[/api/**]":
#Comma-separated list of origins to allow. '*' allows all origins. When not set,CORS support is disabled.
- allowed-origins: "*"
+ allowed-origin-patterns: "*"
#Comma-separated list of methods to allow. '*' allows all methods.
allowed-methods: "*"
#Comma-separated list of headers to allow in a request. '*' allows all headers.
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
index eae6f59198..98e4c12759 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractControllerTest.java
@@ -16,16 +16,25 @@
package org.thingsboard.server.controller;
import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootContextLoader;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
-import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThat;
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
@@ -33,9 +42,49 @@ import org.springframework.test.context.web.WebAppConfiguration;
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@Configuration
@ComponentScan({"org.thingsboard.server"})
-@WebAppConfiguration
-@SpringBootTest()
+@EnableWebSocket
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Slf4j
-public abstract class AbstractControllerTest extends AbstractWebTest {
+public abstract class AbstractControllerTest extends AbstractWebTest {
+
+ public static final String WS_URL = "ws://localhost:";
+
+ @LocalServerPort
+ protected int wsPort;
+
+ private TbTestWebSocketClient wsClient; // lazy
+
+ public TbTestWebSocketClient getWsClient() {
+ if (wsClient == null) {
+ synchronized (this) {
+ try {
+ if (wsClient == null) {
+ wsClient = buildAndConnectWebSocketClient();
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return wsClient;
+ }
+
+ @Before
+ public void beforeWsTest() throws Exception {
+ // placeholder
+ }
+
+ @After
+ public void afterWsTest() throws Exception {
+ if (wsClient != null) {
+ wsClient.close();
+ }
+ }
+
+ private TbTestWebSocketClient buildAndConnectWebSocketClient() throws URISyntaxException, InterruptedException {
+ TbTestWebSocketClient wsClient = new TbTestWebSocketClient(new URI(WS_URL + wsPort + "/api/ws/plugins/telemetry?token=" + token));
+ assertThat(wsClient.connectBlocking(TIMEOUT, TimeUnit.SECONDS)).isTrue();
+ return wsClient;
+ }
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java
index 59f7714233..efa9d9f08a 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractInMemoryStorageTest.java
@@ -23,20 +23,4 @@ import org.thingsboard.server.queue.memory.InMemoryStorage;
@Slf4j
public abstract class AbstractInMemoryStorageTest {
- @Before
- public void setUpInMemoryStorage() {
- log.info("set up InMemoryStorage");
- cleanupInMemStorage();
- }
-
- @After
- public void tearDownInMemoryStorage() {
- log.info("tear down InMemoryStorage");
- cleanupInMemStorage();
- }
-
- public static void cleanupInMemStorage() {
- InMemoryStorage.getInstance().cleanup();
- }
-
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
index cc561e31a8..b4d0fe87e7 100644
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java
@@ -18,6 +18,9 @@ package org.thingsboard.server.controller;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jwt;
@@ -67,6 +70,7 @@ import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.UUIDBased;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.page.TimePageLink;
@@ -97,6 +101,7 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppC
@Slf4j
public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
+ public static final int TIMEOUT = 30;
protected ObjectMapper mapper = new ObjectMapper();
@@ -106,7 +111,7 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
private static final String SYS_ADMIN_PASSWORD = "sysadmin";
protected static final String TENANT_ADMIN_EMAIL = "testtenant@thingsboard.org";
- private static final String TENANT_ADMIN_PASSWORD = "tenant";
+ protected static final String TENANT_ADMIN_PASSWORD = "tenant";
protected static final String CUSTOMER_USER_EMAIL = "testcustomer@thingsboard.org";
private static final String CUSTOMER_USER_PASSWORD = "customer";
@@ -377,18 +382,23 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
}
}
+ protected DeviceProfile createDeviceProfile(String name) {
+ return createDeviceProfile(name, null);
+ }
+
protected DeviceProfile createDeviceProfile(String name, DeviceProfileTransportConfiguration deviceProfileTransportConfiguration) {
DeviceProfile deviceProfile = new DeviceProfile();
deviceProfile.setName(name);
deviceProfile.setType(DeviceProfileType.DEFAULT);
- deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfile.setDescription(name + " Test");
DeviceProfileData deviceProfileData = new DeviceProfileData();
DefaultDeviceProfileConfiguration configuration = new DefaultDeviceProfileConfiguration();
deviceProfileData.setConfiguration(configuration);
if (deviceProfileTransportConfiguration != null) {
+ deviceProfile.setTransportType(deviceProfileTransportConfiguration.getType());
deviceProfileData.setTransportConfiguration(deviceProfileTransportConfiguration);
} else {
+ deviceProfile.setTransportType(DeviceTransportType.DEFAULT);
deviceProfileData.setTransportConfiguration(new DefaultDeviceProfileTransportConfiguration());
}
deviceProfile.setProfileData(deviceProfileData);
@@ -397,10 +407,11 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return deviceProfile;
}
- protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration) {
+ protected MqttDeviceProfileTransportConfiguration createMqttDeviceProfileTransportConfiguration(TransportPayloadTypeConfiguration transportPayloadTypeConfiguration, boolean sendAckOnValidationException) {
MqttDeviceProfileTransportConfiguration mqttDeviceProfileTransportConfiguration = new MqttDeviceProfileTransportConfiguration();
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_TELEMETRY_TOPIC);
mqttDeviceProfileTransportConfiguration.setDeviceTelemetryTopic(MqttTopics.DEVICE_ATTRIBUTES_TOPIC);
+ mqttDeviceProfileTransportConfiguration.setSendAckOnValidationException(sendAckOnValidationException);
mqttDeviceProfileTransportConfiguration.setTransportPayloadTypeConfiguration(transportPayloadTypeConfiguration);
return mqttDeviceProfileTransportConfiguration;
}
@@ -503,16 +514,24 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType);
}
- protected T doPost(String urlTemplate, Class responseClass, String... params) throws Exception {
- return readResponse(doPost(urlTemplate, params).andExpect(status().isOk()), responseClass);
+ protected T doPost(String urlTemplate, Class responseClass, String... params) {
+ try {
+ return readResponse(doPost(urlTemplate, params).andExpect(status().isOk()), responseClass);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
protected T doPost(String urlTemplate, T content, Class responseClass, ResultMatcher resultMatcher, String... params) throws Exception {
return readResponse(doPost(urlTemplate, content, params).andExpect(resultMatcher), responseClass);
}
- protected T doPost(String urlTemplate, T content, Class responseClass, String... params) throws Exception {
- return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
+ protected T doPost(String urlTemplate, T content, Class responseClass, String... params) {
+ try {
+ return readResponse(doPost(urlTemplate, content, params).andExpect(status().isOk()), responseClass);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
}
protected R doPostWithResponse(String urlTemplate, T content, Class responseClass, String... params) throws Exception {
@@ -633,4 +652,15 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest {
edge.setRoutingKey(RandomStringUtils.randomAlphanumeric(20));
return edge;
}
+
+ protected > ListenableFuture> deleteEntitiesAsync(String urlTemplate, List entities, ListeningExecutorService executor) {
+ List> futures = new ArrayList<>(entities.size());
+ for (T entity : entities) {
+ futures.add(executor.submit(() ->
+ doDelete(urlTemplate + entity.getId().getId())
+ .andExpect(status().isOk())));
+ }
+ return Futures.allAsList(futures);
+ }
+
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java
deleted file mode 100644
index 15884f38a0..0000000000
--- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebsocketTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright © 2016-2022 The Thingsboard Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.thingsboard.server.controller;
-
-import lombok.extern.slf4j.Slf4j;
-import org.junit.Assert;
-import org.junit.runner.RunWith;
-import org.springframework.boot.test.context.SpringBootContextLoader;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.web.server.LocalServerPort;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringRunner;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-@ActiveProfiles("test")
-@RunWith(SpringRunner.class)
-@ContextConfiguration(classes = AbstractControllerTest.class, loader = SpringBootContextLoader.class)
-@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
-@Configuration
-@ComponentScan({"org.thingsboard.server"})
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@Slf4j
-public abstract class AbstractWebsocketTest extends AbstractWebTest {
-
- protected static final String WS_URL = "ws://localhost:";
-
- @LocalServerPort
- protected int wsPort;
-
- protected TbTestWebSocketClient buildAndConnectWebSocketClient() throws URISyntaxException, InterruptedException {
- TbTestWebSocketClient wsClient = new TbTestWebSocketClient(new URI(WS_URL + wsPort + "/api/ws/plugins/telemetry?token=" + token));
- Assert.assertTrue(wsClient.connectBlocking());
- return wsClient;
- }
-
-}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
index c44c005efb..0861ab34c8 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseAssetControllerTest.java
@@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.EntitySubtype;
+import org.thingsboard.server.common.data.EntityView;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
import org.thingsboard.server.common.data.asset.Asset;
@@ -182,6 +183,39 @@ public abstract class BaseAssetControllerTest extends AbstractControllerTest {
.andExpect(status().isNotFound());
}
+ @Test
+ public void testDeleteAssetAssignedToEntityView() throws Exception {
+ Asset asset1 = new Asset();
+ asset1.setName("My asset 1");
+ asset1.setType("default");
+ Asset savedAsset1 = doPost("/api/asset", asset1, Asset.class);
+
+ Asset asset2 = new Asset();
+ asset2.setName("My asset 2");
+ asset2.setType("default");
+ Asset savedAsset2 = doPost("/api/asset", asset2, Asset.class);
+
+ EntityView view = new EntityView();
+ view.setEntityId(savedAsset1.getId());
+ view.setTenantId(savedTenant.getId());
+ view.setName("My entity view");
+ view.setType("default");
+ EntityView savedView = doPost("/api/entityView", view, EntityView.class);
+
+ doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
+ .andExpect(status().isBadRequest());
+
+ savedView.setEntityId(savedAsset2.getId());
+
+ doPost("/api/entityView", savedView, EntityView.class);
+
+ doDelete("/api/asset/" + savedAsset1.getId().getId().toString())
+ .andExpect(status().isOk());
+
+ doGet("/api/asset/" + savedAsset1.getId().getId().toString())
+ .andExpect(status().isNotFound());
+ }
+
@Test
public void testSaveAssetWithEmptyType() throws Exception {
Asset asset = new Asset();
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java
index dcf3f85a71..a7f623d2e4 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseCustomerControllerTest.java
@@ -15,16 +15,17 @@
*/
package org.thingsboard.server.controller;
-import static org.hamcrest.Matchers.containsString;
-import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
+import org.junit.Test;
+import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Tenant;
import org.thingsboard.server.common.data.User;
@@ -32,20 +33,28 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink;
import org.thingsboard.server.common.data.security.Authority;
-import org.junit.Assert;
-import org.junit.Test;
-import com.fasterxml.jackson.core.type.TypeReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
public abstract class BaseCustomerControllerTest extends AbstractControllerTest {
+ static final TypeReference> PAGE_DATA_CUSTOMER_TYPE_REFERENCE = new TypeReference<>() {
+ };
- private IdComparator idComparator = new IdComparator<>();
+ ListeningExecutorService executor;
private Tenant savedTenant;
private User tenantAdmin;
@Before
public void beforeTest() throws Exception {
+ executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
+
loginSysAdmin();
Tenant tenant = new Tenant();
@@ -65,6 +74,8 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
@After
public void afterTest() throws Exception {
+ executor.shutdownNow();
+
loginSysAdmin();
doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
@@ -83,11 +94,11 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
savedCustomer.setTitle("My new customer");
doPost("/api/customer", savedCustomer, Customer.class);
- Customer foundCustomer = doGet("/api/customer/"+savedCustomer.getId().getId().toString(), Customer.class);
+ Customer foundCustomer = doGet("/api/customer/" + savedCustomer.getId().getId().toString(), Customer.class);
Assert.assertEquals(foundCustomer.getTitle(), savedCustomer.getTitle());
- doDelete("/api/customer/"+savedCustomer.getId().getId().toString())
- .andExpect(status().isOk());
+ doDelete("/api/customer/" + savedCustomer.getId().getId().toString())
+ .andExpect(status().isOk());
}
@Test
@@ -182,29 +193,30 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
public void testFindCustomers() throws Exception {
TenantId tenantId = savedTenant.getId();
- List customers = new ArrayList<>();
+ List> futures = new ArrayList<>(135);
for (int i = 0; i < 135; i++) {
Customer customer = new Customer();
customer.setTenantId(tenantId);
customer.setTitle("Customer" + i);
- customers.add(doPost("/api/customer", customer, Customer.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/customer", customer, Customer.class)));
}
+ List customers = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
- List loadedCustomers = new ArrayList<>();
+ List loadedCustomers = new ArrayList<>(135);
PageLink pageLink = new PageLink(23);
PageData pageData = null;
do {
- pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference>(){}, pageLink);
+ pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomers.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
- Collections.sort(customers, idComparator);
- Collections.sort(loadedCustomers, idComparator);
+ assertThat(customers).containsExactlyInAnyOrderElementsOf(loadedCustomers);
- Assert.assertEquals(customers, loadedCustomers);
+ deleteEntitiesAsync("/api/customer/", loadedCustomers, executor).get(TIMEOUT, TimeUnit.SECONDS);
}
@Test
@@ -212,7 +224,7 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
TenantId tenantId = savedTenant.getId();
String title1 = "Customer title 1";
- List customersTitle1 = new ArrayList<>();
+ List> futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) {
Customer customer = new Customer();
customer.setTenantId(tenantId);
@@ -220,10 +232,13 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
String title = title1 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
customer.setTitle(title);
- customersTitle1.add(doPost("/api/customer", customer, Customer.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/customer", customer, Customer.class)));
}
+ List customersTitle1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
String title2 = "Customer title 2";
- List customersTitle2 = new ArrayList<>();
+ futures = new ArrayList<>(175);
for (int i = 0; i < 175; i++) {
Customer customer = new Customer();
customer.setTenantId(tenantId);
@@ -231,57 +246,48 @@ public abstract class BaseCustomerControllerTest extends AbstractControllerTest
String title = title2 + suffix;
title = i % 2 == 0 ? title.toLowerCase() : title.toUpperCase();
customer.setTitle(title);
- customersTitle2.add(doPost("/api/customer", customer, Customer.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/customer", customer, Customer.class)));
}
+ List customersTitle2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
List loadedCustomersTitle1 = new ArrayList<>();
PageLink pageLink = new PageLink(15, 0, title1);
PageData pageData = null;
do {
- pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference>(){}, pageLink);
+ pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomersTitle1.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
- Collections.sort(customersTitle1, idComparator);
- Collections.sort(loadedCustomersTitle1, idComparator);
-
- Assert.assertEquals(customersTitle1, loadedCustomersTitle1);
+ assertThat(customersTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedCustomersTitle1);
List loadedCustomersTitle2 = new ArrayList<>();
pageLink = new PageLink(4, 0, title2);
do {
- pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference>(){}, pageLink);
+ pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
loadedCustomersTitle2.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
- Collections.sort(customersTitle2, idComparator);
- Collections.sort(loadedCustomersTitle2, idComparator);
+ assertThat(customersTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedCustomersTitle2);
- Assert.assertEquals(customersTitle2, loadedCustomersTitle2);
-
- for (Customer customer : loadedCustomersTitle1) {
- doDelete("/api/customer/" + customer.getId().getId().toString())
- .andExpect(status().isOk());
- }
+ deleteEntitiesAsync("/api/customer/", loadedCustomersTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
pageLink = new PageLink(4, 0, title1);
- pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference>(){}, pageLink);
+ pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
- for (Customer customer : loadedCustomersTitle2) {
- doDelete("/api/customer/" + customer.getId().getId().toString())
- .andExpect(status().isOk());
- }
+ deleteEntitiesAsync("/api/customer/", loadedCustomersTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
pageLink = new PageLink(4, 0, title2);
- pageData = doGetTypedWithPageLink("/api/customers?", new TypeReference>(){}, pageLink);
+ pageData = doGetTypedWithPageLink("/api/customers?", PAGE_DATA_CUSTOMER_TYPE_REFERENCE, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}
diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
index 27173b3e38..d6e30c644c 100644
--- a/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
+++ b/application/src/test/java/org/thingsboard/server/controller/BaseDeviceControllerTest.java
@@ -17,11 +17,17 @@ package org.thingsboard.server.controller;
import com.datastax.oss.driver.api.core.uuid.Uuids;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.thingsboard.common.util.ThingsBoardExecutors;
import org.thingsboard.server.common.data.Customer;
import org.thingsboard.server.common.data.Device;
import org.thingsboard.server.common.data.EntitySubtype;
@@ -41,22 +47,32 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType;
import org.thingsboard.server.dao.model.ModelConstants;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import java.util.concurrent.TimeUnit;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID;
+@Slf4j
public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
+ static final TypeReference> PAGE_DATA_DEVICE_TYPE_REF = new TypeReference<>() {
+ };
- private IdComparator idComparator = new IdComparator<>();
+ ListeningExecutorService executor;
+
+ List> futures;
+ PageData pageData;
private Tenant savedTenant;
private User tenantAdmin;
@Before
public void beforeTest() throws Exception {
+ log.debug("beforeTest");
+ executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(8, getClass()));
+
loginSysAdmin();
Tenant tenant = new Tenant();
@@ -76,10 +92,14 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@After
public void afterTest() throws Exception {
+ log.debug("afterTest...");
+ executor.shutdownNow();
+
loginSysAdmin();
- doDelete("/api/tenant/" + savedTenant.getId().getId().toString())
+ doDelete("/api/tenant/" + savedTenant.getId().getId())
.andExpect(status().isOk());
+ log.debug("afterTest done");
}
@Test
@@ -98,7 +118,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals(device.getName(), savedDevice.getName());
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertNotNull(deviceCredentials);
Assert.assertNotNull(deviceCredentials.getId());
@@ -110,7 +130,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
savedDevice.setName("My new device");
doPost("/api/device", savedDevice, Device.class);
- Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
+ Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(foundDevice.getName(), savedDevice.getName());
}
@@ -145,7 +165,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setName("My device");
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
- Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
+ Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertNotNull(foundDevice);
Assert.assertEquals(savedDevice, foundDevice);
}
@@ -180,6 +200,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
Assert.assertEquals("typeA", deviceTypes.get(0).getType());
Assert.assertEquals("typeB", deviceTypes.get(1).getType());
Assert.assertEquals("typeC", deviceTypes.get(2).getType());
+
+ deleteEntitiesAsync("/api/device/", devices, executor).get(TIMEOUT, TimeUnit.SECONDS);
}
@Test
@@ -189,10 +211,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
- doDelete("/api/device/" + savedDevice.getId().getId().toString())
+ doDelete("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isOk());
- doGet("/api/device/" + savedDevice.getId().getId().toString())
+ doGet("/api/device/" + savedDevice.getId().getId())
.andExpect(status().isNotFound());
}
@@ -224,18 +246,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
customer.setTitle("My customer");
Customer savedCustomer = doPost("/api/customer", customer, Customer.class);
- Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString()
- + "/device/" + savedDevice.getId().getId().toString(), Device.class);
+ Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId()
+ + "/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId());
- Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
+ Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId());
Device unassignedDevice =
- doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class);
+ doDelete("/api/customer/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId());
- foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class);
+ foundDevice = doGet("/api/device/" + savedDevice.getId().getId(), Device.class);
Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId());
}
@@ -246,7 +268,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
doPost("/api/customer/" + Uuids.timeBased().toString()
- + "/device/" + savedDevice.getId().getId().toString())
+ + "/device/" + savedDevice.getId().getId())
.andExpect(status().isNotFound());
}
@@ -279,13 +301,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
- doPost("/api/customer/" + savedCustomer.getId().getId().toString()
- + "/device/" + savedDevice.getId().getId().toString())
+ doPost("/api/customer/" + savedCustomer.getId().getId()
+ + "/device/" + savedDevice.getId().getId())
.andExpect(status().isForbidden());
loginSysAdmin();
- doDelete("/api/tenant/" + savedTenant2.getId().getId().toString())
+ doDelete("/api/tenant/" + savedTenant2.getId().getId())
.andExpect(status().isOk());
}
@@ -296,7 +318,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
}
@@ -307,7 +329,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId());
deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN);
deviceCredentials.setCredentialsId("access_token");
@@ -315,7 +337,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
.andExpect(status().isOk());
DeviceCredentials foundDeviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
Assert.assertEquals(deviceCredentials, foundDeviceCredentials);
}
@@ -334,7 +356,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsType(null);
doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest())
@@ -348,7 +370,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setCredentialsId(null);
doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isBadRequest())
@@ -362,7 +384,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(Uuids.timeBased()));
newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime());
newDeviceCredentials.setDeviceId(deviceCredentials.getDeviceId());
@@ -380,7 +402,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
device.setType("default");
Device savedDevice = doPost("/api/device", device, Device.class);
DeviceCredentials deviceCredentials =
- doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class);
+ doGet("/api/device/" + savedDevice.getId().getId() + "/credentials", DeviceCredentials.class);
deviceCredentials.setDeviceId(new DeviceId(Uuids.timeBased()));
doPost("/api/device/credentials", deviceCredentials)
.andExpect(status().isNotFound());
@@ -388,19 +410,24 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
@Test
public void testFindTenantDevices() throws Exception {
- List devices = new ArrayList<>();
+ log.debug("testFindTenantDevices");
+ futures = new ArrayList<>(178);
for (int i = 0; i < 178; i++) {
Device device = new Device();
device.setName("Device" + i);
device.setType("default");
- devices.add(doPost("/api/device", device, Device.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/device", device, Device.class)));
}
- List loadedDevices = new ArrayList<>();
+ log.debug("await create devices");
+ List devices = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
+ log.debug("start reading");
+ List loadedDevices = new ArrayList<>(178);
PageLink pageLink = new PageLink(23);
- PageData pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?",
- new TypeReference>(){}, pageLink);
+ PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevices.addAll(pageData.getData());
if (pageData.hasNext()) {
@@ -408,16 +435,18 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
}
} while (pageData.hasNext());
- Collections.sort(devices, idComparator);
- Collections.sort(loadedDevices, idComparator);
-
- Assert.assertEquals(devices, loadedDevices);
+ log.debug("asserting");
+ assertThat(devices).containsExactlyInAnyOrderElementsOf(loadedDevices);
+ log.debug("delete devices async");
+ deleteEntitiesAsync("/api/device/", loadedDevices, executor).get(TIMEOUT, TimeUnit.SECONDS);
+ log.debug("done");
}
@Test
public void testFindTenantDevicesByName() throws Exception {
String title1 = "Device title 1";
- List devicesTitle1 = new ArrayList<>();
+
+ futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) {
Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15);
@@ -425,10 +454,13 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
device.setType("default");
- devicesTitle1.add(doPost("/api/device", device, Device.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/device", device, Device.class)));
}
+ List devicesTitle1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
String title2 = "Device title 2";
- List devicesTitle2 = new ArrayList<>();
+ futures = new ArrayList<>(75);
for (int i = 0; i < 75; i++) {
Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15);
@@ -436,59 +468,50 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
device.setType("default");
- devicesTitle2.add(doPost("/api/device", device, Device.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/device", device, Device.class)));
}
+ List devicesTitle2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
- List loadedDevicesTitle1 = new ArrayList<>();
+ List loadedDevicesTitle1 = new ArrayList<>(143);
PageLink pageLink = new PageLink(15, 0, title1);
- PageData pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?",
- new TypeReference>(){}, pageLink);
+ PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle1.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
- Collections.sort(devicesTitle1, idComparator);
- Collections.sort(loadedDevicesTitle1, idComparator);
-
- Assert.assertEquals(devicesTitle1, loadedDevicesTitle1);
+ assertThat(devicesTitle1).as(title1).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle1);
- List loadedDevicesTitle2 = new ArrayList<>();
+ List loadedDevicesTitle2 = new ArrayList<>(75);
pageLink = new PageLink(4, 0, title2);
do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?",
- new TypeReference>(){}, pageLink);
+ PAGE_DATA_DEVICE_TYPE_REF, pageLink);
loadedDevicesTitle2.addAll(pageData.getData());
if (pageData.hasNext()) {
pageLink = pageLink.nextPageLink();
}
} while (pageData.hasNext());
- Collections.sort(devicesTitle2, idComparator);
- Collections.sort(loadedDevicesTitle2, idComparator);
+ assertThat(devicesTitle2).as(title2).containsExactlyInAnyOrderElementsOf(loadedDevicesTitle2);
- Assert.assertEquals(devicesTitle2, loadedDevicesTitle2);
+ deleteEntitiesAsync("/api/device/", loadedDevicesTitle1, executor).get(TIMEOUT, TimeUnit.SECONDS);
- for (Device device : loadedDevicesTitle1) {
- doDelete("/api/device/" + device.getId().getId().toString())
- .andExpect(status().isOk());
- }
pageLink = new PageLink(4, 0, title1);
pageData = doGetTypedWithPageLink("/api/tenant/devices?",
- new TypeReference>(){}, pageLink);
+ PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
- for (Device device : loadedDevicesTitle2) {
- doDelete("/api/device/" + device.getId().getId().toString())
- .andExpect(status().isOk());
- }
+ deleteEntitiesAsync("/api/device/", loadedDevicesTitle2, executor).get(TIMEOUT, TimeUnit.SECONDS);
+
pageLink = new PageLink(4, 0, title2);
pageData = doGetTypedWithPageLink("/api/tenant/devices?",
- new TypeReference>(){}, pageLink);
+ PAGE_DATA_DEVICE_TYPE_REF, pageLink);
Assert.assertFalse(pageData.hasNext());
Assert.assertEquals(0, pageData.getData().size());
}
@@ -497,7 +520,7 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
public void testFindTenantDevicesByType() throws Exception {
String title1 = "Device title 1";
String type1 = "typeA";
- List devicesType1 = new ArrayList<>();
+ futures = new ArrayList<>(143);
for (int i = 0; i < 143; i++) {
Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15);
@@ -505,11 +528,17 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
device.setType(type1);
- devicesType1.add(doPost("/api/device", device, Device.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/device", device, Device.class)));
+ if (i == 0) {
+ futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
+ }
}
+ List devicesType1 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
String title2 = "Device title 2";
String type2 = "typeB";
- List devicesType2 = new ArrayList<>();
+ futures = new ArrayList<>(75);
for (int i = 0; i < 75; i++) {
Device device = new Device();
String suffix = RandomStringUtils.randomAlphanumeric(15);
@@ -517,61 +546,54 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest {
name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase();
device.setName(name);
device.setType(type2);
- devicesType2.add(doPost("/api/device", device, Device.class));
+ futures.add(executor.submit(() ->
+ doPost("/api/device", device, Device.class)));
+ if (i == 0) {
+ futures.get(0).get(TIMEOUT, TimeUnit.SECONDS); // wait for the device profile created first time
+ }
}
- List loadedDevicesType1 = new ArrayList<>();
+ List devicesType2 = Futures.allAsList(futures).get(TIMEOUT, TimeUnit.SECONDS);
+
+ List loadedDevicesType1 = new ArrayList<>(143);
PageLink pageLink = new PageLink(15);
- PageData pageData = null;
do {
pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&",
- new TypeReference