Commit e583b0a1d3c07bed59ac80fd0e8c2ce3186cef5f

Authored by Yevhen Bondarenko
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
@@ -31,7 +31,7 @@ import org.springframework.http.client.support.HttpRequestWrapper; @@ -31,7 +31,7 @@ import org.springframework.http.client.support.HttpRequestWrapper;
31 import org.springframework.util.StringUtils; 31 import org.springframework.util.StringUtils;
32 import org.springframework.web.client.HttpClientErrorException; 32 import org.springframework.web.client.HttpClientErrorException;
33 import org.springframework.web.client.RestTemplate; 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 import org.thingsboard.server.common.data.AdminSettings; 35 import org.thingsboard.server.common.data.AdminSettings;
36 import org.thingsboard.server.common.data.ClaimRequest; 36 import org.thingsboard.server.common.data.ClaimRequest;
37 import org.thingsboard.server.common.data.Customer; 37 import org.thingsboard.server.common.data.Customer;
@@ -57,6 +57,8 @@ import org.thingsboard.server.common.data.id.CustomerId; @@ -57,6 +57,8 @@ import org.thingsboard.server.common.data.id.CustomerId;
57 import org.thingsboard.server.common.data.id.DashboardId; 57 import org.thingsboard.server.common.data.id.DashboardId;
58 import org.thingsboard.server.common.data.id.DeviceId; 58 import org.thingsboard.server.common.data.id.DeviceId;
59 import org.thingsboard.server.common.data.id.EntityId; 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 import org.thingsboard.server.common.data.page.TextPageData; 62 import org.thingsboard.server.common.data.page.TextPageData;
61 import org.thingsboard.server.common.data.page.TextPageLink; 63 import org.thingsboard.server.common.data.page.TextPageLink;
62 import org.thingsboard.server.common.data.page.TimePageData; 64 import org.thingsboard.server.common.data.page.TimePageData;
@@ -74,6 +76,7 @@ import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; @@ -74,6 +76,7 @@ import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
74 import org.thingsboard.server.common.data.widget.WidgetType; 76 import org.thingsboard.server.common.data.widget.WidgetType;
75 import org.thingsboard.server.common.data.widget.WidgetsBundle; 77 import org.thingsboard.server.common.data.widget.WidgetsBundle;
76 78
  79 +import java.io.Closeable;
77 import java.io.IOException; 80 import java.io.IOException;
78 import java.net.URI; 81 import java.net.URI;
79 import java.util.Collections; 82 import java.util.Collections;
@@ -81,19 +84,23 @@ import java.util.HashMap; @@ -81,19 +84,23 @@ import java.util.HashMap;
81 import java.util.List; 84 import java.util.List;
82 import java.util.Map; 85 import java.util.Map;
83 import java.util.Optional; 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 import static org.springframework.util.StringUtils.isEmpty; 91 import static org.springframework.util.StringUtils.isEmpty;
86 92
87 /** 93 /**
88 * @author Andrew Shvayka 94 * @author Andrew Shvayka
89 */ 95 */
90 -public class RestClient implements ClientHttpRequestInterceptor { 96 +public class RestClient implements ClientHttpRequestInterceptor, Closeable {
91 private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; 97 private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
92 protected final RestTemplate restTemplate; 98 protected final RestTemplate restTemplate;
93 protected final String baseURL; 99 protected final String baseURL;
94 private String token; 100 private String token;
95 private String refreshToken; 101 private String refreshToken;
96 private final ObjectMapper objectMapper = new ObjectMapper(); 102 private final ObjectMapper objectMapper = new ObjectMapper();
  103 + private ExecutorService service = Executors.newWorkStealingPool(10);
97 104
98 105
99 protected static final String ACTIVATE_TOKEN_REGEX = "/api/noauth/activate?activateToken="; 106 protected static final String ACTIVATE_TOKEN_REGEX = "/api/noauth/activate?activateToken=";
@@ -256,6 +263,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -256,6 +263,7 @@ public class RestClient implements ClientHttpRequestInterceptor {
256 } 263 }
257 return restTemplate.postForEntity(baseURL + deviceCreationUrl, device, Device.class, params).getBody(); 264 return restTemplate.postForEntity(baseURL + deviceCreationUrl, device, Device.class, params).getBody();
258 } 265 }
  266 +
