Commit c526d13e453cc8acd07dcca96598abc06ae6e4d6
Merge remote-tracking branch 'upstream/develop/2.5.5' into feature/edge
Showing
130 changed files
with
1488 additions
and
503 deletions
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>application</artifactId> | 26 | <artifactId>application</artifactId> |
@@ -64,6 +64,7 @@ BEGIN | @@ -64,6 +64,7 @@ BEGIN | ||
64 | AND tablename like 'ts_kv_' || '%' | 64 | AND tablename like 'ts_kv_' || '%' |
65 | AND tablename != 'ts_kv_latest' | 65 | AND tablename != 'ts_kv_latest' |
66 | AND tablename != 'ts_kv_dictionary' | 66 | AND tablename != 'ts_kv_dictionary' |
67 | + AND tablename != 'ts_kv_indefinite' | ||
67 | LOOP | 68 | LOOP |
68 | IF partition != partition_by_max_ttl_date THEN | 69 | IF partition != partition_by_max_ttl_date THEN |
69 | IF partition_year IS NOT NULL THEN | 70 | IF partition_year IS NOT NULL THEN |
@@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | @@ -28,6 +28,7 @@ import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; | ||
28 | import org.thingsboard.server.actors.ActorSystemContext; | 28 | import org.thingsboard.server.actors.ActorSystemContext; |
29 | import org.thingsboard.server.actors.TbActorCtx; | 29 | import org.thingsboard.server.actors.TbActorCtx; |
30 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; | 30 | import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; |
31 | +import org.thingsboard.server.common.data.DataConstants; | ||
31 | import org.thingsboard.server.common.data.Device; | 32 | import org.thingsboard.server.common.data.Device; |
32 | import org.thingsboard.server.common.data.id.DeviceId; | 33 | import org.thingsboard.server.common.data.id.DeviceId; |
33 | import org.thingsboard.server.common.data.id.TenantId; | 34 | import org.thingsboard.server.common.data.id.TenantId; |
@@ -79,8 +80,6 @@ import java.util.UUID; | @@ -79,8 +80,6 @@ import java.util.UUID; | ||
79 | import java.util.function.Consumer; | 80 | import java.util.function.Consumer; |
80 | import java.util.stream.Collectors; | 81 | import java.util.stream.Collectors; |
81 | 82 | ||
82 | -import static org.thingsboard.server.common.data.DataConstants.CLIENT_SCOPE; | ||
83 | -import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; | ||
84 | 83 | ||
85 | /** | 84 | /** |
86 | * @author Andrew Shvayka | 85 | * @author Andrew Shvayka |
@@ -279,17 +278,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -279,17 +278,17 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
279 | ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture; | 278 | ListenableFuture<List<AttributeKvEntry>> clientAttributesFuture; |
280 | ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture; | 279 | ListenableFuture<List<AttributeKvEntry>> sharedAttributesFuture; |
281 | if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { | 280 | if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { |
282 | - clientAttributesFuture = findAllAttributesByScope(CLIENT_SCOPE); | ||
283 | - sharedAttributesFuture = findAllAttributesByScope(SHARED_SCOPE); | 281 | + clientAttributesFuture = findAllAttributesByScope(DataConstants.CLIENT_SCOPE); |
282 | + sharedAttributesFuture = findAllAttributesByScope(DataConstants.SHARED_SCOPE); | ||
284 | } else if (!CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { | 283 | } else if (!CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { |
285 | - clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), CLIENT_SCOPE); | ||
286 | - sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); | 284 | + clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), DataConstants.CLIENT_SCOPE); |
285 | + sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), DataConstants.SHARED_SCOPE); | ||
287 | } else if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { | 286 | } else if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { |
288 | clientAttributesFuture = Futures.immediateFuture(Collections.emptyList()); | 287 | clientAttributesFuture = Futures.immediateFuture(Collections.emptyList()); |
289 | - sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); | 288 | + sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), DataConstants.SHARED_SCOPE); |
290 | } else { | 289 | } else { |
291 | sharedAttributesFuture = Futures.immediateFuture(Collections.emptyList()); | 290 | sharedAttributesFuture = Futures.immediateFuture(Collections.emptyList()); |
292 | - clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), CLIENT_SCOPE); | 291 | + clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), DataConstants.CLIENT_SCOPE); |
293 | } | 292 | } |
294 | return Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)); | 293 | return Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)); |
295 | } | 294 | } |
@@ -316,7 +315,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -316,7 +315,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
316 | AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); | 315 | AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); |
317 | if (msg.isDeleted()) { | 316 | if (msg.isDeleted()) { |
318 | List<String> sharedKeys = msg.getDeletedKeys().stream() | 317 | List<String> sharedKeys = msg.getDeletedKeys().stream() |
319 | - .filter(key -> SHARED_SCOPE.equals(key.getScope())) | 318 | + .filter(key -> DataConstants.SHARED_SCOPE.equals(key.getScope())) |
320 | .map(AttributeKey::getAttributeKey) | 319 | .map(AttributeKey::getAttributeKey) |
321 | .collect(Collectors.toList()); | 320 | .collect(Collectors.toList()); |
322 | if (!sharedKeys.isEmpty()) { | 321 | if (!sharedKeys.isEmpty()) { |
@@ -324,7 +323,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -324,7 +323,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
324 | hasNotificationData = true; | 323 | hasNotificationData = true; |
325 | } | 324 | } |
326 | } else { | 325 | } else { |
327 | - if (SHARED_SCOPE.equals(msg.getScope())) { | 326 | + if (DataConstants.SHARED_SCOPE.equals(msg.getScope())) { |
328 | List<AttributeKvEntry> attributes = new ArrayList<>(msg.getValues()); | 327 | List<AttributeKvEntry> attributes = new ArrayList<>(msg.getValues()); |
329 | if (attributes.size() > 0) { | 328 | if (attributes.size() > 0) { |
330 | List<TsKvProto> sharedUpdated = msg.getValues().stream().map(this::toTsKvProto) | 329 | List<TsKvProto> sharedUpdated = msg.getValues().stream().map(this::toTsKvProto) |
@@ -334,7 +333,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | @@ -334,7 +333,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { | ||
334 | hasNotificationData = true; | 333 | hasNotificationData = true; |
335 | } | 334 | } |
336 | } else { | 335 | } else { |
337 | - log.debug("[{}] No public server side attributes changed!", deviceId); | 336 | + log.debug("[{}] No public shared side attributes changed!", deviceId); |
338 | } | 337 | } |
339 | } | 338 | } |
340 | } | 339 | } |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
18 | import org.springframework.beans.factory.annotation.Autowired; | 19 | import org.springframework.beans.factory.annotation.Autowired; |
19 | import org.springframework.security.access.prepost.PreAuthorize; | 20 | import org.springframework.security.access.prepost.PreAuthorize; |
20 | import org.springframework.web.bind.annotation.PathVariable; | 21 | import org.springframework.web.bind.annotation.PathVariable; |
@@ -59,7 +60,11 @@ public class AdminController extends BaseController { | @@ -59,7 +60,11 @@ public class AdminController extends BaseController { | ||
59 | public AdminSettings getAdminSettings(@PathVariable("key") String key) throws ThingsboardException { | 60 | public AdminSettings getAdminSettings(@PathVariable("key") String key) throws ThingsboardException { |
60 | try { | 61 | try { |
61 | accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); | 62 | accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ); |
62 | - return checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key)); | 63 | + AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key)); |
64 | + if (adminSettings.getKey().equals("mail")) { | ||
65 | + ((ObjectNode) adminSettings.getJsonValue()).put("password", ""); | ||
66 | + } | ||
67 | + return adminSettings; | ||
63 | } catch (Exception e) { | 68 | } catch (Exception e) { |
64 | throw handleException(e); | 69 | throw handleException(e); |
65 | } | 70 | } |
@@ -74,6 +79,7 @@ public class AdminController extends BaseController { | @@ -74,6 +79,7 @@ public class AdminController extends BaseController { | ||
74 | adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings)); | 79 | adminSettings = checkNotNull(adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings)); |
75 | if (adminSettings.getKey().equals("mail")) { | 80 | if (adminSettings.getKey().equals("mail")) { |
76 | mailService.updateMailConfiguration(); | 81 | mailService.updateMailConfiguration(); |
82 | + ((ObjectNode) adminSettings.getJsonValue()).put("password", ""); | ||
77 | } | 83 | } |
78 | return adminSettings; | 84 | return adminSettings; |
79 | } catch (Exception e) { | 85 | } catch (Exception e) { |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
18 | import com.fasterxml.jackson.databind.ObjectMapper; | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | import com.fasterxml.jackson.databind.node.ArrayNode; | 20 | import com.fasterxml.jackson.databind.node.ArrayNode; |
20 | import com.fasterxml.jackson.databind.node.ObjectNode; | 21 | import com.fasterxml.jackson.databind.node.ObjectNode; |
@@ -624,6 +625,12 @@ public abstract class BaseController { | @@ -624,6 +625,12 @@ public abstract class BaseController { | ||
624 | case ALARM_CLEAR: | 625 | case ALARM_CLEAR: |
625 | msgType = DataConstants.ALARM_CLEAR; | 626 | msgType = DataConstants.ALARM_CLEAR; |
626 | break; | 627 | break; |
628 | + case ASSIGNED_FROM_TENANT: | ||
629 | + msgType = DataConstants.ENTITY_ASSIGNED_FROM_TENANT; | ||
630 | + break; | ||
631 | + case ASSIGNED_TO_TENANT: | ||
632 | + msgType = DataConstants.ENTITY_ASSIGNED_TO_TENANT; | ||
633 | + break; | ||
627 | case ASSIGNED_TO_EDGE: | 634 | case ASSIGNED_TO_EDGE: |
628 | msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; | 635 | msgType = DataConstants.ENTITY_ASSIGNED_TO_EDGE; |
629 | break; | 636 | break; |
@@ -649,7 +656,17 @@ public abstract class BaseController { | @@ -649,7 +656,17 @@ public abstract class BaseController { | ||
649 | String strCustomerName = extractParameter(String.class, 2, additionalInfo); | 656 | String strCustomerName = extractParameter(String.class, 2, additionalInfo); |
650 | metaData.putValue("unassignedCustomerId", strCustomerId); | 657 | metaData.putValue("unassignedCustomerId", strCustomerId); |
651 | metaData.putValue("unassignedCustomerName", strCustomerName); | 658 | metaData.putValue("unassignedCustomerName", strCustomerName); |
652 | - } if (actionType == ActionType.ASSIGNED_TO_EDGE) { | 659 | + } else if (actionType == ActionType.ASSIGNED_FROM_TENANT) { |
660 | + String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
661 | + String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
662 | + metaData.putValue("assignedFromTenantId", strTenantId); | ||
663 | + metaData.putValue("assignedFromTenantName", strTenantName); | ||
664 | + } else if (actionType == ActionType.ASSIGNED_TO_TENANT) { | ||
665 | + String strTenantId = extractParameter(String.class, 0, additionalInfo); | ||
666 | + String strTenantName = extractParameter(String.class, 1, additionalInfo); | ||
667 | + metaData.putValue("assignedToTenantId", strTenantId); | ||
668 | + metaData.putValue("assignedToTenantName", strTenantName); | ||
669 | + } else if (actionType == ActionType.ASSIGNED_TO_EDGE) { | ||
653 | String strEdgeId = extractParameter(String.class, 1, additionalInfo); | 670 | String strEdgeId = extractParameter(String.class, 1, additionalInfo); |
654 | metaData.putValue("assignedEdgeId", strEdgeId); | 671 | metaData.putValue("assignedEdgeId", strEdgeId); |
655 | } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { | 672 | } else if (actionType == ActionType.UNASSIGNED_FROM_EDGE) { |
@@ -718,6 +735,15 @@ public abstract class BaseController { | @@ -718,6 +735,15 @@ public abstract class BaseController { | ||
718 | return result; | 735 | return result; |
719 | } | 736 | } |
720 | 737 | ||
738 | + protected <E extends HasName> String entityToStr(E entity) { | ||
739 | + try { | ||
740 | + return json.writeValueAsString(json.valueToTree(entity)); | ||
741 | + } catch (JsonProcessingException e) { | ||
742 | + log.warn("[{}] Failed to convert entity to string!", entity, e); | ||
743 | + } | ||
744 | + return null; | ||
745 | + } | ||
746 | + | ||
721 | protected void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, CustomerId customerId, ActionType edgeEventAction) { | 747 | protected void sendNotificationMsgToEdgeService(TenantId tenantId, EdgeId edgeId, CustomerId customerId, ActionType edgeEventAction) { |
722 | try { | 748 | try { |
723 | sendNotificationMsgToEdgeService(tenantId, edgeId, null, json.writeValueAsString(customerId), EdgeEventType.EDGE, edgeEventAction); | 749 | sendNotificationMsgToEdgeService(tenantId, edgeId, null, json.writeValueAsString(customerId), EdgeEventType.EDGE, edgeEventAction); |
@@ -39,10 +39,11 @@ import org.thingsboard.server.common.data.DataConstants; | @@ -39,10 +39,11 @@ import org.thingsboard.server.common.data.DataConstants; | ||
39 | import org.thingsboard.server.common.data.Device; | 39 | import org.thingsboard.server.common.data.Device; |
40 | import org.thingsboard.server.common.data.EntitySubtype; | 40 | import org.thingsboard.server.common.data.EntitySubtype; |
41 | import org.thingsboard.server.common.data.EntityType; | 41 | import org.thingsboard.server.common.data.EntityType; |
42 | +import org.thingsboard.server.common.data.Tenant; | ||
42 | import org.thingsboard.server.common.data.audit.ActionType; | 43 | import org.thingsboard.server.common.data.audit.ActionType; |
43 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; | 44 | import org.thingsboard.server.common.data.device.DeviceSearchQuery; |
44 | import org.thingsboard.server.common.data.edge.Edge; | 45 | import org.thingsboard.server.common.data.edge.Edge; |
45 | -import org.thingsboard.server.common.data.edge.EdgeEventType; | 46 | +import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; |
46 | import org.thingsboard.server.common.data.exception.ThingsboardException; | 47 | import org.thingsboard.server.common.data.exception.ThingsboardException; |
47 | import org.thingsboard.server.common.data.id.CustomerId; | 48 | import org.thingsboard.server.common.data.id.CustomerId; |
48 | import org.thingsboard.server.common.data.id.DeviceId; | 49 | import org.thingsboard.server.common.data.id.DeviceId; |
@@ -52,13 +53,14 @@ import org.thingsboard.server.common.data.page.TextPageData; | @@ -52,13 +53,14 @@ import org.thingsboard.server.common.data.page.TextPageData; | ||
52 | import org.thingsboard.server.common.data.page.TextPageLink; | 53 | import org.thingsboard.server.common.data.page.TextPageLink; |
53 | import org.thingsboard.server.common.data.page.TimePageData; | 54 | import org.thingsboard.server.common.data.page.TimePageData; |
54 | import org.thingsboard.server.common.data.page.TimePageLink; | 55 | import org.thingsboard.server.common.data.page.TimePageLink; |
55 | -import org.thingsboard.server.common.data.rule.RuleChain; | ||
56 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 56 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
57 | +import org.thingsboard.server.common.msg.TbMsg; | ||
58 | +import org.thingsboard.server.common.msg.TbMsgDataType; | ||
59 | +import org.thingsboard.server.common.msg.TbMsgMetaData; | ||
57 | import org.thingsboard.server.dao.device.claim.ClaimResponse; | 60 | import org.thingsboard.server.dao.device.claim.ClaimResponse; |
58 | import org.thingsboard.server.dao.device.claim.ClaimResult; | 61 | import org.thingsboard.server.dao.device.claim.ClaimResult; |
59 | import org.thingsboard.server.dao.exception.IncorrectParameterException; | 62 | import org.thingsboard.server.dao.exception.IncorrectParameterException; |
60 | import org.thingsboard.server.dao.model.ModelConstants; | 63 | import org.thingsboard.server.dao.model.ModelConstants; |
61 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
62 | import org.thingsboard.server.queue.util.TbCoreComponent; | 64 | import org.thingsboard.server.queue.util.TbCoreComponent; |
63 | import org.thingsboard.server.service.security.model.SecurityUser; | 65 | import org.thingsboard.server.service.security.model.SecurityUser; |
64 | import org.thingsboard.server.service.security.permission.Operation; | 66 | import org.thingsboard.server.service.security.permission.Operation; |
@@ -79,6 +81,7 @@ public class DeviceController extends BaseController { | @@ -79,6 +81,7 @@ public class DeviceController extends BaseController { | ||
79 | 81 | ||
80 | private static final String DEVICE_ID = "deviceId"; | 82 | private static final String DEVICE_ID = "deviceId"; |
81 | private static final String DEVICE_NAME = "deviceName"; | 83 | private static final String DEVICE_NAME = "deviceName"; |
84 | + private static final String TENANT_ID = "tenantId"; | ||
82 | 85 | ||
83 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") | 86 | @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')") |
84 | @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) | 87 | @RequestMapping(value = "/device/{deviceId}", method = RequestMethod.GET) |
@@ -506,6 +509,56 @@ public class DeviceController extends BaseController { | @@ -506,6 +509,56 @@ public class DeviceController extends BaseController { | ||
506 | } | 509 | } |
507 | 510 | ||
508 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") | 511 | @PreAuthorize("hasAuthority('TENANT_ADMIN')") |
512 | + @RequestMapping(value = "/tenant/{tenantId}/device/{deviceId}", method = RequestMethod.POST) | ||
513 | + @ResponseBody | ||
514 | + public Device assignDeviceToTenant(@PathVariable(TENANT_ID) String strTenantId, | ||
515 | + @PathVariable(DEVICE_ID) String strDeviceId) throws ThingsboardException { | ||
516 | + checkParameter(TENANT_ID, strTenantId); | ||
517 | + checkParameter(DEVICE_ID, strDeviceId); | ||
518 | + try { | ||
519 | + DeviceId deviceId = new DeviceId(toUUID(strDeviceId)); | ||
520 | + Device device = checkDeviceId(deviceId, Operation.ASSIGN_TO_TENANT); | ||
521 | + | ||
522 | + TenantId newTenantId = new TenantId(toUUID(strTenantId)); | ||
523 | + Tenant newTenant = tenantService.findTenantById(newTenantId); | ||
524 | + if (newTenant == null) { | ||
525 | + throw new ThingsboardException("Could not find the specified Tenant!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); | ||
526 | + } | ||
527 | + | ||
528 | + Device assignedDevice = deviceService.assignDeviceToTenant(newTenantId, device); | ||
529 | + | ||
530 | + logEntityAction(getCurrentUser(), deviceId, assignedDevice, | ||
531 | + assignedDevice.getCustomerId(), | ||
532 | + ActionType.ASSIGNED_TO_TENANT, null, strTenantId, newTenant.getName()); | ||
533 | + | ||
534 | + Tenant currentTenant = tenantService.findTenantById(getTenantId()); | ||
535 | + pushAssignedFromNotification(currentTenant, newTenantId, assignedDevice); | ||
536 | + | ||
537 | + return assignedDevice; | ||
538 | + } catch (Exception e) { | ||
539 | + logEntityAction(getCurrentUser(), emptyId(EntityType.DEVICE), null, | ||
540 | + null, | ||
541 | + ActionType.ASSIGNED_TO_TENANT, e, strTenantId); | ||
542 | + throw handleException(e); | ||
543 | + } | ||
544 | + } | ||
545 | + | ||
546 | + private void pushAssignedFromNotification(Tenant currentTenant, TenantId newTenantId, Device assignedDevice) { | ||
547 | + String data = entityToStr(assignedDevice); | ||
548 | + if (data != null) { | ||
549 | + TbMsg tbMsg = TbMsg.newMsg(DataConstants.ENTITY_ASSIGNED_FROM_TENANT, assignedDevice.getId(), getMetaDataForAssignedFrom(currentTenant), TbMsgDataType.JSON, data); | ||
550 | + tbClusterService.pushMsgToRuleEngine(newTenantId, assignedDevice.getId(), tbMsg, null); | ||
551 | + } | ||
552 | + } | ||
553 | + | ||
554 | + private TbMsgMetaData getMetaDataForAssignedFrom(Tenant tenant) { | ||
555 | + TbMsgMetaData metaData = new TbMsgMetaData(); | ||
556 | + metaData.putValue("assignedFromTenantId", tenant.getId().getId().toString()); | ||
557 | + metaData.putValue("assignedFromTenantName", tenant.getName()); | ||
558 | + return metaData; | ||
559 | + } | ||
560 | + | ||
561 | + @PreAuthorize("hasAuthority('TENANT_ADMIN')") | ||
509 | @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) | 562 | @RequestMapping(value = "/edge/{edgeId}/device/{deviceId}", method = RequestMethod.POST) |
510 | @ResponseBody | 563 | @ResponseBody |
511 | public Device assignDeviceToEdge(@PathVariable(EDGE_ID) String strEdgeId, | 564 | public Device assignDeviceToEdge(@PathVariable(EDGE_ID) String strEdgeId, |
@@ -197,19 +197,21 @@ public class TelemetryController extends BaseController { | @@ -197,19 +197,21 @@ public class TelemetryController extends BaseController { | ||
197 | @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) | 197 | @RequestMapping(value = "/{entityType}/{entityId}/values/timeseries", method = RequestMethod.GET, params = {"keys", "startTs", "endTs"}) |
198 | @ResponseBody | 198 | @ResponseBody |
199 | public DeferredResult<ResponseEntity> getTimeseries( | 199 | public DeferredResult<ResponseEntity> getTimeseries( |
200 | - @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr, | 200 | + @PathVariable("entityType") String entityType, |
201 | + @PathVariable("entityId") String entityIdStr, | ||
201 | @RequestParam(name = "keys") String keys, | 202 | @RequestParam(name = "keys") String keys, |
202 | @RequestParam(name = "startTs") Long startTs, | 203 | @RequestParam(name = "startTs") Long startTs, |
203 | @RequestParam(name = "endTs") Long endTs, | 204 | @RequestParam(name = "endTs") Long endTs, |
204 | @RequestParam(name = "interval", defaultValue = "0") Long interval, | 205 | @RequestParam(name = "interval", defaultValue = "0") Long interval, |
205 | @RequestParam(name = "limit", defaultValue = "100") Integer limit, | 206 | @RequestParam(name = "limit", defaultValue = "100") Integer limit, |
206 | @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, | 207 | @RequestParam(name = "agg", defaultValue = "NONE") String aggStr, |
208 | + @RequestParam(name= "orderBy", defaultValue = "DESC") String orderBy, | ||
207 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { | 209 | @RequestParam(name = "useStrictDataTypes", required = false, defaultValue = "false") Boolean useStrictDataTypes) throws ThingsboardException { |
208 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, | 210 | return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr, |
209 | (result, tenantId, entityId) -> { | 211 | (result, tenantId, entityId) -> { |
210 | // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted | 212 | // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted |
211 | Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); | 213 | Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr); |
212 | - List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg)) | 214 | + List<ReadTsKvQuery> queries = toKeysList(keys).stream().map(key -> new BaseReadTsKvQuery(key, startTs, endTs, interval, limit, agg, orderBy)) |
213 | .collect(Collectors.toList()); | 215 | .collect(Collectors.toList()); |
214 | 216 | ||
215 | Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); | 217 | Futures.addCallback(tsService.findAll(tenantId, entityId, queries), getTsKvListCallback(result, useStrictDataTypes), MoreExecutors.directExecutor()); |
@@ -146,6 +146,11 @@ public class ThingsboardInstallService { | @@ -146,6 +146,11 @@ public class ThingsboardInstallService { | ||
146 | databaseTsUpgradeService.upgradeDatabase("2.5.0"); | 146 | databaseTsUpgradeService.upgradeDatabase("2.5.0"); |
147 | } | 147 | } |
148 | 148 | ||
149 | + case "2.5.4": | ||
150 | + log.info("Upgrading ThingsBoard from version 2.5.4 to 2.5.5 ..."); | ||
151 | + if (databaseTsUpgradeService != null) { | ||
152 | + databaseTsUpgradeService.upgradeDatabase("2.5.4"); | ||
153 | + } | ||
149 | 154 | ||
150 | log.info("Updating system data..."); | 155 | log.info("Updating system data..."); |
151 | 156 |
@@ -49,6 +49,7 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase | @@ -49,6 +49,7 @@ public class CassandraTsDatabaseUpgradeService extends AbstractCassandraDatabase | ||
49 | log.info("Schema updated."); | 49 | log.info("Schema updated."); |
50 | break; | 50 | break; |
51 | case "2.5.0": | 51 | case "2.5.0": |
52 | + case "2.5.4": | ||
52 | break; | 53 | break; |
53 | default: | 54 | default: |
54 | throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); | 55 | throw new RuntimeException("Unable to upgrade Cassandra database, unsupported fromVersion: " + fromVersion); |
@@ -195,6 +195,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe | @@ -195,6 +195,12 @@ public class PsqlTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgradeSe | ||
195 | executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); | 195 | executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); |
196 | } | 196 | } |
197 | break; | 197 | break; |
198 | + case "2.5.4": | ||
199 | + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { | ||
200 | + log.info("Load Drop Partitions functions ..."); | ||
201 | + loadSql(conn, LOAD_DROP_PARTITIONS_FUNCTIONS_SQL); | ||
202 | + } | ||
203 | + break; | ||
198 | default: | 204 | default: |
199 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); | 205 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
200 | } | 206 | } |
@@ -177,6 +177,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr | @@ -177,6 +177,8 @@ public class TimescaleTsDatabaseUpgradeService extends AbstractSqlTsDatabaseUpgr | ||
177 | executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); | 177 | executeQuery(conn, "UPDATE tb_schema_settings SET schema_version = 2005001"); |
178 | } | 178 | } |
179 | break; | 179 | break; |
180 | + case "2.5.4": | ||
181 | + break; | ||
180 | default: | 182 | default: |
181 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); | 183 | throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); |
182 | } | 184 | } |
@@ -18,7 +18,7 @@ package org.thingsboard.server.service.security.permission; | @@ -18,7 +18,7 @@ package org.thingsboard.server.service.security.permission; | ||
18 | public enum Operation { | 18 | public enum Operation { |
19 | 19 | ||
20 | ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER, RPC_CALL, | 20 | ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER, RPC_CALL, |
21 | - READ_CREDENTIALS, WRITE_CREDENTIALS, READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_TELEMETRY, WRITE_TELEMETRY, CLAIM_DEVICES, | 21 | + READ_CREDENTIALS, WRITE_CREDENTIALS, READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_TELEMETRY, WRITE_TELEMETRY, CLAIM_DEVICES, ASSIGN_TO_TENANT, |
22 | ASSIGN_TO_EDGE, UNASSIGN_FROM_EDGE | 22 | ASSIGN_TO_EDGE, UNASSIGN_FROM_EDGE |
23 | 23 | ||
24 | } | 24 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.service.state; | 16 | package org.thingsboard.server.service.state; |
17 | 17 | ||
18 | -import com.fasterxml.jackson.databind.ObjectMapper; | 18 | +import com.fasterxml.jackson.databind.node.ObjectNode; |
19 | import com.google.common.base.Function; | 19 | import com.google.common.base.Function; |
20 | import com.google.common.util.concurrent.FutureCallback; | 20 | import com.google.common.util.concurrent.FutureCallback; |
21 | import com.google.common.util.concurrent.Futures; | 21 | import com.google.common.util.concurrent.Futures; |
@@ -45,16 +45,17 @@ import org.thingsboard.server.common.data.page.TextPageLink; | @@ -45,16 +45,17 @@ import org.thingsboard.server.common.data.page.TextPageLink; | ||
45 | import org.thingsboard.server.common.msg.TbMsg; | 45 | import org.thingsboard.server.common.msg.TbMsg; |
46 | import org.thingsboard.server.common.msg.TbMsgDataType; | 46 | import org.thingsboard.server.common.msg.TbMsgDataType; |
47 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 47 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
48 | +import org.thingsboard.server.common.msg.queue.ServiceType; | ||
49 | +import org.thingsboard.server.common.msg.queue.TbCallback; | ||
50 | +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
48 | import org.thingsboard.server.dao.attributes.AttributesService; | 51 | import org.thingsboard.server.dao.attributes.AttributesService; |
49 | import org.thingsboard.server.dao.device.DeviceService; | 52 | import org.thingsboard.server.dao.device.DeviceService; |
50 | import org.thingsboard.server.dao.tenant.TenantService; | 53 | import org.thingsboard.server.dao.tenant.TenantService; |
51 | import org.thingsboard.server.dao.timeseries.TimeseriesService; | 54 | import org.thingsboard.server.dao.timeseries.TimeseriesService; |
55 | +import org.thingsboard.server.dao.util.mapping.JacksonUtil; | ||
56 | +import org.thingsboard.server.gen.transport.TransportProtos; | ||
52 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; | 57 | import org.thingsboard.server.queue.discovery.PartitionChangeEvent; |
53 | import org.thingsboard.server.queue.discovery.PartitionService; | 58 | import org.thingsboard.server.queue.discovery.PartitionService; |
54 | -import org.thingsboard.server.common.msg.queue.ServiceType; | ||
55 | -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; | ||
56 | -import org.thingsboard.server.gen.transport.TransportProtos; | ||
57 | -import org.thingsboard.server.common.msg.queue.TbCallback; | ||
58 | import org.thingsboard.server.queue.util.TbCoreComponent; | 59 | import org.thingsboard.server.queue.util.TbCoreComponent; |
59 | import org.thingsboard.server.service.queue.TbClusterService; | 60 | import org.thingsboard.server.service.queue.TbClusterService; |
60 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; | 61 | import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; |
@@ -90,7 +91,6 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; | @@ -90,7 +91,6 @@ import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; | ||
90 | @Slf4j | 91 | @Slf4j |
91 | public class DefaultDeviceStateService implements DeviceStateService { | 92 | public class DefaultDeviceStateService implements DeviceStateService { |
92 | 93 | ||
93 | - private static final ObjectMapper json = new ObjectMapper(); | ||
94 | public static final String ACTIVITY_STATE = "active"; | 94 | public static final String ACTIVITY_STATE = "active"; |
95 | public static final String LAST_CONNECT_TIME = "lastConnectTime"; | 95 | public static final String LAST_CONNECT_TIME = "lastConnectTime"; |
96 | public static final String LAST_DISCONNECT_TIME = "lastDisconnectTime"; | 96 | public static final String LAST_DISCONNECT_TIME = "lastDisconnectTime"; |
@@ -197,15 +197,15 @@ public class DefaultDeviceStateService implements DeviceStateService { | @@ -197,15 +197,15 @@ public class DefaultDeviceStateService implements DeviceStateService { | ||
197 | if (lastReportedActivity > 0 && lastReportedActivity > lastSavedActivity) { | 197 | if (lastReportedActivity > 0 && lastReportedActivity > lastSavedActivity) { |
198 | DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); | 198 | DeviceStateData stateData = getOrFetchDeviceStateData(deviceId); |
199 | if (stateData != null) { | 199 | if (stateData != null) { |
200 | - DeviceState state = stateData.getState(); | ||
201 | - stateData.getState().setLastActivityTime(lastReportedActivity); | ||
202 | - stateData.getMetaData().putValue("scope", SERVER_SCOPE); | ||
203 | - pushRuleEngineMessage(stateData, ACTIVITY_EVENT); | ||
204 | save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity); | 200 | save(deviceId, LAST_ACTIVITY_TIME, lastReportedActivity); |
205 | deviceLastSavedActivity.put(deviceId, lastReportedActivity); | 201 | deviceLastSavedActivity.put(deviceId, lastReportedActivity); |
202 | + DeviceState state = stateData.getState(); | ||
203 | + state.setLastActivityTime(lastReportedActivity); | ||
206 | if (!state.isActive()) { | 204 | if (!state.isActive()) { |
207 | state.setActive(true); | 205 | state.setActive(true); |
208 | save(deviceId, ACTIVITY_STATE, state.isActive()); | 206 | save(deviceId, ACTIVITY_STATE, state.isActive()); |
207 | + stateData.getMetaData().putValue("scope", SERVER_SCOPE); | ||
208 | + pushRuleEngineMessage(stateData, ACTIVITY_EVENT); | ||
209 | } | 209 | } |
210 | } | 210 | } |
211 | } | 211 | } |
@@ -503,8 +503,15 @@ public class DefaultDeviceStateService implements DeviceStateService { | @@ -503,8 +503,15 @@ public class DefaultDeviceStateService implements DeviceStateService { | ||
503 | private void pushRuleEngineMessage(DeviceStateData stateData, String msgType) { | 503 | private void pushRuleEngineMessage(DeviceStateData stateData, String msgType) { |
504 | DeviceState state = stateData.getState(); | 504 | DeviceState state = stateData.getState(); |
505 | try { | 505 | try { |
506 | - TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), stateData.getMetaData().copy(), TbMsgDataType.JSON | ||
507 | - , json.writeValueAsString(state)); | 506 | + String data; |
507 | + if (msgType.equals(CONNECT_EVENT)) { | ||
508 | + ObjectNode stateNode = JacksonUtil.convertValue(state, ObjectNode.class); | ||
509 | + stateNode.remove(ACTIVITY_STATE); | ||
510 | + data = JacksonUtil.toString(stateNode); | ||
511 | + } else { | ||
512 | + data = JacksonUtil.toString(state); | ||
513 | + } | ||
514 | + TbMsg tbMsg = TbMsg.newMsg(msgType, stateData.getDeviceId(), stateData.getMetaData().copy(), TbMsgDataType.JSON, data); | ||
508 | clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null); | 515 | clusterService.pushMsgToRuleEngine(stateData.getTenantId(), stateData.getDeviceId(), tbMsg, null); |
509 | } catch (Exception e) { | 516 | } catch (Exception e) { |
510 | log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e); | 517 | log.warn("[{}] Failed to push inactivity alarm: {}", stateData.getDeviceId(), state, e); |
@@ -154,7 +154,7 @@ public class DefaultTransportApiService implements TransportApiService { | @@ -154,7 +154,7 @@ public class DefaultTransportApiService implements TransportApiService { | ||
154 | return TransportApiResponseMsg.newBuilder() | 154 | return TransportApiResponseMsg.newBuilder() |
155 | .setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); | 155 | .setGetOrCreateDeviceResponseMsg(GetOrCreateDeviceFromGatewayResponseMsg.newBuilder().setDeviceInfo(getDeviceInfoProto(device)).build()).build(); |
156 | } catch (JsonProcessingException e) { | 156 | } catch (JsonProcessingException e) { |
157 | - log.warn("[{}] Failed to lookup device by gateway id and name", gatewayId, requestMsg.getDeviceName(), e); | 157 | + log.warn("[{}][{}] Failed to lookup device by gateway id and name", gatewayId, requestMsg.getDeviceName(), e); |
158 | throw new RuntimeException(e); | 158 | throw new RuntimeException(e); |
159 | } finally { | 159 | } finally { |
160 | deviceCreationLock.unlock(); | 160 | deviceCreationLock.unlock(); |
@@ -38,19 +38,15 @@ public abstract class AbstractCleanUpService { | @@ -38,19 +38,15 @@ public abstract class AbstractCleanUpService { | ||
38 | @Value("${spring.datasource.password}") | 38 | @Value("${spring.datasource.password}") |
39 | protected String dbPassword; | 39 | protected String dbPassword; |
40 | 40 | ||
41 | - protected long executeQuery(Connection conn, String query) { | ||
42 | - long removed = 0L; | ||
43 | - try { | ||
44 | - Statement statement = conn.createStatement(); | 41 | + protected long executeQuery(Connection conn, String query) throws SQLException { |
42 | + try (Statement statement = conn.createStatement()) { | ||
45 | ResultSet resultSet = statement.executeQuery(query); | 43 | ResultSet resultSet = statement.executeQuery(query); |
46 | - getWarnings(statement); | 44 | + if (log.isDebugEnabled()) { |
45 | + getWarnings(statement); | ||
46 | + } | ||
47 | resultSet.next(); | 47 | resultSet.next(); |
48 | - removed = resultSet.getLong(1); | ||
49 | - log.debug("Successfully executed query: {}", query); | ||
50 | - } catch (SQLException e) { | ||
51 | - log.debug("Failed to execute query: {} due to: {}", query, e.getMessage()); | 48 | + return resultSet.getLong(1); |
52 | } | 49 | } |
53 | - return removed; | ||
54 | } | 50 | } |
55 | 51 | ||
56 | protected void getWarnings(Statement statement) throws SQLException { | 52 | protected void getWarnings(Statement statement) throws SQLException { |
@@ -65,6 +61,6 @@ public abstract class AbstractCleanUpService { | @@ -65,6 +61,6 @@ public abstract class AbstractCleanUpService { | ||
65 | } | 61 | } |
66 | } | 62 | } |
67 | 63 | ||
68 | - protected abstract void doCleanUp(Connection connection); | 64 | + protected abstract void doCleanUp(Connection connection) throws SQLException; |
69 | 65 | ||
70 | } | 66 | } |
@@ -49,7 +49,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | @@ -49,7 +49,7 @@ public class EdgeEventsCleanUpService extends AbstractCleanUpService { | ||
49 | } | 49 | } |
50 | 50 | ||
51 | @Override | 51 | @Override |
52 | - protected void doCleanUp(Connection connection) { | 52 | + protected void doCleanUp(Connection connection) throws SQLException { |
53 | long totalEdgeEventsRemoved = executeQuery(connection, "call cleanup_edge_events_by_ttl(" + ttl + ", 0);"); | 53 | long totalEdgeEventsRemoved = executeQuery(connection, "call cleanup_edge_events_by_ttl(" + ttl + ", 0);"); |
54 | log.info("Total edge events removed by TTL: [{}]", totalEdgeEventsRemoved); | 54 | log.info("Total edge events removed by TTL: [{}]", totalEdgeEventsRemoved); |
55 | } | 55 | } |
@@ -54,7 +54,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | @@ -54,7 +54,7 @@ public class EventsCleanUpService extends AbstractCleanUpService { | ||
54 | } | 54 | } |
55 | 55 | ||
56 | @Override | 56 | @Override |
57 | - protected void doCleanUp(Connection connection) { | 57 | + protected void doCleanUp(Connection connection) throws SQLException { |
58 | long totalEventsRemoved = executeQuery(connection, "call cleanup_events_by_ttl(" + ttl + ", " + debugTtl + ", 0);"); | 58 | long totalEventsRemoved = executeQuery(connection, "call cleanup_events_by_ttl(" + ttl + ", " + debugTtl + ", 0);"); |
59 | log.info("Total events removed by TTL: [{}]", totalEventsRemoved); | 59 | log.info("Total events removed by TTL: [{}]", totalEventsRemoved); |
60 | } | 60 | } |
@@ -22,6 +22,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | @@ -22,6 +22,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | ||
22 | import org.thingsboard.server.dao.util.PsqlTsDao; | 22 | import org.thingsboard.server.dao.util.PsqlTsDao; |
23 | 23 | ||
24 | import java.sql.Connection; | 24 | import java.sql.Connection; |
25 | +import java.sql.SQLException; | ||
25 | 26 | ||
26 | @PsqlTsDao | 27 | @PsqlTsDao |
27 | @Service | 28 | @Service |
@@ -32,7 +33,7 @@ public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpServi | @@ -32,7 +33,7 @@ public class PsqlTimeseriesCleanUpService extends AbstractTimeseriesCleanUpServi | ||
32 | private String partitionType; | 33 | private String partitionType; |
33 | 34 | ||
34 | @Override | 35 | @Override |
35 | - protected void doCleanUp(Connection connection) { | 36 | + protected void doCleanUp(Connection connection) throws SQLException { |
36 | long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);"); | 37 | long totalPartitionsRemoved = executeQuery(connection, "call drop_partitions_by_max_ttl('" + partitionType + "'," + systemTtl + ", 0);"); |
37 | log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved); | 38 | log.info("Total partitions removed by TTL: [{}]", totalPartitionsRemoved); |
38 | long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); | 39 | long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); |
@@ -21,6 +21,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | @@ -21,6 +21,7 @@ import org.thingsboard.server.dao.model.ModelConstants; | ||
21 | import org.thingsboard.server.dao.util.TimescaleDBTsDao; | 21 | import org.thingsboard.server.dao.util.TimescaleDBTsDao; |
22 | 22 | ||
23 | import java.sql.Connection; | 23 | import java.sql.Connection; |
24 | +import java.sql.SQLException; | ||
24 | 25 | ||
25 | @TimescaleDBTsDao | 26 | @TimescaleDBTsDao |
26 | @Service | 27 | @Service |
@@ -28,7 +29,7 @@ import java.sql.Connection; | @@ -28,7 +29,7 @@ import java.sql.Connection; | ||
28 | public class TimescaleTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { | 29 | public class TimescaleTimeseriesCleanUpService extends AbstractTimeseriesCleanUpService { |
29 | 30 | ||
30 | @Override | 31 | @Override |
31 | - protected void doCleanUp(Connection connection) { | 32 | + protected void doCleanUp(Connection connection) throws SQLException { |
32 | long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); | 33 | long totalEntitiesTelemetryRemoved = executeQuery(connection, "call cleanup_timeseries_by_ttl('" + ModelConstants.NULL_UUID_STR + "'," + systemTtl + ", 0);"); |
33 | log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); | 34 | log.info("Total telemetry removed stats by TTL for entities: [{}]", totalEntitiesTelemetryRemoved); |
34 | } | 35 | } |
@@ -30,6 +30,8 @@ | @@ -30,6 +30,8 @@ | ||
30 | 30 | ||
31 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> | 31 | <!-- <logger name="org.thingsboard.server.service.queue" level="TRACE" />--> |
32 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> | 32 | <!-- <logger name="org.thingsboard.server.service.transport" level="TRACE" />--> |
33 | +<!-- <logger name="org.thingsboard.server.queue.memory.InMemoryStorage" level="DEBUG" />--> | ||
34 | + | ||
33 | 35 | ||
34 | <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" /> | 36 | <logger name="com.microsoft.azure.servicebus.primitives.CoreMessageReceiver" level="OFF" /> |
35 | 37 |
@@ -589,7 +589,7 @@ transport: | @@ -589,7 +589,7 @@ transport: | ||
589 | edges: | 589 | edges: |
590 | rpc: | 590 | rpc: |
591 | enabled: "${EDGES_RPC_ENABLED:true}" | 591 | enabled: "${EDGES_RPC_ENABLED:true}" |
592 | - port: "${EDGES_RPC_PORT:60100}" | 592 | + port: "${EDGES_RPC_PORT:7070}" |
593 | ssl: | 593 | ssl: |
594 | # Enable/disable SSL support | 594 | # Enable/disable SSL support |
595 | enabled: "${EDGES_RPC_SSL_ENABLED:false}" | 595 | enabled: "${EDGES_RPC_SSL_ENABLED:false}" |
@@ -619,6 +619,10 @@ swagger: | @@ -619,6 +619,10 @@ swagger: | ||
619 | 619 | ||
620 | queue: | 620 | queue: |
621 | type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) | 621 | type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) |
622 | + in_memory: | ||
623 | + stats: | ||
624 | + # For debug lvl | ||
625 | + print-interval-ms: "${TB_QUEUE_IN_MEMORY_STATS_PRINT_INTERVAL_MS:60000}" | ||
622 | kafka: | 626 | kafka: |
623 | bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" | 627 | bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" |
624 | acks: "${TB_KAFKA_ACKS:all}" | 628 | acks: "${TB_KAFKA_ACKS:all}" |
@@ -630,13 +634,21 @@ queue: | @@ -630,13 +634,21 @@ queue: | ||
630 | max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" | 634 | max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" |
631 | max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" | 635 | max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" |
632 | fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" | 636 | fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" |
637 | + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" | ||
638 | + confluent: | ||
639 | + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" | ||
640 | + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" | ||
641 | + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" | ||
642 | + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" | ||
643 | + other: | ||
633 | topic-properties: | 644 | topic-properties: |
634 | - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
635 | - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
636 | - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
637 | - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
638 | - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}" | 645 | + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
646 | + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
647 | + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
648 | + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
649 | + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" | ||
639 | aws_sqs: | 650 | aws_sqs: |
651 | + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" | ||
640 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" | 652 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" |
641 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" | 653 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" |
642 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" | 654 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" |
@@ -79,8 +79,14 @@ import java.util.Comparator; | @@ -79,8 +79,14 @@ import java.util.Comparator; | ||
79 | import java.util.List; | 79 | import java.util.List; |
80 | 80 | ||
81 | import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; | 81 | import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; |
82 | -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; | ||
83 | -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; | 82 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch; |
83 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; | ||
84 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; | ||
85 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; | ||
86 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; | ||
87 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; | ||
88 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; | ||
89 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
84 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; | 90 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup; |
85 | 91 | ||
86 | @ActiveProfiles("test") | 92 | @ActiveProfiles("test") |
@@ -221,6 +227,7 @@ public abstract class AbstractControllerTest { | @@ -221,6 +227,7 @@ public abstract class AbstractControllerTest { | ||
221 | } | 227 | } |
222 | 228 | ||
223 | private Tenant savedDifferentTenant; | 229 | private Tenant savedDifferentTenant; |
230 | + | ||
224 | protected void loginDifferentTenant() throws Exception { | 231 | protected void loginDifferentTenant() throws Exception { |
225 | loginSysAdmin(); | 232 | loginSysAdmin(); |
226 | Tenant tenant = new Tenant(); | 233 | Tenant tenant = new Tenant(); |
@@ -316,6 +323,10 @@ public abstract class AbstractControllerTest { | @@ -316,6 +323,10 @@ public abstract class AbstractControllerTest { | ||
316 | return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); | 323 | return readResponse(doGet(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); |
317 | } | 324 | } |
318 | 325 | ||
326 | + protected <T> T doGet(String urlTemplate, Class<T> responseClass, ResultMatcher resultMatcher, Object... urlVariables) throws Exception { | ||
327 | + return readResponse(doGet(urlTemplate, urlVariables).andExpect(resultMatcher), responseClass); | ||
328 | + } | ||
329 | + | ||
319 | protected <T> T doGetAsync(String urlTemplate, Class<T> responseClass, Object... urlVariables) throws Exception { | 330 | protected <T> T doGetAsync(String urlTemplate, Class<T> responseClass, Object... urlVariables) throws Exception { |
320 | return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); | 331 | return readResponse(doGetAsync(urlTemplate, urlVariables).andExpect(status().isOk()), responseClass); |
321 | } | 332 | } |
@@ -357,9 +368,9 @@ public abstract class AbstractControllerTest { | @@ -357,9 +368,9 @@ public abstract class AbstractControllerTest { | ||
357 | return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType); | 368 | return readResponse(doGet(urlTemplate, vars).andExpect(status().isOk()), responseType); |
358 | } | 369 | } |
359 | 370 | ||
360 | - protected <T> T doGetTypedWithTimePageLink(String urlTemplate, TypeReference<T> responseType, | ||
361 | - TimePageLink pageLink, | ||
362 | - Object... urlVariables) throws Exception { | 371 | + protected <T> T doGetTypedWithTimePageLink(String urlTemplate, TypeReference<T> responseType, |
372 | + TimePageLink pageLink, | ||
373 | + Object... urlVariables) throws Exception { | ||
363 | List<Object> pageLinkVariables = new ArrayList<>(); | 374 | List<Object> pageLinkVariables = new ArrayList<>(); |
364 | urlTemplate += "limit={limit}"; | 375 | urlTemplate += "limit={limit}"; |
365 | pageLinkVariables.add(pageLink.getLimit()); | 376 | pageLinkVariables.add(pageLink.getLimit()); |
@@ -425,7 +436,7 @@ public abstract class AbstractControllerTest { | @@ -425,7 +436,7 @@ public abstract class AbstractControllerTest { | ||
425 | return mockMvc.perform(postRequest); | 436 | return mockMvc.perform(postRequest); |
426 | } | 437 | } |
427 | 438 | ||
428 | - protected <T> ResultActions doPostAsync(String urlTemplate, T content, Long timeout, String... params) throws Exception { | 439 | + protected <T> ResultActions doPostAsync(String urlTemplate, T content, Long timeout, String... params) throws Exception { |
429 | MockHttpServletRequestBuilder postRequest = post(urlTemplate); | 440 | MockHttpServletRequestBuilder postRequest = post(urlTemplate); |
430 | setJwtToken(postRequest); | 441 | setJwtToken(postRequest); |
431 | String json = json(content); | 442 | String json = json(content); |
@@ -15,74 +15,79 @@ | @@ -15,74 +15,79 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.controller; | 16 | package org.thingsboard.server.controller; |
17 | 17 | ||
18 | -import static org.hamcrest.Matchers.containsString; | ||
19 | -import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | ||
20 | -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
21 | - | ||
22 | -import java.util.ArrayList; | ||
23 | -import java.util.Collections; | ||
24 | -import java.util.List; | ||
25 | - | ||
26 | import com.datastax.driver.core.utils.UUIDs; | 18 | import com.datastax.driver.core.utils.UUIDs; |
19 | +import com.fasterxml.jackson.core.type.TypeReference; | ||
27 | import org.apache.commons.lang3.RandomStringUtils; | 20 | import org.apache.commons.lang3.RandomStringUtils; |
28 | -import org.thingsboard.server.common.data.*; | 21 | +import org.junit.After; |
22 | +import org.junit.Assert; | ||
23 | +import org.junit.Before; | ||
24 | +import org.junit.Test; | ||
25 | +import org.thingsboard.server.common.data.Customer; | ||
26 | +import org.thingsboard.server.common.data.Device; | ||
27 | +import org.thingsboard.server.common.data.EntitySubtype; | ||
28 | +import org.thingsboard.server.common.data.Tenant; | ||
29 | +import org.thingsboard.server.common.data.User; | ||
29 | import org.thingsboard.server.common.data.id.CustomerId; | 30 | import org.thingsboard.server.common.data.id.CustomerId; |
30 | import org.thingsboard.server.common.data.id.DeviceCredentialsId; | 31 | import org.thingsboard.server.common.data.id.DeviceCredentialsId; |
31 | import org.thingsboard.server.common.data.id.DeviceId; | 32 | import org.thingsboard.server.common.data.id.DeviceId; |
32 | import org.thingsboard.server.common.data.page.TextPageData; | 33 | import org.thingsboard.server.common.data.page.TextPageData; |
33 | import org.thingsboard.server.common.data.page.TextPageLink; | 34 | import org.thingsboard.server.common.data.page.TextPageLink; |
35 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
36 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
34 | import org.thingsboard.server.common.data.security.Authority; | 37 | import org.thingsboard.server.common.data.security.Authority; |
35 | import org.thingsboard.server.common.data.security.DeviceCredentials; | 38 | import org.thingsboard.server.common.data.security.DeviceCredentials; |
36 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; | 39 | import org.thingsboard.server.common.data.security.DeviceCredentialsType; |
37 | import org.thingsboard.server.dao.model.ModelConstants; | 40 | import org.thingsboard.server.dao.model.ModelConstants; |
38 | -import org.junit.After; | ||
39 | -import org.junit.Assert; | ||
40 | -import org.junit.Before; | ||
41 | -import org.junit.Test; | ||
42 | 41 | ||
43 | -import com.fasterxml.jackson.core.type.TypeReference; | 42 | +import java.util.ArrayList; |
43 | +import java.util.Collections; | ||
44 | +import java.util.List; | ||
45 | + | ||
46 | +import static org.hamcrest.Matchers.containsString; | ||
47 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
48 | +import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; | ||
44 | 49 | ||
45 | public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | 50 | public abstract class BaseDeviceControllerTest extends AbstractControllerTest { |
46 | - | 51 | + |
47 | private IdComparator<Device> idComparator = new IdComparator<>(); | 52 | private IdComparator<Device> idComparator = new IdComparator<>(); |
48 | - | 53 | + |
49 | private Tenant savedTenant; | 54 | private Tenant savedTenant; |
50 | private User tenantAdmin; | 55 | private User tenantAdmin; |
51 | - | 56 | + |
52 | @Before | 57 | @Before |
53 | public void beforeTest() throws Exception { | 58 | public void beforeTest() throws Exception { |
54 | loginSysAdmin(); | 59 | loginSysAdmin(); |
55 | - | 60 | + |
56 | Tenant tenant = new Tenant(); | 61 | Tenant tenant = new Tenant(); |
57 | tenant.setTitle("My tenant"); | 62 | tenant.setTitle("My tenant"); |
58 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); | 63 | savedTenant = doPost("/api/tenant", tenant, Tenant.class); |
59 | Assert.assertNotNull(savedTenant); | 64 | Assert.assertNotNull(savedTenant); |
60 | - | 65 | + |
61 | tenantAdmin = new User(); | 66 | tenantAdmin = new User(); |
62 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); | 67 | tenantAdmin.setAuthority(Authority.TENANT_ADMIN); |
63 | tenantAdmin.setTenantId(savedTenant.getId()); | 68 | tenantAdmin.setTenantId(savedTenant.getId()); |
64 | tenantAdmin.setEmail("tenant2@thingsboard.org"); | 69 | tenantAdmin.setEmail("tenant2@thingsboard.org"); |
65 | tenantAdmin.setFirstName("Joe"); | 70 | tenantAdmin.setFirstName("Joe"); |
66 | tenantAdmin.setLastName("Downs"); | 71 | tenantAdmin.setLastName("Downs"); |
67 | - | 72 | + |
68 | tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); | 73 | tenantAdmin = createUserAndLogin(tenantAdmin, "testPassword1"); |
69 | } | 74 | } |
70 | - | 75 | + |
71 | @After | 76 | @After |
72 | public void afterTest() throws Exception { | 77 | public void afterTest() throws Exception { |
73 | loginSysAdmin(); | 78 | loginSysAdmin(); |
74 | - | ||
75 | - doDelete("/api/tenant/"+savedTenant.getId().getId().toString()) | ||
76 | - .andExpect(status().isOk()); | 79 | + |
80 | + doDelete("/api/tenant/" + savedTenant.getId().getId().toString()) | ||
81 | + .andExpect(status().isOk()); | ||
77 | } | 82 | } |
78 | - | 83 | + |
79 | @Test | 84 | @Test |
80 | public void testSaveDevice() throws Exception { | 85 | public void testSaveDevice() throws Exception { |
81 | Device device = new Device(); | 86 | Device device = new Device(); |
82 | device.setName("My device"); | 87 | device.setName("My device"); |
83 | device.setType("default"); | 88 | device.setType("default"); |
84 | Device savedDevice = doPost("/api/device", device, Device.class); | 89 | Device savedDevice = doPost("/api/device", device, Device.class); |
85 | - | 90 | + |
86 | Assert.assertNotNull(savedDevice); | 91 | Assert.assertNotNull(savedDevice); |
87 | Assert.assertNotNull(savedDevice.getId()); | 92 | Assert.assertNotNull(savedDevice.getId()); |
88 | Assert.assertTrue(savedDevice.getCreatedTime() > 0); | 93 | Assert.assertTrue(savedDevice.getCreatedTime() > 0); |
@@ -90,9 +95,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -90,9 +95,9 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
90 | Assert.assertNotNull(savedDevice.getCustomerId()); | 95 | Assert.assertNotNull(savedDevice.getCustomerId()); |
91 | Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId()); | 96 | Assert.assertEquals(NULL_UUID, savedDevice.getCustomerId().getId()); |
92 | Assert.assertEquals(device.getName(), savedDevice.getName()); | 97 | Assert.assertEquals(device.getName(), savedDevice.getName()); |
93 | - | ||
94 | - DeviceCredentials deviceCredentials = | ||
95 | - doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 98 | + |
99 | + DeviceCredentials deviceCredentials = | ||
100 | + doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | ||
96 | 101 | ||
97 | Assert.assertNotNull(deviceCredentials); | 102 | Assert.assertNotNull(deviceCredentials); |
98 | Assert.assertNotNull(deviceCredentials.getId()); | 103 | Assert.assertNotNull(deviceCredentials.getId()); |
@@ -100,10 +105,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -100,10 +105,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
100 | Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType()); | 105 | Assert.assertEquals(DeviceCredentialsType.ACCESS_TOKEN, deviceCredentials.getCredentialsType()); |
101 | Assert.assertNotNull(deviceCredentials.getCredentialsId()); | 106 | Assert.assertNotNull(deviceCredentials.getCredentialsId()); |
102 | Assert.assertEquals(20, deviceCredentials.getCredentialsId().length()); | 107 | Assert.assertEquals(20, deviceCredentials.getCredentialsId().length()); |
103 | - | 108 | + |
104 | savedDevice.setName("My new device"); | 109 | savedDevice.setName("My new device"); |
105 | doPost("/api/device", savedDevice, Device.class); | 110 | doPost("/api/device", savedDevice, Device.class); |
106 | - | 111 | + |
107 | Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); | 112 | Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); |
108 | Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); | 113 | Assert.assertEquals(foundDevice.getName(), savedDevice.getName()); |
109 | } | 114 | } |
@@ -115,10 +120,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -115,10 +120,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
115 | device.setType("default"); | 120 | device.setType("default"); |
116 | Device savedDevice = doPost("/api/device", device, Device.class); | 121 | Device savedDevice = doPost("/api/device", device, Device.class); |
117 | loginDifferentTenant(); | 122 | loginDifferentTenant(); |
118 | - doPost("/api/device", savedDevice, Device.class, status().isForbidden()); | 123 | + doPost("/api/device", savedDevice, Device.class, status().isNotFound()); |
119 | deleteDifferentTenant(); | 124 | deleteDifferentTenant(); |
120 | } | 125 | } |
121 | - | 126 | + |
122 | @Test | 127 | @Test |
123 | public void testFindDeviceById() throws Exception { | 128 | public void testFindDeviceById() throws Exception { |
124 | Device device = new Device(); | 129 | Device device = new Device(); |
@@ -133,26 +138,27 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -133,26 +138,27 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
133 | @Test | 138 | @Test |
134 | public void testFindDeviceTypesByTenantId() throws Exception { | 139 | public void testFindDeviceTypesByTenantId() throws Exception { |
135 | List<Device> devices = new ArrayList<>(); | 140 | List<Device> devices = new ArrayList<>(); |
136 | - for (int i=0;i<3;i++) { | 141 | + for (int i = 0; i < 3; i++) { |
137 | Device device = new Device(); | 142 | Device device = new Device(); |
138 | - device.setName("My device B"+i); | 143 | + device.setName("My device B" + i); |
139 | device.setType("typeB"); | 144 | device.setType("typeB"); |
140 | devices.add(doPost("/api/device", device, Device.class)); | 145 | devices.add(doPost("/api/device", device, Device.class)); |
141 | } | 146 | } |
142 | - for (int i=0;i<7;i++) { | 147 | + for (int i = 0; i < 7; i++) { |
143 | Device device = new Device(); | 148 | Device device = new Device(); |
144 | - device.setName("My device C"+i); | 149 | + device.setName("My device C" + i); |
145 | device.setType("typeC"); | 150 | device.setType("typeC"); |
146 | devices.add(doPost("/api/device", device, Device.class)); | 151 | devices.add(doPost("/api/device", device, Device.class)); |
147 | } | 152 | } |
148 | - for (int i=0;i<9;i++) { | 153 | + for (int i = 0; i < 9; i++) { |
149 | Device device = new Device(); | 154 | Device device = new Device(); |
150 | - device.setName("My device A"+i); | 155 | + device.setName("My device A" + i); |
151 | device.setType("typeA"); | 156 | device.setType("typeA"); |
152 | devices.add(doPost("/api/device", device, Device.class)); | 157 | devices.add(doPost("/api/device", device, Device.class)); |
153 | } | 158 | } |
154 | List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types", | 159 | List<EntitySubtype> deviceTypes = doGetTyped("/api/device/types", |
155 | - new TypeReference<List<EntitySubtype>>(){}); | 160 | + new TypeReference<List<EntitySubtype>>() { |
161 | + }); | ||
156 | 162 | ||
157 | Assert.assertNotNull(deviceTypes); | 163 | Assert.assertNotNull(deviceTypes); |
158 | Assert.assertEquals(3, deviceTypes.size()); | 164 | Assert.assertEquals(3, deviceTypes.size()); |
@@ -160,19 +166,19 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -160,19 +166,19 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
160 | Assert.assertEquals("typeB", deviceTypes.get(1).getType()); | 166 | Assert.assertEquals("typeB", deviceTypes.get(1).getType()); |
161 | Assert.assertEquals("typeC", deviceTypes.get(2).getType()); | 167 | Assert.assertEquals("typeC", deviceTypes.get(2).getType()); |
162 | } | 168 | } |
163 | - | 169 | + |
164 | @Test | 170 | @Test |
165 | public void testDeleteDevice() throws Exception { | 171 | public void testDeleteDevice() throws Exception { |
166 | Device device = new Device(); | 172 | Device device = new Device(); |
167 | device.setName("My device"); | 173 | device.setName("My device"); |
168 | device.setType("default"); | 174 | device.setType("default"); |
169 | Device savedDevice = doPost("/api/device", device, Device.class); | 175 | Device savedDevice = doPost("/api/device", device, Device.class); |
170 | - | ||
171 | - doDelete("/api/device/"+savedDevice.getId().getId().toString()) | ||
172 | - .andExpect(status().isOk()); | ||
173 | 176 | ||
174 | - doGet("/api/device/"+savedDevice.getId().getId().toString()) | ||
175 | - .andExpect(status().isNotFound()); | 177 | + doDelete("/api/device/" + savedDevice.getId().getId().toString()) |
178 | + .andExpect(status().isOk()); | ||
179 | + | ||
180 | + doGet("/api/device/" + savedDevice.getId().getId().toString()) | ||
181 | + .andExpect(status().isNotFound()); | ||
176 | } | 182 | } |
177 | 183 | ||
178 | @Test | 184 | @Test |
@@ -189,52 +195,52 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -189,52 +195,52 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
189 | Device device = new Device(); | 195 | Device device = new Device(); |
190 | device.setType("default"); | 196 | device.setType("default"); |
191 | doPost("/api/device", device) | 197 | doPost("/api/device", device) |
192 | - .andExpect(status().isBadRequest()) | ||
193 | - .andExpect(statusReason(containsString("Device name should be specified"))); | 198 | + .andExpect(status().isBadRequest()) |
199 | + .andExpect(statusReason(containsString("Device name should be specified"))); | ||
194 | } | 200 | } |
195 | - | 201 | + |
196 | @Test | 202 | @Test |
197 | public void testAssignUnassignDeviceToCustomer() throws Exception { | 203 | public void testAssignUnassignDeviceToCustomer() throws Exception { |
198 | Device device = new Device(); | 204 | Device device = new Device(); |
199 | device.setName("My device"); | 205 | device.setName("My device"); |
200 | device.setType("default"); | 206 | device.setType("default"); |
201 | Device savedDevice = doPost("/api/device", device, Device.class); | 207 | Device savedDevice = doPost("/api/device", device, Device.class); |
202 | - | 208 | + |
203 | Customer customer = new Customer(); | 209 | Customer customer = new Customer(); |
204 | customer.setTitle("My customer"); | 210 | customer.setTitle("My customer"); |
205 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); | 211 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
206 | - | ||
207 | - Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString() | 212 | + |
213 | + Device assignedDevice = doPost("/api/customer/" + savedCustomer.getId().getId().toString() | ||
208 | + "/device/" + savedDevice.getId().getId().toString(), Device.class); | 214 | + "/device/" + savedDevice.getId().getId().toString(), Device.class); |
209 | Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); | 215 | Assert.assertEquals(savedCustomer.getId(), assignedDevice.getCustomerId()); |
210 | - | 216 | + |
211 | Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); | 217 | Device foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); |
212 | Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); | 218 | Assert.assertEquals(savedCustomer.getId(), foundDevice.getCustomerId()); |
213 | 219 | ||
214 | - Device unassignedDevice = | 220 | + Device unassignedDevice = |
215 | doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class); | 221 | doDelete("/api/customer/device/" + savedDevice.getId().getId().toString(), Device.class); |
216 | Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); | 222 | Assert.assertEquals(ModelConstants.NULL_UUID, unassignedDevice.getCustomerId().getId()); |
217 | - | 223 | + |
218 | foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); | 224 | foundDevice = doGet("/api/device/" + savedDevice.getId().getId().toString(), Device.class); |
219 | Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId()); | 225 | Assert.assertEquals(ModelConstants.NULL_UUID, foundDevice.getCustomerId().getId()); |
220 | } | 226 | } |
221 | - | 227 | + |
222 | @Test | 228 | @Test |
223 | public void testAssignDeviceToNonExistentCustomer() throws Exception { | 229 | public void testAssignDeviceToNonExistentCustomer() throws Exception { |
224 | Device device = new Device(); | 230 | Device device = new Device(); |
225 | device.setName("My device"); | 231 | device.setName("My device"); |
226 | device.setType("default"); | 232 | device.setType("default"); |
227 | Device savedDevice = doPost("/api/device", device, Device.class); | 233 | Device savedDevice = doPost("/api/device", device, Device.class); |
228 | - | 234 | + |
229 | doPost("/api/customer/" + UUIDs.timeBased().toString() | 235 | doPost("/api/customer/" + UUIDs.timeBased().toString() |
230 | + "/device/" + savedDevice.getId().getId().toString()) | 236 | + "/device/" + savedDevice.getId().getId().toString()) |
231 | - .andExpect(status().isNotFound()); | 237 | + .andExpect(status().isNotFound()); |
232 | } | 238 | } |
233 | - | 239 | + |
234 | @Test | 240 | @Test |
235 | public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { | 241 | public void testAssignDeviceToCustomerFromDifferentTenant() throws Exception { |
236 | loginSysAdmin(); | 242 | loginSysAdmin(); |
237 | - | 243 | + |
238 | Tenant tenant2 = new Tenant(); | 244 | Tenant tenant2 = new Tenant(); |
239 | tenant2.setTitle("Different tenant"); | 245 | tenant2.setTitle("Different tenant"); |
240 | Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); | 246 | Tenant savedTenant2 = doPost("/api/tenant", tenant2, Tenant.class); |
@@ -246,103 +252,103 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -246,103 +252,103 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
246 | tenantAdmin2.setEmail("tenant3@thingsboard.org"); | 252 | tenantAdmin2.setEmail("tenant3@thingsboard.org"); |
247 | tenantAdmin2.setFirstName("Joe"); | 253 | tenantAdmin2.setFirstName("Joe"); |
248 | tenantAdmin2.setLastName("Downs"); | 254 | tenantAdmin2.setLastName("Downs"); |
249 | - | 255 | + |
250 | tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); | 256 | tenantAdmin2 = createUserAndLogin(tenantAdmin2, "testPassword1"); |
251 | - | 257 | + |
252 | Customer customer = new Customer(); | 258 | Customer customer = new Customer(); |
253 | customer.setTitle("Different customer"); | 259 | customer.setTitle("Different customer"); |
254 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); | 260 | Customer savedCustomer = doPost("/api/customer", customer, Customer.class); |
255 | 261 | ||
256 | login(tenantAdmin.getEmail(), "testPassword1"); | 262 | login(tenantAdmin.getEmail(), "testPassword1"); |
257 | - | 263 | + |
258 | Device device = new Device(); | 264 | Device device = new Device(); |
259 | device.setName("My device"); | 265 | device.setName("My device"); |
260 | device.setType("default"); | 266 | device.setType("default"); |
261 | Device savedDevice = doPost("/api/device", device, Device.class); | 267 | Device savedDevice = doPost("/api/device", device, Device.class); |
262 | - | 268 | + |
263 | doPost("/api/customer/" + savedCustomer.getId().getId().toString() | 269 | doPost("/api/customer/" + savedCustomer.getId().getId().toString() |
264 | + "/device/" + savedDevice.getId().getId().toString()) | 270 | + "/device/" + savedDevice.getId().getId().toString()) |
265 | - .andExpect(status().isForbidden()); | ||
266 | - | 271 | + .andExpect(status().isForbidden()); |
272 | + | ||
267 | loginSysAdmin(); | 273 | loginSysAdmin(); |
268 | - | ||
269 | - doDelete("/api/tenant/"+savedTenant2.getId().getId().toString()) | ||
270 | - .andExpect(status().isOk()); | 274 | + |
275 | + doDelete("/api/tenant/" + savedTenant2.getId().getId().toString()) | ||
276 | + .andExpect(status().isOk()); | ||
271 | } | 277 | } |
272 | - | 278 | + |
273 | @Test | 279 | @Test |
274 | public void testFindDeviceCredentialsByDeviceId() throws Exception { | 280 | public void testFindDeviceCredentialsByDeviceId() throws Exception { |
275 | Device device = new Device(); | 281 | Device device = new Device(); |
276 | device.setName("My device"); | 282 | device.setName("My device"); |
277 | device.setType("default"); | 283 | device.setType("default"); |
278 | Device savedDevice = doPost("/api/device", device, Device.class); | 284 | Device savedDevice = doPost("/api/device", device, Device.class); |
279 | - DeviceCredentials deviceCredentials = | ||
280 | - doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 285 | + DeviceCredentials deviceCredentials = |
286 | + doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | ||
281 | Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); | 287 | Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); |
282 | } | 288 | } |
283 | - | 289 | + |
284 | @Test | 290 | @Test |
285 | public void testSaveDeviceCredentials() throws Exception { | 291 | public void testSaveDeviceCredentials() throws Exception { |
286 | Device device = new Device(); | 292 | Device device = new Device(); |
287 | device.setName("My device"); | 293 | device.setName("My device"); |
288 | device.setType("default"); | 294 | device.setType("default"); |
289 | Device savedDevice = doPost("/api/device", device, Device.class); | 295 | Device savedDevice = doPost("/api/device", device, Device.class); |
290 | - DeviceCredentials deviceCredentials = | ||
291 | - doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 296 | + DeviceCredentials deviceCredentials = |
297 | + doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | ||
292 | Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); | 298 | Assert.assertEquals(savedDevice.getId(), deviceCredentials.getDeviceId()); |
293 | deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); | 299 | deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); |
294 | deviceCredentials.setCredentialsId("access_token"); | 300 | deviceCredentials.setCredentialsId("access_token"); |
295 | doPost("/api/device/credentials", deviceCredentials) | 301 | doPost("/api/device/credentials", deviceCredentials) |
296 | - .andExpect(status().isOk()); | ||
297 | - | ||
298 | - DeviceCredentials foundDeviceCredentials = | 302 | + .andExpect(status().isOk()); |
303 | + | ||
304 | + DeviceCredentials foundDeviceCredentials = | ||
299 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 305 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
300 | - | 306 | + |
301 | Assert.assertEquals(deviceCredentials, foundDeviceCredentials); | 307 | Assert.assertEquals(deviceCredentials, foundDeviceCredentials); |
302 | } | 308 | } |
303 | - | 309 | + |
304 | @Test | 310 | @Test |
305 | public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception { | 311 | public void testSaveDeviceCredentialsWithEmptyDevice() throws Exception { |
306 | DeviceCredentials deviceCredentials = new DeviceCredentials(); | 312 | DeviceCredentials deviceCredentials = new DeviceCredentials(); |
307 | doPost("/api/device/credentials", deviceCredentials) | 313 | doPost("/api/device/credentials", deviceCredentials) |
308 | - .andExpect(status().isBadRequest()); | 314 | + .andExpect(status().isBadRequest()); |
309 | } | 315 | } |
310 | - | 316 | + |
311 | @Test | 317 | @Test |
312 | public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { | 318 | public void testSaveDeviceCredentialsWithEmptyCredentialsType() throws Exception { |
313 | Device device = new Device(); | 319 | Device device = new Device(); |
314 | device.setName("My device"); | 320 | device.setName("My device"); |
315 | device.setType("default"); | 321 | device.setType("default"); |
316 | Device savedDevice = doPost("/api/device", device, Device.class); | 322 | Device savedDevice = doPost("/api/device", device, Device.class); |
317 | - DeviceCredentials deviceCredentials = | 323 | + DeviceCredentials deviceCredentials = |
318 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 324 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
319 | deviceCredentials.setCredentialsType(null); | 325 | deviceCredentials.setCredentialsType(null); |
320 | doPost("/api/device/credentials", deviceCredentials) | 326 | doPost("/api/device/credentials", deviceCredentials) |
321 | - .andExpect(status().isBadRequest()) | ||
322 | - .andExpect(statusReason(containsString("Device credentials type should be specified"))); | 327 | + .andExpect(status().isBadRequest()) |
328 | + .andExpect(statusReason(containsString("Device credentials type should be specified"))); | ||
323 | } | 329 | } |
324 | - | 330 | + |
325 | @Test | 331 | @Test |
326 | public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { | 332 | public void testSaveDeviceCredentialsWithEmptyCredentialsId() throws Exception { |
327 | Device device = new Device(); | 333 | Device device = new Device(); |
328 | device.setName("My device"); | 334 | device.setName("My device"); |
329 | device.setType("default"); | 335 | device.setType("default"); |
330 | Device savedDevice = doPost("/api/device", device, Device.class); | 336 | Device savedDevice = doPost("/api/device", device, Device.class); |
331 | - DeviceCredentials deviceCredentials = | 337 | + DeviceCredentials deviceCredentials = |
332 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 338 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
333 | deviceCredentials.setCredentialsId(null); | 339 | deviceCredentials.setCredentialsId(null); |
334 | doPost("/api/device/credentials", deviceCredentials) | 340 | doPost("/api/device/credentials", deviceCredentials) |
335 | - .andExpect(status().isBadRequest()) | ||
336 | - .andExpect(statusReason(containsString("Device credentials id should be specified"))); | 341 | + .andExpect(status().isBadRequest()) |
342 | + .andExpect(statusReason(containsString("Device credentials id should be specified"))); | ||
337 | } | 343 | } |
338 | - | 344 | + |
339 | @Test | 345 | @Test |
340 | public void testSaveNonExistentDeviceCredentials() throws Exception { | 346 | public void testSaveNonExistentDeviceCredentials() throws Exception { |
341 | Device device = new Device(); | 347 | Device device = new Device(); |
342 | device.setName("My device"); | 348 | device.setName("My device"); |
343 | device.setType("default"); | 349 | device.setType("default"); |
344 | Device savedDevice = doPost("/api/device", device, Device.class); | 350 | Device savedDevice = doPost("/api/device", device, Device.class); |
345 | - DeviceCredentials deviceCredentials = | 351 | + DeviceCredentials deviceCredentials = |
346 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 352 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
347 | DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(UUIDs.timeBased())); | 353 | DeviceCredentials newDeviceCredentials = new DeviceCredentials(new DeviceCredentialsId(UUIDs.timeBased())); |
348 | newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime()); | 354 | newDeviceCredentials.setCreatedTime(deviceCredentials.getCreatedTime()); |
@@ -350,29 +356,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -350,29 +356,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
350 | newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); | 356 | newDeviceCredentials.setCredentialsType(deviceCredentials.getCredentialsType()); |
351 | newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); | 357 | newDeviceCredentials.setCredentialsId(deviceCredentials.getCredentialsId()); |
352 | doPost("/api/device/credentials", newDeviceCredentials) | 358 | doPost("/api/device/credentials", newDeviceCredentials) |
353 | - .andExpect(status().isBadRequest()) | ||
354 | - .andExpect(statusReason(containsString("Unable to update non-existent device credentials"))); | 359 | + .andExpect(status().isBadRequest()) |
360 | + .andExpect(statusReason(containsString("Unable to update non-existent device credentials"))); | ||
355 | } | 361 | } |
356 | - | 362 | + |
357 | @Test | 363 | @Test |
358 | public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { | 364 | public void testSaveDeviceCredentialsWithNonExistentDevice() throws Exception { |
359 | Device device = new Device(); | 365 | Device device = new Device(); |
360 | device.setName("My device"); | 366 | device.setName("My device"); |
361 | device.setType("default"); | 367 | device.setType("default"); |
362 | Device savedDevice = doPost("/api/device", device, Device.class); | 368 | Device savedDevice = doPost("/api/device", device, Device.class); |
363 | - DeviceCredentials deviceCredentials = | 369 | + DeviceCredentials deviceCredentials = |
364 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); | 370 | doGet("/api/device/" + savedDevice.getId().getId().toString() + "/credentials", DeviceCredentials.class); |
365 | deviceCredentials.setDeviceId(new DeviceId(UUIDs.timeBased())); | 371 | deviceCredentials.setDeviceId(new DeviceId(UUIDs.timeBased())); |
366 | doPost("/api/device/credentials", deviceCredentials) | 372 | doPost("/api/device/credentials", deviceCredentials) |
367 | - .andExpect(status().isNotFound()); | 373 | + .andExpect(status().isNotFound()); |
368 | } | 374 | } |
369 | 375 | ||
370 | @Test | 376 | @Test |
371 | public void testFindTenantDevices() throws Exception { | 377 | public void testFindTenantDevices() throws Exception { |
372 | List<Device> devices = new ArrayList<>(); | 378 | List<Device> devices = new ArrayList<>(); |
373 | - for (int i=0;i<178;i++) { | 379 | + for (int i = 0; i < 178; i++) { |
374 | Device device = new Device(); | 380 | Device device = new Device(); |
375 | - device.setName("Device"+i); | 381 | + device.setName("Device" + i); |
376 | device.setType("default"); | 382 | device.setType("default"); |
377 | devices.add(doPost("/api/device", device, Device.class)); | 383 | devices.add(doPost("/api/device", device, Device.class)); |
378 | } | 384 | } |
@@ -380,28 +386,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -380,28 +386,29 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
380 | TextPageLink pageLink = new TextPageLink(23); | 386 | TextPageLink pageLink = new TextPageLink(23); |
381 | TextPageData<Device> pageData = null; | 387 | TextPageData<Device> pageData = null; |
382 | do { | 388 | do { |
383 | - pageData = doGetTypedWithPageLink("/api/tenant/devices?", | ||
384 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 389 | + pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
390 | + new TypeReference<TextPageData<Device>>() { | ||
391 | + }, pageLink); | ||
385 | loadedDevices.addAll(pageData.getData()); | 392 | loadedDevices.addAll(pageData.getData()); |
386 | if (pageData.hasNext()) { | 393 | if (pageData.hasNext()) { |
387 | pageLink = pageData.getNextPageLink(); | 394 | pageLink = pageData.getNextPageLink(); |
388 | } | 395 | } |
389 | } while (pageData.hasNext()); | 396 | } while (pageData.hasNext()); |
390 | - | 397 | + |
391 | Collections.sort(devices, idComparator); | 398 | Collections.sort(devices, idComparator); |
392 | Collections.sort(loadedDevices, idComparator); | 399 | Collections.sort(loadedDevices, idComparator); |
393 | - | 400 | + |
394 | Assert.assertEquals(devices, loadedDevices); | 401 | Assert.assertEquals(devices, loadedDevices); |
395 | } | 402 | } |
396 | - | 403 | + |
397 | @Test | 404 | @Test |
398 | public void testFindTenantDevicesByName() throws Exception { | 405 | public void testFindTenantDevicesByName() throws Exception { |
399 | String title1 = "Device title 1"; | 406 | String title1 = "Device title 1"; |
400 | List<Device> devicesTitle1 = new ArrayList<>(); | 407 | List<Device> devicesTitle1 = new ArrayList<>(); |
401 | - for (int i=0;i<143;i++) { | 408 | + for (int i = 0; i < 143; i++) { |
402 | Device device = new Device(); | 409 | Device device = new Device(); |
403 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 410 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
404 | - String name = title1+suffix; | 411 | + String name = title1 + suffix; |
405 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 412 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
406 | device.setName(name); | 413 | device.setName(name); |
407 | device.setType("default"); | 414 | device.setType("default"); |
@@ -409,38 +416,40 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -409,38 +416,40 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
409 | } | 416 | } |
410 | String title2 = "Device title 2"; | 417 | String title2 = "Device title 2"; |
411 | List<Device> devicesTitle2 = new ArrayList<>(); | 418 | List<Device> devicesTitle2 = new ArrayList<>(); |
412 | - for (int i=0;i<75;i++) { | 419 | + for (int i = 0; i < 75; i++) { |
413 | Device device = new Device(); | 420 | Device device = new Device(); |
414 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 421 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
415 | - String name = title2+suffix; | 422 | + String name = title2 + suffix; |
416 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 423 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
417 | device.setName(name); | 424 | device.setName(name); |
418 | device.setType("default"); | 425 | device.setType("default"); |
419 | devicesTitle2.add(doPost("/api/device", device, Device.class)); | 426 | devicesTitle2.add(doPost("/api/device", device, Device.class)); |
420 | } | 427 | } |
421 | - | 428 | + |
422 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); | 429 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); |
423 | TextPageLink pageLink = new TextPageLink(15, title1); | 430 | TextPageLink pageLink = new TextPageLink(15, title1); |
424 | TextPageData<Device> pageData = null; | 431 | TextPageData<Device> pageData = null; |
425 | do { | 432 | do { |
426 | - pageData = doGetTypedWithPageLink("/api/tenant/devices?", | ||
427 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 433 | + pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
434 | + new TypeReference<TextPageData<Device>>() { | ||
435 | + }, pageLink); | ||
428 | loadedDevicesTitle1.addAll(pageData.getData()); | 436 | loadedDevicesTitle1.addAll(pageData.getData()); |
429 | if (pageData.hasNext()) { | 437 | if (pageData.hasNext()) { |
430 | pageLink = pageData.getNextPageLink(); | 438 | pageLink = pageData.getNextPageLink(); |
431 | } | 439 | } |
432 | } while (pageData.hasNext()); | 440 | } while (pageData.hasNext()); |
433 | - | 441 | + |
434 | Collections.sort(devicesTitle1, idComparator); | 442 | Collections.sort(devicesTitle1, idComparator); |
435 | Collections.sort(loadedDevicesTitle1, idComparator); | 443 | Collections.sort(loadedDevicesTitle1, idComparator); |
436 | - | 444 | + |
437 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); | 445 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); |
438 | - | 446 | + |
439 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); | 447 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); |
440 | pageLink = new TextPageLink(4, title2); | 448 | pageLink = new TextPageLink(4, title2); |
441 | do { | 449 | do { |
442 | - pageData = doGetTypedWithPageLink("/api/tenant/devices?", | ||
443 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 450 | + pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
451 | + new TypeReference<TextPageData<Device>>() { | ||
452 | + }, pageLink); | ||
444 | loadedDevicesTitle2.addAll(pageData.getData()); | 453 | loadedDevicesTitle2.addAll(pageData.getData()); |
445 | if (pageData.hasNext()) { | 454 | if (pageData.hasNext()) { |
446 | pageLink = pageData.getNextPageLink(); | 455 | pageLink = pageData.getNextPageLink(); |
@@ -449,28 +458,30 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -449,28 +458,30 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
449 | 458 | ||
450 | Collections.sort(devicesTitle2, idComparator); | 459 | Collections.sort(devicesTitle2, idComparator); |
451 | Collections.sort(loadedDevicesTitle2, idComparator); | 460 | Collections.sort(loadedDevicesTitle2, idComparator); |
452 | - | 461 | + |
453 | Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); | 462 | Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); |
454 | - | 463 | + |
455 | for (Device device : loadedDevicesTitle1) { | 464 | for (Device device : loadedDevicesTitle1) { |
456 | - doDelete("/api/device/"+device.getId().getId().toString()) | ||
457 | - .andExpect(status().isOk()); | 465 | + doDelete("/api/device/" + device.getId().getId().toString()) |
466 | + .andExpect(status().isOk()); | ||
458 | } | 467 | } |
459 | - | 468 | + |
460 | pageLink = new TextPageLink(4, title1); | 469 | pageLink = new TextPageLink(4, title1); |
461 | - pageData = doGetTypedWithPageLink("/api/tenant/devices?", | ||
462 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 470 | + pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
471 | + new TypeReference<TextPageData<Device>>() { | ||
472 | + }, pageLink); | ||
463 | Assert.assertFalse(pageData.hasNext()); | 473 | Assert.assertFalse(pageData.hasNext()); |
464 | Assert.assertEquals(0, pageData.getData().size()); | 474 | Assert.assertEquals(0, pageData.getData().size()); |
465 | - | 475 | + |
466 | for (Device device : loadedDevicesTitle2) { | 476 | for (Device device : loadedDevicesTitle2) { |
467 | - doDelete("/api/device/"+device.getId().getId().toString()) | ||
468 | - .andExpect(status().isOk()); | 477 | + doDelete("/api/device/" + device.getId().getId().toString()) |
478 | + .andExpect(status().isOk()); | ||
469 | } | 479 | } |
470 | - | 480 | + |
471 | pageLink = new TextPageLink(4, title2); | 481 | pageLink = new TextPageLink(4, title2); |
472 | - pageData = doGetTypedWithPageLink("/api/tenant/devices?", | ||
473 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 482 | + pageData = doGetTypedWithPageLink("/api/tenant/devices?", |
483 | + new TypeReference<TextPageData<Device>>() { | ||
484 | + }, pageLink); | ||
474 | Assert.assertFalse(pageData.hasNext()); | 485 | Assert.assertFalse(pageData.hasNext()); |
475 | Assert.assertEquals(0, pageData.getData().size()); | 486 | Assert.assertEquals(0, pageData.getData().size()); |
476 | } | 487 | } |
@@ -480,10 +491,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -480,10 +491,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
480 | String title1 = "Device title 1"; | 491 | String title1 = "Device title 1"; |
481 | String type1 = "typeA"; | 492 | String type1 = "typeA"; |
482 | List<Device> devicesType1 = new ArrayList<>(); | 493 | List<Device> devicesType1 = new ArrayList<>(); |
483 | - for (int i=0;i<143;i++) { | 494 | + for (int i = 0; i < 143; i++) { |
484 | Device device = new Device(); | 495 | Device device = new Device(); |
485 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 496 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
486 | - String name = title1+suffix; | 497 | + String name = title1 + suffix; |
487 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 498 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
488 | device.setName(name); | 499 | device.setName(name); |
489 | device.setType(type1); | 500 | device.setType(type1); |
@@ -492,10 +503,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -492,10 +503,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
492 | String title2 = "Device title 2"; | 503 | String title2 = "Device title 2"; |
493 | String type2 = "typeB"; | 504 | String type2 = "typeB"; |
494 | List<Device> devicesType2 = new ArrayList<>(); | 505 | List<Device> devicesType2 = new ArrayList<>(); |
495 | - for (int i=0;i<75;i++) { | 506 | + for (int i = 0; i < 75; i++) { |
496 | Device device = new Device(); | 507 | Device device = new Device(); |
497 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 508 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
498 | - String name = title2+suffix; | 509 | + String name = title2 + suffix; |
499 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 510 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
500 | device.setName(name); | 511 | device.setName(name); |
501 | device.setType(type2); | 512 | device.setType(type2); |
@@ -507,7 +518,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -507,7 +518,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
507 | TextPageData<Device> pageData = null; | 518 | TextPageData<Device> pageData = null; |
508 | do { | 519 | do { |
509 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", | 520 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
510 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | 521 | + new TypeReference<TextPageData<Device>>() { |
522 | + }, pageLink, type1); | ||
511 | loadedDevicesType1.addAll(pageData.getData()); | 523 | loadedDevicesType1.addAll(pageData.getData()); |
512 | if (pageData.hasNext()) { | 524 | if (pageData.hasNext()) { |
513 | pageLink = pageData.getNextPageLink(); | 525 | pageLink = pageData.getNextPageLink(); |
@@ -523,7 +535,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -523,7 +535,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
523 | pageLink = new TextPageLink(4); | 535 | pageLink = new TextPageLink(4); |
524 | do { | 536 | do { |
525 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", | 537 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
526 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | 538 | + new TypeReference<TextPageData<Device>>() { |
539 | + }, pageLink, type2); | ||
527 | loadedDevicesType2.addAll(pageData.getData()); | 540 | loadedDevicesType2.addAll(pageData.getData()); |
528 | if (pageData.hasNext()) { | 541 | if (pageData.hasNext()) { |
529 | pageLink = pageData.getNextPageLink(); | 542 | pageLink = pageData.getNextPageLink(); |
@@ -536,63 +549,66 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -536,63 +549,66 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
536 | Assert.assertEquals(devicesType2, loadedDevicesType2); | 549 | Assert.assertEquals(devicesType2, loadedDevicesType2); |
537 | 550 | ||
538 | for (Device device : loadedDevicesType1) { | 551 | for (Device device : loadedDevicesType1) { |
539 | - doDelete("/api/device/"+device.getId().getId().toString()) | 552 | + doDelete("/api/device/" + device.getId().getId().toString()) |
540 | .andExpect(status().isOk()); | 553 | .andExpect(status().isOk()); |
541 | } | 554 | } |
542 | 555 | ||
543 | pageLink = new TextPageLink(4); | 556 | pageLink = new TextPageLink(4); |
544 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", | 557 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
545 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | 558 | + new TypeReference<TextPageData<Device>>() { |
559 | + }, pageLink, type1); | ||
546 | Assert.assertFalse(pageData.hasNext()); | 560 | Assert.assertFalse(pageData.hasNext()); |
547 | Assert.assertEquals(0, pageData.getData().size()); | 561 | Assert.assertEquals(0, pageData.getData().size()); |
548 | 562 | ||
549 | for (Device device : loadedDevicesType2) { | 563 | for (Device device : loadedDevicesType2) { |
550 | - doDelete("/api/device/"+device.getId().getId().toString()) | 564 | + doDelete("/api/device/" + device.getId().getId().toString()) |
551 | .andExpect(status().isOk()); | 565 | .andExpect(status().isOk()); |
552 | } | 566 | } |
553 | 567 | ||
554 | pageLink = new TextPageLink(4); | 568 | pageLink = new TextPageLink(4); |
555 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", | 569 | pageData = doGetTypedWithPageLink("/api/tenant/devices?type={type}&", |
556 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | 570 | + new TypeReference<TextPageData<Device>>() { |
571 | + }, pageLink, type2); | ||
557 | Assert.assertFalse(pageData.hasNext()); | 572 | Assert.assertFalse(pageData.hasNext()); |
558 | Assert.assertEquals(0, pageData.getData().size()); | 573 | Assert.assertEquals(0, pageData.getData().size()); |
559 | } | 574 | } |
560 | - | 575 | + |
561 | @Test | 576 | @Test |
562 | public void testFindCustomerDevices() throws Exception { | 577 | public void testFindCustomerDevices() throws Exception { |
563 | Customer customer = new Customer(); | 578 | Customer customer = new Customer(); |
564 | customer.setTitle("Test customer"); | 579 | customer.setTitle("Test customer"); |
565 | customer = doPost("/api/customer", customer, Customer.class); | 580 | customer = doPost("/api/customer", customer, Customer.class); |
566 | CustomerId customerId = customer.getId(); | 581 | CustomerId customerId = customer.getId(); |
567 | - | 582 | + |
568 | List<Device> devices = new ArrayList<>(); | 583 | List<Device> devices = new ArrayList<>(); |
569 | - for (int i=0;i<128;i++) { | 584 | + for (int i = 0; i < 128; i++) { |
570 | Device device = new Device(); | 585 | Device device = new Device(); |
571 | - device.setName("Device"+i); | 586 | + device.setName("Device" + i); |
572 | device.setType("default"); | 587 | device.setType("default"); |
573 | device = doPost("/api/device", device, Device.class); | 588 | device = doPost("/api/device", device, Device.class); |
574 | - devices.add(doPost("/api/customer/" + customerId.getId().toString() | ||
575 | - + "/device/" + device.getId().getId().toString(), Device.class)); | 589 | + devices.add(doPost("/api/customer/" + customerId.getId().toString() |
590 | + + "/device/" + device.getId().getId().toString(), Device.class)); | ||
576 | } | 591 | } |
577 | - | 592 | + |
578 | List<Device> loadedDevices = new ArrayList<>(); | 593 | List<Device> loadedDevices = new ArrayList<>(); |
579 | TextPageLink pageLink = new TextPageLink(23); | 594 | TextPageLink pageLink = new TextPageLink(23); |
580 | TextPageData<Device> pageData = null; | 595 | TextPageData<Device> pageData = null; |
581 | do { | 596 | do { |
582 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", | ||
583 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 597 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
598 | + new TypeReference<TextPageData<Device>>() { | ||
599 | + }, pageLink); | ||
584 | loadedDevices.addAll(pageData.getData()); | 600 | loadedDevices.addAll(pageData.getData()); |
585 | if (pageData.hasNext()) { | 601 | if (pageData.hasNext()) { |
586 | pageLink = pageData.getNextPageLink(); | 602 | pageLink = pageData.getNextPageLink(); |
587 | } | 603 | } |
588 | } while (pageData.hasNext()); | 604 | } while (pageData.hasNext()); |
589 | - | 605 | + |
590 | Collections.sort(devices, idComparator); | 606 | Collections.sort(devices, idComparator); |
591 | Collections.sort(loadedDevices, idComparator); | 607 | Collections.sort(loadedDevices, idComparator); |
592 | - | 608 | + |
593 | Assert.assertEquals(devices, loadedDevices); | 609 | Assert.assertEquals(devices, loadedDevices); |
594 | } | 610 | } |
595 | - | 611 | + |
596 | @Test | 612 | @Test |
597 | public void testFindCustomerDevicesByName() throws Exception { | 613 | public void testFindCustomerDevicesByName() throws Exception { |
598 | Customer customer = new Customer(); | 614 | Customer customer = new Customer(); |
@@ -602,53 +618,55 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -602,53 +618,55 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
602 | 618 | ||
603 | String title1 = "Device title 1"; | 619 | String title1 = "Device title 1"; |
604 | List<Device> devicesTitle1 = new ArrayList<>(); | 620 | List<Device> devicesTitle1 = new ArrayList<>(); |
605 | - for (int i=0;i<125;i++) { | 621 | + for (int i = 0; i < 125; i++) { |
606 | Device device = new Device(); | 622 | Device device = new Device(); |
607 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 623 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
608 | - String name = title1+suffix; | 624 | + String name = title1 + suffix; |
609 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 625 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
610 | device.setName(name); | 626 | device.setName(name); |
611 | device.setType("default"); | 627 | device.setType("default"); |
612 | device = doPost("/api/device", device, Device.class); | 628 | device = doPost("/api/device", device, Device.class); |
613 | - devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() | 629 | + devicesTitle1.add(doPost("/api/customer/" + customerId.getId().toString() |
614 | + "/device/" + device.getId().getId().toString(), Device.class)); | 630 | + "/device/" + device.getId().getId().toString(), Device.class)); |
615 | } | 631 | } |
616 | String title2 = "Device title 2"; | 632 | String title2 = "Device title 2"; |
617 | List<Device> devicesTitle2 = new ArrayList<>(); | 633 | List<Device> devicesTitle2 = new ArrayList<>(); |
618 | - for (int i=0;i<143;i++) { | 634 | + for (int i = 0; i < 143; i++) { |
619 | Device device = new Device(); | 635 | Device device = new Device(); |
620 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 636 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
621 | - String name = title2+suffix; | 637 | + String name = title2 + suffix; |
622 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 638 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
623 | device.setName(name); | 639 | device.setName(name); |
624 | device.setType("default"); | 640 | device.setType("default"); |
625 | device = doPost("/api/device", device, Device.class); | 641 | device = doPost("/api/device", device, Device.class); |
626 | - devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() | 642 | + devicesTitle2.add(doPost("/api/customer/" + customerId.getId().toString() |
627 | + "/device/" + device.getId().getId().toString(), Device.class)); | 643 | + "/device/" + device.getId().getId().toString(), Device.class)); |
628 | } | 644 | } |
629 | - | 645 | + |
630 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); | 646 | List<Device> loadedDevicesTitle1 = new ArrayList<>(); |
631 | TextPageLink pageLink = new TextPageLink(15, title1); | 647 | TextPageLink pageLink = new TextPageLink(15, title1); |
632 | TextPageData<Device> pageData = null; | 648 | TextPageData<Device> pageData = null; |
633 | do { | 649 | do { |
634 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", | ||
635 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 650 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
651 | + new TypeReference<TextPageData<Device>>() { | ||
652 | + }, pageLink); | ||
636 | loadedDevicesTitle1.addAll(pageData.getData()); | 653 | loadedDevicesTitle1.addAll(pageData.getData()); |
637 | if (pageData.hasNext()) { | 654 | if (pageData.hasNext()) { |
638 | pageLink = pageData.getNextPageLink(); | 655 | pageLink = pageData.getNextPageLink(); |
639 | } | 656 | } |
640 | } while (pageData.hasNext()); | 657 | } while (pageData.hasNext()); |
641 | - | 658 | + |
642 | Collections.sort(devicesTitle1, idComparator); | 659 | Collections.sort(devicesTitle1, idComparator); |
643 | Collections.sort(loadedDevicesTitle1, idComparator); | 660 | Collections.sort(loadedDevicesTitle1, idComparator); |
644 | - | 661 | + |
645 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); | 662 | Assert.assertEquals(devicesTitle1, loadedDevicesTitle1); |
646 | - | 663 | + |
647 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); | 664 | List<Device> loadedDevicesTitle2 = new ArrayList<>(); |
648 | pageLink = new TextPageLink(4, title2); | 665 | pageLink = new TextPageLink(4, title2); |
649 | do { | 666 | do { |
650 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", | ||
651 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 667 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
668 | + new TypeReference<TextPageData<Device>>() { | ||
669 | + }, pageLink); | ||
652 | loadedDevicesTitle2.addAll(pageData.getData()); | 670 | loadedDevicesTitle2.addAll(pageData.getData()); |
653 | if (pageData.hasNext()) { | 671 | if (pageData.hasNext()) { |
654 | pageLink = pageData.getNextPageLink(); | 672 | pageLink = pageData.getNextPageLink(); |
@@ -657,28 +675,30 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -657,28 +675,30 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
657 | 675 | ||
658 | Collections.sort(devicesTitle2, idComparator); | 676 | Collections.sort(devicesTitle2, idComparator); |
659 | Collections.sort(loadedDevicesTitle2, idComparator); | 677 | Collections.sort(loadedDevicesTitle2, idComparator); |
660 | - | 678 | + |
661 | Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); | 679 | Assert.assertEquals(devicesTitle2, loadedDevicesTitle2); |
662 | - | 680 | + |
663 | for (Device device : loadedDevicesTitle1) { | 681 | for (Device device : loadedDevicesTitle1) { |
664 | doDelete("/api/customer/device/" + device.getId().getId().toString()) | 682 | doDelete("/api/customer/device/" + device.getId().getId().toString()) |
665 | - .andExpect(status().isOk()); | 683 | + .andExpect(status().isOk()); |
666 | } | 684 | } |
667 | - | 685 | + |
668 | pageLink = new TextPageLink(4, title1); | 686 | pageLink = new TextPageLink(4, title1); |
669 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", | ||
670 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 687 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
688 | + new TypeReference<TextPageData<Device>>() { | ||
689 | + }, pageLink); | ||
671 | Assert.assertFalse(pageData.hasNext()); | 690 | Assert.assertFalse(pageData.hasNext()); |
672 | Assert.assertEquals(0, pageData.getData().size()); | 691 | Assert.assertEquals(0, pageData.getData().size()); |
673 | - | 692 | + |
674 | for (Device device : loadedDevicesTitle2) { | 693 | for (Device device : loadedDevicesTitle2) { |
675 | doDelete("/api/customer/device/" + device.getId().getId().toString()) | 694 | doDelete("/api/customer/device/" + device.getId().getId().toString()) |
676 | - .andExpect(status().isOk()); | 695 | + .andExpect(status().isOk()); |
677 | } | 696 | } |
678 | - | 697 | + |
679 | pageLink = new TextPageLink(4, title2); | 698 | pageLink = new TextPageLink(4, title2); |
680 | - pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", | ||
681 | - new TypeReference<TextPageData<Device>>(){}, pageLink); | 699 | + pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?", |
700 | + new TypeReference<TextPageData<Device>>() { | ||
701 | + }, pageLink); | ||
682 | Assert.assertFalse(pageData.hasNext()); | 702 | Assert.assertFalse(pageData.hasNext()); |
683 | Assert.assertEquals(0, pageData.getData().size()); | 703 | Assert.assertEquals(0, pageData.getData().size()); |
684 | } | 704 | } |
@@ -693,10 +713,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -693,10 +713,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
693 | String title1 = "Device title 1"; | 713 | String title1 = "Device title 1"; |
694 | String type1 = "typeC"; | 714 | String type1 = "typeC"; |
695 | List<Device> devicesType1 = new ArrayList<>(); | 715 | List<Device> devicesType1 = new ArrayList<>(); |
696 | - for (int i=0;i<125;i++) { | 716 | + for (int i = 0; i < 125; i++) { |
697 | Device device = new Device(); | 717 | Device device = new Device(); |
698 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 718 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
699 | - String name = title1+suffix; | 719 | + String name = title1 + suffix; |
700 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 720 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
701 | device.setName(name); | 721 | device.setName(name); |
702 | device.setType(type1); | 722 | device.setType(type1); |
@@ -707,10 +727,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -707,10 +727,10 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
707 | String title2 = "Device title 2"; | 727 | String title2 = "Device title 2"; |
708 | String type2 = "typeD"; | 728 | String type2 = "typeD"; |
709 | List<Device> devicesType2 = new ArrayList<>(); | 729 | List<Device> devicesType2 = new ArrayList<>(); |
710 | - for (int i=0;i<143;i++) { | 730 | + for (int i = 0; i < 143; i++) { |
711 | Device device = new Device(); | 731 | Device device = new Device(); |
712 | String suffix = RandomStringUtils.randomAlphanumeric(15); | 732 | String suffix = RandomStringUtils.randomAlphanumeric(15); |
713 | - String name = title2+suffix; | 733 | + String name = title2 + suffix; |
714 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); | 734 | name = i % 2 == 0 ? name.toLowerCase() : name.toUpperCase(); |
715 | device.setName(name); | 735 | device.setName(name); |
716 | device.setType(type2); | 736 | device.setType(type2); |
@@ -724,7 +744,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -724,7 +744,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
724 | TextPageData<Device> pageData = null; | 744 | TextPageData<Device> pageData = null; |
725 | do { | 745 | do { |
726 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", | 746 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
727 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | 747 | + new TypeReference<TextPageData<Device>>() { |
748 | + }, pageLink, type1); | ||
728 | loadedDevicesType1.addAll(pageData.getData()); | 749 | loadedDevicesType1.addAll(pageData.getData()); |
729 | if (pageData.hasNext()) { | 750 | if (pageData.hasNext()) { |
730 | pageLink = pageData.getNextPageLink(); | 751 | pageLink = pageData.getNextPageLink(); |
@@ -740,7 +761,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -740,7 +761,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
740 | pageLink = new TextPageLink(4); | 761 | pageLink = new TextPageLink(4); |
741 | do { | 762 | do { |
742 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", | 763 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
743 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | 764 | + new TypeReference<TextPageData<Device>>() { |
765 | + }, pageLink, type2); | ||
744 | loadedDevicesType2.addAll(pageData.getData()); | 766 | loadedDevicesType2.addAll(pageData.getData()); |
745 | if (pageData.hasNext()) { | 767 | if (pageData.hasNext()) { |
746 | pageLink = pageData.getNextPageLink(); | 768 | pageLink = pageData.getNextPageLink(); |
@@ -759,7 +781,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -759,7 +781,8 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
759 | 781 | ||
760 | pageLink = new TextPageLink(4); | 782 | pageLink = new TextPageLink(4); |
761 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", | 783 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
762 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type1); | 784 | + new TypeReference<TextPageData<Device>>() { |
785 | + }, pageLink, type1); | ||
763 | Assert.assertFalse(pageData.hasNext()); | 786 | Assert.assertFalse(pageData.hasNext()); |
764 | Assert.assertEquals(0, pageData.getData().size()); | 787 | Assert.assertEquals(0, pageData.getData().size()); |
765 | 788 | ||
@@ -770,9 +793,60 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | @@ -770,9 +793,60 @@ public abstract class BaseDeviceControllerTest extends AbstractControllerTest { | ||
770 | 793 | ||
771 | pageLink = new TextPageLink(4); | 794 | pageLink = new TextPageLink(4); |
772 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", | 795 | pageData = doGetTypedWithPageLink("/api/customer/" + customerId.getId().toString() + "/devices?type={type}&", |
773 | - new TypeReference<TextPageData<Device>>(){}, pageLink, type2); | 796 | + new TypeReference<TextPageData<Device>>() { |
797 | + }, pageLink, type2); | ||
774 | Assert.assertFalse(pageData.hasNext()); | 798 | Assert.assertFalse(pageData.hasNext()); |
775 | Assert.assertEquals(0, pageData.getData().size()); | 799 | Assert.assertEquals(0, pageData.getData().size()); |
776 | } | 800 | } |
777 | 801 | ||
802 | + @Test | ||
803 | + public void testAssignDeviceToTenant() throws Exception { | ||
804 | + Device device = new Device(); | ||
805 | + device.setName("My device"); | ||
806 | + device.setType("default"); | ||
807 | + Device savedDevice = doPost("/api/device", device, Device.class); | ||
808 | + | ||
809 | + Device anotherDevice = new Device(); | ||
810 | + anotherDevice.setName("My device1"); | ||
811 | + anotherDevice.setType("default"); | ||
812 | + Device savedAnotherDevice = doPost("/api/device", anotherDevice, Device.class); | ||
813 | + | ||
814 | + EntityRelation relation = new EntityRelation(); | ||
815 | + relation.setFrom(savedDevice.getId()); | ||
816 | + relation.setTo(savedAnotherDevice.getId()); | ||
817 | + relation.setTypeGroup(RelationTypeGroup.COMMON); | ||
818 | + relation.setType("Contains"); | ||
819 | + doPost("/api/relation", relation).andExpect(status().isOk()); | ||
820 | + | ||
821 | + loginSysAdmin(); | ||
822 | + Tenant tenant = new Tenant(); | ||
823 | + tenant.setTitle("Different tenant"); | ||
824 | + Tenant savedDifferentTenant = doPost("/api/tenant", tenant, Tenant.class); | ||
825 | + Assert.assertNotNull(savedDifferentTenant); | ||
826 | + | ||
827 | + User user = new User(); | ||
828 | + user.setAuthority(Authority.TENANT_ADMIN); | ||
829 | + user.setTenantId(savedDifferentTenant.getId()); | ||
830 | + user.setEmail("tenant9@thingsboard.org"); | ||
831 | + user.setFirstName("Sam"); | ||
832 | + user.setLastName("Downs"); | ||
833 | + | ||
834 | + createUserAndLogin(user, "testPassword1"); | ||
835 | + | ||
836 | + login("tenant2@thingsboard.org", "testPassword1"); | ||
837 | + Device assignedDevice = doPost("/api/tenant/" + savedDifferentTenant.getId().getId() + "/device/" + savedDevice.getId().getId(), Device.class); | ||
838 | + | ||
839 | + doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class, status().isNotFound()); | ||
840 | + | ||
841 | + login("tenant9@thingsboard.org", "testPassword1"); | ||
842 | + | ||
843 | + Device foundDevice1 = doGet("/api/device/" + assignedDevice.getId().getId().toString(), Device.class); | ||
844 | + Assert.assertNotNull(foundDevice1); | ||
845 | + | ||
846 | + doGet("/api/relation?fromId=" + savedDevice.getId().getId() + "&fromType=DEVICE&relationType=Contains&toId=" + savedAnotherDevice.getId().getId() + "&toType=DEVICE", EntityRelation.class, status().isNotFound()); | ||
847 | + | ||
848 | + loginSysAdmin(); | ||
849 | + doDelete("/api/tenant/" + savedDifferentTenant.getId().getId().toString()) | ||
850 | + .andExpect(status().isOk()); | ||
851 | + } | ||
778 | } | 852 | } |
@@ -93,7 +93,7 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest { | @@ -93,7 +93,7 @@ public class BaseEdgeEventControllerTest extends AbstractControllerTest { | ||
93 | 93 | ||
94 | doPost("/api/relation", relation); | 94 | doPost("/api/relation", relation); |
95 | 95 | ||
96 | - Thread.sleep(1000); | 96 | + Thread.sleep(2000); |
97 | 97 | ||
98 | List<EdgeEvent> edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?", | 98 | List<EdgeEvent> edgeEvents = doGetTypedWithTimePageLink("/api/edge/" + edge.getId().toString() + "/events?", |
99 | new TypeReference<TimePageData<EdgeEvent>>() { | 99 | new TypeReference<TimePageData<EdgeEvent>>() { |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -16,14 +16,12 @@ | @@ -16,14 +16,12 @@ | ||
16 | package org.thingsboard.server.dao.audit; | 16 | package org.thingsboard.server.dao.audit; |
17 | 17 | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | -import org.thingsboard.server.common.data.BaseData; | ||
20 | import org.thingsboard.server.common.data.HasName; | 19 | import org.thingsboard.server.common.data.HasName; |
21 | import org.thingsboard.server.common.data.audit.ActionType; | 20 | import org.thingsboard.server.common.data.audit.ActionType; |
22 | import org.thingsboard.server.common.data.audit.AuditLog; | 21 | import org.thingsboard.server.common.data.audit.AuditLog; |
23 | import org.thingsboard.server.common.data.id.CustomerId; | 22 | import org.thingsboard.server.common.data.id.CustomerId; |
24 | import org.thingsboard.server.common.data.id.EntityId; | 23 | import org.thingsboard.server.common.data.id.EntityId; |
25 | import org.thingsboard.server.common.data.id.TenantId; | 24 | import org.thingsboard.server.common.data.id.TenantId; |
26 | -import org.thingsboard.server.common.data.id.UUIDBased; | ||
27 | import org.thingsboard.server.common.data.id.UserId; | 25 | import org.thingsboard.server.common.data.id.UserId; |
28 | import org.thingsboard.server.common.data.page.TimePageData; | 26 | import org.thingsboard.server.common.data.page.TimePageData; |
29 | import org.thingsboard.server.common.data.page.TimePageLink; | 27 | import org.thingsboard.server.common.data.page.TimePageLink; |
@@ -49,5 +47,4 @@ public interface AuditLogService { | @@ -49,5 +47,4 @@ public interface AuditLogService { | ||
49 | E entity, | 47 | E entity, |
50 | ActionType actionType, | 48 | ActionType actionType, |
51 | Exception e, Object... additionalInfo); | 49 | Exception e, Object... additionalInfo); |
52 | - | ||
53 | } | 50 | } |
@@ -68,6 +68,8 @@ public interface DeviceService { | @@ -68,6 +68,8 @@ public interface DeviceService { | ||
68 | 68 | ||
69 | ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId); | 69 | ListenableFuture<List<EntitySubtype>> findDeviceTypesByTenantId(TenantId tenantId); |
70 | 70 | ||
71 | + Device assignDeviceToTenant(TenantId tenantId, Device device); | ||
72 | + | ||
71 | Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); | 73 | Device assignDeviceToEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); |
72 | 74 | ||
73 | Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); | 75 | Device unassignDeviceFromEdge(TenantId tenantId, DeviceId deviceId, EdgeId edgeId); |
@@ -41,4 +41,6 @@ public interface EventService { | @@ -41,4 +41,6 @@ public interface EventService { | ||
41 | 41 | ||
42 | List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit); | 42 | List<Event> findLatestEvents(TenantId tenantId, EntityId entityId, String eventType, int limit); |
43 | 43 | ||
44 | + void removeEvents(TenantId tenantId, EntityId entityId); | ||
45 | + | ||
44 | } | 46 | } |
@@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery; | @@ -24,7 +24,6 @@ import org.thingsboard.server.common.data.relation.EntityRelationsQuery; | ||
24 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 24 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
25 | 25 | ||
26 | import java.util.List; | 26 | import java.util.List; |
27 | -import java.util.concurrent.ExecutionException; | ||
28 | 27 | ||
29 | /** | 28 | /** |
30 | * Created by ashvayka on 27.04.17. | 29 | * Created by ashvayka on 27.04.17. |
@@ -77,6 +76,8 @@ public interface RelationService { | @@ -77,6 +76,8 @@ public interface RelationService { | ||
77 | 76 | ||
78 | ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(TenantId tenantId, EntityRelationsQuery query); | 77 | ListenableFuture<List<EntityRelationInfo>> findInfoByQuery(TenantId tenantId, EntityRelationsQuery query); |
79 | 78 | ||
79 | + void removeRelations(TenantId tenantId, EntityId entityId); | ||
80 | + | ||
80 | // TODO: This method may be useful for some validations in the future | 81 | // TODO: This method may be useful for some validations in the future |
81 | // ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to); | 82 | // ListenableFuture<Boolean> checkRecursiveRelation(EntityId from, EntityId to); |
82 | 83 |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -57,6 +57,8 @@ public class DataConstants { | @@ -57,6 +57,8 @@ public class DataConstants { | ||
57 | public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; | 57 | public static final String ATTRIBUTES_DELETED = "ATTRIBUTES_DELETED"; |
58 | public static final String ALARM_ACK = "ALARM_ACK"; | 58 | public static final String ALARM_ACK = "ALARM_ACK"; |
59 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; | 59 | public static final String ALARM_CLEAR = "ALARM_CLEAR"; |
60 | + public static final String ENTITY_ASSIGNED_FROM_TENANT = "ENTITY_ASSIGNED_FROM_TENANT"; | ||
61 | + public static final String ENTITY_ASSIGNED_TO_TENANT = "ENTITY_ASSIGNED_TO_TENANT"; | ||
60 | public static final String ENTITY_ASSIGNED_TO_EDGE = "ENTITY_ASSIGNED_TO_EDGE"; | 62 | public static final String ENTITY_ASSIGNED_TO_EDGE = "ENTITY_ASSIGNED_TO_EDGE"; |
61 | public static final String ENTITY_UNASSIGNED_FROM_EDGE = "ENTITY_UNASSIGNED_FROM_EDGE"; | 63 | public static final String ENTITY_UNASSIGNED_FROM_EDGE = "ENTITY_UNASSIGNED_FROM_EDGE"; |
62 | 64 |
@@ -42,6 +42,8 @@ public enum ActionType { | @@ -42,6 +42,8 @@ public enum ActionType { | ||
42 | LOGIN(false), | 42 | LOGIN(false), |
43 | LOGOUT(false), | 43 | LOGOUT(false), |
44 | LOCKOUT(false), | 44 | LOCKOUT(false), |
45 | + ASSIGNED_FROM_TENANT(false), | ||
46 | + ASSIGNED_TO_TENANT(false), | ||
45 | ASSIGNED_TO_EDGE(false), // log edge name | 47 | ASSIGNED_TO_EDGE(false), // log edge name |
46 | UNASSIGNED_FROM_EDGE(false), // log edge name | 48 | UNASSIGNED_FROM_EDGE(false), // log edge name |
47 | CREDENTIALS_REQUEST(false), // request credentials from edge | 49 | CREDENTIALS_REQUEST(false), // request credentials from edge |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
common/message/src/main/java/org/thingsboard/server/common/msg/kv/AttributesKVMsg.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.common.msg.kv; | ||
17 | - | ||
18 | -import java.io.Serializable; | ||
19 | -import java.util.List; | ||
20 | - | ||
21 | -import org.thingsboard.server.common.data.kv.AttributeKey; | ||
22 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
23 | - | ||
24 | -public interface AttributesKVMsg extends Serializable { | ||
25 | - | ||
26 | - List<AttributeKvEntry> getClientAttributes(); | ||
27 | - List<AttributeKvEntry> getSharedAttributes(); | ||
28 | - List<AttributeKey> getDeletedAttributes(); | ||
29 | -} |
common/message/src/main/java/org/thingsboard/server/common/msg/kv/BasicAttributeKVMsg.java
deleted
100644 → 0
1 | -/** | ||
2 | - * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | - * | ||
4 | - * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | - * you may not use this file except in compliance with the License. | ||
6 | - * You may obtain a copy of the License at | ||
7 | - * | ||
8 | - * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | - * | ||
10 | - * Unless required by applicable law or agreed to in writing, software | ||
11 | - * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | - * See the License for the specific language governing permissions and | ||
14 | - * limitations under the License. | ||
15 | - */ | ||
16 | -package org.thingsboard.server.common.msg.kv; | ||
17 | - | ||
18 | -import lombok.AccessLevel; | ||
19 | -import lombok.Data; | ||
20 | -import lombok.RequiredArgsConstructor; | ||
21 | -import org.thingsboard.server.common.data.kv.AttributeKey; | ||
22 | -import org.thingsboard.server.common.data.kv.AttributeKvEntry; | ||
23 | - | ||
24 | -import java.util.Collections; | ||
25 | -import java.util.List; | ||
26 | - | ||
27 | -@Data | ||
28 | -@RequiredArgsConstructor(access = AccessLevel.PRIVATE) | ||
29 | -public class BasicAttributeKVMsg implements AttributesKVMsg { | ||
30 | - | ||
31 | - private static final long serialVersionUID = 1L; | ||
32 | - | ||
33 | - private final List<AttributeKvEntry> clientAttributes; | ||
34 | - private final List<AttributeKvEntry> sharedAttributes; | ||
35 | - private final List<AttributeKey> deletedAttributes; | ||
36 | - | ||
37 | - public static BasicAttributeKVMsg fromClient(List<AttributeKvEntry> attributes) { | ||
38 | - return new BasicAttributeKVMsg(attributes, Collections.emptyList(), Collections.emptyList()); | ||
39 | - } | ||
40 | - | ||
41 | - public static BasicAttributeKVMsg fromShared(List<AttributeKvEntry> attributes) { | ||
42 | - return new BasicAttributeKVMsg(Collections.emptyList(), attributes, Collections.emptyList()); | ||
43 | - } | ||
44 | - | ||
45 | - public static BasicAttributeKVMsg from(List<AttributeKvEntry> client, List<AttributeKvEntry> shared) { | ||
46 | - return new BasicAttributeKVMsg(client, shared, Collections.emptyList()); | ||
47 | - } | ||
48 | - | ||
49 | - public static AttributesKVMsg fromDeleted(List<AttributeKey> shared) { | ||
50 | - return new BasicAttributeKVMsg(Collections.emptyList(), Collections.emptyList(), shared); | ||
51 | - } | ||
52 | -} |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>common</artifactId> | 26 | <artifactId>common</artifactId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -37,6 +37,7 @@ public class TbKafkaAdmin implements TbQueueAdmin { | @@ -37,6 +37,7 @@ public class TbKafkaAdmin implements TbQueueAdmin { | ||
37 | private final AdminClient client; | 37 | private final AdminClient client; |
38 | private final Map<String, String> topicConfigs; | 38 | private final Map<String, String> topicConfigs; |
39 | private final Set<String> topics = ConcurrentHashMap.newKeySet(); | 39 | private final Set<String> topics = ConcurrentHashMap.newKeySet(); |
40 | + private final int numPartitions; | ||
40 | 41 | ||
41 | private final short replicationFactor; | 42 | private final short replicationFactor; |
42 | 43 | ||
@@ -50,6 +51,13 @@ public class TbKafkaAdmin implements TbQueueAdmin { | @@ -50,6 +51,13 @@ public class TbKafkaAdmin implements TbQueueAdmin { | ||
50 | log.error("Failed to get all topics.", e); | 51 | log.error("Failed to get all topics.", e); |
51 | } | 52 | } |
52 | 53 | ||
54 | + String numPartitionsStr = topicConfigs.get("partitions"); | ||
55 | + if (numPartitionsStr != null) { | ||
56 | + numPartitions = Integer.parseInt(numPartitionsStr); | ||
57 | + topicConfigs.remove("partitions"); | ||
58 | + } else { | ||
59 | + numPartitions = 1; | ||
60 | + } | ||
53 | replicationFactor = settings.getReplicationFactor(); | 61 | replicationFactor = settings.getReplicationFactor(); |
54 | } | 62 | } |
55 | 63 | ||
@@ -59,7 +67,7 @@ public class TbKafkaAdmin implements TbQueueAdmin { | @@ -59,7 +67,7 @@ public class TbKafkaAdmin implements TbQueueAdmin { | ||
59 | return; | 67 | return; |
60 | } | 68 | } |
61 | try { | 69 | try { |
62 | - NewTopic newTopic = new NewTopic(topic, 1, replicationFactor).configs(topicConfigs); | 70 | + NewTopic newTopic = new NewTopic(topic, numPartitions, replicationFactor).configs(topicConfigs); |
63 | createTopic(newTopic).values().get(topic).get(); | 71 | createTopic(newTopic).values().get(topic).get(); |
64 | topics.add(topic); | 72 | topics.add(topic); |
65 | } catch (ExecutionException ee) { | 73 | } catch (ExecutionException ee) { |
@@ -16,10 +16,13 @@ | @@ -16,10 +16,13 @@ | ||
16 | package org.thingsboard.server.queue.kafka; | 16 | package org.thingsboard.server.queue.kafka; |
17 | 17 | ||
18 | import lombok.Getter; | 18 | import lombok.Getter; |
19 | +import lombok.Setter; | ||
19 | import lombok.extern.slf4j.Slf4j; | 20 | import lombok.extern.slf4j.Slf4j; |
21 | +import org.apache.kafka.clients.CommonClientConfigs; | ||
20 | import org.apache.kafka.clients.producer.ProducerConfig; | 22 | import org.apache.kafka.clients.producer.ProducerConfig; |
21 | import org.springframework.beans.factory.annotation.Value; | 23 | import org.springframework.beans.factory.annotation.Value; |
22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
25 | +import org.springframework.boot.context.properties.ConfigurationProperties; | ||
23 | import org.springframework.stereotype.Component; | 26 | import org.springframework.stereotype.Component; |
24 | 27 | ||
25 | import java.util.List; | 28 | import java.util.List; |
@@ -30,6 +33,7 @@ import java.util.Properties; | @@ -30,6 +33,7 @@ import java.util.Properties; | ||
30 | */ | 33 | */ |
31 | @Slf4j | 34 | @Slf4j |
32 | @ConditionalOnExpression("'${queue.type:null}'=='kafka'") | 35 | @ConditionalOnExpression("'${queue.type:null}'=='kafka'") |
36 | +@ConfigurationProperties(prefix = "queue.kafka") | ||
33 | @Component | 37 | @Component |
34 | public class TbKafkaSettings { | 38 | public class TbKafkaSettings { |
35 | 39 | ||
@@ -65,20 +69,44 @@ public class TbKafkaSettings { | @@ -65,20 +69,44 @@ public class TbKafkaSettings { | ||
65 | 69 | ||
66 | @Value("${queue.kafka.fetch_max_bytes:134217728}") | 70 | @Value("${queue.kafka.fetch_max_bytes:134217728}") |
67 | @Getter | 71 | @Getter |
68 | - private int fetchMaxBytes; | 72 | + private int fetchMaxBytes; |
69 | 73 | ||
70 | - @Value("${kafka.other:#{null}}") | 74 | + @Value("${queue.kafka.use_confluent_cloud:false}") |
75 | + private boolean useConfluent; | ||
76 | + | ||
77 | + @Value("${queue.kafka.confluent.ssl.algorithm}") | ||
78 | + private String sslAlgorithm; | ||
79 | + | ||
80 | + @Value("${queue.kafka.confluent.sasl.mechanism}") | ||
81 | + private String saslMechanism; | ||
82 | + | ||
83 | + @Value("${queue.kafka.confluent.sasl.config}") | ||
84 | + private String saslConfig; | ||
85 | + | ||
86 | + @Value("${queue.kafka.confluent.security.protocol}") | ||
87 | + private String securityProtocol; | ||
88 | + | ||
89 | + @Setter | ||
71 | private List<TbKafkaProperty> other; | 90 | private List<TbKafkaProperty> other; |
72 | 91 | ||
73 | public Properties toProps() { | 92 | public Properties toProps() { |
74 | Properties props = new Properties(); | 93 | Properties props = new Properties(); |
75 | props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); | 94 | props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, servers); |
76 | - props.put(ProducerConfig.ACKS_CONFIG, acks); | ||
77 | props.put(ProducerConfig.RETRIES_CONFIG, retries); | 95 | props.put(ProducerConfig.RETRIES_CONFIG, retries); |
78 | - props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize); | ||
79 | - props.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs); | ||
80 | - props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory); | ||
81 | - if(other != null){ | 96 | + |
97 | + if (useConfluent) { | ||
98 | + props.put("ssl.endpoint.identification.algorithm", sslAlgorithm); | ||
99 | + props.put("sasl.mechanism", saslMechanism); | ||
100 | + props.put("sasl.jaas.config", saslConfig); | ||
101 | + props.put(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG, securityProtocol); | ||
102 | + } else { | ||
103 | + props.put(ProducerConfig.ACKS_CONFIG, acks); | ||
104 | + props.put(ProducerConfig.BATCH_SIZE_CONFIG, batchSize); | ||
105 | + props.put(ProducerConfig.LINGER_MS_CONFIG, lingerMs); | ||
106 | + props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, bufferMemory); | ||
107 | + } | ||
108 | + | ||
109 | + if (other != null) { | ||
82 | other.forEach(kv -> props.put(kv.getKey(), kv.getValue())); | 110 | other.forEach(kv -> props.put(kv.getKey(), kv.getValue())); |
83 | } | 111 | } |
84 | return props; | 112 | return props; |
@@ -24,7 +24,6 @@ import java.util.List; | @@ -24,7 +24,6 @@ import java.util.List; | ||
24 | import java.util.concurrent.BlockingQueue; | 24 | import java.util.concurrent.BlockingQueue; |
25 | import java.util.concurrent.ConcurrentHashMap; | 25 | import java.util.concurrent.ConcurrentHashMap; |
26 | import java.util.concurrent.LinkedBlockingQueue; | 26 | import java.util.concurrent.LinkedBlockingQueue; |
27 | -import java.util.concurrent.TimeUnit; | ||
28 | 27 | ||
29 | @Slf4j | 28 | @Slf4j |
30 | public final class InMemoryStorage { | 29 | public final class InMemoryStorage { |
@@ -35,6 +34,14 @@ public final class InMemoryStorage { | @@ -35,6 +34,14 @@ public final class InMemoryStorage { | ||
35 | storage = new ConcurrentHashMap<>(); | 34 | storage = new ConcurrentHashMap<>(); |
36 | } | 35 | } |
37 | 36 | ||
37 | + public void printStats() { | ||
38 | + storage.forEach((topic, queue) -> { | ||
39 | + if (queue.size() > 0) { | ||
40 | + log.debug("[{}] Queue Size [{}]", topic, queue.size()); | ||
41 | + } | ||
42 | + }); | ||
43 | + } | ||
44 | + | ||
38 | public static InMemoryStorage getInstance() { | 45 | public static InMemoryStorage getInstance() { |
39 | if (instance == null) { | 46 | if (instance == null) { |
40 | synchronized (InMemoryStorage.class) { | 47 | synchronized (InMemoryStorage.class) { |
@@ -17,6 +17,7 @@ package org.thingsboard.server.queue.provider; | @@ -17,6 +17,7 @@ package org.thingsboard.server.queue.provider; | ||
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; | 19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; |
20 | +import org.springframework.scheduling.annotation.Scheduled; | ||
20 | import org.springframework.stereotype.Component; | 21 | import org.springframework.stereotype.Component; |
21 | import org.thingsboard.server.common.msg.queue.ServiceType; | 22 | import org.thingsboard.server.common.msg.queue.ServiceType; |
22 | import org.thingsboard.server.gen.js.JsInvokeProtos; | 23 | import org.thingsboard.server.gen.js.JsInvokeProtos; |
@@ -28,6 +29,7 @@ import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; | @@ -28,6 +29,7 @@ import org.thingsboard.server.queue.common.TbProtoJsQueueMsg; | ||
28 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; | 29 | import org.thingsboard.server.queue.common.TbProtoQueueMsg; |
29 | import org.thingsboard.server.queue.discovery.PartitionService; | 30 | import org.thingsboard.server.queue.discovery.PartitionService; |
30 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; | 31 | import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; |
32 | +import org.thingsboard.server.queue.memory.InMemoryStorage; | ||
31 | import org.thingsboard.server.queue.memory.InMemoryTbQueueConsumer; | 33 | import org.thingsboard.server.queue.memory.InMemoryTbQueueConsumer; |
32 | import org.thingsboard.server.queue.memory.InMemoryTbQueueProducer; | 34 | import org.thingsboard.server.queue.memory.InMemoryTbQueueProducer; |
33 | import org.thingsboard.server.queue.settings.TbQueueCoreSettings; | 35 | import org.thingsboard.server.queue.settings.TbQueueCoreSettings; |
@@ -47,6 +49,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | @@ -47,6 +49,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | ||
47 | private final TbQueueRuleEngineSettings ruleEngineSettings; | 49 | private final TbQueueRuleEngineSettings ruleEngineSettings; |
48 | private final TbQueueTransportApiSettings transportApiSettings; | 50 | private final TbQueueTransportApiSettings transportApiSettings; |
49 | private final TbQueueTransportNotificationSettings transportNotificationSettings; | 51 | private final TbQueueTransportNotificationSettings transportNotificationSettings; |
52 | + private final InMemoryStorage storage; | ||
50 | 53 | ||
51 | public InMemoryMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, | 54 | public InMemoryMonolithQueueFactory(PartitionService partitionService, TbQueueCoreSettings coreSettings, |
52 | TbQueueRuleEngineSettings ruleEngineSettings, | 55 | TbQueueRuleEngineSettings ruleEngineSettings, |
@@ -59,6 +62,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | @@ -59,6 +62,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | ||
59 | this.ruleEngineSettings = ruleEngineSettings; | 62 | this.ruleEngineSettings = ruleEngineSettings; |
60 | this.transportApiSettings = transportApiSettings; | 63 | this.transportApiSettings = transportApiSettings; |
61 | this.transportNotificationSettings = transportNotificationSettings; | 64 | this.transportNotificationSettings = transportNotificationSettings; |
65 | + this.storage = InMemoryStorage.getInstance(); | ||
62 | } | 66 | } |
63 | 67 | ||
64 | @Override | 68 | @Override |
@@ -120,4 +124,9 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | @@ -120,4 +124,9 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE | ||
120 | public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { | 124 | public TbQueueRequestTemplate<TbProtoJsQueueMsg<JsInvokeProtos.RemoteJsRequest>, TbProtoQueueMsg<JsInvokeProtos.RemoteJsResponse>> createRemoteJsRequestTemplate() { |
121 | return null; | 125 | return null; |
122 | } | 126 | } |
127 | + | ||
128 | + @Scheduled(fixedRateString = "${queue.in_memory.stats.print-interval-ms:60000}") | ||
129 | + private void printInMemoryStats() { | ||
130 | + storage.printStats(); | ||
131 | + } | ||
123 | } | 132 | } |
@@ -16,8 +16,10 @@ | @@ -16,8 +16,10 @@ | ||
16 | package org.thingsboard.server.queue.sqs; | 16 | package org.thingsboard.server.queue.sqs; |
17 | 17 | ||
18 | import com.amazonaws.auth.AWSCredentials; | 18 | import com.amazonaws.auth.AWSCredentials; |
19 | +import com.amazonaws.auth.AWSCredentialsProvider; | ||
19 | import com.amazonaws.auth.AWSStaticCredentialsProvider; | 20 | import com.amazonaws.auth.AWSStaticCredentialsProvider; |
20 | import com.amazonaws.auth.BasicAWSCredentials; | 21 | import com.amazonaws.auth.BasicAWSCredentials; |
22 | +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; | ||
21 | import com.amazonaws.services.sqs.AmazonSQS; | 23 | import com.amazonaws.services.sqs.AmazonSQS; |
22 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; | 24 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; |
23 | import com.amazonaws.services.sqs.model.CreateQueueRequest; | 25 | import com.amazonaws.services.sqs.model.CreateQueueRequest; |
@@ -37,9 +39,16 @@ public class TbAwsSqsAdmin implements TbQueueAdmin { | @@ -37,9 +39,16 @@ public class TbAwsSqsAdmin implements TbQueueAdmin { | ||
37 | public TbAwsSqsAdmin(TbAwsSqsSettings sqsSettings, Map<String, String> attributes) { | 39 | public TbAwsSqsAdmin(TbAwsSqsSettings sqsSettings, Map<String, String> attributes) { |
38 | this.attributes = attributes; | 40 | this.attributes = attributes; |
39 | 41 | ||
40 | - AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | 42 | + AWSCredentialsProvider credentialsProvider; |
43 | + if (sqsSettings.getUseDefaultCredentialProviderChain()) { | ||
44 | + credentialsProvider = new DefaultAWSCredentialsProviderChain(); | ||
45 | + } else { | ||
46 | + AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | ||
47 | + credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); | ||
48 | + } | ||
49 | + | ||
41 | sqsClient = AmazonSQSClientBuilder.standard() | 50 | sqsClient = AmazonSQSClientBuilder.standard() |
42 | - .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) | 51 | + .withCredentials(credentialsProvider) |
43 | .withRegion(sqsSettings.getRegion()) | 52 | .withRegion(sqsSettings.getRegion()) |
44 | .build(); | 53 | .build(); |
45 | 54 |
@@ -16,8 +16,10 @@ | @@ -16,8 +16,10 @@ | ||
16 | package org.thingsboard.server.queue.sqs; | 16 | package org.thingsboard.server.queue.sqs; |
17 | 17 | ||
18 | import com.amazonaws.auth.AWSCredentials; | 18 | import com.amazonaws.auth.AWSCredentials; |
19 | +import com.amazonaws.auth.AWSCredentialsProvider; | ||
19 | import com.amazonaws.auth.AWSStaticCredentialsProvider; | 20 | import com.amazonaws.auth.AWSStaticCredentialsProvider; |
20 | import com.amazonaws.auth.BasicAWSCredentials; | 21 | import com.amazonaws.auth.BasicAWSCredentials; |
22 | +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; | ||
21 | import com.amazonaws.services.sqs.AmazonSQS; | 23 | import com.amazonaws.services.sqs.AmazonSQS; |
22 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; | 24 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; |
23 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequestEntry; | 25 | import com.amazonaws.services.sqs.model.DeleteMessageBatchRequestEntry; |
@@ -67,13 +69,19 @@ public class TbAwsSqsConsumerTemplate<T extends TbQueueMsg> extends AbstractPara | @@ -67,13 +69,19 @@ public class TbAwsSqsConsumerTemplate<T extends TbQueueMsg> extends AbstractPara | ||
67 | this.decoder = decoder; | 69 | this.decoder = decoder; |
68 | this.sqsSettings = sqsSettings; | 70 | this.sqsSettings = sqsSettings; |
69 | 71 | ||
70 | - AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | ||
71 | - AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials); | 72 | + AWSCredentialsProvider credentialsProvider; |
73 | + if (sqsSettings.getUseDefaultCredentialProviderChain()) { | ||
74 | + credentialsProvider = new DefaultAWSCredentialsProviderChain(); | ||
75 | + } else { | ||
76 | + AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | ||
77 | + credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); | ||
78 | + } | ||
72 | 79 | ||
73 | - this.sqsClient = AmazonSQSClientBuilder.standard() | ||
74 | - .withCredentials(credProvider) | 80 | + sqsClient = AmazonSQSClientBuilder.standard() |
81 | + .withCredentials(credentialsProvider) | ||
75 | .withRegion(sqsSettings.getRegion()) | 82 | .withRegion(sqsSettings.getRegion()) |
76 | .build(); | 83 | .build(); |
84 | + | ||
77 | } | 85 | } |
78 | 86 | ||
79 | @Override | 87 | @Override |
@@ -16,8 +16,10 @@ | @@ -16,8 +16,10 @@ | ||
16 | package org.thingsboard.server.queue.sqs; | 16 | package org.thingsboard.server.queue.sqs; |
17 | 17 | ||
18 | import com.amazonaws.auth.AWSCredentials; | 18 | import com.amazonaws.auth.AWSCredentials; |
19 | +import com.amazonaws.auth.AWSCredentialsProvider; | ||
19 | import com.amazonaws.auth.AWSStaticCredentialsProvider; | 20 | import com.amazonaws.auth.AWSStaticCredentialsProvider; |
20 | import com.amazonaws.auth.BasicAWSCredentials; | 21 | import com.amazonaws.auth.BasicAWSCredentials; |
22 | +import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; | ||
21 | import com.amazonaws.services.sqs.AmazonSQS; | 23 | import com.amazonaws.services.sqs.AmazonSQS; |
22 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; | 24 | import com.amazonaws.services.sqs.AmazonSQSClientBuilder; |
23 | import com.amazonaws.services.sqs.model.SendMessageRequest; | 25 | import com.amazonaws.services.sqs.model.SendMessageRequest; |
@@ -54,14 +56,18 @@ public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueuePr | @@ -54,14 +56,18 @@ public class TbAwsSqsProducerTemplate<T extends TbQueueMsg> implements TbQueuePr | ||
54 | this.admin = admin; | 56 | this.admin = admin; |
55 | this.defaultTopic = defaultTopic; | 57 | this.defaultTopic = defaultTopic; |
56 | 58 | ||
57 | - AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | ||
58 | - AWSStaticCredentialsProvider credProvider = new AWSStaticCredentialsProvider(awsCredentials); | 59 | + AWSCredentialsProvider credentialsProvider; |
60 | + if (sqsSettings.getUseDefaultCredentialProviderChain()) { | ||
61 | + credentialsProvider = new DefaultAWSCredentialsProviderChain(); | ||
62 | + } else { | ||
63 | + AWSCredentials awsCredentials = new BasicAWSCredentials(sqsSettings.getAccessKeyId(), sqsSettings.getSecretAccessKey()); | ||
64 | + credentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); | ||
65 | + } | ||
59 | 66 | ||
60 | - this.sqsClient = AmazonSQSClientBuilder.standard() | ||
61 | - .withCredentials(credProvider) | 67 | + sqsClient = AmazonSQSClientBuilder.standard() |
68 | + .withCredentials(credentialsProvider) | ||
62 | .withRegion(sqsSettings.getRegion()) | 69 | .withRegion(sqsSettings.getRegion()) |
63 | .build(); | 70 | .build(); |
64 | - | ||
65 | producerExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); | 71 | producerExecutor = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool()); |
66 | } | 72 | } |
67 | 73 |
@@ -27,6 +27,9 @@ import org.springframework.stereotype.Component; | @@ -27,6 +27,9 @@ import org.springframework.stereotype.Component; | ||
27 | @Data | 27 | @Data |
28 | public class TbAwsSqsSettings { | 28 | public class TbAwsSqsSettings { |
29 | 29 | ||
30 | + @Value("${queue.aws_sqs.use_default_credential_provider_chain}") | ||
31 | + private Boolean useDefaultCredentialProviderChain; | ||
32 | + | ||
30 | @Value("${queue.aws_sqs.access_key_id}") | 33 | @Value("${queue.aws_sqs.access_key_id}") |
31 | private String accessKeyId; | 34 | private String accessKeyId; |
32 | 35 |
@@ -127,7 +127,6 @@ message GetAttributeResponseMsg { | @@ -127,7 +127,6 @@ message GetAttributeResponseMsg { | ||
127 | int32 requestId = 1; | 127 | int32 requestId = 1; |
128 | repeated TsKvProto clientAttributeList = 2; | 128 | repeated TsKvProto clientAttributeList = 2; |
129 | repeated TsKvProto sharedAttributeList = 3; | 129 | repeated TsKvProto sharedAttributeList = 3; |
130 | - repeated string deletedAttributeKeys = 4; | ||
131 | string error = 5; | 130 | string error = 5; |
132 | } | 131 | } |
133 | 132 |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | <modelVersion>4.0.0</modelVersion> | 22 | <modelVersion>4.0.0</modelVersion> |
23 | <parent> | 23 | <parent> |
24 | <groupId>org.thingsboard</groupId> | 24 | <groupId>org.thingsboard</groupId> |
25 | - <version>2.5.3-SNAPSHOT</version> | 25 | + <version>2.5.5-SNAPSHOT</version> |
26 | <artifactId>common</artifactId> | 26 | <artifactId>common</artifactId> |
27 | </parent> | 27 | </parent> |
28 | <groupId>org.thingsboard.common</groupId> | 28 | <groupId>org.thingsboard.common</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.common</groupId> | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common.transport</groupId> | 26 | <groupId>org.thingsboard.common.transport</groupId> |
@@ -125,7 +125,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { | @@ -125,7 +125,7 @@ public class JsonCoapAdaptor implements CoapTransportAdaptor { | ||
125 | 125 | ||
126 | @Override | 126 | @Override |
127 | public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { | 127 | public Response convertToPublish(CoapTransportResource.CoapSessionListener session, TransportProtos.GetAttributeResponseMsg msg) throws AdaptorException { |
128 | - if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0 && msg.getDeletedAttributeKeysCount() == 0) { | 128 | + if (msg.getClientAttributeListCount() == 0 && msg.getSharedAttributeListCount() == 0) { |
129 | return new Response(CoAP.ResponseCode.NOT_FOUND); | 129 | return new Response(CoAP.ResponseCode.NOT_FOUND); |
130 | } else { | 130 | } else { |
131 | Response response = new Response(CoAP.ResponseCode.CONTENT); | 131 | Response response = new Response(CoAP.ResponseCode.CONTENT); |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.common</groupId> | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common.transport</groupId> | 26 | <groupId>org.thingsboard.common.transport</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.common</groupId> | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common.transport</groupId> | 26 | <groupId>org.thingsboard.common.transport</groupId> |
@@ -53,7 +53,7 @@ import java.util.concurrent.TimeUnit; | @@ -53,7 +53,7 @@ import java.util.concurrent.TimeUnit; | ||
53 | */ | 53 | */ |
54 | @Slf4j | 54 | @Slf4j |
55 | @Component("MqttSslHandlerProvider") | 55 | @Component("MqttSslHandlerProvider") |
56 | -@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.http.enabled}'=='true')") | 56 | +@ConditionalOnExpression("'${transport.type:null}'=='null' || ('${transport.type}'=='local' && '${transport.mqtt.enabled}'=='true')") |
57 | @ConditionalOnProperty(prefix = "transport.mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false) | 57 | @ConditionalOnProperty(prefix = "transport.mqtt.ssl", value = "enabled", havingValue = "true", matchIfMissing = false) |
58 | public class MqttSslHandlerProvider { | 58 | public class MqttSslHandlerProvider { |
59 | 59 |
@@ -207,6 +207,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | @@ -207,6 +207,7 @@ public class JsonMqttAdaptor implements MqttTransportAdaptor { | ||
207 | try { | 207 | try { |
208 | return new JsonParser().parse(payload); | 208 | return new JsonParser().parse(payload); |
209 | } catch (JsonSyntaxException ex) { | 209 | } catch (JsonSyntaxException ex) { |
210 | + log.warn("Payload is in incorrect format: {}", payload); | ||
210 | throw new AdaptorException(ex); | 211 | throw new AdaptorException(ex); |
211 | } | 212 | } |
212 | } | 213 | } |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.common</groupId> | 22 | <groupId>org.thingsboard.common</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common.transport</groupId> | 26 | <groupId>org.thingsboard.common.transport</groupId> |
@@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry; | @@ -35,7 +35,6 @@ import org.thingsboard.server.common.data.kv.JsonDataEntry; | ||
35 | import org.thingsboard.server.common.data.kv.KvEntry; | 35 | import org.thingsboard.server.common.data.kv.KvEntry; |
36 | import org.thingsboard.server.common.data.kv.LongDataEntry; | 36 | import org.thingsboard.server.common.data.kv.LongDataEntry; |
37 | import org.thingsboard.server.common.data.kv.StringDataEntry; | 37 | import org.thingsboard.server.common.data.kv.StringDataEntry; |
38 | -import org.thingsboard.server.common.msg.kv.AttributesKVMsg; | ||
39 | import org.thingsboard.server.gen.transport.TransportProtos; | 38 | import org.thingsboard.server.gen.transport.TransportProtos; |
40 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; | 39 | import org.thingsboard.server.gen.transport.TransportProtos.AttributeUpdateNotificationMsg; |
41 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; | 40 | import org.thingsboard.server.gen.transport.TransportProtos.ClaimDeviceMsg; |
@@ -273,11 +272,6 @@ public class JsonConverter { | @@ -273,11 +272,6 @@ public class JsonConverter { | ||
273 | payload.getSharedAttributeListList().forEach(addToObjectFromProto(attrObject)); | 272 | payload.getSharedAttributeListList().forEach(addToObjectFromProto(attrObject)); |
274 | result.add("shared", attrObject); | 273 | result.add("shared", attrObject); |
275 | } | 274 | } |
276 | - if (payload.getDeletedAttributeKeysCount() > 0) { | ||
277 | - JsonArray attrObject = new JsonArray(); | ||
278 | - payload.getDeletedAttributeKeysList().forEach(attrObject::add); | ||
279 | - result.add("deleted", attrObject); | ||
280 | - } | ||
281 | return result; | 275 | return result; |
282 | } | 276 | } |
283 | 277 | ||
@@ -294,31 +288,6 @@ public class JsonConverter { | @@ -294,31 +288,6 @@ public class JsonConverter { | ||
294 | return result; | 288 | return result; |
295 | } | 289 | } |
296 | 290 | ||
297 | - public static JsonObject toJson(AttributesKVMsg payload, boolean asMap) { | ||
298 | - JsonObject result = new JsonObject(); | ||
299 | - if (asMap) { | ||
300 | - if (!payload.getClientAttributes().isEmpty()) { | ||
301 | - JsonObject attrObject = new JsonObject(); | ||
302 | - payload.getClientAttributes().forEach(addToObject(attrObject)); | ||
303 | - result.add("client", attrObject); | ||
304 | - } | ||
305 | - if (!payload.getSharedAttributes().isEmpty()) { | ||
306 | - JsonObject attrObject = new JsonObject(); | ||
307 | - payload.getSharedAttributes().forEach(addToObject(attrObject)); | ||
308 | - result.add("shared", attrObject); | ||
309 | - } | ||
310 | - } else { | ||
311 | - payload.getClientAttributes().forEach(addToObject(result)); | ||
312 | - payload.getSharedAttributes().forEach(addToObject(result)); | ||
313 | - } | ||
314 | - if (!payload.getDeletedAttributes().isEmpty()) { | ||
315 | - JsonArray attrObject = new JsonArray(); | ||
316 | - payload.getDeletedAttributes().forEach(addToObject(attrObject)); | ||
317 | - result.add("deleted", attrObject); | ||
318 | - } | ||
319 | - return result; | ||
320 | - } | ||
321 | - | ||
322 | public static JsonObject getJsonObjectForGateway(String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) { | 291 | public static JsonObject getJsonObjectForGateway(String deviceName, TransportProtos.GetAttributeResponseMsg responseMsg) { |
323 | JsonObject result = new JsonObject(); | 292 | JsonObject result = new JsonObject(); |
324 | result.addProperty("id", responseMsg.getRequestId()); | 293 | result.addProperty("id", responseMsg.getRequestId()); |
@@ -374,10 +343,6 @@ public class JsonConverter { | @@ -374,10 +343,6 @@ public class JsonConverter { | ||
374 | } | 343 | } |
375 | } | 344 | } |
376 | 345 | ||
377 | - private static Consumer<AttributeKey> addToObject(JsonArray result) { | ||
378 | - return key -> result.add(key.getAttributeKey()); | ||
379 | - } | ||
380 | - | ||
381 | private static Consumer<TsKvProto> addToObjectFromProto(JsonObject result) { | 346 | private static Consumer<TsKvProto> addToObjectFromProto(JsonObject result) { |
382 | return de -> { | 347 | return de -> { |
383 | switch (de.getKv().getType()) { | 348 | switch (de.getKv().getType()) { |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>common</artifactId> | 24 | <artifactId>common</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.common</groupId> | 26 | <groupId>org.thingsboard.common</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>dao</artifactId> | 26 | <artifactId>dao</artifactId> |
@@ -166,7 +166,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | @@ -166,7 +166,7 @@ public class BaseAssetService extends AbstractEntityService implements AssetServ | ||
166 | try { | 166 | try { |
167 | List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get(); | 167 | List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(asset.getTenantId(), assetId).get(); |
168 | if (entityViews != null && !entityViews.isEmpty()) { | 168 | if (entityViews != null && !entityViews.isEmpty()) { |
169 | - throw new DataValidationException("Can't delete asset that is assigned to entity views!"); | 169 | + throw new DataValidationException("Can't delete asset that has entity views!"); |
170 | } | 170 | } |
171 | } catch (ExecutionException | InterruptedException e) { | 171 | } catch (ExecutionException | InterruptedException e) { |
172 | log.error("Exception while finding entity views for assetId [{}]", assetId, e); | 172 | log.error("Exception while finding entity views for assetId [{}]", assetId, e); |
@@ -22,11 +22,12 @@ import org.thingsboard.server.common.data.id.CustomerId; | @@ -22,11 +22,12 @@ import org.thingsboard.server.common.data.id.CustomerId; | ||
22 | import org.thingsboard.server.common.data.id.EntityId; | 22 | import org.thingsboard.server.common.data.id.EntityId; |
23 | import org.thingsboard.server.common.data.id.UserId; | 23 | import org.thingsboard.server.common.data.id.UserId; |
24 | import org.thingsboard.server.common.data.page.TimePageLink; | 24 | import org.thingsboard.server.common.data.page.TimePageLink; |
25 | +import org.thingsboard.server.dao.Dao; | ||
25 | 26 | ||
26 | import java.util.List; | 27 | import java.util.List; |
27 | import java.util.UUID; | 28 | import java.util.UUID; |
28 | 29 | ||
29 | -public interface AuditLogDao { | 30 | +public interface AuditLogDao extends Dao<AuditLog> { |
30 | 31 | ||
31 | ListenableFuture<Void> saveByTenantId(AuditLog auditLog); | 32 | ListenableFuture<Void> saveByTenantId(AuditLog auditLog); |
32 | 33 |
@@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; | @@ -28,7 +28,6 @@ import org.springframework.beans.factory.annotation.Autowired; | ||
28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 28 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
29 | import org.springframework.stereotype.Service; | 29 | import org.springframework.stereotype.Service; |
30 | import org.springframework.util.StringUtils; | 30 | import org.springframework.util.StringUtils; |
31 | -import org.thingsboard.server.common.data.BaseData; | ||
32 | import org.thingsboard.server.common.data.EntityType; | 31 | import org.thingsboard.server.common.data.EntityType; |
33 | import org.thingsboard.server.common.data.HasName; | 32 | import org.thingsboard.server.common.data.HasName; |
34 | import org.thingsboard.server.common.data.audit.ActionStatus; | 33 | import org.thingsboard.server.common.data.audit.ActionStatus; |
@@ -38,7 +37,6 @@ import org.thingsboard.server.common.data.id.AuditLogId; | @@ -38,7 +37,6 @@ import org.thingsboard.server.common.data.id.AuditLogId; | ||
38 | import org.thingsboard.server.common.data.id.CustomerId; | 37 | import org.thingsboard.server.common.data.id.CustomerId; |
39 | import org.thingsboard.server.common.data.id.EntityId; | 38 | import org.thingsboard.server.common.data.id.EntityId; |
40 | import org.thingsboard.server.common.data.id.TenantId; | 39 | import org.thingsboard.server.common.data.id.TenantId; |
41 | -import org.thingsboard.server.common.data.id.UUIDBased; | ||
42 | import org.thingsboard.server.common.data.id.UserId; | 40 | import org.thingsboard.server.common.data.id.UserId; |
43 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 41 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
44 | import org.thingsboard.server.common.data.page.TimePageData; | 42 | import org.thingsboard.server.common.data.page.TimePageData; |
@@ -117,8 +115,8 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -117,8 +115,8 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
117 | 115 | ||
118 | @Override | 116 | @Override |
119 | public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> | 117 | public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> |
120 | - logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, | ||
121 | - ActionType actionType, Exception e, Object... additionalInfo) { | 118 | + logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, |
119 | + ActionType actionType, Exception e, Object... additionalInfo) { | ||
122 | if (canLog(entityId.getEntityType(), actionType)) { | 120 | if (canLog(entityId.getEntityType(), actionType)) { |
123 | JsonNode actionData = constructActionData(entityId, entity, actionType, additionalInfo); | 121 | JsonNode actionData = constructActionData(entityId, entity, actionType, additionalInfo); |
124 | ActionStatus actionStatus = ActionStatus.SUCCESS; | 122 | ActionStatus actionStatus = ActionStatus.SUCCESS; |
@@ -129,7 +127,8 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -129,7 +127,8 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
129 | } else { | 127 | } else { |
130 | try { | 128 | try { |
131 | entityName = entityService.fetchEntityNameAsync(tenantId, entityId).get(); | 129 | entityName = entityService.fetchEntityNameAsync(tenantId, entityId).get(); |
132 | - } catch (Exception ex) {} | 130 | + } catch (Exception ex) { |
131 | + } | ||
133 | } | 132 | } |
134 | if (e != null) { | 133 | if (e != null) { |
135 | actionStatus = ActionStatus.FAILURE; | 134 | actionStatus = ActionStatus.FAILURE; |
@@ -158,15 +157,16 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -158,15 +157,16 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
158 | } | 157 | } |
159 | 158 | ||
160 | private <E extends HasName, I extends EntityId> JsonNode constructActionData(I entityId, E entity, | 159 | private <E extends HasName, I extends EntityId> JsonNode constructActionData(I entityId, E entity, |
161 | - ActionType actionType, | ||
162 | - Object... additionalInfo) { | 160 | + ActionType actionType, |
161 | + Object... additionalInfo) { | ||
163 | ObjectNode actionData = objectMapper.createObjectNode(); | 162 | ObjectNode actionData = objectMapper.createObjectNode(); |
164 | - switch(actionType) { | 163 | + switch (actionType) { |
165 | case ADDED: | 164 | case ADDED: |
166 | case UPDATED: | 165 | case UPDATED: |
167 | case ALARM_ACK: | 166 | case ALARM_ACK: |
168 | case ALARM_CLEAR: | 167 | case ALARM_CLEAR: |
169 | case RELATIONS_DELETED: | 168 | case RELATIONS_DELETED: |
169 | + case ASSIGNED_TO_TENANT: | ||
170 | if (entity != null) { | 170 | if (entity != null) { |
171 | ObjectNode entityNode = objectMapper.valueToTree(entity); | 171 | ObjectNode entityNode = objectMapper.valueToTree(entity); |
172 | if (entityId.getEntityType() == EntityType.DASHBOARD) { | 172 | if (entityId.getEntityType() == EntityType.DASHBOARD) { |
@@ -208,7 +208,7 @@ public class AuditLogServiceImpl implements AuditLogService { | @@ -208,7 +208,7 @@ public class AuditLogServiceImpl implements AuditLogService { | ||
208 | scope = extractParameter(String.class, 0, additionalInfo); | 208 | scope = extractParameter(String.class, 0, additionalInfo); |
209 | actionData.put("scope", scope); | 209 | actionData.put("scope", scope); |
210 | List<String> keys = extractParameter(List.class, 1, additionalInfo); | 210 | List<String> keys = extractParameter(List.class, 1, additionalInfo); |
211 | - ArrayNode attrsArrayNode = actionData.putArray("attributes"); | 211 | + ArrayNode attrsArrayNode = actionData.putArray("attributes"); |
212 | if (keys != null) { | 212 | if (keys != null) { |
213 | keys.forEach(attrsArrayNode::add); | 213 | keys.forEach(attrsArrayNode::add); |
214 | } | 214 | } |
@@ -18,14 +18,12 @@ package org.thingsboard.server.dao.audit; | @@ -18,14 +18,12 @@ package org.thingsboard.server.dao.audit; | ||
18 | import com.google.common.util.concurrent.ListenableFuture; | 18 | import com.google.common.util.concurrent.ListenableFuture; |
19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; | 19 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
20 | import org.springframework.stereotype.Service; | 20 | import org.springframework.stereotype.Service; |
21 | -import org.thingsboard.server.common.data.BaseData; | ||
22 | import org.thingsboard.server.common.data.HasName; | 21 | import org.thingsboard.server.common.data.HasName; |
23 | import org.thingsboard.server.common.data.audit.ActionType; | 22 | import org.thingsboard.server.common.data.audit.ActionType; |
24 | import org.thingsboard.server.common.data.audit.AuditLog; | 23 | import org.thingsboard.server.common.data.audit.AuditLog; |
25 | import org.thingsboard.server.common.data.id.CustomerId; | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
26 | import org.thingsboard.server.common.data.id.EntityId; | 25 | import org.thingsboard.server.common.data.id.EntityId; |
27 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
28 | -import org.thingsboard.server.common.data.id.UUIDBased; | ||
29 | import org.thingsboard.server.common.data.id.UserId; | 27 | import org.thingsboard.server.common.data.id.UserId; |
30 | import org.thingsboard.server.common.data.page.TimePageData; | 28 | import org.thingsboard.server.common.data.page.TimePageData; |
31 | import org.thingsboard.server.common.data.page.TimePageLink; | 29 | import org.thingsboard.server.common.data.page.TimePageLink; |
@@ -60,5 +58,4 @@ public class DummyAuditLogServiceImpl implements AuditLogService { | @@ -60,5 +58,4 @@ public class DummyAuditLogServiceImpl implements AuditLogService { | ||
60 | public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { | 58 | public <E extends HasName, I extends EntityId> ListenableFuture<List<Void>> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { |
61 | return null; | 59 | return null; |
62 | } | 60 | } |
63 | - | ||
64 | } | 61 | } |
@@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | @@ -38,6 +38,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation; | ||
38 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; | 38 | import org.thingsboard.server.common.data.relation.RelationTypeGroup; |
39 | import org.thingsboard.server.dao.DaoUtil; | 39 | import org.thingsboard.server.dao.DaoUtil; |
40 | import org.thingsboard.server.dao.model.EntitySubtypeEntity; | 40 | import org.thingsboard.server.dao.model.EntitySubtypeEntity; |
41 | +import org.thingsboard.server.dao.model.ModelConstants; | ||
41 | import org.thingsboard.server.dao.model.nosql.DeviceEntity; | 42 | import org.thingsboard.server.dao.model.nosql.DeviceEntity; |
42 | import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; | 43 | import org.thingsboard.server.dao.nosql.CassandraAbstractSearchTextDao; |
43 | import org.thingsboard.server.dao.relation.RelationDao; | 44 | import org.thingsboard.server.dao.relation.RelationDao; |
@@ -199,6 +200,21 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt | @@ -199,6 +200,21 @@ public class CassandraDeviceDao extends CassandraAbstractSearchTextDao<DeviceEnt | ||
199 | } | 200 | } |
200 | 201 | ||
201 | @Override | 202 | @Override |
203 | + public Device findDeviceByTenantIdAndId(TenantId tenantId, UUID id) { | ||
204 | + Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.TENANT_ID_PROPERTY, tenantId.getId())).and(eq(ModelConstants.ID_PROPERTY, id)); | ||
205 | + log.trace("Execute query {}", query); | ||
206 | + DeviceEntity entity = findOneByStatement(tenantId, query); | ||
207 | + return DaoUtil.getData(entity); | ||
208 | + } | ||
209 | + | ||
210 | + @Override | ||
211 | + public ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id) { | ||
212 | + Select.Where query = select().from(getColumnFamilyName()).where(eq(ModelConstants.TENANT_ID_PROPERTY, tenantId.getId())).and(eq(ModelConstants.ID_PROPERTY, id)); | ||
213 | + log.trace("Execute query {}", query); | ||
214 | + return findOneByStatementAsync(tenantId, query); | ||
215 | + } | ||
216 | + | ||
217 | + @Override | ||
202 | public ListenableFuture<List<Device>> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { | 218 | public ListenableFuture<List<Device>> findDevicesByTenantIdAndEdgeId(UUID tenantId, UUID edgeId, TimePageLink pageLink) { |
203 | log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); | 219 | log.debug("Try to find devices by tenantId [{}], edgeId [{}] and pageLink [{}]", tenantId, edgeId, pageLink); |
204 | ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink); | 220 | ListenableFuture<List<EntityRelation>> relations = relationDao.findRelations(new TenantId(tenantId), new EdgeId(edgeId), EntityRelation.CONTAINS_TYPE, RelationTypeGroup.EDGE, EntityType.DEVICE, pageLink); |
@@ -118,6 +118,23 @@ public interface DeviceDao extends Dao<Device> { | @@ -118,6 +118,23 @@ public interface DeviceDao extends Dao<Device> { | ||
118 | ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId); | 118 | ListenableFuture<List<EntitySubtype>> findTenantDeviceTypesAsync(UUID tenantId); |
119 | 119 | ||
120 | /** | 120 | /** |
121 | + * Find devices by tenantId and device id. | ||
122 | + * @param tenantId the tenant Id | ||
123 | + * @param id the device Id | ||
124 | + * @return the device object | ||
125 | + */ | ||
126 | + Device findDeviceByTenantIdAndId(TenantId tenantId, UUID id); | ||
127 | + | ||
128 | + /** | ||
129 | + * Find devices by tenantId and device id. | ||
130 | + * @param tenantId tenantId the tenantId | ||
131 | + * @param id the deviceId | ||
132 | + * @return the device object | ||
133 | + */ | ||
134 | + ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id); | ||
135 | + | ||
136 | + | ||
137 | + /** | ||
121 | * Find devices by tenantId, edgeId and page link. | 138 | * Find devices by tenantId, edgeId and page link. |
122 | * | 139 | * |
123 | * @param tenantId the tenantId | 140 | * @param tenantId the tenantId |
@@ -28,6 +28,8 @@ import org.springframework.cache.CacheManager; | @@ -28,6 +28,8 @@ import org.springframework.cache.CacheManager; | ||
28 | import org.springframework.cache.annotation.CacheEvict; | 28 | import org.springframework.cache.annotation.CacheEvict; |
29 | import org.springframework.cache.annotation.Cacheable; | 29 | import org.springframework.cache.annotation.Cacheable; |
30 | import org.springframework.stereotype.Service; | 30 | import org.springframework.stereotype.Service; |
31 | +import org.springframework.transaction.annotation.Transactional; | ||
32 | +import org.springframework.util.CollectionUtils; | ||
31 | import org.springframework.util.StringUtils; | 33 | import org.springframework.util.StringUtils; |
32 | import org.thingsboard.server.common.data.Customer; | 34 | import org.thingsboard.server.common.data.Customer; |
33 | import org.thingsboard.server.common.data.Device; | 35 | import org.thingsboard.server.common.data.Device; |
@@ -54,6 +56,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType; | @@ -54,6 +56,7 @@ import org.thingsboard.server.common.data.security.DeviceCredentialsType; | ||
54 | import org.thingsboard.server.dao.customer.CustomerDao; | 56 | import org.thingsboard.server.dao.customer.CustomerDao; |
55 | import org.thingsboard.server.dao.edge.EdgeService; | 57 | import org.thingsboard.server.dao.edge.EdgeService; |
56 | import org.thingsboard.server.dao.entity.AbstractEntityService; | 58 | import org.thingsboard.server.dao.entity.AbstractEntityService; |
59 | +import org.thingsboard.server.dao.event.EventService; | ||
57 | import org.thingsboard.server.dao.exception.DataValidationException; | 60 | import org.thingsboard.server.dao.exception.DataValidationException; |
58 | import org.thingsboard.server.dao.service.DataValidator; | 61 | import org.thingsboard.server.dao.service.DataValidator; |
59 | import org.thingsboard.server.dao.service.PaginatedRemover; | 62 | import org.thingsboard.server.dao.service.PaginatedRemover; |
@@ -104,18 +107,29 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -104,18 +107,29 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
104 | @Autowired | 107 | @Autowired |
105 | private CacheManager cacheManager; | 108 | private CacheManager cacheManager; |
106 | 109 | ||
110 | + @Autowired | ||
111 | + private EventService eventService; | ||
112 | + | ||
107 | @Override | 113 | @Override |
108 | public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { | 114 | public Device findDeviceById(TenantId tenantId, DeviceId deviceId) { |
109 | log.trace("Executing findDeviceById [{}]", deviceId); | 115 | log.trace("Executing findDeviceById [{}]", deviceId); |
110 | validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); | 116 | validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); |
111 | - return deviceDao.findById(tenantId, deviceId.getId()); | 117 | + if (TenantId.SYS_TENANT_ID.equals(tenantId)) { |
118 | + return deviceDao.findById(tenantId, deviceId.getId()); | ||
119 | + } else { | ||
120 | + return deviceDao.findDeviceByTenantIdAndId(tenantId, deviceId.getId()); | ||
121 | + } | ||
112 | } | 122 | } |
113 | 123 | ||
114 | @Override | 124 | @Override |
115 | public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) { | 125 | public ListenableFuture<Device> findDeviceByIdAsync(TenantId tenantId, DeviceId deviceId) { |
116 | log.trace("Executing findDeviceById [{}]", deviceId); | 126 | log.trace("Executing findDeviceById [{}]", deviceId); |
117 | validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); | 127 | validateId(deviceId, INCORRECT_DEVICE_ID + deviceId); |
118 | - return deviceDao.findByIdAsync(tenantId, deviceId.getId()); | 128 | + if (TenantId.SYS_TENANT_ID.equals(tenantId)) { |
129 | + return deviceDao.findByIdAsync(tenantId, deviceId.getId()); | ||
130 | + } else { | ||
131 | + return deviceDao.findDeviceByTenantIdAndIdAsync(tenantId, deviceId.getId()); | ||
132 | + } | ||
119 | } | 133 | } |
120 | 134 | ||
121 | @Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}") | 135 | @Cacheable(cacheNames = DEVICE_CACHE, key = "{#tenantId, #name}") |
@@ -190,7 +204,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -190,7 +204,7 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
190 | try { | 204 | try { |
191 | List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); | 205 | List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), deviceId).get(); |
192 | if (entityViews != null && !entityViews.isEmpty()) { | 206 | if (entityViews != null && !entityViews.isEmpty()) { |
193 | - throw new DataValidationException("Can't delete device that is assigned to entity views!"); | 207 | + throw new DataValidationException("Can't delete device that has entity views!"); |
194 | } | 208 | } |
195 | } catch (ExecutionException | InterruptedException e) { | 209 | } catch (ExecutionException | InterruptedException e) { |
196 | log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); | 210 | log.error("Exception while finding entity views for deviceId [{}]", deviceId, e); |
@@ -378,6 +392,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | @@ -378,6 +392,31 @@ public class DeviceServiceImpl extends AbstractEntityService implements DeviceSe | ||
378 | }, MoreExecutors.directExecutor()); | 392 | }, MoreExecutors.directExecutor()); |
379 | } | 393 | } |
380 | 394 | ||
395 | + @Transactional | ||
396 | + @CacheEvict(cacheNames = DEVICE_CACHE, key = "{#device.tenantId, #device.name}") | ||
397 | + @Override | ||
398 | + public Device assignDeviceToTenant(TenantId tenantId, Device device) { | ||
399 | + log.trace("Executing assignDeviceToTenant [{}][{}]", tenantId, device); | ||
400 | + | ||
401 | + try { | ||
402 | + List<EntityView> entityViews = entityViewService.findEntityViewsByTenantIdAndEntityIdAsync(device.getTenantId(), device.getId()).get(); | ||
403 | + if (!CollectionUtils.isEmpty(entityViews)) { | ||
404 | + throw new DataValidationException("Can't assign device that has entity views to another tenant!"); | ||
405 | + } | ||
406 | + } catch (ExecutionException | InterruptedException e) { | ||
407 | + log.error("Exception while finding entity views for deviceId [{}]", device.getId(), e); | ||
408 | + throw new RuntimeException("Exception while finding entity views for deviceId [" + device.getId() + "]", e); | ||
409 | + } | ||
410 | + | ||
411 | + eventService.removeEvents(device.getTenantId(), device.getId()); | ||
412 | + | ||
413 | + relationService.removeRelations(device.getTenantId(), device.getId()); | ||
414 | + | ||
415 | + device.setTenantId(tenantId); | ||
416 | + device.setCustomerId(null); | ||
417 | + return doSaveDevice(device, null); | ||
418 | + } | ||
419 | + | ||
381 | private DataValidator<Device> deviceValidator = | 420 | private DataValidator<Device> deviceValidator = |
382 | new DataValidator<Device>() { | 421 | new DataValidator<Device>() { |
383 | 422 |
@@ -94,6 +94,21 @@ public class BaseEventService implements EventService { | @@ -94,6 +94,21 @@ public class BaseEventService implements EventService { | ||
94 | return eventDao.findLatestEvents(tenantId.getId(), entityId, eventType, limit); | 94 | return eventDao.findLatestEvents(tenantId.getId(), entityId, eventType, limit); |
95 | } | 95 | } |
96 | 96 | ||
97 | + @Override | ||
98 | + public void removeEvents(TenantId tenantId, EntityId entityId) { | ||
99 | + TimePageData<Event> eventPageData; | ||
100 | + TimePageLink eventPageLink = new TimePageLink(1000); | ||
101 | + do { | ||
102 | + eventPageData = findEvents(tenantId, entityId, eventPageLink); | ||
103 | + for (Event event : eventPageData.getData()) { | ||
104 | + eventDao.removeById(tenantId, event.getUuidId()); | ||
105 | + } | ||
106 | + if (eventPageData.hasNext()) { | ||
107 | + eventPageLink = eventPageData.getNextPageLink(); | ||
108 | + } | ||
109 | + } while (eventPageData.hasNext()); | ||
110 | + } | ||
111 | + | ||
97 | private DataValidator<Event> eventValidator = | 112 | private DataValidator<Event> eventValidator = |
98 | new DataValidator<Event>() { | 113 | new DataValidator<Event>() { |
99 | @Override | 114 | @Override |
@@ -506,6 +506,22 @@ public class BaseRelationService implements RelationService { | @@ -506,6 +506,22 @@ public class BaseRelationService implements RelationService { | ||
506 | }, MoreExecutors.directExecutor()); | 506 | }, MoreExecutors.directExecutor()); |
507 | } | 507 | } |
508 | 508 | ||
509 | + @Override | ||
510 | + public void removeRelations(TenantId tenantId, EntityId entityId) { | ||
511 | + Cache cache = cacheManager.getCache(RELATIONS_CACHE); | ||
512 | + | ||
513 | + List<EntityRelation> relations = new ArrayList<>(); | ||
514 | + for (RelationTypeGroup relationTypeGroup : RelationTypeGroup.values()) { | ||
515 | + relations.addAll(findByFrom(tenantId, entityId, relationTypeGroup)); | ||
516 | + relations.addAll(findByTo(tenantId, entityId, relationTypeGroup)); | ||
517 | + } | ||
518 | + | ||
519 | + for (EntityRelation relation : relations) { | ||
520 | + cacheEviction(relation, cache); | ||
521 | + deleteRelation(tenantId, relation); | ||
522 | + } | ||
523 | + } | ||
524 | + | ||
509 | protected void validate(EntityRelation relation) { | 525 | protected void validate(EntityRelation relation) { |
510 | if (relation == null) { | 526 | if (relation == null) { |
511 | throw new DataValidationException("Relation type should be specified!"); | 527 | throw new DataValidationException("Relation type should be specified!"); |
@@ -15,6 +15,7 @@ | @@ -15,6 +15,7 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.dao.settings; | 16 | package org.thingsboard.server.dao.settings; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
18 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
19 | import org.apache.commons.lang3.StringUtils; | 20 | import org.apache.commons.lang3.StringUtils; |
20 | import org.springframework.beans.factory.annotation.Autowired; | 21 | import org.springframework.beans.factory.annotation.Autowired; |
@@ -52,6 +53,13 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { | @@ -52,6 +53,13 @@ public class AdminSettingsServiceImpl implements AdminSettingsService { | ||
52 | public AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings) { | 53 | public AdminSettings saveAdminSettings(TenantId tenantId, AdminSettings adminSettings) { |
53 | log.trace("Executing saveAdminSettings [{}]", adminSettings); | 54 | log.trace("Executing saveAdminSettings [{}]", adminSettings); |
54 | adminSettingsValidator.validate(adminSettings, data -> tenantId); | 55 | adminSettingsValidator.validate(adminSettings, data -> tenantId); |
56 | + if (adminSettings.getKey().equals("mail") && "".equals(adminSettings.getJsonValue().get("password").asText())) { | ||
57 | + AdminSettings mailSettings = findAdminSettingsByKey(tenantId, "mail"); | ||
58 | + if (mailSettings != null) { | ||
59 | + ((ObjectNode) adminSettings.getJsonValue()).put("password", mailSettings.getJsonValue().get("password").asText()); | ||
60 | + } | ||
61 | + } | ||
62 | + | ||
55 | return adminSettingsDao.save(tenantId, adminSettings); | 63 | return adminSettingsDao.save(tenantId, adminSettings); |
56 | } | 64 | } |
57 | 65 |
@@ -85,4 +85,7 @@ public interface DeviceRepository extends CrudRepository<DeviceEntity, String> { | @@ -85,4 +85,7 @@ public interface DeviceRepository extends CrudRepository<DeviceEntity, String> { | ||
85 | List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List<String> deviceIds); | 85 | List<DeviceEntity> findDevicesByTenantIdAndCustomerIdAndIdIn(String tenantId, String customerId, List<String> deviceIds); |
86 | 86 | ||
87 | List<DeviceEntity> findDevicesByTenantIdAndIdIn(String tenantId, List<String> deviceIds); | 87 | List<DeviceEntity> findDevicesByTenantIdAndIdIn(String tenantId, List<String> deviceIds); |
88 | + | ||
89 | + DeviceEntity findByTenantIdAndId(String tenantId, String id); | ||
90 | + | ||
88 | } | 91 | } |
@@ -151,6 +151,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | @@ -151,6 +151,16 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> | ||
151 | return service.submit(() -> convertTenantDeviceTypesToDto(tenantId, deviceRepository.findTenantDeviceTypes(fromTimeUUID(tenantId)))); | 151 | return service.submit(() -> convertTenantDeviceTypesToDto(tenantId, deviceRepository.findTenantDeviceTypes(fromTimeUUID(tenantId)))); |
152 | } | 152 | } |
153 | 153 | ||
154 | + @Override | ||
155 | + public Device findDeviceByTenantIdAndId(TenantId tenantId, UUID id) { | ||
156 | + return DaoUtil.getData(deviceRepository.findByTenantIdAndId(fromTimeUUID(tenantId.getId()), fromTimeUUID(id))); | ||
157 | + } | ||
158 | + | ||
159 | + @Override | ||
160 | + public ListenableFuture<Device> findDeviceByTenantIdAndIdAsync(TenantId tenantId, UUID id) { | ||
161 | + return service.submit(() -> DaoUtil.getData(deviceRepository.findByTenantIdAndId(fromTimeUUID(tenantId.getId()), fromTimeUUID(id)))); | ||
162 | + } | ||
163 | + | ||
154 | private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { | 164 | private List<EntitySubtype> convertTenantDeviceTypesToDto(UUID tenantId, List<String> types) { |
155 | List<EntitySubtype> list = Collections.emptyList(); | 165 | List<EntitySubtype> list = Collections.emptyList(); |
156 | if (types != null && !types.isEmpty()) { | 166 | if (types != null && !types.isEmpty()) { |
@@ -46,6 +46,7 @@ public class JpaHsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa | @@ -46,6 +46,7 @@ public class JpaHsqlTimeseriesDao extends AbstractChunkedAggregationTimeseriesDa | ||
46 | entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null)); | 46 | entity.setDoubleValue(tsKvEntry.getDoubleValue().orElse(null)); |
47 | entity.setLongValue(tsKvEntry.getLongValue().orElse(null)); | 47 | entity.setLongValue(tsKvEntry.getLongValue().orElse(null)); |
48 | entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null)); | 48 | entity.setBooleanValue(tsKvEntry.getBooleanValue().orElse(null)); |
49 | + entity.setJsonValue(tsKvEntry.getJsonValue().orElse(null)); | ||
49 | log.trace("Saving entity: {}", entity); | 50 | log.trace("Saving entity: {}", entity); |
50 | return tsQueue.add(entity); | 51 | return tsQueue.add(entity); |
51 | } | 52 | } |
@@ -41,8 +41,8 @@ public class HsqlLatestInsertTsRepository extends AbstractInsertRepository imple | @@ -41,8 +41,8 @@ public class HsqlLatestInsertTsRepository extends AbstractInsertRepository imple | ||
41 | "ON (ts_kv_latest.entity_id=T.entity_id " + | 41 | "ON (ts_kv_latest.entity_id=T.entity_id " + |
42 | "AND ts_kv_latest.key=T.key) " + | 42 | "AND ts_kv_latest.key=T.key) " + |
43 | "WHEN MATCHED THEN UPDATE SET ts_kv_latest.ts = T.ts, ts_kv_latest.bool_v = T.bool_v, ts_kv_latest.str_v = T.str_v, ts_kv_latest.long_v = T.long_v, ts_kv_latest.dbl_v = T.dbl_v, ts_kv_latest.json_v = T.json_v " + | 43 | "WHEN MATCHED THEN UPDATE SET ts_kv_latest.ts = T.ts, ts_kv_latest.bool_v = T.bool_v, ts_kv_latest.str_v = T.str_v, ts_kv_latest.long_v = T.long_v, ts_kv_latest.dbl_v = T.dbl_v, ts_kv_latest.json_v = T.json_v " + |
44 | - "WHEN NOT MATCHED THEN INSERT (entity_id, key, ts, bool_v, str_v, long_v, dbl_v) " + | ||
45 | - "VALUES (T.entity_id, T.key, T.ts, T.bool_v, T.str_v, T.long_v, T.dbl_v);"; | 44 | + "WHEN NOT MATCHED THEN INSERT (entity_id, key, ts, bool_v, str_v, long_v, dbl_v, json_v) " + |
45 | + "VALUES (T.entity_id, T.key, T.ts, T.bool_v, T.str_v, T.long_v, T.dbl_v, T.json_v);"; | ||
46 | 46 | ||
47 | @Override | 47 | @Override |
48 | public void saveOrUpdate(List<TsKvLatestEntity> entities) { | 48 | public void saveOrUpdate(List<TsKvLatestEntity> entities) { |
@@ -114,7 +114,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic | @@ -114,7 +114,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic | ||
114 | public User saveUser(User user) { | 114 | public User saveUser(User user) { |
115 | log.trace("Executing saveUser [{}]", user); | 115 | log.trace("Executing saveUser [{}]", user); |
116 | userValidator.validate(user, User::getTenantId); | 116 | userValidator.validate(user, User::getTenantId); |
117 | - if (user.getId() == null && !userLoginCaseSensitive) { | 117 | + if (!userLoginCaseSensitive) { |
118 | user.setEmail(user.getEmail().toLowerCase()); | 118 | user.setEmail(user.getEmail().toLowerCase()); |
119 | } | 119 | } |
120 | User savedUser = userDao.save(user.getTenantId(), user); | 120 | User savedUser = userDao.save(user.getTenantId(), user); |
@@ -28,6 +28,15 @@ public class JacksonUtil { | @@ -28,6 +28,15 @@ public class JacksonUtil { | ||
28 | 28 | ||
29 | public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); | 29 | public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); |
30 | 30 | ||
31 | + public static <T> T convertValue(Object fromValue, Class<T> toValueType) { | ||
32 | + try { | ||
33 | + return OBJECT_MAPPER.convertValue(fromValue, toValueType); | ||
34 | + } catch (IllegalArgumentException e) { | ||
35 | + throw new IllegalArgumentException("The given object value: " | ||
36 | + + fromValue + " cannot be converted to " + toValueType); | ||
37 | + } | ||
38 | + } | ||
39 | + | ||
31 | public static <T> T fromString(String string, Class<T> clazz) { | 40 | public static <T> T fromString(String string, Class<T> clazz) { |
32 | try { | 41 | try { |
33 | return OBJECT_MAPPER.readValue(string, clazz); | 42 | return OBJECT_MAPPER.readValue(string, clazz); |
@@ -60,4 +69,4 @@ public class JacksonUtil { | @@ -60,4 +69,4 @@ public class JacksonUtil { | ||
60 | public static <T> T clone(T value) { | 69 | public static <T> T clone(T value) { |
61 | return fromString(toString(value), (Class<T>) value.getClass()); | 70 | return fromString(toString(value), (Class<T>) value.getClass()); |
62 | } | 71 | } |
63 | -} | ||
72 | +} |
@@ -105,6 +105,7 @@ BEGIN | @@ -105,6 +105,7 @@ BEGIN | ||
105 | AND tablename like 'ts_kv_' || '%' | 105 | AND tablename like 'ts_kv_' || '%' |
106 | AND tablename != 'ts_kv_latest' | 106 | AND tablename != 'ts_kv_latest' |
107 | AND tablename != 'ts_kv_dictionary' | 107 | AND tablename != 'ts_kv_dictionary' |
108 | + AND tablename != 'ts_kv_indefinite' | ||
108 | LOOP | 109 | LOOP |
109 | IF partition != partition_by_max_ttl_date THEN | 110 | IF partition != partition_by_max_ttl_date THEN |
110 | IF partition_year IS NOT NULL THEN | 111 | IF partition_year IS NOT NULL THEN |
@@ -13,6 +13,7 @@ DROP TABLE IF EXISTS relation; | @@ -13,6 +13,7 @@ DROP TABLE IF EXISTS relation; | ||
13 | DROP TABLE IF EXISTS tb_user; | 13 | DROP TABLE IF EXISTS tb_user; |
14 | DROP TABLE IF EXISTS tenant; | 14 | DROP TABLE IF EXISTS tenant; |
15 | DROP TABLE IF EXISTS ts_kv; | 15 | DROP TABLE IF EXISTS ts_kv; |
16 | +DROP TABLE IF EXISTS ts_kv_dictionary; | ||
16 | DROP TABLE IF EXISTS ts_kv_latest; | 17 | DROP TABLE IF EXISTS ts_kv_latest; |
17 | DROP TABLE IF EXISTS user_credentials; | 18 | DROP TABLE IF EXISTS user_credentials; |
18 | DROP TABLE IF EXISTS widget_type; | 19 | DROP TABLE IF EXISTS widget_type; |
@@ -39,6 +39,9 @@ function additionalComposeQueueArgs() { | @@ -39,6 +39,9 @@ function additionalComposeQueueArgs() { | ||
39 | kafka) | 39 | kafka) |
40 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.kafka.yml" | 40 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.kafka.yml" |
41 | ;; | 41 | ;; |
42 | + confluent) | ||
43 | + ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.confluent.yml" | ||
44 | + ;; | ||
42 | aws-sqs) | 45 | aws-sqs) |
43 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.aws-sqs.yml" | 46 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.aws-sqs.yml" |
44 | ;; | 47 | ;; |
@@ -52,7 +55,7 @@ function additionalComposeQueueArgs() { | @@ -52,7 +55,7 @@ function additionalComposeQueueArgs() { | ||
52 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.service-bus.yml" | 55 | ADDITIONAL_COMPOSE_QUEUE_ARGS="-f docker-compose.service-bus.yml" |
53 | ;; | 56 | ;; |
54 | *) | 57 | *) |
55 | - echo "Unknown Queue service value specified: '${TB_QUEUE_TYPE}'. Should be either kafka or aws-sqs or pubsub or rabbitmq or service-bus." >&2 | 58 | + echo "Unknown Queue service value specified: '${TB_QUEUE_TYPE}'. Should be either kafka or confluent or aws-sqs or pubsub or rabbitmq or service-bus." >&2 |
56 | exit 1 | 59 | exit 1 |
57 | esac | 60 | esac |
58 | echo $ADDITIONAL_COMPOSE_QUEUE_ARGS | 61 | echo $ADDITIONAL_COMPOSE_QUEUE_ARGS |
docker/docker-compose.confluent.yml
0 → 100644
1 | +# | ||
2 | +# Copyright © 2016-2020 The Thingsboard Authors | ||
3 | +# | ||
4 | +# Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | +# you may not use this file except in compliance with the License. | ||
6 | +# You may obtain a copy of the License at | ||
7 | +# | ||
8 | +# http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | +# | ||
10 | +# Unless required by applicable law or agreed to in writing, software | ||
11 | +# distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | +# See the License for the specific language governing permissions and | ||
14 | +# limitations under the License. | ||
15 | +# | ||
16 | + | ||
17 | +version: '2.2' | ||
18 | + | ||
19 | +services: | ||
20 | + tb-js-executor: | ||
21 | + env_file: | ||
22 | + - queue-confluent.env | ||
23 | + tb-core1: | ||
24 | + env_file: | ||
25 | + - queue-confluent.env | ||
26 | + depends_on: | ||
27 | + - redis | ||
28 | + tb-core2: | ||
29 | + env_file: | ||
30 | + - queue-confluent.env | ||
31 | + depends_on: | ||
32 | + - redis | ||
33 | + tb-rule-engine1: | ||
34 | + env_file: | ||
35 | + - queue-confluent.env | ||
36 | + depends_on: | ||
37 | + - redis | ||
38 | + tb-rule-engine2: | ||
39 | + env_file: | ||
40 | + - queue-confluent.env | ||
41 | + depends_on: | ||
42 | + - redis | ||
43 | + tb-mqtt-transport1: | ||
44 | + env_file: | ||
45 | + - queue-confluent.env | ||
46 | + tb-mqtt-transport2: | ||
47 | + env_file: | ||
48 | + - queue-confluent.env | ||
49 | + tb-http-transport1: | ||
50 | + env_file: | ||
51 | + - queue-confluent.env | ||
52 | + tb-http-transport2: | ||
53 | + env_file: | ||
54 | + - queue-confluent.env | ||
55 | + tb-coap-transport: | ||
56 | + env_file: | ||
57 | + - queue-confluent.env |
docker/queue-confluent.env
0 → 100644
1 | +TB_QUEUE_TYPE=kafka | ||
2 | + | ||
3 | +TB_KAFKA_SERVERS=confluent.cloud:9092 | ||
4 | +TB_QUEUE_KAFKA_REPLICATION_FACTOR=3 | ||
5 | + | ||
6 | +TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD=true | ||
7 | +TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM=https | ||
8 | +TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM=PLAIN | ||
9 | +TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG=org.apache.kafka.common.security.plain.PlainLoginModule required username="CLUSTER_API_KEY" password="CLUSTER_API_SECRET"; | ||
10 | +TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL=SASL_SSL | ||
11 | +TB_QUEUE_KAFKA_CONFLUENT_USERNAME=CLUSTER_API_KEY | ||
12 | +TB_QUEUE_KAFKA_CONFLUENT_PASSWORD=CLUSTER_API_SECRET | ||
13 | + | ||
14 | +TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000 | ||
15 | +TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000 | ||
16 | +TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000 | ||
17 | +TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:1048576000 | ||
18 | +TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES=retention.ms:604800000;segment.bytes:52428800;retention.bytes:104857600 |
@@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
21 | 21 | ||
22 | <parent> | 22 | <parent> |
23 | <groupId>org.thingsboard</groupId> | 23 | <groupId>org.thingsboard</groupId> |
24 | - <version>2.5.3-SNAPSHOT</version> | 24 | + <version>2.5.5-SNAPSHOT</version> |
25 | <artifactId>msa</artifactId> | 25 | <artifactId>msa</artifactId> |
26 | </parent> | 26 | </parent> |
27 | <groupId>org.thingsboard.msa</groupId> | 27 | <groupId>org.thingsboard.msa</groupId> |
@@ -15,11 +15,15 @@ | @@ -15,11 +15,15 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.msa; | 16 | package org.thingsboard.server.msa; |
17 | 17 | ||
18 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
19 | +import com.fasterxml.jackson.databind.JsonMappingException; | ||
20 | +import com.fasterxml.jackson.databind.JsonNode; | ||
18 | import com.fasterxml.jackson.databind.ObjectMapper; | 21 | import com.fasterxml.jackson.databind.ObjectMapper; |
19 | import com.google.common.collect.ImmutableMap; | 22 | import com.google.common.collect.ImmutableMap; |
20 | import com.google.gson.JsonArray; | 23 | import com.google.gson.JsonArray; |
21 | import com.google.gson.JsonObject; | 24 | import com.google.gson.JsonObject; |
22 | import lombok.extern.slf4j.Slf4j; | 25 | import lombok.extern.slf4j.Slf4j; |
26 | +import org.apache.cassandra.cql3.Json; | ||
23 | import org.apache.commons.lang3.RandomStringUtils; | 27 | import org.apache.commons.lang3.RandomStringUtils; |
24 | import org.apache.http.config.Registry; | 28 | import org.apache.http.config.Registry; |
25 | import org.apache.http.config.RegistryBuilder; | 29 | import org.apache.http.config.RegistryBuilder; |
@@ -32,6 +36,7 @@ import org.apache.http.impl.client.HttpClients; | @@ -32,6 +36,7 @@ import org.apache.http.impl.client.HttpClients; | ||
32 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; | 36 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; |
33 | import org.apache.http.ssl.SSLContextBuilder; | 37 | import org.apache.http.ssl.SSLContextBuilder; |
34 | import org.apache.http.ssl.SSLContexts; | 38 | import org.apache.http.ssl.SSLContexts; |
39 | +import org.json.simple.JSONObject; | ||
35 | import org.junit.BeforeClass; | 40 | import org.junit.BeforeClass; |
36 | import org.junit.Rule; | 41 | import org.junit.Rule; |
37 | import org.junit.rules.TestRule; | 42 | import org.junit.rules.TestRule; |
@@ -42,6 +47,7 @@ import org.thingsboard.rest.client.RestClient; | @@ -42,6 +47,7 @@ import org.thingsboard.rest.client.RestClient; | ||
42 | import org.thingsboard.server.common.data.Device; | 47 | import org.thingsboard.server.common.data.Device; |
43 | import org.thingsboard.server.common.data.EntityType; | 48 | import org.thingsboard.server.common.data.EntityType; |
44 | import org.thingsboard.server.common.data.id.DeviceId; | 49 | import org.thingsboard.server.common.data.id.DeviceId; |
50 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | ||
45 | import org.thingsboard.server.msa.mapper.WsTelemetryResponse; | 51 | import org.thingsboard.server.msa.mapper.WsTelemetryResponse; |
46 | 52 | ||
47 | 53 | ||
@@ -52,6 +58,7 @@ import java.net.URI; | @@ -52,6 +58,7 @@ import java.net.URI; | ||
52 | import java.security.cert.X509Certificate; | 58 | import java.security.cert.X509Certificate; |
53 | import java.util.List; | 59 | import java.util.List; |
54 | import java.util.Map; | 60 | import java.util.Map; |
61 | +import java.util.Optional; | ||
55 | import java.util.Random; | 62 | import java.util.Random; |
56 | 63 | ||
57 | @Slf4j | 64 | @Slf4j |
@@ -95,6 +102,17 @@ public abstract class AbstractContainerTest { | @@ -95,6 +102,17 @@ public abstract class AbstractContainerTest { | ||
95 | } | 102 | } |
96 | }; | 103 | }; |
97 | 104 | ||
105 | + protected Device createGatewayDevice() throws JsonProcessingException { | ||
106 | + String isGateway = "{\"gateway\":true}"; | ||
107 | + ObjectMapper objectMapper = new ObjectMapper(); | ||
108 | + JsonNode additionalInfo = objectMapper.readTree(isGateway); | ||
109 | + Device gatewayDeviceTemplate = new Device(); | ||
110 | + gatewayDeviceTemplate.setName("mqtt_gateway"); | ||
111 | + gatewayDeviceTemplate.setType("gateway"); | ||
112 | + gatewayDeviceTemplate.setAdditionalInfo(additionalInfo); | ||
113 | + return restClient.saveDevice(gatewayDeviceTemplate); | ||
114 | + } | ||
115 | + | ||
98 | protected Device createDevice(String name) { | 116 | protected Device createDevice(String name) { |
99 | return restClient.createDevice(name + RandomStringUtils.randomAlphanumeric(7), "DEFAULT"); | 117 | return restClient.createDevice(name + RandomStringUtils.randomAlphanumeric(7), "DEFAULT"); |
100 | } | 118 | } |
@@ -140,6 +158,27 @@ public abstract class AbstractContainerTest { | @@ -140,6 +158,27 @@ public abstract class AbstractContainerTest { | ||
140 | return expectedValue.equals(list.get(1)); | 158 | return expectedValue.equals(list.get(1)); |
141 | } | 159 | } |
142 | 160 | ||
161 | + protected JsonObject createGatewayConnectPayload(String deviceName){ | ||
162 | + JsonObject payload = new JsonObject(); | ||
163 | + payload.addProperty("device", deviceName); | ||
164 | + return payload; | ||
165 | + } | ||
166 | + | ||
167 | + protected JsonObject createGatewayPayload(String deviceName, long ts){ | ||
168 | + JsonObject payload = new JsonObject(); | ||
169 | + payload.add(deviceName, createGatewayTelemetryArray(ts)); | ||
170 | + return payload; | ||
171 | + } | ||
172 | + | ||
173 | + protected JsonArray createGatewayTelemetryArray(long ts){ | ||
174 | + JsonArray telemetryArray = new JsonArray(); | ||
175 | + if (ts > 0) | ||
176 | + telemetryArray.add(createPayload(ts)); | ||
177 | + else | ||
178 | + telemetryArray.add(createPayload()); | ||
179 | + return telemetryArray; | ||
180 | + } | ||
181 | + | ||
143 | protected JsonObject createPayload(long ts) { | 182 | protected JsonObject createPayload(long ts) { |
144 | JsonObject values = createPayload(); | 183 | JsonObject values = createPayload(); |
145 | JsonObject payload = new JsonObject(); | 184 | JsonObject payload = new JsonObject(); |
msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/MqttGatewayClientTest.java
0 → 100644
1 | +/** | ||
2 | + * Copyright © 2016-2020 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.msa.connectivity; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
19 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
20 | +import com.google.common.collect.Sets; | ||
21 | +import com.google.common.util.concurrent.ListenableFuture; | ||
22 | +import com.google.common.util.concurrent.ListeningExecutorService; | ||
23 | +import com.google.common.util.concurrent.MoreExecutors; | ||
24 | +import com.google.gson.JsonElement; | ||
25 | +import com.google.gson.JsonObject; | ||
26 | +import com.google.gson.JsonParser; | ||
27 | +import io.netty.buffer.ByteBuf; | ||
28 | +import io.netty.buffer.Unpooled; | ||
29 | +import io.netty.handler.codec.mqtt.MqttQoS; | ||
30 | +import lombok.Data; | ||
31 | +import lombok.extern.slf4j.Slf4j; | ||
32 | +import org.apache.commons.lang3.RandomStringUtils; | ||
33 | +import org.checkerframework.checker.units.qual.A; | ||
34 | +import org.junit.After; | ||
35 | +import org.junit.Assert; | ||
36 | +import org.junit.Before; | ||
37 | +import org.junit.Test; | ||
38 | +import org.springframework.core.ParameterizedTypeReference; | ||
39 | +import org.springframework.http.HttpMethod; | ||
40 | +import org.springframework.http.ResponseEntity; | ||
41 | +import org.thingsboard.mqtt.MqttClient; | ||
42 | +import org.thingsboard.mqtt.MqttClientConfig; | ||
43 | +import org.thingsboard.mqtt.MqttHandler; | ||
44 | +import org.thingsboard.server.common.data.Device; | ||
45 | +import org.thingsboard.server.common.data.id.DeviceId; | ||
46 | +import org.thingsboard.server.common.data.id.EntityId; | ||
47 | +import org.thingsboard.server.common.data.id.RuleChainId; | ||
48 | +import org.thingsboard.server.common.data.page.TextPageData; | ||
49 | +import org.thingsboard.server.common.data.relation.EntityRelation; | ||
50 | +import org.thingsboard.server.common.data.relation.EntityRelationInfo; | ||
51 | +import org.thingsboard.server.common.data.relation.RelationTypeGroup; | ||
52 | +import org.thingsboard.server.common.data.rule.NodeConnectionInfo; | ||
53 | +import org.thingsboard.server.common.data.rule.RuleChain; | ||
54 | +import org.thingsboard.server.common.data.rule.RuleChainMetaData; | ||
55 | +import org.thingsboard.server.common.data.rule.RuleNode; | ||
56 | +import org.thingsboard.server.common.data.security.DeviceCredentials; | ||
57 | +import org.thingsboard.server.msa.AbstractContainerTest; | ||
58 | +import org.thingsboard.server.msa.WsClient; | ||
59 | +import org.thingsboard.server.msa.mapper.AttributesResponse; | ||
60 | +import org.thingsboard.server.msa.mapper.WsTelemetryResponse; | ||
61 | + | ||
62 | +import java.io.IOException; | ||
63 | +import java.nio.charset.StandardCharsets; | ||
64 | +import java.util.*; | ||
65 | +import java.util.concurrent.*; | ||
66 | + | ||
67 | +@Slf4j | ||
68 | +public class MqttGatewayClientTest extends AbstractContainerTest { | ||
69 | + Device gatewayDevice; | ||
70 | + MqttClient mqttClient; | ||
71 | + Device createdDevice; | ||
72 | + MqttMessageListener listener; | ||
73 | + | ||
74 | + @Before | ||
75 | + public void createGateway() throws Exception { | ||
76 | + restClient.login("tenant@thingsboard.org", "tenant"); | ||
77 | + this.gatewayDevice = createGatewayDevice(); | ||
78 | + Optional<DeviceCredentials> gatewayDeviceCredentials = restClient.getDeviceCredentialsByDeviceId(gatewayDevice.getId()); | ||
79 | + Assert.assertTrue(gatewayDeviceCredentials.isPresent()); | ||
80 | + this.listener = new MqttMessageListener(); | ||
81 | + this.mqttClient = getMqttClient(gatewayDeviceCredentials.get(), listener); | ||
82 | + this.createdDevice = createDeviceThroughGateway(mqttClient, gatewayDevice); | ||
83 | + } | ||
84 | + | ||
85 | + @After | ||
86 | + public void removeGateway() throws Exception { | ||
87 | + restClient.getRestTemplate().delete(HTTPS_URL + "/api/device/" + this.gatewayDevice.getId()); | ||
88 | + restClient.getRestTemplate().delete(HTTPS_URL + "/api/device/" + this.createdDevice.getId()); | ||
89 | + this.listener = null; | ||
90 | + this.mqttClient = null; | ||
91 | + this.createdDevice = null; | ||
92 | + } | ||
93 | + | ||
94 | + @Test | ||
95 | + public void telemetryUpload() throws Exception { | ||
96 | + WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS); | ||
97 | + mqttClient.publish("v1/gateway/telemetry", Unpooled.wrappedBuffer(createGatewayPayload(createdDevice.getName(), -1).toString().getBytes())).get(); | ||
98 | + WsTelemetryResponse actualLatestTelemetry = wsClient.getLastMessage(); | ||
99 | + log.info("Received telemetry: {}", actualLatestTelemetry); | ||
100 | + wsClient.closeBlocking(); | ||
101 | + | ||
102 | + Assert.assertEquals(4, actualLatestTelemetry.getData().size()); | ||
103 | + Assert.assertEquals(Sets.newHashSet("booleanKey", "stringKey", "doubleKey", "longKey"), | ||
104 | + actualLatestTelemetry.getLatestValues().keySet()); | ||
105 | + | ||
106 | + Assert.assertTrue(verify(actualLatestTelemetry, "booleanKey", Boolean.TRUE.toString())); | ||
107 | + Assert.assertTrue(verify(actualLatestTelemetry, "stringKey", "value1")); | ||
108 | + Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", Double.toString(42.0))); | ||
109 | + Assert.assertTrue(verify(actualLatestTelemetry, "longKey", Long.toString(73))); | ||
110 | + } | ||
111 | + | ||
112 | + @Test | ||
113 | + public void telemetryUploadWithTs() throws Exception { | ||
114 | + long ts = 1451649600512L; | ||
115 | + | ||
116 | + restClient.login("tenant@thingsboard.org", "tenant"); | ||
117 | + WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "LATEST_TELEMETRY", CmdsType.TS_SUB_CMDS); | ||
118 | + mqttClient.publish("v1/gateway/telemetry", Unpooled.wrappedBuffer(createGatewayPayload(createdDevice.getName(), ts).toString().getBytes())).get(); | ||
119 | + WsTelemetryResponse actualLatestTelemetry = wsClient.getLastMessage(); | ||
120 | + log.info("Received telemetry: {}", actualLatestTelemetry); | ||
121 | + wsClient.closeBlocking(); | ||
122 | + | ||
123 | + Assert.assertEquals(4, actualLatestTelemetry.getData().size()); | ||
124 | + Assert.assertEquals(getExpectedLatestValues(ts), actualLatestTelemetry.getLatestValues()); | ||
125 | + | ||
126 | + Assert.assertTrue(verify(actualLatestTelemetry, "booleanKey", ts, Boolean.TRUE.toString())); | ||
127 | + Assert.assertTrue(verify(actualLatestTelemetry, "stringKey", ts, "value1")); | ||
128 | + Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", ts, Double.toString(42.0))); | ||
129 | + Assert.assertTrue(verify(actualLatestTelemetry, "longKey", ts, Long.toString(73))); | ||
130 | + } | ||
131 | + | ||
132 | + @Test | ||
133 | + public void publishAttributeUpdateToServer() throws Exception { | ||
134 | + Optional<DeviceCredentials> createdDeviceCredentials = restClient.getDeviceCredentialsByDeviceId(createdDevice.getId()); | ||
135 | + Assert.assertTrue(createdDeviceCredentials.isPresent()); | ||
136 | + WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); | ||
137 | + JsonObject clientAttributes = new JsonObject(); | ||
138 | + clientAttributes.addProperty("attr1", "value1"); | ||
139 | + clientAttributes.addProperty("attr2", true); | ||
140 | + clientAttributes.addProperty("attr3", 42.0); | ||
141 | + clientAttributes.addProperty("attr4", 73); | ||
142 | + JsonObject gatewayClientAttributes = new JsonObject(); | ||
143 | + gatewayClientAttributes.add(createdDevice.getName(), clientAttributes); | ||
144 | + mqttClient.publish("v1/gateway/attributes", Unpooled.wrappedBuffer(gatewayClientAttributes.toString().getBytes())).get(); | ||
145 | + WsTelemetryResponse actualLatestTelemetry = wsClient.getLastMessage(); | ||
146 | + log.info("Received attributes: {}", actualLatestTelemetry); | ||
147 | + wsClient.closeBlocking(); | ||
148 | + | ||
149 | + Assert.assertEquals(4, actualLatestTelemetry.getData().size()); | ||
150 | + Assert.assertEquals(Sets.newHashSet("attr1", "attr2", "attr3", "attr4"), | ||
151 | + actualLatestTelemetry.getLatestValues().keySet()); | ||
152 | + | ||
153 | + Assert.assertTrue(verify(actualLatestTelemetry, "attr1", "value1")); | ||
154 | + Assert.assertTrue(verify(actualLatestTelemetry, "attr2", Boolean.TRUE.toString())); | ||
155 | + Assert.assertTrue(verify(actualLatestTelemetry, "attr3", Double.toString(42.0))); | ||
156 | + Assert.assertTrue(verify(actualLatestTelemetry, "attr4", Long.toString(73))); | ||
157 | + } | ||
158 | + | ||
159 | + @Test | ||
160 | + public void requestAttributeValuesFromServer() throws Exception { | ||
161 | + WsClient wsClient = subscribeToWebSocket(createdDevice.getId(), "CLIENT_SCOPE", CmdsType.ATTR_SUB_CMDS); | ||
162 | + // Add a new client attribute | ||
163 | + JsonObject clientAttributes = new JsonObject(); | ||
164 | + String clientAttributeValue = RandomStringUtils.randomAlphanumeric(8); | ||
165 | + clientAttributes.addProperty("clientAttr", clientAttributeValue); | ||
166 | + | ||
167 | + JsonObject gatewayClientAttributes = new JsonObject(); | ||
168 | + gatewayClientAttributes.add(createdDevice.getName(), clientAttributes); | ||
169 | + mqttClient.publish("v1/gateway/attributes", Unpooled.wrappedBuffer(gatewayClientAttributes.toString().getBytes())).get(); | ||
170 | + | ||
171 | + WsTelemetryResponse actualLatestTelemetry = wsClient.getLastMessage(); | ||
172 | + log.info("Received ws telemetry: {}", actualLatestTelemetry); | ||
173 | + wsClient.closeBlocking(); | ||
174 | + | ||
175 | + Assert.assertEquals(1, actualLatestTelemetry.getData().size()); | ||
176 | + Assert.assertEquals(Sets.newHashSet("clientAttr"), | ||
177 | + actualLatestTelemetry.getLatestValues().keySet()); | ||
178 | + | ||
179 | + Assert.assertTrue(verify(actualLatestTelemetry, "clientAttr", clientAttributeValue)); | ||
180 | + | ||
181 | + // Add a new shared attribute | ||
182 | + JsonObject sharedAttributes = new JsonObject(); | ||
183 | + String sharedAttributeValue = RandomStringUtils.randomAlphanumeric(8); | ||
184 | + sharedAttributes.addProperty("sharedAttr", sharedAttributeValue); | ||
185 | + | ||
186 | + ResponseEntity sharedAttributesResponse = restClient.getRestTemplate() | ||
187 | + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/DEVICE/{deviceId}/SHARED_SCOPE", | ||
188 | + mapper.readTree(sharedAttributes.toString()), ResponseEntity.class, | ||
189 | + createdDevice.getId()); | ||
190 | + Assert.assertTrue(sharedAttributesResponse.getStatusCode().is2xxSuccessful()); | ||
191 | + MqttEvent sharedAttributeEvent = listener.getEvents().poll(10, TimeUnit.SECONDS); | ||
192 | + | ||
193 | + // Catch attribute update event | ||
194 | + Assert.assertNotNull(sharedAttributeEvent); | ||
195 | + Assert.assertEquals("v1/gateway/attributes", sharedAttributeEvent.getTopic()); | ||
196 | + | ||
197 | + // Subscribe to attributes response | ||
198 | + mqttClient.on("v1/gateway/attributes/response", listener, MqttQoS.AT_LEAST_ONCE).get(); | ||
199 | + | ||
200 | + // Wait until subscription is processed | ||
201 | + TimeUnit.SECONDS.sleep(3); | ||
202 | + | ||
203 | + checkAttribute(true, clientAttributeValue); | ||
204 | + checkAttribute(false, sharedAttributeValue); | ||
205 | + } | ||
206 | + | ||
207 | + @Test | ||
208 | + public void subscribeToAttributeUpdatesFromServer() throws Exception { | ||
209 | + mqttClient.on("v1/gateway/attributes", listener, MqttQoS.AT_LEAST_ONCE).get(); | ||
210 | + // Wait until subscription is processed | ||
211 | + TimeUnit.SECONDS.sleep(3); | ||
212 | + String sharedAttributeName = "sharedAttr"; | ||
213 | + // Add a new shared attribute | ||
214 | + | ||
215 | + JsonObject sharedAttributes = new JsonObject(); | ||
216 | + String sharedAttributeValue = RandomStringUtils.randomAlphanumeric(8); | ||
217 | + sharedAttributes.addProperty(sharedAttributeName, sharedAttributeValue); | ||
218 | + | ||
219 | + JsonObject gatewaySharedAttributeValue = new JsonObject(); | ||
220 | + gatewaySharedAttributeValue.addProperty("device", createdDevice.getName()); | ||
221 | + gatewaySharedAttributeValue.add("data", sharedAttributes); | ||
222 | + | ||
223 | + ResponseEntity sharedAttributesResponse = restClient.getRestTemplate() | ||
224 | + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/DEVICE/{deviceId}/SHARED_SCOPE", | ||
225 | + mapper.readTree(sharedAttributes.toString()), ResponseEntity.class, | ||
226 | + createdDevice.getId()); | ||
227 | + Assert.assertTrue(sharedAttributesResponse.getStatusCode().is2xxSuccessful()); | ||
228 | + | ||
229 | + MqttEvent event = listener.getEvents().poll(10, TimeUnit.SECONDS); | ||
230 | + Assert.assertEquals(sharedAttributeValue, | ||
231 | + mapper.readValue(Objects.requireNonNull(event).getMessage(), JsonNode.class).get("data").get(sharedAttributeName).asText()); | ||
232 | + | ||
233 | + // Update the shared attribute value | ||
234 | + JsonObject updatedSharedAttributes = new JsonObject(); | ||
235 | + String updatedSharedAttributeValue = RandomStringUtils.randomAlphanumeric(8); | ||
236 | + updatedSharedAttributes.addProperty(sharedAttributeName, updatedSharedAttributeValue); | ||
237 | + | ||
238 | + JsonObject gatewayUpdatedSharedAttributeValue = new JsonObject(); | ||
239 | + gatewayUpdatedSharedAttributeValue.addProperty("device", createdDevice.getName()); | ||
240 | + gatewayUpdatedSharedAttributeValue.add("data", updatedSharedAttributes); | ||
241 | + | ||
242 | + ResponseEntity updatedSharedAttributesResponse = restClient.getRestTemplate() | ||
243 | + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/DEVICE/{deviceId}/SHARED_SCOPE", | ||
244 | + mapper.readTree(updatedSharedAttributes.toString()), ResponseEntity.class, | ||
245 | + createdDevice.getId()); | ||
246 | + Assert.assertTrue(updatedSharedAttributesResponse.getStatusCode().is2xxSuccessful()); | ||
247 | + | ||
248 | + event = listener.getEvents().poll(10, TimeUnit.SECONDS); | ||
249 | + Assert.assertEquals(updatedSharedAttributeValue, | ||
250 | + mapper.readValue(Objects.requireNonNull(event).getMessage(), JsonNode.class).get("data").get(sharedAttributeName).asText()); | ||
251 | + } | ||
252 | + | ||
253 | + @Test | ||
254 | + public void serverSideRpc() throws Exception { | ||
255 | + String gatewayRpcTopic = "v1/gateway/rpc"; | ||
256 | + mqttClient.on(gatewayRpcTopic, listener, MqttQoS.AT_LEAST_ONCE).get(); | ||
257 | + | ||
258 | + // Wait until subscription is processed | ||
259 | + TimeUnit.SECONDS.sleep(3); | ||
260 | + | ||
261 | + // Send an RPC from the server | ||
262 | + JsonObject serverRpcPayload = new JsonObject(); | ||
263 | + serverRpcPayload.addProperty("method", "getValue"); | ||
264 | + serverRpcPayload.addProperty("params", true); | ||
265 | + ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()); | ||
266 | + ListenableFuture<ResponseEntity> future = service.submit(() -> { | ||
267 | + try { | ||
268 | + return restClient.getRestTemplate() | ||
269 | + .postForEntity(HTTPS_URL + "/api/plugins/rpc/twoway/{deviceId}", | ||
270 | + mapper.readTree(serverRpcPayload.toString()), String.class, | ||
271 | + createdDevice.getId()); | ||
272 | + } catch (IOException e) { | ||
273 | + return ResponseEntity.badRequest().build(); | ||
274 | + } | ||
275 | + }); | ||
276 | + | ||
277 | + // Wait for RPC call from the server and send the response | ||
278 | + MqttEvent requestFromServer = listener.getEvents().poll(10, TimeUnit.SECONDS); | ||
279 | + | ||
280 | + Assert.assertNotNull(requestFromServer); | ||
281 | + Assert.assertNotNull(requestFromServer.getMessage()); | ||
282 | + | ||
283 | + JsonObject requestFromServerJson = new JsonParser().parse(requestFromServer.getMessage()).getAsJsonObject(); | ||
284 | + | ||
285 | + Assert.assertEquals(createdDevice.getName(), requestFromServerJson.get("device").getAsString()); | ||
286 | + | ||
287 | + JsonObject requestFromServerData = requestFromServerJson.get("data").getAsJsonObject(); | ||
288 | + | ||
289 | + Assert.assertEquals("getValue", requestFromServerData.get("method").getAsString()); | ||
290 | + Assert.assertTrue(requestFromServerData.get("params").getAsBoolean()); | ||
291 | + | ||
292 | + int requestId = requestFromServerData.get("id").getAsInt(); | ||
293 | + | ||
294 | + JsonObject clientResponse = new JsonObject(); | ||
295 | + clientResponse.addProperty("response", "someResponse"); | ||
296 | + JsonObject gatewayResponse = new JsonObject(); | ||
297 | + gatewayResponse.addProperty("device", createdDevice.getName()); | ||
298 | + gatewayResponse.addProperty("id", requestId); | ||
299 | + gatewayResponse.add("data", clientResponse); | ||
300 | + // Send a response to the server's RPC request | ||
301 | + | ||
302 | + mqttClient.publish(gatewayRpcTopic, Unpooled.wrappedBuffer(gatewayResponse.toString().getBytes())).get(); | ||
303 | + ResponseEntity serverResponse = future.get(5, TimeUnit.SECONDS); | ||
304 | + Assert.assertTrue(serverResponse.getStatusCode().is2xxSuccessful()); | ||
305 | + Assert.assertEquals(clientResponse.toString(), serverResponse.getBody()); | ||
306 | + } | ||
307 | + | ||
308 | + private void checkAttribute(boolean client, String expectedValue) throws Exception{ | ||
309 | + JsonObject gatewayAttributesRequest = new JsonObject(); | ||
310 | + int messageId = new Random().nextInt(100); | ||
311 | + gatewayAttributesRequest.addProperty("id", messageId); | ||
312 | + gatewayAttributesRequest.addProperty("device", createdDevice.getName()); | ||
313 | + gatewayAttributesRequest.addProperty("client", client); | ||
314 | + String attributeName; | ||
315 | + if (client) | ||
316 | + attributeName = "clientAttr"; | ||
317 | + else | ||
318 | + attributeName = "sharedAttr"; | ||
319 | + gatewayAttributesRequest.addProperty("key", attributeName); | ||
320 | + log.info(gatewayAttributesRequest.toString()); | ||
321 | + mqttClient.publish("v1/gateway/attributes/request", Unpooled.wrappedBuffer(gatewayAttributesRequest.toString().getBytes())).get(); | ||
322 | + MqttEvent clientAttributeEvent = listener.getEvents().poll(10, TimeUnit.SECONDS); | ||
323 | + Assert.assertNotNull(clientAttributeEvent); | ||
324 | + JsonObject responseMessage = new JsonParser().parse(Objects.requireNonNull(clientAttributeEvent).getMessage()).getAsJsonObject(); | ||
325 | + | ||
326 | + Assert.assertEquals(messageId, responseMessage.get("id").getAsInt()); | ||
327 | + Assert.assertEquals(createdDevice.getName(), responseMessage.get("device").getAsString()); | ||
328 | + Assert.assertEquals(3, responseMessage.entrySet().size()); | ||
329 | + Assert.assertEquals(expectedValue, responseMessage.get("value").getAsString()); | ||
330 | + } | ||
331 | + | ||
332 | + private Device createDeviceThroughGateway(MqttClient mqttClient, Device gatewayDevice) throws Exception { | ||
333 | + String deviceName = "mqtt_device"; | ||
334 | + mqttClient.publish("v1/gateway/connect", Unpooled.wrappedBuffer(createGatewayConnectPayload(deviceName).toString().getBytes())).get(); | ||
335 | + | ||
336 | + TimeUnit.SECONDS.sleep(3); | ||
337 | + List<EntityRelation> relations = restClient.findByFrom(gatewayDevice.getId(), RelationTypeGroup.COMMON); | ||
338 | + | ||
339 | + Assert.assertEquals(1, relations.size()); | ||
340 | + | ||
341 | + EntityId createdEntityId = relations.get(0).getTo(); | ||
342 | + DeviceId createdDeviceId = new DeviceId(createdEntityId.getId()); | ||
343 | + Optional<Device> createdDevice = restClient.getDeviceById(createdDeviceId); | ||
344 | + | ||
345 | + Assert.assertTrue(createdDevice.isPresent()); | ||
346 | + | ||
347 | + return createdDevice.get(); | ||
348 | + } | ||
349 | + | ||
350 | + private MqttClient getMqttClient(DeviceCredentials deviceCredentials, MqttMessageListener listener) throws InterruptedException, ExecutionException { | ||
351 | + MqttClientConfig clientConfig = new MqttClientConfig(); | ||
352 | + clientConfig.setClientId("MQTT client from test"); | ||
353 | + clientConfig.setUsername(deviceCredentials.getCredentialsId()); | ||
354 | + MqttClient mqttClient = MqttClient.create(clientConfig, listener); | ||
355 | + mqttClient.connect("localhost", 1883).get(); | ||
356 | + return mqttClient; | ||
357 | + } | ||
358 | + | ||
359 | + @Data | ||
360 | + private class MqttMessageListener implements MqttHandler { | ||
361 | + private final BlockingQueue<MqttEvent> events; | ||
362 | + | ||
363 | + private MqttMessageListener() { | ||
364 | + events = new ArrayBlockingQueue<>(100); | ||
365 | + } | ||
366 | + | ||
367 | + @Override | ||
368 | + public void onMessage(String topic, ByteBuf message) { | ||
369 | + log.info("MQTT message [{}], topic [{}]", message.toString(StandardCharsets.UTF_8), topic); | ||
370 | + events.add(new MqttEvent(topic, message.toString(StandardCharsets.UTF_8))); | ||
371 | + } | ||
372 | + | ||
373 | + } | ||
374 | + | ||
375 | + @Data | ||
376 | + private class MqttEvent { | ||
377 | + private final String topic; | ||
378 | + private final String message; | ||
379 | + } | ||
380 | + | ||
381 | + | ||
382 | +} |
@@ -26,6 +26,12 @@ kafka: | @@ -26,6 +26,12 @@ kafka: | ||
26 | servers: "TB_KAFKA_SERVERS" | 26 | servers: "TB_KAFKA_SERVERS" |
27 | replication_factor: "TB_QUEUE_KAFKA_REPLICATION_FACTOR" | 27 | replication_factor: "TB_QUEUE_KAFKA_REPLICATION_FACTOR" |
28 | topic_properties: "TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES" | 28 | topic_properties: "TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES" |
29 | + use_confluent_cloud: "TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD" | ||
30 | + confluent: | ||
31 | + sasl: | ||
32 | + mechanism: "TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM" | ||
33 | + username: "TB_QUEUE_KAFKA_CONFLUENT_USERNAME" | ||
34 | + password: "TB_QUEUE_KAFKA_CONFLUENT_PASSWORD" | ||
29 | 35 | ||
30 | pubsub: | 36 | pubsub: |
31 | project_id: "TB_QUEUE_PUBSUB_PROJECT_ID" | 37 | project_id: "TB_QUEUE_PUBSUB_PROJECT_ID" |
@@ -25,7 +25,11 @@ kafka: | @@ -25,7 +25,11 @@ kafka: | ||
25 | # Kafka Bootstrap Servers | 25 | # Kafka Bootstrap Servers |
26 | servers: "localhost:9092" | 26 | servers: "localhost:9092" |
27 | replication_factor: "1" | 27 | replication_factor: "1" |
28 | - topic_properties: "retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600" | 28 | + topic_properties: "retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100" |
29 | + use_confluent_cloud: false | ||
30 | + confluent: | ||
31 | + sasl: | ||
32 | + mechanism: "PLAIN" | ||
29 | 33 | ||
30 | pubsub: | 34 | pubsub: |
31 | queue_properties: "ackDeadlineInSec:30;messageRetentionInSec:604800" | 35 | queue_properties: "ackDeadlineInSec:30;messageRetentionInSec:604800" |
@@ -1872,12 +1872,14 @@ | @@ -1872,12 +1872,14 @@ | ||
1872 | "balanced-match": { | 1872 | "balanced-match": { |
1873 | "version": "1.0.0", | 1873 | "version": "1.0.0", |
1874 | "bundled": true, | 1874 | "bundled": true, |
1875 | - "dev": true | 1875 | + "dev": true, |
1876 | + "optional": true | ||
1876 | }, | 1877 | }, |
1877 | "brace-expansion": { | 1878 | "brace-expansion": { |
1878 | "version": "1.1.11", | 1879 | "version": "1.1.11", |
1879 | "bundled": true, | 1880 | "bundled": true, |
1880 | "dev": true, | 1881 | "dev": true, |
1882 | + "optional": true, | ||
1881 | "requires": { | 1883 | "requires": { |
1882 | "balanced-match": "^1.0.0", | 1884 | "balanced-match": "^1.0.0", |
1883 | "concat-map": "0.0.1" | 1885 | "concat-map": "0.0.1" |
@@ -1892,17 +1894,20 @@ | @@ -1892,17 +1894,20 @@ | ||
1892 | "code-point-at": { | 1894 | "code-point-at": { |
1893 | "version": "1.1.0", | 1895 | "version": "1.1.0", |
1894 | "bundled": true, | 1896 | "bundled": true, |
1895 | - "dev": true | 1897 | + "dev": true, |
1898 | + "optional": true | ||
1896 | }, | 1899 | }, |
1897 | "concat-map": { | 1900 | "concat-map": { |
1898 | "version": "0.0.1", | 1901 | "version": "0.0.1", |
1899 | "bundled": true, | 1902 | "bundled": true, |
1900 | - "dev": true | 1903 | + "dev": true, |
1904 | + "optional": true | ||
1901 | }, | 1905 | }, |
1902 | "console-control-strings": { | 1906 | "console-control-strings": { |
1903 | "version": "1.1.0", | 1907 | "version": "1.1.0", |
1904 | "bundled": true, | 1908 | "bundled": true, |
1905 | - "dev": true | 1909 | + "dev": true, |
1910 | + "optional": true | ||
1906 | }, | 1911 | }, |
1907 | "core-util-is": { | 1912 | "core-util-is": { |
1908 | "version": "1.0.2", | 1913 | "version": "1.0.2", |
@@ -2019,7 +2024,8 @@ | @@ -2019,7 +2024,8 @@ | ||
2019 | "inherits": { | 2024 | "inherits": { |
2020 | "version": "2.0.3", | 2025 | "version": "2.0.3", |
2021 | "bundled": true, | 2026 | "bundled": true, |
2022 | - "dev": true | 2027 | + "dev": true, |
2028 | + "optional": true | ||
2023 | }, | 2029 | }, |
2024 | "ini": { | 2030 | "ini": { |
2025 | "version": "1.3.5", | 2031 | "version": "1.3.5", |
@@ -2031,6 +2037,7 @@ | @@ -2031,6 +2037,7 @@ | ||
2031 | "version": "1.0.0", | 2037 | "version": "1.0.0", |
2032 | "bundled": true, | 2038 | "bundled": true, |
2033 | "dev": true, | 2039 | "dev": true, |
2040 | + "optional": true, | ||
2034 | "requires": { | 2041 | "requires": { |
2035 | "number-is-nan": "^1.0.0" | 2042 | "number-is-nan": "^1.0.0" |
2036 | } | 2043 | } |
@@ -2045,6 +2052,7 @@ | @@ -2045,6 +2052,7 @@ | ||
2045 | "version": "3.0.4", | 2052 | "version": "3.0.4", |
2046 | "bundled": true, | 2053 | "bundled": true, |
2047 | "dev": true, | 2054 | "dev": true, |
2055 | + "optional": true, | ||
2048 | "requires": { | 2056 | "requires": { |
2049 | "brace-expansion": "^1.1.7" | 2057 | "brace-expansion": "^1.1.7" |
2050 | } | 2058 | } |
@@ -2156,7 +2164,8 @@ | @@ -2156,7 +2164,8 @@ | ||
2156 | "number-is-nan": { | 2164 | "number-is-nan": { |
2157 | "version": "1.0.1", | 2165 | "version": "1.0.1", |
2158 | "bundled": true, | 2166 | "bundled": true, |
2159 | - "dev": true | 2167 | + "dev": true, |
2168 | + "optional": true | ||
2160 | }, | 2169 | }, |
2161 | "object-assign": { | 2170 | "object-assign": { |
2162 | "version": "4.1.1", | 2171 | "version": "4.1.1", |
@@ -2168,6 +2177,7 @@ | @@ -2168,6 +2177,7 @@ | ||
2168 | "version": "1.4.0", | 2177 | "version": "1.4.0", |
2169 | "bundled": true, | 2178 | "bundled": true, |
2170 | "dev": true, | 2179 | "dev": true, |
2180 | + "optional": true, | ||
2171 | "requires": { | 2181 | "requires": { |
2172 | "wrappy": "1" | 2182 | "wrappy": "1" |
2173 | } | 2183 | } |
@@ -2289,6 +2299,7 @@ | @@ -2289,6 +2299,7 @@ | ||
2289 | "version": "1.0.2", | 2299 | "version": "1.0.2", |
2290 | "bundled": true, | 2300 | "bundled": true, |
2291 | "dev": true, | 2301 | "dev": true, |
2302 | + "optional": true, | ||
2292 | "requires": { | 2303 | "requires": { |
2293 | "code-point-at": "^1.0.0", | 2304 | "code-point-at": "^1.0.0", |
2294 | "is-fullwidth-code-point": "^1.0.0", | 2305 | "is-fullwidth-code-point": "^1.0.0", |
1 | { | 1 | { |
2 | "name": "thingsboard-js-executor", | 2 | "name": "thingsboard-js-executor", |
3 | "private": true, | 3 | "private": true, |
4 | - "version": "2.5.3", | 4 | + "version": "2.5.5", |
5 | "description": "ThingsBoard JavaScript Executor Microservice", | 5 | "description": "ThingsBoard JavaScript Executor Microservice", |
6 | "main": "server.js", | 6 | "main": "server.js", |
7 | "bin": "server.js", | 7 | "bin": "server.js", |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>msa</artifactId> | 24 | <artifactId>msa</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa</groupId> | 26 | <groupId>org.thingsboard.msa</groupId> |
@@ -34,7 +34,7 @@ function KafkaProducer() { | @@ -34,7 +34,7 @@ function KafkaProducer() { | ||
34 | this.send = async (responseTopic, scriptId, rawResponse, headers) => { | 34 | this.send = async (responseTopic, scriptId, rawResponse, headers) => { |
35 | 35 | ||
36 | if (!topics.includes(responseTopic)) { | 36 | if (!topics.includes(responseTopic)) { |
37 | - let createResponseTopicResult = await createTopic(responseTopic); | 37 | + let createResponseTopicResult = await createTopic(responseTopic, 1); |
38 | topics.push(responseTopic); | 38 | topics.push(responseTopic); |
39 | if (createResponseTopicResult) { | 39 | if (createResponseTopicResult) { |
40 | logger.info('Created new topic: %s', requestTopic); | 40 | logger.info('Created new topic: %s', requestTopic); |
@@ -61,22 +61,45 @@ function KafkaProducer() { | @@ -61,22 +61,45 @@ function KafkaProducer() { | ||
61 | 61 | ||
62 | const kafkaBootstrapServers = config.get('kafka.bootstrap.servers'); | 62 | const kafkaBootstrapServers = config.get('kafka.bootstrap.servers'); |
63 | const requestTopic = config.get('request_topic'); | 63 | const requestTopic = config.get('request_topic'); |
64 | + const useConfluent = config.get('kafka.use_confluent_cloud'); | ||
64 | 65 | ||
65 | logger.info('Kafka Bootstrap Servers: %s', kafkaBootstrapServers); | 66 | logger.info('Kafka Bootstrap Servers: %s', kafkaBootstrapServers); |
66 | logger.info('Kafka Requests Topic: %s', requestTopic); | 67 | logger.info('Kafka Requests Topic: %s', requestTopic); |
67 | 68 | ||
68 | - kafkaClient = new Kafka({ | 69 | + let kafkaConfig = { |
69 | brokers: kafkaBootstrapServers.split(','), | 70 | brokers: kafkaBootstrapServers.split(','), |
70 | - logLevel: logLevel.INFO, | ||
71 | - logCreator: KafkaJsWinstonLogCreator | ||
72 | - }); | 71 | + logLevel: logLevel.INFO, |
72 | + logCreator: KafkaJsWinstonLogCreator | ||
73 | + }; | ||
74 | + | ||
75 | + if (useConfluent) { | ||
76 | + kafkaConfig['sasl'] = { | ||
77 | + mechanism: config.get('kafka.confluent.sasl.mechanism'), | ||
78 | + username: config.get('kafka.confluent.username'), | ||
79 | + password: config.get('kafka.confluent.password') | ||
80 | + }; | ||
81 | + kafkaConfig['ssl'] = true; | ||
82 | + } | ||
83 | + | ||
84 | + kafkaClient = new Kafka(kafkaConfig); | ||
73 | 85 | ||
74 | parseTopicProperties(); | 86 | parseTopicProperties(); |
75 | 87 | ||
76 | kafkaAdmin = kafkaClient.admin(); | 88 | kafkaAdmin = kafkaClient.admin(); |
77 | await kafkaAdmin.connect(); | 89 | await kafkaAdmin.connect(); |
78 | 90 | ||
79 | - let createRequestTopicResult = await createTopic(requestTopic); | 91 | + let partitions = 1; |
92 | + | ||
93 | + for (let i = 0; i < configEntries.length; i++) { | ||
94 | + let param = configEntries[i]; | ||
95 | + if (param.name === 'partitions') { | ||
96 | + partitions = param.value; | ||
97 | + configEntries.splice(i, 1); | ||
98 | + break; | ||
99 | + } | ||
100 | + } | ||
101 | + | ||
102 | + let createRequestTopicResult = await createTopic(requestTopic, partitions); | ||
80 | 103 | ||
81 | if (createRequestTopicResult) { | 104 | if (createRequestTopicResult) { |
82 | logger.info('Created new topic: %s', requestTopic); | 105 | logger.info('Created new topic: %s', requestTopic); |
@@ -109,10 +132,11 @@ function KafkaProducer() { | @@ -109,10 +132,11 @@ function KafkaProducer() { | ||
109 | } | 132 | } |
110 | })(); | 133 | })(); |
111 | 134 | ||
112 | -function createTopic(topic) { | 135 | +function createTopic(topic, partitions) { |
113 | return kafkaAdmin.createTopics({ | 136 | return kafkaAdmin.createTopics({ |
114 | topics: [{ | 137 | topics: [{ |
115 | topic: topic, | 138 | topic: topic, |
139 | + numPartitions: partitions, | ||
116 | replicationFactor: replicationFactor, | 140 | replicationFactor: replicationFactor, |
117 | configEntries: configEntries | 141 | configEntries: configEntries |
118 | }] | 142 | }] |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>msa</artifactId> | 26 | <artifactId>msa</artifactId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>msa</artifactId> | 24 | <artifactId>msa</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa</groupId> | 26 | <groupId>org.thingsboard.msa</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>msa</artifactId> | 24 | <artifactId>msa</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa</groupId> | 26 | <groupId>org.thingsboard.msa</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.msa</groupId> | 22 | <groupId>org.thingsboard.msa</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa.transport</groupId> | 26 | <groupId>org.thingsboard.msa.transport</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.msa</groupId> | 22 | <groupId>org.thingsboard.msa</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa.transport</groupId> | 26 | <groupId>org.thingsboard.msa.transport</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard.msa</groupId> | 22 | <groupId>org.thingsboard.msa</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa.transport</groupId> | 26 | <groupId>org.thingsboard.msa.transport</groupId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>msa</artifactId> | 24 | <artifactId>msa</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa</groupId> | 26 | <groupId>org.thingsboard.msa</groupId> |
1 | { | 1 | { |
2 | "name": "thingsboard-web-ui", | 2 | "name": "thingsboard-web-ui", |
3 | "private": true, | 3 | "private": true, |
4 | - "version": "2.5.3", | 4 | + "version": "2.5.5", |
5 | "description": "ThingsBoard Web UI Microservice", | 5 | "description": "ThingsBoard Web UI Microservice", |
6 | "main": "server.js", | 6 | "main": "server.js", |
7 | "bin": "server.js", | 7 | "bin": "server.js", |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>msa</artifactId> | 24 | <artifactId>msa</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.msa</groupId> | 26 | <groupId>org.thingsboard.msa</groupId> |
@@ -19,11 +19,11 @@ | @@ -19,11 +19,11 @@ | ||
19 | <modelVersion>4.0.0</modelVersion> | 19 | <modelVersion>4.0.0</modelVersion> |
20 | <parent> | 20 | <parent> |
21 | <groupId>org.thingsboard</groupId> | 21 | <groupId>org.thingsboard</groupId> |
22 | - <version>2.5.3-SNAPSHOT</version> | 22 | + <version>2.5.5-SNAPSHOT</version> |
23 | <artifactId>thingsboard</artifactId> | 23 | <artifactId>thingsboard</artifactId> |
24 | </parent> | 24 | </parent> |
25 | <artifactId>netty-mqtt</artifactId> | 25 | <artifactId>netty-mqtt</artifactId> |
26 | - <version>2.5.3-SNAPSHOT</version> | 26 | + <version>2.5.5-SNAPSHOT</version> |
27 | <packaging>jar</packaging> | 27 | <packaging>jar</packaging> |
28 | 28 | ||
29 | <name>Netty MQTT Client</name> | 29 | <name>Netty MQTT Client</name> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <groupId>org.thingsboard</groupId> | 21 | <groupId>org.thingsboard</groupId> |
22 | <artifactId>thingsboard</artifactId> | 22 | <artifactId>thingsboard</artifactId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <packaging>pom</packaging> | 24 | <packaging>pom</packaging> |
25 | 25 | ||
26 | <name>Thingsboard</name> | 26 | <name>Thingsboard</name> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>rest-client</artifactId> | 26 | <artifactId>rest-client</artifactId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>rule-engine</artifactId> | 26 | <artifactId>rule-engine</artifactId> |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | <modelVersion>4.0.0</modelVersion> | 22 | <modelVersion>4.0.0</modelVersion> |
23 | <parent> | 23 | <parent> |
24 | <groupId>org.thingsboard</groupId> | 24 | <groupId>org.thingsboard</groupId> |
25 | - <version>2.5.3-SNAPSHOT</version> | 25 | + <version>2.5.5-SNAPSHOT</version> |
26 | <artifactId>rule-engine</artifactId> | 26 | <artifactId>rule-engine</artifactId> |
27 | </parent> | 27 | </parent> |
28 | <groupId>org.thingsboard.rule-engine</groupId> | 28 | <groupId>org.thingsboard.rule-engine</groupId> |
@@ -17,11 +17,15 @@ package org.thingsboard.rule.engine.api.util; | @@ -17,11 +17,15 @@ package org.thingsboard.rule.engine.api.util; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.core.JsonProcessingException; | 18 | import com.fasterxml.jackson.core.JsonProcessingException; |
19 | import com.fasterxml.jackson.databind.ObjectMapper; | 19 | import com.fasterxml.jackson.databind.ObjectMapper; |
20 | +import org.springframework.util.CollectionUtils; | ||
20 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; | 21 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
21 | import org.thingsboard.rule.engine.api.TbNodeException; | 22 | import org.thingsboard.rule.engine.api.TbNodeException; |
22 | import org.thingsboard.server.common.msg.TbMsgMetaData; | 23 | import org.thingsboard.server.common.msg.TbMsgMetaData; |
23 | 24 | ||
25 | +import java.util.Collections; | ||
26 | +import java.util.List; | ||
24 | import java.util.Map; | 27 | import java.util.Map; |
28 | +import java.util.stream.Collectors; | ||
25 | 29 | ||
26 | /** | 30 | /** |
27 | * Created by ashvayka on 19.01.18. | 31 | * Created by ashvayka on 19.01.18. |
@@ -41,6 +45,13 @@ public class TbNodeUtils { | @@ -41,6 +45,13 @@ public class TbNodeUtils { | ||
41 | } | 45 | } |
42 | } | 46 | } |
43 | 47 | ||
48 | + public static List<String> processPatterns(List<String> patterns, TbMsgMetaData metaData) { | ||
49 | + if (!CollectionUtils.isEmpty(patterns)) { | ||
50 | + return patterns.stream().map(p -> processPattern(p, metaData)).collect(Collectors.toList()); | ||
51 | + } | ||
52 | + return Collections.emptyList(); | ||
53 | + } | ||
54 | + | ||
44 | public static String processPattern(String pattern, TbMsgMetaData metaData) { | 55 | public static String processPattern(String pattern, TbMsgMetaData metaData) { |
45 | String result = new String(pattern); | 56 | String result = new String(pattern); |
46 | for (Map.Entry<String,String> keyVal : metaData.values().entrySet()) { | 57 | for (Map.Entry<String,String> keyVal : metaData.values().entrySet()) { |
@@ -22,7 +22,7 @@ | @@ -22,7 +22,7 @@ | ||
22 | <modelVersion>4.0.0</modelVersion> | 22 | <modelVersion>4.0.0</modelVersion> |
23 | <parent> | 23 | <parent> |
24 | <groupId>org.thingsboard</groupId> | 24 | <groupId>org.thingsboard</groupId> |
25 | - <version>2.5.3-SNAPSHOT</version> | 25 | + <version>2.5.5-SNAPSHOT</version> |
26 | <artifactId>rule-engine</artifactId> | 26 | <artifactId>rule-engine</artifactId> |
27 | </parent> | 27 | </parent> |
28 | <groupId>org.thingsboard.rule-engine</groupId> | 28 | <groupId>org.thingsboard.rule-engine</groupId> |
@@ -18,15 +18,16 @@ package org.thingsboard.rule.engine.action; | @@ -18,15 +18,16 @@ package org.thingsboard.rule.engine.action; | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import com.google.common.util.concurrent.Futures; | 19 | import com.google.common.util.concurrent.Futures; |
20 | import com.google.common.util.concurrent.ListenableFuture; | 20 | import com.google.common.util.concurrent.ListenableFuture; |
21 | -import com.google.common.util.concurrent.MoreExecutors; | ||
22 | import lombok.extern.slf4j.Slf4j; | 21 | import lombok.extern.slf4j.Slf4j; |
23 | import org.thingsboard.rule.engine.api.RuleNode; | 22 | import org.thingsboard.rule.engine.api.RuleNode; |
24 | import org.thingsboard.rule.engine.api.TbContext; | 23 | import org.thingsboard.rule.engine.api.TbContext; |
25 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; | 24 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
26 | import org.thingsboard.rule.engine.api.TbNodeException; | 25 | import org.thingsboard.rule.engine.api.TbNodeException; |
27 | import org.thingsboard.rule.engine.api.util.TbNodeUtils; | 26 | import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
27 | +import org.thingsboard.server.common.data.EntityType; | ||
28 | import org.thingsboard.server.common.data.alarm.Alarm; | 28 | import org.thingsboard.server.common.data.alarm.Alarm; |
29 | import org.thingsboard.server.common.data.alarm.AlarmStatus; | 29 | import org.thingsboard.server.common.data.alarm.AlarmStatus; |
30 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
30 | import org.thingsboard.server.common.data.plugin.ComponentType; | 31 | import org.thingsboard.server.common.data.plugin.ComponentType; |
31 | import org.thingsboard.server.common.data.rule.RuleChainType; | 32 | import org.thingsboard.server.common.data.rule.RuleChainType; |
32 | import org.thingsboard.server.common.msg.TbMsg; | 33 | import org.thingsboard.server.common.msg.TbMsg; |
@@ -56,8 +57,13 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig | @@ -56,8 +57,13 @@ public class TbClearAlarmNode extends TbAbstractAlarmNode<TbClearAlarmNodeConfig | ||
56 | @Override | 57 | @Override |
57 | protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) { | 58 | protected ListenableFuture<AlarmResult> processAlarm(TbContext ctx, TbMsg msg) { |
58 | String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData()); | 59 | String alarmType = TbNodeUtils.processPattern(this.config.getAlarmType(), msg.getMetaData()); |
59 | - ListenableFuture<Alarm> latest = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), alarmType); | ||
60 | - return Futures.transformAsync(latest, a -> { | 60 | + ListenableFuture<Alarm> alarmFuture; |
61 | + if (msg.getOriginator().getEntityType().equals(EntityType.ALARM)) { | ||
62 | + alarmFuture = ctx.getAlarmService().findAlarmByIdAsync(ctx.getTenantId(), new AlarmId(msg.getOriginator().getId())); | ||
63 | + } else { | ||
64 | + alarmFuture = ctx.getAlarmService().findLatestByOriginatorAndType(ctx.getTenantId(), msg.getOriginator(), alarmType); | ||
65 | + } | ||
66 | + return Futures.transformAsync(alarmFuture, a -> { | ||
61 | if (a != null && !a.getStatus().isCleared()) { | 67 | if (a != null && !a.getStatus().isCleared()) { |
62 | return clearAlarm(ctx, msg, a); | 68 | return clearAlarm(ctx, msg, a); |
63 | } | 69 | } |
@@ -16,8 +16,13 @@ | @@ -16,8 +16,13 @@ | ||
16 | package org.thingsboard.rule.engine.filter; | 16 | package org.thingsboard.rule.engine.filter; |
17 | 17 | ||
18 | import lombok.extern.slf4j.Slf4j; | 18 | import lombok.extern.slf4j.Slf4j; |
19 | +import org.thingsboard.rule.engine.api.EmptyNodeConfiguration; | ||
20 | +import org.thingsboard.rule.engine.api.RuleNode; | ||
21 | +import org.thingsboard.rule.engine.api.TbContext; | ||
22 | +import org.thingsboard.rule.engine.api.TbNode; | ||
23 | +import org.thingsboard.rule.engine.api.TbNodeConfiguration; | ||
24 | +import org.thingsboard.rule.engine.api.TbNodeException; | ||
19 | import org.thingsboard.rule.engine.api.util.TbNodeUtils; | 25 | import org.thingsboard.rule.engine.api.util.TbNodeUtils; |
20 | -import org.thingsboard.rule.engine.api.*; | ||
21 | import org.thingsboard.server.common.data.DataConstants; | 26 | import org.thingsboard.server.common.data.DataConstants; |
22 | import org.thingsboard.server.common.data.plugin.ComponentType; | 27 | import org.thingsboard.server.common.data.plugin.ComponentType; |
23 | import org.thingsboard.server.common.data.rule.RuleChainType; | 28 | import org.thingsboard.server.common.data.rule.RuleChainType; |
@@ -31,7 +36,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | @@ -31,7 +36,7 @@ import org.thingsboard.server.common.msg.session.SessionMsgType; | ||
31 | configClazz = EmptyNodeConfiguration.class, | 36 | configClazz = EmptyNodeConfiguration.class, |
32 | relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", | 37 | relationTypes = {"Post attributes", "Post telemetry", "RPC Request from Device", "RPC Request to Device", "Activity Event", "Inactivity Event", |
33 | "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", | 38 | "Connect Event", "Disconnect Event", "Entity Created", "Entity Updated", "Entity Deleted", "Entity Assigned", |
34 | - "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other"}, | 39 | + "Entity Unassigned", "Attributes Updated", "Attributes Deleted", "Alarm Acknowledged", "Alarm Cleared", "Other", "Entity Assigned From Tenant", "Entity Assigned To Tenant"}, |
35 | nodeDescription = "Route incoming messages by Message Type", | 40 | nodeDescription = "Route incoming messages by Message Type", |
36 | nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", | 41 | nodeDetails = "Sends messages with message types <b>\"Post attributes\", \"Post telemetry\", \"RPC Request\"</b> etc. via corresponding chain, otherwise <b>Other</b> chain is used.", |
37 | uiResources = {"static/rulenode/rulenode-core-config.js"}, | 42 | uiResources = {"static/rulenode/rulenode-core-config.js"}, |
@@ -83,6 +88,10 @@ public class TbMsgTypeSwitchNode implements TbNode { | @@ -83,6 +88,10 @@ public class TbMsgTypeSwitchNode implements TbNode { | ||
83 | relationType = "Alarm Cleared"; | 88 | relationType = "Alarm Cleared"; |
84 | } else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) { | 89 | } else if (msg.getType().equals(DataConstants.RPC_CALL_FROM_SERVER_TO_DEVICE)) { |
85 | relationType = "RPC Request to Device"; | 90 | relationType = "RPC Request to Device"; |
91 | + } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_FROM_TENANT)) { | ||
92 | + relationType = "Entity Assigned From Tenant"; | ||
93 | + } else if (msg.getType().equals(DataConstants.ENTITY_ASSIGNED_TO_TENANT)) { | ||
94 | + relationType = "Entity Assigned To Tenant"; | ||
86 | } else { | 95 | } else { |
87 | relationType = "Other"; | 96 | relationType = "Other"; |
88 | } | 97 | } |
@@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbContext; | @@ -29,6 +29,7 @@ import org.thingsboard.rule.engine.api.TbContext; | ||
29 | import org.thingsboard.rule.engine.api.TbNode; | 29 | import org.thingsboard.rule.engine.api.TbNode; |
30 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; | 30 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
31 | import org.thingsboard.rule.engine.api.TbNodeException; | 31 | import org.thingsboard.rule.engine.api.TbNodeException; |
32 | +import org.thingsboard.rule.engine.api.util.TbNodeUtils; | ||
32 | import org.thingsboard.server.common.data.id.EntityId; | 33 | import org.thingsboard.server.common.data.id.EntityId; |
33 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; | 34 | import org.thingsboard.server.common.data.kv.AttributeKvEntry; |
34 | import org.thingsboard.server.common.data.kv.KvEntry; | 35 | import org.thingsboard.server.common.data.kv.KvEntry; |
@@ -91,10 +92,10 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC | @@ -91,10 +92,10 @@ public abstract class TbAbstractGetAttributesNode<C extends TbGetAttributesNodeC | ||
91 | } | 92 | } |
92 | ConcurrentHashMap<String, List<String>> failuresMap = new ConcurrentHashMap<>(); | 93 | ConcurrentHashMap<String, List<String>> failuresMap = new ConcurrentHashMap<>(); |
93 | ListenableFuture<List<Void>> allFutures = Futures.allAsList( | 94 | ListenableFuture<List<Void>> allFutures = Futures.allAsList( |
94 | - putLatestTelemetry(ctx, entityId, msg, LATEST_TS, config.getLatestTsKeyNames(), failuresMap), | ||
95 | - putAttrAsync(ctx, entityId, msg, CLIENT_SCOPE, config.getClientAttributeNames(), failuresMap, "cs_"), | ||
96 | - putAttrAsync(ctx, entityId, msg, SHARED_SCOPE, config.getSharedAttributeNames(), failuresMap, "shared_"), | ||
97 | - putAttrAsync(ctx, entityId, msg, SERVER_SCOPE, config.getServerAttributeNames(), failuresMap, "ss_") | 95 | + putLatestTelemetry(ctx, entityId, msg, LATEST_TS, TbNodeUtils.processPatterns(config.getLatestTsKeyNames(), msg.getMetaData()), failuresMap), |
96 | + putAttrAsync(ctx, entityId, msg, CLIENT_SCOPE, TbNodeUtils.processPatterns(config.getClientAttributeNames(), msg.getMetaData()), failuresMap, "cs_"), | ||
97 | + putAttrAsync(ctx, entityId, msg, SHARED_SCOPE, TbNodeUtils.processPatterns(config.getSharedAttributeNames(), msg.getMetaData()), failuresMap, "shared_"), | ||
98 | + putAttrAsync(ctx, entityId, msg, SERVER_SCOPE, TbNodeUtils.processPatterns(config.getServerAttributeNames(), msg.getMetaData()), failuresMap, "ss_") | ||
98 | ); | 99 | ); |
99 | withCallback(allFutures, i -> { | 100 | withCallback(allFutures, i -> { |
100 | if (!failuresMap.isEmpty()) { | 101 | if (!failuresMap.isEmpty()) { |
@@ -105,9 +105,10 @@ public class TbGetTelemetryNode implements TbNode { | @@ -105,9 +105,10 @@ public class TbGetTelemetryNode implements TbNode { | ||
105 | if (config.isUseMetadataIntervalPatterns()) { | 105 | if (config.isUseMetadataIntervalPatterns()) { |
106 | checkMetadataKeyPatterns(msg); | 106 | checkMetadataKeyPatterns(msg); |
107 | } | 107 | } |
108 | - ListenableFuture<List<TsKvEntry>> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(msg)); | 108 | + List<String> keys = TbNodeUtils.processPatterns(tsKeyNames, msg.getMetaData()); |
109 | + ListenableFuture<List<TsKvEntry>> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(msg, keys)); | ||
109 | DonAsynchron.withCallback(list, data -> { | 110 | DonAsynchron.withCallback(list, data -> { |
110 | - process(data, msg); | 111 | + process(data, msg, keys); |
111 | ctx.tellSuccess(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), msg.getData())); | 112 | ctx.tellSuccess(ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), msg.getData())); |
112 | }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); | 113 | }, error -> ctx.tellFailure(msg, error), ctx.getDbCallbackExecutor()); |
113 | } catch (Exception e) { | 114 | } catch (Exception e) { |
@@ -120,8 +121,8 @@ public class TbGetTelemetryNode implements TbNode { | @@ -120,8 +121,8 @@ public class TbGetTelemetryNode implements TbNode { | ||
120 | public void destroy() { | 121 | public void destroy() { |
121 | } | 122 | } |
122 | 123 | ||
123 | - private List<ReadTsKvQuery> buildQueries(TbMsg msg) { | ||
124 | - return tsKeyNames.stream() | 124 | + private List<ReadTsKvQuery> buildQueries(TbMsg msg, List<String> keys) { |
125 | + return keys.stream() | ||
125 | .map(key -> new BaseReadTsKvQuery(key, getInterval(msg).getStartTs(), getInterval(msg).getEndTs(), 1, limit, NONE, getOrderBy())) | 126 | .map(key -> new BaseReadTsKvQuery(key, getInterval(msg).getStartTs(), getInterval(msg).getEndTs(), 1, limit, NONE, getOrderBy())) |
126 | .collect(Collectors.toList()); | 127 | .collect(Collectors.toList()); |
127 | } | 128 | } |
@@ -137,7 +138,7 @@ public class TbGetTelemetryNode implements TbNode { | @@ -137,7 +138,7 @@ public class TbGetTelemetryNode implements TbNode { | ||
137 | } | 138 | } |
138 | } | 139 | } |
139 | 140 | ||
140 | - private void process(List<TsKvEntry> entries, TbMsg msg) { | 141 | + private void process(List<TsKvEntry> entries, TbMsg msg, List<String> keys) { |
141 | ObjectNode resultNode = mapper.createObjectNode(); | 142 | ObjectNode resultNode = mapper.createObjectNode(); |
142 | if (FETCH_MODE_ALL.equals(fetchMode)) { | 143 | if (FETCH_MODE_ALL.equals(fetchMode)) { |
143 | entries.forEach(entry -> processArray(resultNode, entry)); | 144 | entries.forEach(entry -> processArray(resultNode, entry)); |
@@ -145,7 +146,7 @@ public class TbGetTelemetryNode implements TbNode { | @@ -145,7 +146,7 @@ public class TbGetTelemetryNode implements TbNode { | ||
145 | entries.forEach(entry -> processSingle(resultNode, entry)); | 146 | entries.forEach(entry -> processSingle(resultNode, entry)); |
146 | } | 147 | } |
147 | 148 | ||
148 | - for (String key : tsKeyNames) { | 149 | + for (String key : keys) { |
149 | if (resultNode.has(key)) { | 150 | if (resultNode.has(key)) { |
150 | msg.getMetaData().putValue(key, resultNode.get(key).toString()); | 151 | msg.getMetaData().putValue(key, resultNode.get(key).toString()); |
151 | } | 152 | } |
@@ -35,6 +35,7 @@ import org.thingsboard.rule.engine.api.TbContext; | @@ -35,6 +35,7 @@ import org.thingsboard.rule.engine.api.TbContext; | ||
35 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; | 35 | import org.thingsboard.rule.engine.api.TbNodeConfiguration; |
36 | import org.thingsboard.rule.engine.api.TbNodeException; | 36 | import org.thingsboard.rule.engine.api.TbNodeException; |
37 | import org.thingsboard.server.common.data.alarm.Alarm; | 37 | import org.thingsboard.server.common.data.alarm.Alarm; |
38 | +import org.thingsboard.server.common.data.id.AlarmId; | ||
38 | import org.thingsboard.server.common.data.id.DeviceId; | 39 | import org.thingsboard.server.common.data.id.DeviceId; |
39 | import org.thingsboard.server.common.data.id.EntityId; | 40 | import org.thingsboard.server.common.data.id.EntityId; |
40 | import org.thingsboard.server.common.data.id.RuleChainId; | 41 | import org.thingsboard.server.common.data.id.RuleChainId; |
@@ -95,6 +96,7 @@ public class TbAlarmNodeTest { | @@ -95,6 +96,7 @@ public class TbAlarmNodeTest { | ||
95 | private ListeningExecutor dbExecutor; | 96 | private ListeningExecutor dbExecutor; |
96 | 97 | ||
97 | private EntityId originator = new DeviceId(UUIDs.timeBased()); | 98 | private EntityId originator = new DeviceId(UUIDs.timeBased()); |
99 | + private EntityId alarmOriginator = new AlarmId(UUIDs.timeBased()); | ||
98 | private TenantId tenantId = new TenantId(UUIDs.timeBased()); | 100 | private TenantId tenantId = new TenantId(UUIDs.timeBased()); |
99 | private TbMsgMetaData metaData = new TbMsgMetaData(); | 101 | private TbMsgMetaData metaData = new TbMsgMetaData(); |
100 | private String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; | 102 | private String rawJson = "{\"name\": \"Vit\", \"passed\": 5}"; |
@@ -325,6 +327,55 @@ public class TbAlarmNodeTest { | @@ -325,6 +327,55 @@ public class TbAlarmNodeTest { | ||
325 | assertEquals(expectedAlarm, actualAlarm); | 327 | assertEquals(expectedAlarm, actualAlarm); |
326 | } | 328 | } |
327 | 329 | ||
330 | + @Test | ||
331 | + public void alarmCanBeClearedWithAlarmOriginator() throws ScriptException, IOException { | ||
332 | + initWithClearAlarmScript(); | ||
333 | + metaData.putValue("key", "value"); | ||
334 | + TbMsg msg = TbMsg.newMsg( "USER", alarmOriginator, metaData, TbMsgDataType.JSON, rawJson, ruleChainId, ruleNodeId); | ||
335 | + | ||
336 | + long oldEndDate = System.currentTimeMillis(); | ||
337 | + AlarmId id = new AlarmId(alarmOriginator.getId()); | ||
338 | + Alarm activeAlarm = Alarm.builder().type("SomeType").tenantId(tenantId).originator(originator).status(ACTIVE_UNACK).severity(WARNING).endTs(oldEndDate).build(); | ||
339 | + activeAlarm.setId(id); | ||
340 | + | ||
341 | + when(detailsJs.executeJsonAsync(msg)).thenReturn(Futures.immediateFuture(null)); | ||
342 | + when(alarmService.findAlarmByIdAsync(tenantId, id)).thenReturn(Futures.immediateFuture(activeAlarm)); | ||
343 | + when(alarmService.clearAlarm(eq(activeAlarm.getTenantId()), eq(activeAlarm.getId()), org.mockito.Mockito.any(JsonNode.class), anyLong())).thenReturn(Futures.immediateFuture(true)); | ||
344 | +// doAnswer((Answer<Alarm>) invocationOnMock -> (Alarm) (invocationOnMock.getArguments())[0]).when(alarmService).createOrUpdateAlarm(activeAlarm); | ||
345 | + | ||
346 | + node.onMsg(ctx, msg); | ||
347 | + | ||
348 | + verify(ctx).tellNext(any(), eq("Cleared")); | ||
349 | + | ||
350 | + ArgumentCaptor<TbMsg> msgCaptor = ArgumentCaptor.forClass(TbMsg.class); | ||
351 | + ArgumentCaptor<String> typeCaptor = ArgumentCaptor.forClass(String.class); | ||
352 | + ArgumentCaptor<EntityId> originatorCaptor = ArgumentCaptor.forClass(EntityId.class); | ||
353 | + ArgumentCaptor<TbMsgMetaData> metadataCaptor = ArgumentCaptor.forClass(TbMsgMetaData.class); | ||
354 | + ArgumentCaptor<String> dataCaptor = ArgumentCaptor.forClass(String.class); | ||
355 | + verify(ctx).transformMsg(msgCaptor.capture(), typeCaptor.capture(), originatorCaptor.capture(), metadataCaptor.capture(), dataCaptor.capture()); | ||
356 | + | ||
357 | + assertEquals("ALARM", typeCaptor.getValue()); | ||
358 | + assertEquals(alarmOriginator, originatorCaptor.getValue()); | ||
359 | + assertEquals("value", metadataCaptor.getValue().getValue("key")); | ||
360 | + assertEquals(Boolean.TRUE.toString(), metadataCaptor.getValue().getValue(IS_CLEARED_ALARM)); | ||
361 | + assertNotSame(metaData, metadataCaptor.getValue()); | ||
362 | + | ||
363 | + Alarm actualAlarm = new ObjectMapper().readValue(dataCaptor.getValue().getBytes(), Alarm.class); | ||
364 | + Alarm expectedAlarm = Alarm.builder() | ||
365 | + .tenantId(tenantId) | ||
366 | + .originator(originator) | ||
367 | + .status(CLEARED_UNACK) | ||
368 | + .severity(WARNING) | ||
369 | + .propagate(false) | ||
370 | + .type("SomeType") | ||
371 | + .details(null) | ||
372 | + .endTs(oldEndDate) | ||
373 | + .build(); | ||
374 | + expectedAlarm.setId(id); | ||
375 | + | ||
376 | + assertEquals(expectedAlarm, actualAlarm); | ||
377 | + } | ||
378 | + | ||
328 | private void initWithCreateAlarmScript() { | 379 | private void initWithCreateAlarmScript() { |
329 | try { | 380 | try { |
330 | TbCreateAlarmNodeConfiguration config = new TbCreateAlarmNodeConfiguration(); | 381 | TbCreateAlarmNodeConfiguration config = new TbCreateAlarmNodeConfiguration(); |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>tools</artifactId> | 26 | <artifactId>tools</artifactId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.transport</groupId> | 26 | <groupId>org.thingsboard.transport</groupId> |
@@ -69,13 +69,21 @@ queue: | @@ -69,13 +69,21 @@ queue: | ||
69 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" | 69 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" |
70 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" | 70 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" |
71 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" | 71 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" |
72 | + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" | ||
73 | + confluent: | ||
74 | + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" | ||
75 | + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" | ||
76 | + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" | ||
77 | + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" | ||
78 | + other: | ||
72 | topic-properties: | 79 | topic-properties: |
73 | - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
74 | - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
75 | - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
76 | - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
77 | - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}" | 80 | + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
81 | + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
82 | + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
83 | + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
84 | + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" | ||
78 | aws_sqs: | 85 | aws_sqs: |
86 | + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" | ||
79 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" | 87 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" |
80 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" | 88 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" |
81 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" | 89 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.transport</groupId> | 26 | <groupId>org.thingsboard.transport</groupId> |
@@ -62,13 +62,21 @@ queue: | @@ -62,13 +62,21 @@ queue: | ||
62 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" | 62 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" |
63 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" | 63 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" |
64 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" | 64 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" |
65 | + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" | ||
66 | + confluent: | ||
67 | + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" | ||
68 | + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" | ||
69 | + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" | ||
70 | + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" | ||
71 | + other: | ||
65 | topic-properties: | 72 | topic-properties: |
66 | - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
67 | - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
68 | - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
69 | - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
70 | - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}" | 73 | + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
74 | + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
75 | + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
76 | + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
77 | + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" | ||
71 | aws_sqs: | 78 | aws_sqs: |
79 | + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" | ||
72 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" | 80 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" |
73 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" | 81 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" |
74 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" | 82 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>transport</artifactId> | 24 | <artifactId>transport</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard.transport</groupId> | 26 | <groupId>org.thingsboard.transport</groupId> |
@@ -90,13 +90,21 @@ queue: | @@ -90,13 +90,21 @@ queue: | ||
90 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" | 90 | linger.ms: "${TB_KAFKA_LINGER_MS:1}" |
91 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" | 91 | buffer.memory: "${TB_BUFFER_MEMORY:33554432}" |
92 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" | 92 | replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" |
93 | + use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" | ||
94 | + confluent: | ||
95 | + ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" | ||
96 | + sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" | ||
97 | + sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" | ||
98 | + security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" | ||
99 | + other: | ||
93 | topic-properties: | 100 | topic-properties: |
94 | - rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
95 | - core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
96 | - transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
97 | - notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000}" | ||
98 | - js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600}" | 101 | + rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" |
102 | + core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
103 | + transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
104 | + notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1}" | ||
105 | + js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100}" | ||
99 | aws_sqs: | 106 | aws_sqs: |
107 | + use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" | ||
100 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" | 108 | access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" |
101 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" | 109 | secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" |
102 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" | 110 | region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <artifactId>transport</artifactId> | 26 | <artifactId>transport</artifactId> |
@@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
20 | <modelVersion>4.0.0</modelVersion> | 20 | <modelVersion>4.0.0</modelVersion> |
21 | <parent> | 21 | <parent> |
22 | <groupId>org.thingsboard</groupId> | 22 | <groupId>org.thingsboard</groupId> |
23 | - <version>2.5.3-SNAPSHOT</version> | 23 | + <version>2.5.5-SNAPSHOT</version> |
24 | <artifactId>thingsboard</artifactId> | 24 | <artifactId>thingsboard</artifactId> |
25 | </parent> | 25 | </parent> |
26 | <groupId>org.thingsboard</groupId> | 26 | <groupId>org.thingsboard</groupId> |
@@ -123,16 +123,16 @@ | @@ -123,16 +123,16 @@ | ||
123 | </md-input-container> | 123 | </md-input-container> |
124 | <md-input-container class="md-block"> | 124 | <md-input-container class="md-block"> |
125 | <label translate>admin.proxy-password</label> | 125 | <label translate>admin.proxy-password</label> |
126 | - <input name="proxyPassword" ng-model="vm.settings.jsonValue.proxyPassword"> | 126 | + <input name="proxyPassword" type="password" autocomplete="new-password" ng-model="vm.settings.jsonValue.proxyPassword"> |
127 | </md-input-container> | 127 | </md-input-container> |
128 | </section> | 128 | </section> |
129 | <md-input-container class="md-block"> | 129 | <md-input-container class="md-block"> |
130 | <label translate>common.username</label> | 130 | <label translate>common.username</label> |
131 | - <input name="username" placeholder="{{ 'common.enter-username' | translate }}" ng-model="vm.settings.jsonValue.username"> | 131 | + <input placeholder="{{ 'common.enter-username' | translate }}" ng-model="vm.settings.jsonValue.username" autocomplete="new-username" > |
132 | </md-input-container> | 132 | </md-input-container> |
133 | <md-input-container class="md-block"> | 133 | <md-input-container class="md-block"> |
134 | <label translate>common.password</label> | 134 | <label translate>common.password</label> |
135 | - <input name="password" placeholder="{{ 'common.enter-password' | translate }}" type="password" ng-model="vm.settings.jsonValue.password"> | 135 | + <input placeholder="{{ 'common.enter-password' | translate }}" type="password" ng-model="vm.settings.jsonValue.password" autocomplete="new-password"> |
136 | </md-input-container> | 136 | </md-input-container> |
137 | <div layout="row" layout-align="end center" width="100%" layout-wrap> | 137 | <div layout="row" layout-align="end center" width="100%" layout-wrap> |
138 | <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid" ng-click="vm.sendTestMail()" class="md-raised">{{'admin.send-test-mail' | translate}}</md-button> | 138 | <md-button ng-disabled="$root.loading || vm.settingsForm.$invalid" ng-click="vm.sendTestMail()" class="md-raised">{{'admin.send-test-mail' | translate}}</md-button> |
@@ -228,7 +228,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | @@ -228,7 +228,7 @@ function AttributeService($http, $q, $filter, types, telemetryWebsocketService) | ||
228 | } | 228 | } |
229 | var deleteEntityAttributesPromise; | 229 | var deleteEntityAttributesPromise; |
230 | if (deleteAttributes.length) { | 230 | if (deleteAttributes.length) { |
231 | - deleteEntityAttributesPromise = deleteEntityAttributes(entityType, entityId, attributeScope, deleteAttributes); | 231 | + deleteEntityAttributesPromise = deleteEntityAttributes(entityType, entityId, attributeScope, deleteAttributes, config); |
232 | } | 232 | } |
233 | if (Object.keys(attributesData).length) { | 233 | if (Object.keys(attributesData).length) { |
234 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope; | 234 | var url = '/api/plugins/telemetry/' + entityType + '/' + entityId + '/' + attributeScope; |
@@ -223,6 +223,12 @@ export default angular.module('thingsboard.types', []) | @@ -223,6 +223,12 @@ export default angular.module('thingsboard.types', []) | ||
223 | "LOCKOUT": { | 223 | "LOCKOUT": { |
224 | name: "audit-log.type-lockout" | 224 | name: "audit-log.type-lockout" |
225 | }, | 225 | }, |
226 | + "ASSIGNED_FROM_TENANT": { | ||
227 | + name: "audit-log.type-assigned-from-tenant" | ||
228 | + }, | ||
229 | + "ASSIGNED_TO_TENANT": { | ||
230 | + name: "audit-log.type-assigned-to-tenant" | ||
231 | + }, | ||
226 | "ASSIGNED_TO_EDGE": { | 232 | "ASSIGNED_TO_EDGE": { |
227 | name: "audit-log.type-assigned-to-edge" | 233 | name: "audit-log.type-assigned-to-edge" |
228 | }, | 234 | }, |
@@ -150,7 +150,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t | @@ -150,7 +150,8 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t | ||
150 | customTranslation: customTranslation, | 150 | customTranslation: customTranslation, |
151 | objToBase64: objToBase64, | 151 | objToBase64: objToBase64, |
152 | base64toObj: base64toObj, | 152 | base64toObj: base64toObj, |
153 | - loadImageAspect: loadImageAspect | 153 | + loadImageAspect: loadImageAspect, |
154 | + sortObjectKeys: sortObjectKeys | ||
154 | } | 155 | } |
155 | 156 | ||
156 | return service; | 157 | return service; |
@@ -605,4 +606,14 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t | @@ -605,4 +606,14 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t | ||
605 | return deferred.promise; | 606 | return deferred.promise; |
606 | } | 607 | } |
607 | 608 | ||
609 | + function sortObjectKeys(obj) { | ||
610 | + var sortedObj = {}; | ||
611 | + var keys = Object.keys(obj).sort(); | ||
612 | + for (var i = 0; i < keys.length; i++) { | ||
613 | + var key = keys[i]; | ||
614 | + sortedObj[key] = obj[key]; | ||
615 | + } | ||
616 | + return sortedObj; | ||
617 | + } | ||
618 | + | ||
608 | } | 619 | } |
@@ -27,7 +27,7 @@ import eventRowEdgeEventTemplate from './event-row-edge-event.tpl.html'; | @@ -27,7 +27,7 @@ import eventRowEdgeEventTemplate from './event-row-edge-event.tpl.html'; | ||
27 | 27 | ||
28 | /*@ngInject*/ | 28 | /*@ngInject*/ |
29 | export default function EventRowDirective($compile, $templateCache, $mdDialog, $document, $translate, | 29 | export default function EventRowDirective($compile, $templateCache, $mdDialog, $document, $translate, |
30 | - types, toast, entityService, ruleChainService) { | 30 | + types, utils, toast, entityService, ruleChainService) { |
31 | 31 | ||
32 | var linker = function (scope, element, attrs) { | 32 | var linker = function (scope, element, attrs) { |
33 | 33 | ||
@@ -76,11 +76,18 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | @@ -76,11 +76,18 @@ export default function EventRowDirective($compile, $templateCache, $mdDialog, $ | ||
76 | if (!contentType) { | 76 | if (!contentType) { |
77 | contentType = null; | 77 | contentType = null; |
78 | } | 78 | } |
79 | + var sortedContent; | ||
80 | + try { | ||
81 | + sortedContent = angular.toJson(utils.sortObjectKeys(angular.fromJson(content))); | ||
82 | + } | ||
83 | + catch(err) { | ||
84 | + sortedContent = content; | ||
85 | + } | ||
79 | $mdDialog.show({ | 86 | $mdDialog.show({ |
80 | controller: 'EventContentDialogController', | 87 | controller: 'EventContentDialogController', |
81 | controllerAs: 'vm', | 88 | controllerAs: 'vm', |
82 | templateUrl: eventErrorDialogTemplate, | 89 | templateUrl: eventErrorDialogTemplate, |
83 | - locals: {content: content, title: title, contentType: contentType, showingCallback: onShowingCallback}, | 90 | + locals: {content: sortedContent, title: title, contentType: contentType, showingCallback: onShowingCallback}, |
84 | parent: angular.element($document[0].body), | 91 | parent: angular.element($document[0].body), |
85 | fullscreen: true, | 92 | fullscreen: true, |
86 | targetEvent: $event, | 93 | targetEvent: $event, |
@@ -44,6 +44,7 @@ var ruleNodeClazzHelpLinkMap = { | @@ -44,6 +44,7 @@ var ruleNodeClazzHelpLinkMap = { | ||
44 | 'org.thingsboard.rule.engine.aws.sqs.TbSqsNode': 'ruleNodeAwsSqs', | 44 | 'org.thingsboard.rule.engine.aws.sqs.TbSqsNode': 'ruleNodeAwsSqs', |
45 | 'org.thingsboard.rule.engine.kafka.TbKafkaNode': 'ruleNodeKafka', | 45 | 'org.thingsboard.rule.engine.kafka.TbKafkaNode': 'ruleNodeKafka', |
46 | 'org.thingsboard.rule.engine.mqtt.TbMqttNode': 'ruleNodeMqtt', | 46 | 'org.thingsboard.rule.engine.mqtt.TbMqttNode': 'ruleNodeMqtt', |
47 | + 'org.thingsboard.rule.engine.mqtt.azure.TbAzureIotHubNode': 'ruleNodeAzureIotHub', | ||
47 | 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode': 'ruleNodeRabbitMq', | 48 | 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode': 'ruleNodeRabbitMq', |
48 | 'org.thingsboard.rule.engine.rest.TbRestApiCallNode': 'ruleNodeRestApiCall', | 49 | 'org.thingsboard.rule.engine.rest.TbRestApiCallNode': 'ruleNodeRestApiCall', |
49 | 'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail' | 50 | 'org.thingsboard.rule.engine.mail.TbSendEmailNode': 'ruleNodeSendEmail' |
@@ -88,6 +89,7 @@ export default angular.module('thingsboard.help', []) | @@ -88,6 +89,7 @@ export default angular.module('thingsboard.help', []) | ||
88 | ruleNodeAwsSqs: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sqs-node", | 89 | ruleNodeAwsSqs: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#aws-sqs-node", |
89 | ruleNodeKafka: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#kafka-node", | 90 | ruleNodeKafka: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#kafka-node", |
90 | ruleNodeMqtt: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#mqtt-node", | 91 | ruleNodeMqtt: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#mqtt-node", |
92 | + ruleNodeAzureIotHub: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#azure-iot-hub-node", | ||
91 | ruleNodeRabbitMq: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#rabbitmq-node", | 93 | ruleNodeRabbitMq: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#rabbitmq-node", |
92 | ruleNodeRestApiCall: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node", | 94 | ruleNodeRestApiCall: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#rest-api-call-node", |
93 | ruleNodeSendEmail: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node", | 95 | ruleNodeSendEmail: helpBaseUrl + "/docs/user-guide/rule-engine-2-0/external-nodes/#send-email-node", |
@@ -373,7 +373,9 @@ | @@ -373,7 +373,9 @@ | ||
373 | "action-data": "Action data", | 373 | "action-data": "Action data", |
374 | "failure-details": "Failure details", | 374 | "failure-details": "Failure details", |
375 | "search": "Search audit logs", | 375 | "search": "Search audit logs", |
376 | - "clear-search": "Clear search" | 376 | + "clear-search": "Clear search", |
377 | + "type-assigned-from-tenant": "Assigned from Tenant", | ||
378 | + "type-assigned-to-tenant": "Assigned to Tenant" | ||
377 | }, | 379 | }, |
378 | "confirm-on-exit": { | 380 | "confirm-on-exit": { |
379 | "message": "You have unsaved changes. Are you sure you want to leave this page?", | 381 | "message": "You have unsaved changes. Are you sure you want to leave this page?", |
@@ -20,7 +20,7 @@ import nodeScriptTestTemplate from './node-script-test.tpl.html'; | @@ -20,7 +20,7 @@ import nodeScriptTestTemplate from './node-script-test.tpl.html'; | ||
20 | /* eslint-enable import/no-unresolved, import/default */ | 20 | /* eslint-enable import/no-unresolved, import/default */ |
21 | 21 | ||
22 | /*@ngInject*/ | 22 | /*@ngInject*/ |
23 | -export default function NodeScriptTest($q, $mdDialog, $document, ruleChainService) { | 23 | +export default function NodeScriptTest($q, $mdDialog, $document, ruleChainService, utils) { |
24 | 24 | ||
25 | var service = { | 25 | var service = { |
26 | testNodeScript: testNodeScript | 26 | testNodeScript: testNodeScript |
@@ -89,6 +89,8 @@ export default function NodeScriptTest($q, $mdDialog, $document, ruleChainServic | @@ -89,6 +89,8 @@ export default function NodeScriptTest($q, $mdDialog, $document, ruleChainServic | ||
89 | deviceName: "Test Device", | 89 | deviceName: "Test Device", |
90 | ts: new Date().getTime() + "" | 90 | ts: new Date().getTime() + "" |
91 | }; | 91 | }; |
92 | + } else { | ||
93 | + metadata = utils.sortObjectKeys(metadata); | ||
92 | } | 94 | } |
93 | if (!msgType) { | 95 | if (!msgType) { |
94 | msgType = "POST_TELEMETRY_REQUEST"; | 96 | msgType = "POST_TELEMETRY_REQUEST"; |