Commit e583b0a1d3c07bed59ac80fd0e8c2ce3186cef5f
Committed by
Andrew Shvayka
1 parent
7d0661a8
Feature/rest client (#2347)
* refactored URLs * refactored * refactored * refactored * refactored * refactored rest client * changed executorService from RestClient * refactored rest client and JsonConverter
Showing
2 changed files
with
258 additions
and
138 deletions
... | ... | @@ -31,7 +31,7 @@ import org.springframework.http.client.support.HttpRequestWrapper; |
31 | 31 | import org.springframework.util.StringUtils; |
32 | 32 | import org.springframework.web.client.HttpClientErrorException; |
33 | 33 | import org.springframework.web.client.RestTemplate; |
34 | -import org.springframework.web.context.request.async.DeferredResult; | |
34 | +import org.thingsboard.client.tools.utils.RestJsonConverter; | |
35 | 35 | import org.thingsboard.server.common.data.AdminSettings; |
36 | 36 | import org.thingsboard.server.common.data.ClaimRequest; |
37 | 37 | import org.thingsboard.server.common.data.Customer; |
... | ... | @@ -57,6 +57,8 @@ import org.thingsboard.server.common.data.id.CustomerId; |
57 | 57 | import org.thingsboard.server.common.data.id.DashboardId; |
58 | 58 | import org.thingsboard.server.common.data.id.DeviceId; |
59 | 59 | import org.thingsboard.server.common.data.id.EntityId; |
60 | +import org.thingsboard.server.common.data.kv.AttributeKvEntry; | |
61 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | |
60 | 62 | import org.thingsboard.server.common.data.page.TextPageData; |
61 | 63 | import org.thingsboard.server.common.data.page.TextPageLink; |
62 | 64 | import org.thingsboard.server.common.data.page.TimePageData; |
... | ... | @@ -74,6 +76,7 @@ import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; |
74 | 76 | import org.thingsboard.server.common.data.widget.WidgetType; |
75 | 77 | import org.thingsboard.server.common.data.widget.WidgetsBundle; |
76 | 78 | |
79 | +import java.io.Closeable; | |
77 | 80 | import java.io.IOException; |
78 | 81 | import java.net.URI; |
79 | 82 | import java.util.Collections; |
... | ... | @@ -81,19 +84,23 @@ import java.util.HashMap; |
81 | 84 | import java.util.List; |
82 | 85 | import java.util.Map; |
83 | 86 | import java.util.Optional; |
87 | +import java.util.concurrent.ExecutorService; | |
88 | +import java.util.concurrent.Executors; | |
89 | +import java.util.concurrent.Future; | |
84 | 90 | |
85 | 91 | import static org.springframework.util.StringUtils.isEmpty; |
86 | 92 | |
87 | 93 | /** |
88 | 94 | * @author Andrew Shvayka |
89 | 95 | */ |
90 | -public class RestClient implements ClientHttpRequestInterceptor { | |
96 | +public class RestClient implements ClientHttpRequestInterceptor, Closeable { | |
91 | 97 | private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; |
92 | 98 | protected final RestTemplate restTemplate; |
93 | 99 | protected final String baseURL; |
94 | 100 | private String token; |
95 | 101 | private String refreshToken; |
96 | 102 | private final ObjectMapper objectMapper = new ObjectMapper(); |
103 | + private ExecutorService service = Executors.newWorkStealingPool(10); | |
97 | 104 | |
98 | 105 | |
99 | 106 | protected static final String ACTIVATE_TOKEN_REGEX = "/api/noauth/activate?activateToken="; |
... | ... | @@ -256,6 +263,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
256 | 263 | } |
257 | 264 | return restTemplate.postForEntity(baseURL + deviceCreationUrl, device, Device.class, params).getBody(); |
258 | 265 | } |
266 | + | |
259 | 267 | public Asset createAsset(Asset asset) { |
260 | 268 | return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody(); |
261 | 269 | } |
... | ... | @@ -418,17 +426,17 @@ public class RestClient implements ClientHttpRequestInterceptor { |
418 | 426 | } |
419 | 427 | |
420 | 428 | public void ackAlarm(String alarmId) { |
421 | - restTemplate.postForObject(baseURL + "/api/alarm/{alarmId}/ack", new Object(), Object.class, alarmId); | |
429 | + restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/ack", null, alarmId); | |
422 | 430 | } |
423 | 431 | |
424 | 432 | public void clearAlarm(String alarmId) { |
425 | - restTemplate.postForObject(baseURL + "/api/alarm/{alarmId}/clear", new Object(), Object.class, alarmId); | |
433 | + restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/clear", null, alarmId); | |
426 | 434 | } |
427 | 435 | |
428 | - public TimePageData<AlarmInfo> getAlarms(String entityType, String entityId, String searchStatus, String status, TimePageLink pageLink, Boolean fetchOriginator) { | |
436 | + public TimePageData<AlarmInfo> getAlarms(EntityId entityId, String searchStatus, String status, TimePageLink pageLink, Boolean fetchOriginator) { | |
429 | 437 | Map<String, String> params = new HashMap<>(); |
430 | - params.put("entityType", entityType); | |
431 | - params.put("entityId", entityId); | |
438 | + params.put("entityType", entityId.getEntityType().name()); | |
439 | + params.put("entityId", entityId.getId().toString()); | |
432 | 440 | params.put("searchStatus", searchStatus); |
433 | 441 | params.put("status", status); |
434 | 442 | params.put("fetchOriginator", String.valueOf(fetchOriginator)); |
... | ... | @@ -471,10 +479,10 @@ public class RestClient implements ClientHttpRequestInterceptor { |
471 | 479 | return urlParams; |
472 | 480 | } |
473 | 481 | |
474 | - public Optional<AlarmSeverity> getHighestAlarmSeverity(String entityType, String entityId, String searchStatus, String status) { | |
482 | + public Optional<AlarmSeverity> getHighestAlarmSeverity(EntityId entityId, String searchStatus, String status) { | |
475 | 483 | Map<String, String> params = new HashMap<>(); |
476 | - params.put("entityType", entityType); | |
477 | - params.put("entityId", entityId); | |
484 | + params.put("entityType", entityId.getEntityType().name()); | |
485 | + params.put("entityId", entityId.getId().toString()); | |
478 | 486 | params.put("searchStatus", searchStatus); |
479 | 487 | params.put("status", status); |
480 | 488 | try { |
... | ... | @@ -597,14 +605,14 @@ public class RestClient implements ClientHttpRequestInterceptor { |
597 | 605 | return assets.getBody(); |
598 | 606 | } |
599 | 607 | |
600 | - public List<Asset> getAssetsByIds(String[] assetIds) { | |
608 | + public List<Asset> getAssetsByIds(List<String> assetIds) { | |
601 | 609 | return restTemplate.exchange( |
602 | 610 | baseURL + "/api/assets?assetIds={assetIds}", |
603 | 611 | HttpMethod.GET, |
604 | 612 | HttpEntity.EMPTY, |
605 | 613 | new ParameterizedTypeReference<List<Asset>>() { |
606 | 614 | }, |
607 | - String.join(",", assetIds)).getBody(); | |
615 | + listToString(assetIds)).getBody(); | |
608 | 616 | } |
609 | 617 | |
610 | 618 | public List<Asset> findByQuery(AssetSearchQuery query) { |
... | ... | @@ -657,10 +665,10 @@ public class RestClient implements ClientHttpRequestInterceptor { |
657 | 665 | return auditLog.getBody(); |
658 | 666 | } |
659 | 667 | |
660 | - public TimePageData<AuditLog> getAuditLogsByEntityId(String entityType, String entityId, String actionTypes, TimePageLink pageLink) { | |
668 | + public TimePageData<AuditLog> getAuditLogsByEntityId(EntityId entityId, String actionTypes, TimePageLink pageLink) { | |
661 | 669 | Map<String, String> params = new HashMap<>(); |
662 | - params.put("entityType", entityType); | |
663 | - params.put("entityId", entityId); | |
670 | + params.put("entityType", entityId.getEntityType().name()); | |
671 | + params.put("entityId", entityId.getId().toString()); | |
664 | 672 | params.put("actionTypes", actionTypes); |
665 | 673 | addPageLinkToParam(params, pageLink); |
666 | 674 | |
... | ... | @@ -700,14 +708,14 @@ public class RestClient implements ClientHttpRequestInterceptor { |
700 | 708 | } |
701 | 709 | |
702 | 710 | public void logout() { |
703 | - restTemplate.exchange(URI.create(baseURL + "/api/auth/logout"), HttpMethod.POST, HttpEntity.EMPTY, Object.class); | |
711 | + restTemplate.postForLocation(baseURL + "/api/auth/logout", null); | |
704 | 712 | } |
705 | 713 | |
706 | 714 | public void changePassword(String currentPassword, String newPassword) { |
707 | 715 | ObjectNode changePasswordRequest = objectMapper.createObjectNode(); |
708 | 716 | changePasswordRequest.put("currentPassword", currentPassword); |
709 | 717 | changePasswordRequest.put("newPassword", newPassword); |
710 | - restTemplate.exchange(URI.create(baseURL + "/api/auth/changePassword"), HttpMethod.POST, new HttpEntity<>(changePasswordRequest), Object.class); | |
718 | + restTemplate.postForLocation(baseURL + "/api/auth/changePassword", changePasswordRequest); | |
711 | 719 | } |
712 | 720 | |
713 | 721 | public Optional<UserPasswordPolicy> getUserPasswordPolicy() { |
... | ... | @@ -731,7 +739,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
731 | 739 | public void requestResetPasswordByEmail(String email) { |
732 | 740 | ObjectNode resetPasswordByEmailRequest = objectMapper.createObjectNode(); |
733 | 741 | resetPasswordByEmailRequest.put("email", email); |
734 | - restTemplate.exchange(URI.create(baseURL + "/api/noauth/resetPasswordByEmail"), HttpMethod.POST, new HttpEntity<>(resetPasswordByEmailRequest), Object.class); | |
742 | + restTemplate.postForLocation(baseURL + "/api/noauth/resetPasswordByEmail", resetPasswordByEmailRequest); | |
735 | 743 | } |
736 | 744 | |
737 | 745 | public Optional<JsonNode> activateUser(String userId, String password) { |
... | ... | @@ -772,14 +780,14 @@ public class RestClient implements ClientHttpRequestInterceptor { |
772 | 780 | componentType).getBody(); |
773 | 781 | } |
774 | 782 | |
775 | - public List<ComponentDescriptor> getComponentDescriptorsByTypes(String[] componentTypes) { | |
783 | + public List<ComponentDescriptor> getComponentDescriptorsByTypes(List<String> componentTypes) { | |
776 | 784 | return restTemplate.exchange( |
777 | 785 | baseURL + "/api/components?componentTypes={componentTypes}", |
778 | 786 | HttpMethod.GET, |
779 | 787 | HttpEntity.EMPTY, |
780 | 788 | new ParameterizedTypeReference<List<ComponentDescriptor>>() { |
781 | 789 | }, |
782 | - String.join(",", componentTypes)).getBody(); | |
790 | + listToString(componentTypes)).getBody(); | |
783 | 791 | } |
784 | 792 | |
785 | 793 | public Optional<Customer> getCustomerById(String customerId) { |
... | ... | @@ -915,7 +923,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
915 | 923 | } |
916 | 924 | } |
917 | 925 | |
918 | - public Optional<Dashboard> updateDashboardCustomers(String dashboardId, String[] customerIds) { | |
926 | + public Optional<Dashboard> updateDashboardCustomers(String dashboardId, List<String> customerIds) { | |
919 | 927 | try { |
920 | 928 | ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers", customerIds, Dashboard.class, dashboardId); |
921 | 929 | return Optional.ofNullable(dashboard.getBody()); |
... | ... | @@ -928,7 +936,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
928 | 936 | } |
929 | 937 | } |
930 | 938 | |
931 | - public Optional<Dashboard> addDashboardCustomers(String dashboardId, String[] customerIds) { | |
939 | + public Optional<Dashboard> addDashboardCustomers(String dashboardId, List<String> customerIds) { | |
932 | 940 | try { |
933 | 941 | ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/add", customerIds, Dashboard.class, dashboardId); |
934 | 942 | return Optional.ofNullable(dashboard.getBody()); |
... | ... | @@ -941,7 +949,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
941 | 949 | } |
942 | 950 | } |
943 | 951 | |
944 | - public Optional<Dashboard> removeDashboardCustomers(String dashboardId, String[] customerIds) { | |
952 | + public Optional<Dashboard> removeDashboardCustomers(String dashboardId, List<String> customerIds) { | |
945 | 953 | try { |
946 | 954 | ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/remove", customerIds, Dashboard.class, dashboardId); |
947 | 955 | return Optional.ofNullable(dashboard.getBody()); |
... | ... | @@ -1135,12 +1143,12 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1135 | 1143 | .getBody(); |
1136 | 1144 | } |
1137 | 1145 | |
1138 | - public List<Device> getDevicesByIds(String[] deviceIds) { | |
1146 | + public List<Device> getDevicesByIds(List<String> deviceIds) { | |
1139 | 1147 | return restTemplate.exchange(baseURL + "/api/devices?deviceIds={deviceIds}", |
1140 | 1148 | HttpMethod.GET, |
1141 | 1149 | HttpEntity.EMPTY, new ParameterizedTypeReference<List<Device>>() { |
1142 | 1150 | }, |
1143 | - String.join(",", deviceIds)).getBody(); | |
1151 | + listToString(deviceIds)).getBody(); | |
1144 | 1152 | } |
1145 | 1153 | |
1146 | 1154 | public List<Device> findByQuery(DeviceSearchQuery query) { |
... | ... | @@ -1161,28 +1169,22 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1161 | 1169 | }).getBody(); |
1162 | 1170 | } |
1163 | 1171 | |
1164 | - public DeferredResult<ResponseEntity> claimDevice(String deviceName, ClaimRequest claimRequest) { | |
1172 | + public JsonNode claimDevice(String deviceName, ClaimRequest claimRequest) { | |
1165 | 1173 | return restTemplate.exchange( |
1166 | 1174 | baseURL + "/api/customer/device/{deviceName}/claim", |
1167 | 1175 | HttpMethod.POST, |
1168 | 1176 | new HttpEntity<>(claimRequest), |
1169 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1177 | + new ParameterizedTypeReference<JsonNode>() { | |
1170 | 1178 | }, |
1171 | 1179 | deviceName).getBody(); |
1172 | 1180 | } |
1173 | 1181 | |
1174 | - public DeferredResult<ResponseEntity> reClaimDevice(String deviceName) { | |
1175 | - return restTemplate.exchange( | |
1176 | - baseURL + "/api/customer/device/{deviceName}/claim", | |
1177 | - HttpMethod.DELETE, | |
1178 | - HttpEntity.EMPTY, | |
1179 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1180 | - }, | |
1181 | - deviceName).getBody(); | |
1182 | + public void reClaimDevice(String deviceName) { | |
1183 | + restTemplate.delete(baseURL + "/api/customer/device/{deviceName}/claim", deviceName); | |
1182 | 1184 | } |
1183 | 1185 | |
1184 | 1186 | public void saveRelation(EntityRelation relation) { |
1185 | - restTemplate.postForEntity(baseURL + "/api/relation", relation, Object.class); | |
1187 | + restTemplate.postForLocation(baseURL + "/api/relation", null); | |
1186 | 1188 | } |
1187 | 1189 | |
1188 | 1190 | public void deleteRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { |
... | ... | @@ -1196,8 +1198,8 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1196 | 1198 | restTemplate.delete(baseURL + "/api/relation?fromId={fromId}&fromType={fromType}&relationType={relationType}&relationTypeGroup={relationTypeGroup}&toId={toId}&toType={toType}", params); |
1197 | 1199 | } |
1198 | 1200 | |
1199 | - public void deleteRelations(String entityId, String entityType) { | |
1200 | - restTemplate.delete(baseURL + "/api/relations?entityId={entityId}&entityType={entityType}", entityId, entityType); | |
1201 | + public void deleteRelations(EntityId entityId) { | |
1202 | + restTemplate.delete(baseURL + "/api/relations?entityId={entityId}&entityType={entityType}", entityId.getId().toString(), entityId.getEntityType().name()); | |
1201 | 1203 | } |
1202 | 1204 | |
1203 | 1205 | public Optional<EntityRelation> getRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { |
... | ... | @@ -1448,10 +1450,10 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1448 | 1450 | } |
1449 | 1451 | } |
1450 | 1452 | |
1451 | - public TimePageData<Event> getEvents(String entityType, String entityId, String eventType, String tenantId, TimePageLink pageLink) { | |
1453 | + public TimePageData<Event> getEvents(EntityId entityId, String eventType, String tenantId, TimePageLink pageLink) { | |
1452 | 1454 | Map<String, String> params = new HashMap<>(); |
1453 | - params.put("entityType", entityType); | |
1454 | - params.put("entityId", entityId); | |
1455 | + params.put("entityType", entityId.getEntityType().name()); | |
1456 | + params.put("entityId", entityId.getId().toString()); | |
1455 | 1457 | params.put("eventType", eventType); |
1456 | 1458 | params.put("tenantId", tenantId); |
1457 | 1459 | addPageLinkToParam(params, pageLink); |
... | ... | @@ -1465,10 +1467,10 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1465 | 1467 | params).getBody(); |
1466 | 1468 | } |
1467 | 1469 | |
1468 | - public TimePageData<Event> getEvents(String entityType, String entityId, String tenantId, TimePageLink pageLink) { | |
1470 | + public TimePageData<Event> getEvents(EntityId entityId, String tenantId, TimePageLink pageLink) { | |
1469 | 1471 | Map<String, String> params = new HashMap<>(); |
1470 | - params.put("entityType", entityType); | |
1471 | - params.put("entityId", entityId); | |
1472 | + params.put("entityType", entityId.getEntityType().name()); | |
1473 | + params.put("entityId", entityId.getId().toString()); | |
1472 | 1474 | params.put("tenantId", tenantId); |
1473 | 1475 | addPageLinkToParam(params, pageLink); |
1474 | 1476 | |
... | ... | @@ -1481,22 +1483,16 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1481 | 1483 | params).getBody(); |
1482 | 1484 | } |
1483 | 1485 | |
1484 | - public DeferredResult<ResponseEntity> handleOneWayDeviceRPCRequest(String deviceId, String requestBody) { | |
1485 | - return restTemplate.exchange( | |
1486 | - baseURL + "/api/plugins/rpc/oneway/{deviceId}", | |
1487 | - HttpMethod.POST, | |
1488 | - new HttpEntity<>(requestBody), | |
1489 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1490 | - }, | |
1491 | - deviceId).getBody(); | |
1486 | + public void handleOneWayDeviceRPCRequest(String deviceId, JsonNode requestBody) { | |
1487 | + restTemplate.postForLocation(baseURL + "/api/plugins/rpc/oneway/{deviceId}", requestBody, deviceId); | |
1492 | 1488 | } |
1493 | 1489 | |
1494 | - public DeferredResult<ResponseEntity> handleTwoWayDeviceRPCRequest(String deviceId, String requestBody) { | |
1490 | + public JsonNode handleTwoWayDeviceRPCRequest(String deviceId, JsonNode requestBody) { | |
1495 | 1491 | return restTemplate.exchange( |
1496 | 1492 | baseURL + "/api/plugins/rpc/twoway/{deviceId}", |
1497 | 1493 | HttpMethod.POST, |
1498 | 1494 | new HttpEntity<>(requestBody), |
1499 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1495 | + new ParameterizedTypeReference<JsonNode>() { | |
1500 | 1496 | }, |
1501 | 1497 | deviceId).getBody(); |
1502 | 1498 | } |
... | ... | @@ -1590,206 +1586,233 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1590 | 1586 | } |
1591 | 1587 | } |
1592 | 1588 | |
1593 | - public DeferredResult<ResponseEntity> getAttributeKeys(String entityType, String entityId) { | |
1589 | + public List<String> getAttributeKeys(EntityId entityId) { | |
1594 | 1590 | return restTemplate.exchange( |
1595 | 1591 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes", |
1596 | 1592 | HttpMethod.GET, |
1597 | 1593 | HttpEntity.EMPTY, |
1598 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1594 | + new ParameterizedTypeReference<List<String>>() { | |
1599 | 1595 | }, |
1600 | - entityType, | |
1601 | - entityId).getBody(); | |
1596 | + entityId.getEntityType().name(), | |
1597 | + entityId.getId().toString()).getBody(); | |
1602 | 1598 | } |
1603 | 1599 | |
1604 | - public DeferredResult<ResponseEntity> getAttributeKeysByScope(String entityType, String entityId, String scope) { | |
1600 | + public List<String> getAttributeKeysByScope(EntityId entityId, String scope) { | |
1605 | 1601 | return restTemplate.exchange( |
1606 | 1602 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes/{scope}", |
1607 | 1603 | HttpMethod.GET, |
1608 | 1604 | HttpEntity.EMPTY, |
1609 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1605 | + new ParameterizedTypeReference<List<String>>() { | |
1610 | 1606 | }, |
1611 | - entityType, | |
1612 | - entityId, | |
1607 | + entityId.getEntityType().name(), | |
1608 | + entityId.getId().toString(), | |
1613 | 1609 | scope).getBody(); |
1614 | 1610 | } |
1615 | 1611 | |
1616 | - public DeferredResult<ResponseEntity> getAttributesResponseEntity(String entityType, String entityId, String keys) { | |
1617 | - return restTemplate.exchange( | |
1612 | + public List<AttributeKvEntry> getAttributeKvEntries(EntityId entityId, List<String> keys) { | |
1613 | + List<JsonNode> attributes = restTemplate.exchange( | |
1618 | 1614 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes?keys={keys}", |
1619 | 1615 | HttpMethod.GET, |
1620 | 1616 | HttpEntity.EMPTY, |
1621 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1617 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1622 | 1618 | }, |
1623 | - entityType, | |
1624 | - entityId, | |
1625 | - keys).getBody(); | |
1619 | + entityId.getEntityType().name(), | |
1620 | + entityId.getId(), | |
1621 | + listToString(keys)).getBody(); | |
1622 | + | |
1623 | + return RestJsonConverter.toAttributes(attributes); | |
1626 | 1624 | } |
1627 | 1625 | |
1628 | - public DeferredResult<ResponseEntity> getAttributesByScope(String entityType, String entityId, String scope, String keys) { | |
1629 | - return restTemplate.exchange( | |
1626 | + public Future<List<AttributeKvEntry>> getAttributeKvEntriesAsync(EntityId entityId, List<String> keys) { | |
1627 | + return service.submit(() -> getAttributeKvEntries(entityId, keys)); | |
1628 | + } | |
1629 | + | |
1630 | + public List<AttributeKvEntry> getAttributesByScope(EntityId entityId, String scope, List<String> keys) { | |
1631 | + List<JsonNode> attributes = restTemplate.exchange( | |
1630 | 1632 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes/{scope}?keys={keys}", |
1631 | 1633 | HttpMethod.GET, |
1632 | 1634 | HttpEntity.EMPTY, |
1633 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1635 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1634 | 1636 | }, |
1635 | - entityType, | |
1636 | - entityId, | |
1637 | + entityId.getEntityType().name(), | |
1638 | + entityId.getId().toString(), | |
1637 | 1639 | scope, |
1638 | - keys).getBody(); | |
1640 | + listToString(keys)).getBody(); | |
1641 | + | |
1642 | + return RestJsonConverter.toAttributes(attributes); | |
1639 | 1643 | } |
1640 | 1644 | |
1641 | - public DeferredResult<ResponseEntity> getTimeseriesKeys(String entityType, String entityId) { | |
1645 | + public List<String> getTimeseriesKeys(EntityId entityId) { | |
1642 | 1646 | return restTemplate.exchange( |
1643 | 1647 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/timeseries", |
1644 | 1648 | HttpMethod.GET, |
1645 | 1649 | HttpEntity.EMPTY, |
1646 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1650 | + new ParameterizedTypeReference<List<String>>() { | |
1647 | 1651 | }, |
1648 | - entityType, | |
1649 | - entityId).getBody(); | |
1652 | + entityId.getEntityType().name(), | |
1653 | + entityId.getId().toString()).getBody(); | |
1650 | 1654 | } |
1651 | 1655 | |
1652 | - public DeferredResult<ResponseEntity> getLatestTimeseries(String entityType, String entityId, String keys) { | |
1653 | - return restTemplate.exchange( | |
1656 | + public List<TsKvEntry> getLatestTimeseries(EntityId entityId, List<String> keys) { | |
1657 | + Map<String, List<JsonNode>> timeseries = restTemplate.exchange( | |
1654 | 1658 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}", |
1655 | 1659 | HttpMethod.GET, |
1656 | 1660 | HttpEntity.EMPTY, |
1657 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1661 | + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { | |
1658 | 1662 | }, |
1659 | - entityType, | |
1660 | - entityId, | |
1661 | - keys).getBody(); | |
1663 | + entityId.getEntityType().name(), | |
1664 | + entityId.getId().toString(), | |
1665 | + listToString(keys)).getBody(); | |
1666 | + | |
1667 | + return RestJsonConverter.toTimeseries(timeseries); | |
1662 | 1668 | } |
1663 | 1669 | |
1664 | 1670 | |
1665 | - public DeferredResult<ResponseEntity> getTimeseries(String entityType, String entityId, String keys, Long startTs, Long endTs, Long interval, Integer limit, String agg) { | |
1671 | + public List<TsKvEntry> getTimeseries(EntityId entityId, List<String> keys, Long startTs, Long endTs, Long interval, Integer limit, String agg) { | |
1666 | 1672 | Map<String, String> params = new HashMap<>(); |
1667 | - params.put("entityType", entityType); | |
1668 | - params.put("entityId", entityId); | |
1669 | - params.put("keys", keys); | |
1673 | + params.put("entityType", entityId.getEntityType().name()); | |
1674 | + params.put("entityId", entityId.getId().toString()); | |
1675 | + params.put("keys", listToString(keys)); | |
1670 | 1676 | params.put("startTs", startTs.toString()); |
1671 | 1677 | params.put("endTs", endTs.toString()); |
1672 | 1678 | params.put("interval", interval == null ? "0" : interval.toString()); |
1673 | 1679 | params.put("limit", limit == null ? "100" : limit.toString()); |
1674 | 1680 | params.put("agg", agg == null ? "NONE" : agg); |
1675 | 1681 | |
1676 | - return restTemplate.exchange( | |
1682 | + Map<String, List<JsonNode>> timeseries = restTemplate.exchange( | |
1677 | 1683 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&startTs={startTs}&endTs={endTs}&interval={interval}&limit={limit}&agg={agg}", |
1678 | 1684 | HttpMethod.GET, |
1679 | 1685 | HttpEntity.EMPTY, |
1680 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1686 | + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { | |
1681 | 1687 | }, |
1682 | 1688 | params).getBody(); |
1689 | + | |
1690 | + return RestJsonConverter.toTimeseries(timeseries); | |
1683 | 1691 | } |
1684 | 1692 | |
1685 | - public DeferredResult<ResponseEntity> saveDeviceAttributes(String deviceId, String scope, JsonNode request) { | |
1686 | - return restTemplate.exchange( | |
1693 | + public List<AttributeKvEntry> saveDeviceAttributes(String deviceId, String scope, JsonNode request) { | |
1694 | + List<JsonNode> attributes = restTemplate.exchange( | |
1687 | 1695 | baseURL + "/api/plugins/telemetry/{deviceId}/{scope}", |
1688 | 1696 | HttpMethod.POST, |
1689 | 1697 | new HttpEntity<>(request), |
1690 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1698 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1691 | 1699 | }, |
1692 | 1700 | deviceId, |
1693 | 1701 | scope).getBody(); |
1702 | + | |
1703 | + return RestJsonConverter.toAttributes(attributes); | |
1694 | 1704 | } |
1695 | 1705 | |
1696 | - public DeferredResult<ResponseEntity> saveEntityAttributesV1(String entityType, String entityId, String scope, JsonNode request) { | |
1697 | - return restTemplate.exchange( | |
1706 | + public List<AttributeKvEntry> saveEntityAttributesV1(EntityId entityId, String scope, JsonNode request) { | |
1707 | + List<JsonNode> attributes = restTemplate.exchange( | |
1698 | 1708 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}", |
1699 | 1709 | HttpMethod.POST, |
1700 | 1710 | new HttpEntity<>(request), |
1701 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1711 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1702 | 1712 | }, |
1703 | - entityType, | |
1704 | - entityId, | |
1713 | + entityId.getEntityType().name(), | |
1714 | + entityId.getId().toString(), | |
1705 | 1715 | scope).getBody(); |
1716 | + | |
1717 | + return RestJsonConverter.toAttributes(attributes); | |
1706 | 1718 | } |
1707 | 1719 | |
1708 | - public DeferredResult<ResponseEntity> saveEntityAttributesV2(String entityType, String entityId, String scope, JsonNode request) { | |
1709 | - return restTemplate.exchange( | |
1720 | + public List<AttributeKvEntry> saveEntityAttributesV2(EntityId entityId, String scope, JsonNode request) { | |
1721 | + List<JsonNode> attributes = restTemplate.exchange( | |
1710 | 1722 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/attributes/{scope}", |
1711 | 1723 | HttpMethod.POST, |
1712 | 1724 | new HttpEntity<>(request), |
1713 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1725 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1714 | 1726 | }, |
1715 | - entityType, | |
1716 | - entityId, | |
1727 | + entityId.getEntityType().name(), | |
1728 | + entityId.getId().toString(), | |
1717 | 1729 | scope).getBody(); |
1730 | + | |
1731 | + return RestJsonConverter.toAttributes(attributes); | |
1718 | 1732 | } |
1719 | 1733 | |
1720 | - public DeferredResult<ResponseEntity> saveEntityTelemetry(String entityType, String entityId, String scope, String requestBody) { | |
1721 | - return restTemplate.exchange( | |
1734 | + public List<TsKvEntry> saveEntityTelemetry(EntityId entityId, String scope, String requestBody) { | |
1735 | + Map<String, List<JsonNode>> timeseries = restTemplate.exchange( | |
1722 | 1736 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}", |
1723 | 1737 | HttpMethod.POST, |
1724 | 1738 | new HttpEntity<>(requestBody), |
1725 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1739 | + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { | |
1726 | 1740 | }, |
1727 | - entityType, | |
1728 | - entityId, | |
1741 | + entityId.getEntityType().name(), | |
1742 | + entityId.getId().toString(), | |
1729 | 1743 | scope).getBody(); |
1744 | + | |
1745 | + return RestJsonConverter.toTimeseries(timeseries); | |
1730 | 1746 | } |
1731 | 1747 | |
1732 | - public DeferredResult<ResponseEntity> saveEntityTelemetryWithTTL(String entityType, String entityId, String scope, Long ttl, String requestBody) { | |
1733 | - return restTemplate.exchange( | |
1748 | + public List<TsKvEntry> saveEntityTelemetryWithTTL(EntityId entityId, String scope, Long ttl, String requestBody) { | |
1749 | + Map<String, List<JsonNode>> timeseries = restTemplate.exchange( | |
1734 | 1750 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}/{ttl}", |
1735 | 1751 | HttpMethod.POST, |
1736 | 1752 | new HttpEntity<>(requestBody), |
1737 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1753 | + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { | |
1738 | 1754 | }, |
1739 | - entityType, | |
1740 | - entityId, | |
1755 | + entityId.getEntityType().name(), | |
1756 | + entityId.getId().toString(), | |
1741 | 1757 | scope, |
1742 | 1758 | ttl).getBody(); |
1759 | + | |
1760 | + return RestJsonConverter.toTimeseries(timeseries); | |
1743 | 1761 | } |
1744 | 1762 | |
1745 | - public DeferredResult<ResponseEntity> deleteEntityTimeseries(String entityType, | |
1746 | - String entityId, | |
1747 | - String keys, | |
1748 | - boolean deleteAllDataForKeys, | |
1749 | - Long startTs, | |
1750 | - Long endTs, | |
1751 | - boolean rewriteLatestIfDeleted) { | |
1763 | + public List<TsKvEntry> deleteEntityTimeseries(EntityId entityId, | |
1764 | + List<String> keys, | |
1765 | + boolean deleteAllDataForKeys, | |
1766 | + Long startTs, | |
1767 | + Long endTs, | |
1768 | + boolean rewriteLatestIfDeleted) { | |
1752 | 1769 | Map<String, String> params = new HashMap<>(); |
1753 | - params.put("entityType", entityType); | |
1754 | - params.put("entityId", entityId); | |
1755 | - params.put("keys", keys); | |
1770 | + params.put("entityType", entityId.getEntityType().name()); | |
1771 | + params.put("entityId", entityId.getId().toString()); | |
1772 | + params.put("keys", listToString(keys)); | |
1756 | 1773 | params.put("deleteAllDataForKeys", String.valueOf(deleteAllDataForKeys)); |
1757 | 1774 | params.put("startTs", startTs.toString()); |
1758 | 1775 | params.put("endTs", endTs.toString()); |
1759 | 1776 | params.put("rewriteLatestIfDeleted", String.valueOf(rewriteLatestIfDeleted)); |
1760 | 1777 | |
1761 | - return restTemplate.exchange( | |
1778 | + Map<String, List<JsonNode>> timeseries = restTemplate.exchange( | |
1762 | 1779 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/delete?keys={keys}&deleteAllDataForKeys={deleteAllDataForKeys}&startTs={startTs}&endTs={endTs}&rewriteLatestIfDeleted={rewriteLatestIfDeleted}", |
1763 | 1780 | HttpMethod.DELETE, |
1764 | 1781 | HttpEntity.EMPTY, |
1765 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1782 | + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() { | |
1766 | 1783 | }, |
1767 | 1784 | params).getBody(); |
1785 | + | |
1786 | + return RestJsonConverter.toTimeseries(timeseries); | |
1768 | 1787 | } |
1769 | 1788 | |
1770 | - public DeferredResult<ResponseEntity> deleteEntityAttributes(String deviceId, String scope, String keys) { | |
1771 | - return restTemplate.exchange( | |
1789 | + public List<AttributeKvEntry> deleteEntityAttributes(String deviceId, String scope, List<String> keys) { | |
1790 | + List<JsonNode> attributes = restTemplate.exchange( | |
1772 | 1791 | baseURL + "/api/plugins/telemetry/{deviceId}/{scope}?keys={keys}", |
1773 | 1792 | HttpMethod.DELETE, |
1774 | 1793 | HttpEntity.EMPTY, |
1775 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1794 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1776 | 1795 | }, |
1777 | 1796 | deviceId, |
1778 | 1797 | scope, |
1779 | - keys).getBody(); | |
1798 | + listToString(keys)).getBody(); | |
1799 | + | |
1800 | + return RestJsonConverter.toAttributes(attributes); | |
1780 | 1801 | } |
1781 | 1802 | |
1782 | - public DeferredResult<ResponseEntity> deleteEntityAttributes(String entityType, String entityId, String scope, String keys) { | |
1783 | - return restTemplate.exchange( | |
1803 | + public List<AttributeKvEntry> deleteEntityAttributes(EntityId entityId, String scope, List<String> keys) { | |
1804 | + List<JsonNode> attributes = restTemplate.exchange( | |
1784 | 1805 | baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}?keys={keys}", |
1785 | 1806 | HttpMethod.DELETE, |
1786 | 1807 | HttpEntity.EMPTY, |
1787 | - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { | |
1808 | + new ParameterizedTypeReference<List<JsonNode>>() { | |
1788 | 1809 | }, |
1789 | - entityType, | |
1790 | - entityId, | |
1810 | + entityId.getEntityType().name(), | |
1811 | + entityId.getId().toString(), | |
1791 | 1812 | scope, |
1792 | - keys).getBody(); | |
1813 | + listToString(keys)).getBody(); | |
1814 | + | |
1815 | + return RestJsonConverter.toAttributes(attributes); | |
1793 | 1816 | } |
1794 | 1817 | |
1795 | 1818 | public Optional<Tenant> getTenantById(String tenantId) { |
... | ... | @@ -1860,7 +1883,7 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1860 | 1883 | } |
1861 | 1884 | |
1862 | 1885 | public void sendActivationEmail(String email) { |
1863 | - restTemplate.postForEntity(baseURL + "/api/user/sendActivationMail?email={email}", null, Object.class, email); | |
1886 | + restTemplate.postForLocation(baseURL + "/api/user/sendActivationMail?email={email}", null, email); | |
1864 | 1887 | } |
1865 | 1888 | |
1866 | 1889 | public String getActivationLink(String userId) { |
... | ... | @@ -1900,10 +1923,9 @@ public class RestClient implements ClientHttpRequestInterceptor { |
1900 | 1923 | } |
1901 | 1924 | |
1902 | 1925 | public void setUserCredentialsEnabled(String userId, boolean userCredentialsEnabled) { |
1903 | - restTemplate.postForEntity( | |
1926 | + restTemplate.postForLocation( | |
1904 | 1927 | baseURL + "/api/user/{userId}/userCredentialsEnabled?serCredentialsEnabled={serCredentialsEnabled}", |
1905 | 1928 | null, |
1906 | - Object.class, | |
1907 | 1929 | userId, |
1908 | 1930 | userCredentialsEnabled); |
1909 | 1931 | } |
... | ... | @@ -2030,4 +2052,15 @@ public class RestClient implements ClientHttpRequestInterceptor { |
2030 | 2052 | params.put("textOffset", pageLink.getTextOffset()); |
2031 | 2053 | } |
2032 | 2054 | } |
2055 | + | |
2056 | + private String listToString(List<String> list) { | |
2057 | + return String.join(",", list); | |
2058 | + } | |
2059 | + | |
2060 | + @Override | |
2061 | + public void close() { | |
2062 | + if (service != null) { | |
2063 | + service.shutdown(); | |
2064 | + } | |
2065 | + } | |
2033 | 2066 | } | ... | ... |
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.client.tools.utils; | |
17 | + | |
18 | +import com.fasterxml.jackson.databind.JsonNode; | |
19 | +import org.springframework.util.CollectionUtils; | |
20 | +import org.thingsboard.server.common.data.kv.AttributeKvEntry; | |
21 | +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; | |
22 | +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; | |
23 | +import org.thingsboard.server.common.data.kv.BooleanDataEntry; | |
24 | +import org.thingsboard.server.common.data.kv.DoubleDataEntry; | |
25 | +import org.thingsboard.server.common.data.kv.KvEntry; | |
26 | +import org.thingsboard.server.common.data.kv.LongDataEntry; | |
27 | +import org.thingsboard.server.common.data.kv.StringDataEntry; | |
28 | +import org.thingsboard.server.common.data.kv.TsKvEntry; | |
29 | + | |
30 | +import java.util.ArrayList; | |
31 | +import java.util.Collections; | |
32 | +import java.util.List; | |
33 | +import java.util.Map; | |
34 | +import java.util.stream.Collectors; | |
35 | + | |
36 | +public class RestJsonConverter { | |
37 | + private static final String KEY = "key"; | |
38 | + private static final String VALUE = "value"; | |
39 | + private static final String LAST_UPDATE_TS = "lastUpdateTs"; | |
40 | + private static final String TS = "ts"; | |
41 | + | |
42 | + private static final String CAN_T_PARSE_VALUE = "Can't parse value: "; | |
43 | + | |
44 | + public static List<AttributeKvEntry> toAttributes(List<JsonNode> attributes) { | |
45 | + if (!CollectionUtils.isEmpty(attributes)) { | |
46 | + return attributes.stream().map(attr -> { | |
47 | + KvEntry entry = parseValue(attr.get(KEY).asText(), attr.get(VALUE)); | |
48 | + return new BaseAttributeKvEntry(entry, attr.get(LAST_UPDATE_TS).asLong()); | |
49 | + } | |
50 | + ).collect(Collectors.toList()); | |
51 | + } else { | |
52 | + return Collections.emptyList(); | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + public static List<TsKvEntry> toTimeseries(Map<String, List<JsonNode>> timeseries) { | |
57 | + if (!CollectionUtils.isEmpty(timeseries)) { | |
58 | + List<TsKvEntry> result = new ArrayList<>(); | |
59 | + timeseries.forEach((key, values) -> | |
60 | + result.addAll(values.stream().map(ts -> { | |
61 | + KvEntry entry = parseValue(key, ts.get(VALUE)); | |
62 | + return new BasicTsKvEntry(ts.get(TS).asLong(), entry); | |
63 | + } | |
64 | + ).collect(Collectors.toList())) | |
65 | + ); | |
66 | + return result; | |
67 | + } else { | |
68 | + return Collections.emptyList(); | |
69 | + } | |
70 | + } | |
71 | + | |
72 | + private static KvEntry parseValue(String key, JsonNode value) { | |
73 | + if (!value.isObject()) { | |
74 | + if (value.isBoolean()) { | |
75 | + return new BooleanDataEntry(key, value.asBoolean()); | |
76 | + } else if (value.isDouble()) { | |
77 | + return new DoubleDataEntry(key, value.asDouble()); | |
78 | + } else if (value.isLong()) { | |
79 | + return new LongDataEntry(key, value.asLong()); | |
80 | + } else { | |
81 | + return new StringDataEntry(key, value.asText()); | |
82 | + } | |
83 | + } else { | |
84 | + throw new RuntimeException(CAN_T_PARSE_VALUE + value); | |
85 | + } | |
86 | + } | |
87 | +} | ... | ... |