259 public Asset createAsset(Asset asset) { 267 public Asset createAsset(Asset asset) {
260 return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody(); 268 return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody();
261 } 269 }
@@ -418,17 +426,17 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -418,17 +426,17 @@ public class RestClient implements ClientHttpRequestInterceptor {
418 } 426 }
419 427
420 public void ackAlarm(String alarmId) { 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 public void clearAlarm(String alarmId) { 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 Map<String, String> params = new HashMap<>(); 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 params.put("searchStatus", searchStatus); 440 params.put("searchStatus", searchStatus);
433 params.put("status", status); 441 params.put("status", status);
434 params.put("fetchOriginator", String.valueOf(fetchOriginator)); 442 params.put("fetchOriginator", String.valueOf(fetchOriginator));
@@ -471,10 +479,10 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -471,10 +479,10 @@ public class RestClient implements ClientHttpRequestInterceptor {
471 return urlParams; 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 Map<String, String> params = new HashMap<>(); 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 params.put("searchStatus", searchStatus); 486 params.put("searchStatus", searchStatus);
479 params.put("status", status); 487 params.put("status", status);
480 try { 488 try {
@@ -597,14 +605,14 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -597,14 +605,14 @@ public class RestClient implements ClientHttpRequestInterceptor {
597 return assets.getBody(); 605 return assets.getBody();
598 } 606 }
599 607
600 - public List<Asset> getAssetsByIds(String[] assetIds) { 608 + public List<Asset> getAssetsByIds(List<String> assetIds) {
601 return restTemplate.exchange( 609 return restTemplate.exchange(
602 baseURL + "/api/assets?assetIds={assetIds}", 610 baseURL + "/api/assets?assetIds={assetIds}",
603 HttpMethod.GET, 611 HttpMethod.GET,
604 HttpEntity.EMPTY, 612 HttpEntity.EMPTY,
605 new ParameterizedTypeReference<List<Asset>>() { 613 new ParameterizedTypeReference<List<Asset>>() {
606 }, 614 },
607 - String.join(",", assetIds)).getBody(); 615 + listToString(assetIds)).getBody();
608 } 616 }
609 617
610 public List<Asset> findByQuery(AssetSearchQuery query) { 618 public List<Asset> findByQuery(AssetSearchQuery query) {
@@ -657,10 +665,10 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -657,10 +665,10 @@ public class RestClient implements ClientHttpRequestInterceptor {
657 return auditLog.getBody(); 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 Map<String, String> params = new HashMap<>(); 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 params.put("actionTypes", actionTypes); 672 params.put("actionTypes", actionTypes);
665 addPageLinkToParam(params, pageLink); 673 addPageLinkToParam(params, pageLink);
666 674
@@ -700,14 +708,14 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -700,14 +708,14 @@ public class RestClient implements ClientHttpRequestInterceptor {
700 } 708 }
701 709
702 public void logout() { 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 public void changePassword(String currentPassword, String newPassword) { 714 public void changePassword(String currentPassword, String newPassword) {
707 ObjectNode changePasswordRequest = objectMapper.createObjectNode(); 715 ObjectNode changePasswordRequest = objectMapper.createObjectNode();
708 changePasswordRequest.put("currentPassword", currentPassword); 716 changePasswordRequest.put("currentPassword", currentPassword);
709 changePasswordRequest.put("newPassword", newPassword); 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 public Optional<UserPasswordPolicy> getUserPasswordPolicy() { 721 public Optional<UserPasswordPolicy> getUserPasswordPolicy() {
@@ -731,7 +739,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -731,7 +739,7 @@ public class RestClient implements ClientHttpRequestInterceptor {
731 public void requestResetPasswordByEmail(String email) { 739 public void requestResetPasswordByEmail(String email) {
732 ObjectNode resetPasswordByEmailRequest = objectMapper.createObjectNode(); 740 ObjectNode resetPasswordByEmailRequest = objectMapper.createObjectNode();
733 resetPasswordByEmailRequest.put("email", email); 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 public Optional<JsonNode> activateUser(String userId, String password) { 745 public Optional<JsonNode> activateUser(String userId, String password) {
@@ -772,14 +780,14 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -772,14 +780,14 @@ public class RestClient implements ClientHttpRequestInterceptor {
772 componentType).getBody(); 780 componentType).getBody();
773 } 781 }
774 782
775 - public List<ComponentDescriptor> getComponentDescriptorsByTypes(String[] componentTypes) { 783 + public List<ComponentDescriptor> getComponentDescriptorsByTypes(List<String> componentTypes) {
776 return restTemplate.exchange( 784 return restTemplate.exchange(
777 baseURL + "/api/components?componentTypes={componentTypes}", 785 baseURL + "/api/components?componentTypes={componentTypes}",
778 HttpMethod.GET, 786 HttpMethod.GET,
779 HttpEntity.EMPTY, 787 HttpEntity.EMPTY,
780 new ParameterizedTypeReference<List<ComponentDescriptor>>() { 788 new ParameterizedTypeReference<List<ComponentDescriptor>>() {
781 }, 789 },
782 - String.join(",", componentTypes)).getBody(); 790 + listToString(componentTypes)).getBody();
783 } 791 }
784 792
785 public Optional<Customer> getCustomerById(String customerId) { 793 public Optional<Customer> getCustomerById(String customerId) {
@@ -915,7 +923,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -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 try { 927 try {
920 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers", customerIds, Dashboard.class, dashboardId); 928 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers", customerIds, Dashboard.class, dashboardId);
921 return Optional.ofNullable(dashboard.getBody()); 929 return Optional.ofNullable(dashboard.getBody());
@@ -928,7 +936,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -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 try { 940 try {
933 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/add", customerIds, Dashboard.class, dashboardId); 941 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/add", customerIds, Dashboard.class, dashboardId);
934 return Optional.ofNullable(dashboard.getBody()); 942 return Optional.ofNullable(dashboard.getBody());
@@ -941,7 +949,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -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 try { 953 try {
946 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/remove", customerIds, Dashboard.class, dashboardId); 954 ResponseEntity<Dashboard> dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/remove", customerIds, Dashboard.class, dashboardId);
947 return Optional.ofNullable(dashboard.getBody()); 955 return Optional.ofNullable(dashboard.getBody());
@@ -1135,12 +1143,12 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1135,12 +1143,12 @@ public class RestClient implements ClientHttpRequestInterceptor {
1135 .getBody(); 1143 .getBody();
1136 } 1144 }
1137 1145
1138 - public List<Device> getDevicesByIds(String[] deviceIds) { 1146 + public List<Device> getDevicesByIds(List<String> deviceIds) {
1139 return restTemplate.exchange(baseURL + "/api/devices?deviceIds={deviceIds}", 1147 return restTemplate.exchange(baseURL + "/api/devices?deviceIds={deviceIds}",
1140 HttpMethod.GET, 1148 HttpMethod.GET,
1141 HttpEntity.EMPTY, new ParameterizedTypeReference<List<Device>>() { 1149 HttpEntity.EMPTY, new ParameterizedTypeReference<List<Device>>() {
1142 }, 1150 },
1143 - String.join(",", deviceIds)).getBody(); 1151 + listToString(deviceIds)).getBody();
1144 } 1152 }
1145 1153
1146 public List<Device> findByQuery(DeviceSearchQuery query) { 1154 public List<Device> findByQuery(DeviceSearchQuery query) {
@@ -1161,28 +1169,22 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1161,28 +1169,22 @@ public class RestClient implements ClientHttpRequestInterceptor {
1161 }).getBody(); 1169 }).getBody();
1162 } 1170 }
1163 1171
1164 - public DeferredResult<ResponseEntity> claimDevice(String deviceName, ClaimRequest claimRequest) { 1172 + public JsonNode claimDevice(String deviceName, ClaimRequest claimRequest) {
1165 return restTemplate.exchange( 1173 return restTemplate.exchange(
1166 baseURL + "/api/customer/device/{deviceName}/claim", 1174 baseURL + "/api/customer/device/{deviceName}/claim",
1167 HttpMethod.POST, 1175 HttpMethod.POST,
1168 new HttpEntity<>(claimRequest), 1176 new HttpEntity<>(claimRequest),
1169 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1177 + new ParameterizedTypeReference<JsonNode>() {
1170 }, 1178 },
1171 deviceName).getBody(); 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 public void saveRelation(EntityRelation relation) { 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 public void deleteRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { 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,8 +1198,8 @@ public class RestClient implements ClientHttpRequestInterceptor {
1196 restTemplate.delete(baseURL + "/api/relation?fromId={fromId}&fromType={fromType}&relationType={relationType}&relationTypeGroup={relationTypeGroup}&toId={toId}&toType={toType}", params); 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 public Optional<EntityRelation> getRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { 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,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 Map<String, String> params = new HashMap<>(); 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 params.put("eventType", eventType); 1457 params.put("eventType", eventType);
1456 params.put("tenantId", tenantId); 1458 params.put("tenantId", tenantId);
1457 addPageLinkToParam(params, pageLink); 1459 addPageLinkToParam(params, pageLink);
@@ -1465,10 +1467,10 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1465,10 +1467,10 @@ public class RestClient implements ClientHttpRequestInterceptor {
1465 params).getBody(); 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 Map<String, String> params = new HashMap<>(); 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 params.put("tenantId", tenantId); 1474 params.put("tenantId", tenantId);
1473 addPageLinkToParam(params, pageLink); 1475 addPageLinkToParam(params, pageLink);
1474 1476
@@ -1481,22 +1483,16 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1481,22 +1483,16 @@ public class RestClient implements ClientHttpRequestInterceptor {
1481 params).getBody(); 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 return restTemplate.exchange( 1491 return restTemplate.exchange(
1496 baseURL + "/api/plugins/rpc/twoway/{deviceId}", 1492 baseURL + "/api/plugins/rpc/twoway/{deviceId}",
1497 HttpMethod.POST, 1493 HttpMethod.POST,
1498 new HttpEntity<>(requestBody), 1494 new HttpEntity<>(requestBody),
1499 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1495 + new ParameterizedTypeReference<JsonNode>() {
1500 }, 1496 },
1501 deviceId).getBody(); 1497 deviceId).getBody();
1502 } 1498 }
@@ -1590,206 +1586,233 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -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 return restTemplate.exchange( 1590 return restTemplate.exchange(
1595 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes", 1591 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes",
1596 HttpMethod.GET, 1592 HttpMethod.GET,
1597 HttpEntity.EMPTY, 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 return restTemplate.exchange( 1601 return restTemplate.exchange(
1606 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes/{scope}", 1602 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes/{scope}",
1607 HttpMethod.GET, 1603 HttpMethod.GET,
1608 HttpEntity.EMPTY, 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 scope).getBody(); 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes?keys={keys}", 1614 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes?keys={keys}",
1619 HttpMethod.GET, 1615 HttpMethod.GET,
1620 HttpEntity.EMPTY, 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes/{scope}?keys={keys}", 1632 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes/{scope}?keys={keys}",
1631 HttpMethod.GET, 1633 HttpMethod.GET,
1632 HttpEntity.EMPTY, 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 scope, 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 return restTemplate.exchange( 1646 return restTemplate.exchange(
1643 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/timeseries", 1647 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/timeseries",
1644 HttpMethod.GET, 1648 HttpMethod.GET,
1645 HttpEntity.EMPTY, 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}", 1658 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}",
1655 HttpMethod.GET, 1659 HttpMethod.GET,
1656 HttpEntity.EMPTY, 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 Map<String, String> params = new HashMap<>(); 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 params.put("startTs", startTs.toString()); 1676 params.put("startTs", startTs.toString());
1671 params.put("endTs", endTs.toString()); 1677 params.put("endTs", endTs.toString());
1672 params.put("interval", interval == null ? "0" : interval.toString()); 1678 params.put("interval", interval == null ? "0" : interval.toString());
1673 params.put("limit", limit == null ? "100" : limit.toString()); 1679 params.put("limit", limit == null ? "100" : limit.toString());
1674 params.put("agg", agg == null ? "NONE" : agg); 1680 params.put("agg", agg == null ? "NONE" : agg);
1675 1681
1676 - return restTemplate.exchange( 1682 + Map<String, List<JsonNode>> timeseries = restTemplate.exchange(
1677 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&startTs={startTs}&endTs={endTs}&interval={interval}&limit={limit}&agg={agg}", 1683 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&startTs={startTs}&endTs={endTs}&interval={interval}&limit={limit}&agg={agg}",
1678 HttpMethod.GET, 1684 HttpMethod.GET,
1679 HttpEntity.EMPTY, 1685 HttpEntity.EMPTY,
1680 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1686 + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() {
1681 }, 1687 },
1682 params).getBody(); 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 baseURL + "/api/plugins/telemetry/{deviceId}/{scope}", 1695 baseURL + "/api/plugins/telemetry/{deviceId}/{scope}",
1688 HttpMethod.POST, 1696 HttpMethod.POST,
1689 new HttpEntity<>(request), 1697 new HttpEntity<>(request),
1690 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1698 + new ParameterizedTypeReference<List<JsonNode>>() {
1691 }, 1699 },
1692 deviceId, 1700 deviceId,
1693 scope).getBody(); 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}", 1708 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}",
1699 HttpMethod.POST, 1709 HttpMethod.POST,
1700 new HttpEntity<>(request), 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 scope).getBody(); 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/attributes/{scope}", 1722 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/attributes/{scope}",
1711 HttpMethod.POST, 1723 HttpMethod.POST,
1712 new HttpEntity<>(request), 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 scope).getBody(); 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}", 1736 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}",
1723 HttpMethod.POST, 1737 HttpMethod.POST,
1724 new HttpEntity<>(requestBody), 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 scope).getBody(); 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}/{ttl}", 1750 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}/{ttl}",
1735 HttpMethod.POST, 1751 HttpMethod.POST,
1736 new HttpEntity<>(requestBody), 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 scope, 1757 scope,
1742 ttl).getBody(); 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 Map<String, String> params = new HashMap<>(); 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 params.put("deleteAllDataForKeys", String.valueOf(deleteAllDataForKeys)); 1773 params.put("deleteAllDataForKeys", String.valueOf(deleteAllDataForKeys));
1757 params.put("startTs", startTs.toString()); 1774 params.put("startTs", startTs.toString());
1758 params.put("endTs", endTs.toString()); 1775 params.put("endTs", endTs.toString());
1759 params.put("rewriteLatestIfDeleted", String.valueOf(rewriteLatestIfDeleted)); 1776 params.put("rewriteLatestIfDeleted", String.valueOf(rewriteLatestIfDeleted));
1760 1777
1761 - return restTemplate.exchange( 1778 + Map<String, List<JsonNode>> timeseries = restTemplate.exchange(
1762 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/delete?keys={keys}&deleteAllDataForKeys={deleteAllDataForKeys}&startTs={startTs}&endTs={endTs}&rewriteLatestIfDeleted={rewriteLatestIfDeleted}", 1779 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/delete?keys={keys}&deleteAllDataForKeys={deleteAllDataForKeys}&startTs={startTs}&endTs={endTs}&rewriteLatestIfDeleted={rewriteLatestIfDeleted}",
1763 HttpMethod.DELETE, 1780 HttpMethod.DELETE,
1764 HttpEntity.EMPTY, 1781 HttpEntity.EMPTY,
1765 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1782 + new ParameterizedTypeReference<Map<String, List<JsonNode>>>() {
1766 }, 1783 },
1767 params).getBody(); 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 baseURL + "/api/plugins/telemetry/{deviceId}/{scope}?keys={keys}", 1791 baseURL + "/api/plugins/telemetry/{deviceId}/{scope}?keys={keys}",
1773 HttpMethod.DELETE, 1792 HttpMethod.DELETE,
1774 HttpEntity.EMPTY, 1793 HttpEntity.EMPTY,
1775 - new ParameterizedTypeReference<DeferredResult<ResponseEntity>>() { 1794 + new ParameterizedTypeReference<List<JsonNode>>() {
1776 }, 1795 },
1777 deviceId, 1796 deviceId,
1778 scope, 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 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}?keys={keys}", 1805 baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}?keys={keys}",
1785 HttpMethod.DELETE, 1806 HttpMethod.DELETE,
1786 HttpEntity.EMPTY, 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 scope, 1812 scope,
1792 - keys).getBody(); 1813 + listToString(keys)).getBody();
  1814 +
  1815 + return RestJsonConverter.toAttributes(attributes);
1793 } 1816 }
1794 1817
1795 public Optional<Tenant> getTenantById(String tenantId) { 1818 public Optional<Tenant> getTenantById(String tenantId) {
@@ -1860,7 +1883,7 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1860,7 +1883,7 @@ public class RestClient implements ClientHttpRequestInterceptor {
1860 } 1883 }
1861 1884
1862 public void sendActivationEmail(String email) { 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 public String getActivationLink(String userId) { 1889 public String getActivationLink(String userId) {
@@ -1900,10 +1923,9 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -1900,10 +1923,9 @@ public class RestClient implements ClientHttpRequestInterceptor {
1900 } 1923 }
1901 1924
1902 public void setUserCredentialsEnabled(String userId, boolean userCredentialsEnabled) { 1925 public void setUserCredentialsEnabled(String userId, boolean userCredentialsEnabled) {
1903 - restTemplate.postForEntity( 1926 + restTemplate.postForLocation(
1904 baseURL + "/api/user/{userId}/userCredentialsEnabled?serCredentialsEnabled={serCredentialsEnabled}", 1927 baseURL + "/api/user/{userId}/userCredentialsEnabled?serCredentialsEnabled={serCredentialsEnabled}",
1905 null, 1928 null,
1906 - Object.class,  
1907 userId, 1929 userId,
1908 userCredentialsEnabled); 1930 userCredentialsEnabled);
1909 } 1931 }
@@ -2030,4 +2052,15 @@ public class RestClient implements ClientHttpRequestInterceptor { @@ -2030,4 +2052,15 @@ public class RestClient implements ClientHttpRequestInterceptor {
2030 params.put("textOffset", pageLink.getTextOffset()); 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 +}