From e583b0a1d3c07bed59ac80fd0e8c2ce3186cef5f Mon Sep 17 00:00:00 2001 From: Yevhen Bondarenko <56396344+YevhenBondarenko@users.noreply.github.com> Date: Mon, 20 Jan 2020 15:02:00 +0200 Subject: [PATCH] Feature/rest client (#2347) * refactored URLs * refactored * refactored * refactored * refactored * refactored rest client * changed executorService from RestClient * refactored rest client and JsonConverter --- .../thingsboard/client/tools/RestClient.java | 309 ++++++++++-------- .../client/tools/utils/RestJsonConverter.java | 87 +++++ 2 files changed, 258 insertions(+), 138 deletions(-) create mode 100644 tools/src/main/java/org/thingsboard/client/tools/utils/RestJsonConverter.java diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java index 0bb59c4222..9b64f2292a 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -31,7 +31,7 @@ import org.springframework.http.client.support.HttpRequestWrapper; import org.springframework.util.StringUtils; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; -import org.springframework.web.context.request.async.DeferredResult; +import org.thingsboard.client.tools.utils.RestJsonConverter; import org.thingsboard.server.common.data.AdminSettings; import org.thingsboard.server.common.data.ClaimRequest; import org.thingsboard.server.common.data.Customer; @@ -57,6 +57,8 @@ import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.TextPageData; import org.thingsboard.server.common.data.page.TextPageLink; import org.thingsboard.server.common.data.page.TimePageData; @@ -74,6 +76,7 @@ import org.thingsboard.server.common.data.security.model.UserPasswordPolicy; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetsBundle; +import java.io.Closeable; import java.io.IOException; import java.net.URI; import java.util.Collections; @@ -81,19 +84,23 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; import static org.springframework.util.StringUtils.isEmpty; /** * @author Andrew Shvayka */ -public class RestClient implements ClientHttpRequestInterceptor { +public class RestClient implements ClientHttpRequestInterceptor, Closeable { private static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization"; protected final RestTemplate restTemplate; protected final String baseURL; private String token; private String refreshToken; private final ObjectMapper objectMapper = new ObjectMapper(); + private ExecutorService service = Executors.newWorkStealingPool(10); protected static final String ACTIVATE_TOKEN_REGEX = "/api/noauth/activate?activateToken="; @@ -256,6 +263,7 @@ public class RestClient implements ClientHttpRequestInterceptor { } return restTemplate.postForEntity(baseURL + deviceCreationUrl, device, Device.class, params).getBody(); } + public Asset createAsset(Asset asset) { return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody(); } @@ -418,17 +426,17 @@ public class RestClient implements ClientHttpRequestInterceptor { } public void ackAlarm(String alarmId) { - restTemplate.postForObject(baseURL + "/api/alarm/{alarmId}/ack", new Object(), Object.class, alarmId); + restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/ack", null, alarmId); } public void clearAlarm(String alarmId) { - restTemplate.postForObject(baseURL + "/api/alarm/{alarmId}/clear", new Object(), Object.class, alarmId); + restTemplate.postForLocation(baseURL + "/api/alarm/{alarmId}/clear", null, alarmId); } - public TimePageData getAlarms(String entityType, String entityId, String searchStatus, String status, TimePageLink pageLink, Boolean fetchOriginator) { + public TimePageData getAlarms(EntityId entityId, String searchStatus, String status, TimePageLink pageLink, Boolean fetchOriginator) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); params.put("searchStatus", searchStatus); params.put("status", status); params.put("fetchOriginator", String.valueOf(fetchOriginator)); @@ -471,10 +479,10 @@ public class RestClient implements ClientHttpRequestInterceptor { return urlParams; } - public Optional getHighestAlarmSeverity(String entityType, String entityId, String searchStatus, String status) { + public Optional getHighestAlarmSeverity(EntityId entityId, String searchStatus, String status) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); params.put("searchStatus", searchStatus); params.put("status", status); try { @@ -597,14 +605,14 @@ public class RestClient implements ClientHttpRequestInterceptor { return assets.getBody(); } - public List getAssetsByIds(String[] assetIds) { + public List getAssetsByIds(List assetIds) { return restTemplate.exchange( baseURL + "/api/assets?assetIds={assetIds}", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>() { }, - String.join(",", assetIds)).getBody(); + listToString(assetIds)).getBody(); } public List findByQuery(AssetSearchQuery query) { @@ -657,10 +665,10 @@ public class RestClient implements ClientHttpRequestInterceptor { return auditLog.getBody(); } - public TimePageData getAuditLogsByEntityId(String entityType, String entityId, String actionTypes, TimePageLink pageLink) { + public TimePageData getAuditLogsByEntityId(EntityId entityId, String actionTypes, TimePageLink pageLink) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); params.put("actionTypes", actionTypes); addPageLinkToParam(params, pageLink); @@ -700,14 +708,14 @@ public class RestClient implements ClientHttpRequestInterceptor { } public void logout() { - restTemplate.exchange(URI.create(baseURL + "/api/auth/logout"), HttpMethod.POST, HttpEntity.EMPTY, Object.class); + restTemplate.postForLocation(baseURL + "/api/auth/logout", null); } public void changePassword(String currentPassword, String newPassword) { ObjectNode changePasswordRequest = objectMapper.createObjectNode(); changePasswordRequest.put("currentPassword", currentPassword); changePasswordRequest.put("newPassword", newPassword); - restTemplate.exchange(URI.create(baseURL + "/api/auth/changePassword"), HttpMethod.POST, new HttpEntity<>(changePasswordRequest), Object.class); + restTemplate.postForLocation(baseURL + "/api/auth/changePassword", changePasswordRequest); } public Optional getUserPasswordPolicy() { @@ -731,7 +739,7 @@ public class RestClient implements ClientHttpRequestInterceptor { public void requestResetPasswordByEmail(String email) { ObjectNode resetPasswordByEmailRequest = objectMapper.createObjectNode(); resetPasswordByEmailRequest.put("email", email); - restTemplate.exchange(URI.create(baseURL + "/api/noauth/resetPasswordByEmail"), HttpMethod.POST, new HttpEntity<>(resetPasswordByEmailRequest), Object.class); + restTemplate.postForLocation(baseURL + "/api/noauth/resetPasswordByEmail", resetPasswordByEmailRequest); } public Optional activateUser(String userId, String password) { @@ -772,14 +780,14 @@ public class RestClient implements ClientHttpRequestInterceptor { componentType).getBody(); } - public List getComponentDescriptorsByTypes(String[] componentTypes) { + public List getComponentDescriptorsByTypes(List componentTypes) { return restTemplate.exchange( baseURL + "/api/components?componentTypes={componentTypes}", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>() { }, - String.join(",", componentTypes)).getBody(); + listToString(componentTypes)).getBody(); } public Optional getCustomerById(String customerId) { @@ -915,7 +923,7 @@ public class RestClient implements ClientHttpRequestInterceptor { } } - public Optional updateDashboardCustomers(String dashboardId, String[] customerIds) { + public Optional updateDashboardCustomers(String dashboardId, List customerIds) { try { ResponseEntity dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers", customerIds, Dashboard.class, dashboardId); return Optional.ofNullable(dashboard.getBody()); @@ -928,7 +936,7 @@ public class RestClient implements ClientHttpRequestInterceptor { } } - public Optional addDashboardCustomers(String dashboardId, String[] customerIds) { + public Optional addDashboardCustomers(String dashboardId, List customerIds) { try { ResponseEntity dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/add", customerIds, Dashboard.class, dashboardId); return Optional.ofNullable(dashboard.getBody()); @@ -941,7 +949,7 @@ public class RestClient implements ClientHttpRequestInterceptor { } } - public Optional removeDashboardCustomers(String dashboardId, String[] customerIds) { + public Optional removeDashboardCustomers(String dashboardId, List customerIds) { try { ResponseEntity dashboard = restTemplate.postForEntity(baseURL + "/api/dashboard/{dashboardId}/customers/remove", customerIds, Dashboard.class, dashboardId); return Optional.ofNullable(dashboard.getBody()); @@ -1135,12 +1143,12 @@ public class RestClient implements ClientHttpRequestInterceptor { .getBody(); } - public List getDevicesByIds(String[] deviceIds) { + public List getDevicesByIds(List deviceIds) { return restTemplate.exchange(baseURL + "/api/devices?deviceIds={deviceIds}", HttpMethod.GET, HttpEntity.EMPTY, new ParameterizedTypeReference>() { }, - String.join(",", deviceIds)).getBody(); + listToString(deviceIds)).getBody(); } public List findByQuery(DeviceSearchQuery query) { @@ -1161,28 +1169,22 @@ public class RestClient implements ClientHttpRequestInterceptor { }).getBody(); } - public DeferredResult claimDevice(String deviceName, ClaimRequest claimRequest) { + public JsonNode claimDevice(String deviceName, ClaimRequest claimRequest) { return restTemplate.exchange( baseURL + "/api/customer/device/{deviceName}/claim", HttpMethod.POST, new HttpEntity<>(claimRequest), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference() { }, deviceName).getBody(); } - public DeferredResult reClaimDevice(String deviceName) { - return restTemplate.exchange( - baseURL + "/api/customer/device/{deviceName}/claim", - HttpMethod.DELETE, - HttpEntity.EMPTY, - new ParameterizedTypeReference>() { - }, - deviceName).getBody(); + public void reClaimDevice(String deviceName) { + restTemplate.delete(baseURL + "/api/customer/device/{deviceName}/claim", deviceName); } public void saveRelation(EntityRelation relation) { - restTemplate.postForEntity(baseURL + "/api/relation", relation, Object.class); + restTemplate.postForLocation(baseURL + "/api/relation", null); } public void deleteRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { @@ -1196,8 +1198,8 @@ public class RestClient implements ClientHttpRequestInterceptor { restTemplate.delete(baseURL + "/api/relation?fromId={fromId}&fromType={fromType}&relationType={relationType}&relationTypeGroup={relationTypeGroup}&toId={toId}&toType={toType}", params); } - public void deleteRelations(String entityId, String entityType) { - restTemplate.delete(baseURL + "/api/relations?entityId={entityId}&entityType={entityType}", entityId, entityType); + public void deleteRelations(EntityId entityId) { + restTemplate.delete(baseURL + "/api/relations?entityId={entityId}&entityType={entityType}", entityId.getId().toString(), entityId.getEntityType().name()); } public Optional getRelation(String fromId, String fromType, String relationType, String relationTypeGroup, String toId, String toType) { @@ -1448,10 +1450,10 @@ public class RestClient implements ClientHttpRequestInterceptor { } } - public TimePageData getEvents(String entityType, String entityId, String eventType, String tenantId, TimePageLink pageLink) { + public TimePageData getEvents(EntityId entityId, String eventType, String tenantId, TimePageLink pageLink) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); params.put("eventType", eventType); params.put("tenantId", tenantId); addPageLinkToParam(params, pageLink); @@ -1465,10 +1467,10 @@ public class RestClient implements ClientHttpRequestInterceptor { params).getBody(); } - public TimePageData getEvents(String entityType, String entityId, String tenantId, TimePageLink pageLink) { + public TimePageData getEvents(EntityId entityId, String tenantId, TimePageLink pageLink) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); params.put("tenantId", tenantId); addPageLinkToParam(params, pageLink); @@ -1481,22 +1483,16 @@ public class RestClient implements ClientHttpRequestInterceptor { params).getBody(); } - public DeferredResult handleOneWayDeviceRPCRequest(String deviceId, String requestBody) { - return restTemplate.exchange( - baseURL + "/api/plugins/rpc/oneway/{deviceId}", - HttpMethod.POST, - new HttpEntity<>(requestBody), - new ParameterizedTypeReference>() { - }, - deviceId).getBody(); + public void handleOneWayDeviceRPCRequest(String deviceId, JsonNode requestBody) { + restTemplate.postForLocation(baseURL + "/api/plugins/rpc/oneway/{deviceId}", requestBody, deviceId); } - public DeferredResult handleTwoWayDeviceRPCRequest(String deviceId, String requestBody) { + public JsonNode handleTwoWayDeviceRPCRequest(String deviceId, JsonNode requestBody) { return restTemplate.exchange( baseURL + "/api/plugins/rpc/twoway/{deviceId}", HttpMethod.POST, new HttpEntity<>(requestBody), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference() { }, deviceId).getBody(); } @@ -1590,206 +1586,233 @@ public class RestClient implements ClientHttpRequestInterceptor { } } - public DeferredResult getAttributeKeys(String entityType, String entityId) { + public List getAttributeKeys(EntityId entityId) { return restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId).getBody(); + entityId.getEntityType().name(), + entityId.getId().toString()).getBody(); } - public DeferredResult getAttributeKeysByScope(String entityType, String entityId, String scope) { + public List getAttributeKeysByScope(EntityId entityId, String scope) { return restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/attributes/{scope}", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope).getBody(); } - public DeferredResult getAttributesResponseEntity(String entityType, String entityId, String keys) { - return restTemplate.exchange( + public List getAttributeKvEntries(EntityId entityId, List keys) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes?keys={keys}", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, - keys).getBody(); + entityId.getEntityType().name(), + entityId.getId(), + listToString(keys)).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult getAttributesByScope(String entityType, String entityId, String scope, String keys) { - return restTemplate.exchange( + public Future> getAttributeKvEntriesAsync(EntityId entityId, List keys) { + return service.submit(() -> getAttributeKvEntries(entityId, keys)); + } + + public List getAttributesByScope(EntityId entityId, String scope, List keys) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/attributes/{scope}?keys={keys}", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope, - keys).getBody(); + listToString(keys)).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult getTimeseriesKeys(String entityType, String entityId) { + public List getTimeseriesKeys(EntityId entityId) { return restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/keys/timeseries", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId).getBody(); + entityId.getEntityType().name(), + entityId.getId().toString()).getBody(); } - public DeferredResult getLatestTimeseries(String entityType, String entityId, String keys) { - return restTemplate.exchange( + public List getLatestTimeseries(EntityId entityId, List keys) { + Map> timeseries = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>>() { }, - entityType, - entityId, - keys).getBody(); + entityId.getEntityType().name(), + entityId.getId().toString(), + listToString(keys)).getBody(); + + return RestJsonConverter.toTimeseries(timeseries); } - public DeferredResult getTimeseries(String entityType, String entityId, String keys, Long startTs, Long endTs, Long interval, Integer limit, String agg) { + public List getTimeseries(EntityId entityId, List keys, Long startTs, Long endTs, Long interval, Integer limit, String agg) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); - params.put("keys", keys); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); + params.put("keys", listToString(keys)); params.put("startTs", startTs.toString()); params.put("endTs", endTs.toString()); params.put("interval", interval == null ? "0" : interval.toString()); params.put("limit", limit == null ? "100" : limit.toString()); params.put("agg", agg == null ? "NONE" : agg); - return restTemplate.exchange( + Map> timeseries = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/values/timeseries?keys={keys}&startTs={startTs}&endTs={endTs}&interval={interval}&limit={limit}&agg={agg}", HttpMethod.GET, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>>() { }, params).getBody(); + + return RestJsonConverter.toTimeseries(timeseries); } - public DeferredResult saveDeviceAttributes(String deviceId, String scope, JsonNode request) { - return restTemplate.exchange( + public List saveDeviceAttributes(String deviceId, String scope, JsonNode request) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{deviceId}/{scope}", HttpMethod.POST, new HttpEntity<>(request), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, deviceId, scope).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult saveEntityAttributesV1(String entityType, String entityId, String scope, JsonNode request) { - return restTemplate.exchange( + public List saveEntityAttributesV1(EntityId entityId, String scope, JsonNode request) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}", HttpMethod.POST, new HttpEntity<>(request), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult saveEntityAttributesV2(String entityType, String entityId, String scope, JsonNode request) { - return restTemplate.exchange( + public List saveEntityAttributesV2(EntityId entityId, String scope, JsonNode request) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/attributes/{scope}", HttpMethod.POST, new HttpEntity<>(request), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult saveEntityTelemetry(String entityType, String entityId, String scope, String requestBody) { - return restTemplate.exchange( + public List saveEntityTelemetry(EntityId entityId, String scope, String requestBody) { + Map> timeseries = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}", HttpMethod.POST, new HttpEntity<>(requestBody), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope).getBody(); + + return RestJsonConverter.toTimeseries(timeseries); } - public DeferredResult saveEntityTelemetryWithTTL(String entityType, String entityId, String scope, Long ttl, String requestBody) { - return restTemplate.exchange( + public List saveEntityTelemetryWithTTL(EntityId entityId, String scope, Long ttl, String requestBody) { + Map> timeseries = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/{scope}/{ttl}", HttpMethod.POST, new HttpEntity<>(requestBody), - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope, ttl).getBody(); + + return RestJsonConverter.toTimeseries(timeseries); } - public DeferredResult deleteEntityTimeseries(String entityType, - String entityId, - String keys, - boolean deleteAllDataForKeys, - Long startTs, - Long endTs, - boolean rewriteLatestIfDeleted) { + public List deleteEntityTimeseries(EntityId entityId, + List keys, + boolean deleteAllDataForKeys, + Long startTs, + Long endTs, + boolean rewriteLatestIfDeleted) { Map params = new HashMap<>(); - params.put("entityType", entityType); - params.put("entityId", entityId); - params.put("keys", keys); + params.put("entityType", entityId.getEntityType().name()); + params.put("entityId", entityId.getId().toString()); + params.put("keys", listToString(keys)); params.put("deleteAllDataForKeys", String.valueOf(deleteAllDataForKeys)); params.put("startTs", startTs.toString()); params.put("endTs", endTs.toString()); params.put("rewriteLatestIfDeleted", String.valueOf(rewriteLatestIfDeleted)); - return restTemplate.exchange( + Map> timeseries = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/timeseries/delete?keys={keys}&deleteAllDataForKeys={deleteAllDataForKeys}&startTs={startTs}&endTs={endTs}&rewriteLatestIfDeleted={rewriteLatestIfDeleted}", HttpMethod.DELETE, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>>() { }, params).getBody(); + + return RestJsonConverter.toTimeseries(timeseries); } - public DeferredResult deleteEntityAttributes(String deviceId, String scope, String keys) { - return restTemplate.exchange( + public List deleteEntityAttributes(String deviceId, String scope, List keys) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{deviceId}/{scope}?keys={keys}", HttpMethod.DELETE, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, deviceId, scope, - keys).getBody(); + listToString(keys)).getBody(); + + return RestJsonConverter.toAttributes(attributes); } - public DeferredResult deleteEntityAttributes(String entityType, String entityId, String scope, String keys) { - return restTemplate.exchange( + public List deleteEntityAttributes(EntityId entityId, String scope, List keys) { + List attributes = restTemplate.exchange( baseURL + "/api/plugins/telemetry/{entityType}/{entityId}/{scope}?keys={keys}", HttpMethod.DELETE, HttpEntity.EMPTY, - new ParameterizedTypeReference>() { + new ParameterizedTypeReference>() { }, - entityType, - entityId, + entityId.getEntityType().name(), + entityId.getId().toString(), scope, - keys).getBody(); + listToString(keys)).getBody(); + + return RestJsonConverter.toAttributes(attributes); } public Optional getTenantById(String tenantId) { @@ -1860,7 +1883,7 @@ public class RestClient implements ClientHttpRequestInterceptor { } public void sendActivationEmail(String email) { - restTemplate.postForEntity(baseURL + "/api/user/sendActivationMail?email={email}", null, Object.class, email); + restTemplate.postForLocation(baseURL + "/api/user/sendActivationMail?email={email}", null, email); } public String getActivationLink(String userId) { @@ -1900,10 +1923,9 @@ public class RestClient implements ClientHttpRequestInterceptor { } public void setUserCredentialsEnabled(String userId, boolean userCredentialsEnabled) { - restTemplate.postForEntity( + restTemplate.postForLocation( baseURL + "/api/user/{userId}/userCredentialsEnabled?serCredentialsEnabled={serCredentialsEnabled}", null, - Object.class, userId, userCredentialsEnabled); } @@ -2030,4 +2052,15 @@ public class RestClient implements ClientHttpRequestInterceptor { params.put("textOffset", pageLink.getTextOffset()); } } + + private String listToString(List list) { + return String.join(",", list); + } + + @Override + public void close() { + if (service != null) { + service.shutdown(); + } + } } diff --git a/tools/src/main/java/org/thingsboard/client/tools/utils/RestJsonConverter.java b/tools/src/main/java/org/thingsboard/client/tools/utils/RestJsonConverter.java new file mode 100644 index 0000000000..5e70e78659 --- /dev/null +++ b/tools/src/main/java/org/thingsboard/client/tools/utils/RestJsonConverter.java @@ -0,0 +1,87 @@ +/** + * Copyright © 2016-2020 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.thingsboard.client.tools.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import org.springframework.util.CollectionUtils; +import org.thingsboard.server.common.data.kv.AttributeKvEntry; +import org.thingsboard.server.common.data.kv.BaseAttributeKvEntry; +import org.thingsboard.server.common.data.kv.BasicTsKvEntry; +import org.thingsboard.server.common.data.kv.BooleanDataEntry; +import org.thingsboard.server.common.data.kv.DoubleDataEntry; +import org.thingsboard.server.common.data.kv.KvEntry; +import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.kv.StringDataEntry; +import org.thingsboard.server.common.data.kv.TsKvEntry; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class RestJsonConverter { + private static final String KEY = "key"; + private static final String VALUE = "value"; + private static final String LAST_UPDATE_TS = "lastUpdateTs"; + private static final String TS = "ts"; + + private static final String CAN_T_PARSE_VALUE = "Can't parse value: "; + + public static List toAttributes(List attributes) { + if (!CollectionUtils.isEmpty(attributes)) { + return attributes.stream().map(attr -> { + KvEntry entry = parseValue(attr.get(KEY).asText(), attr.get(VALUE)); + return new BaseAttributeKvEntry(entry, attr.get(LAST_UPDATE_TS).asLong()); + } + ).collect(Collectors.toList()); + } else { + return Collections.emptyList(); + } + } + + public static List toTimeseries(Map> timeseries) { + if (!CollectionUtils.isEmpty(timeseries)) { + List result = new ArrayList<>(); + timeseries.forEach((key, values) -> + result.addAll(values.stream().map(ts -> { + KvEntry entry = parseValue(key, ts.get(VALUE)); + return new BasicTsKvEntry(ts.get(TS).asLong(), entry); + } + ).collect(Collectors.toList())) + ); + return result; + } else { + return Collections.emptyList(); + } + } + + private static KvEntry parseValue(String key, JsonNode value) { + if (!value.isObject()) { + if (value.isBoolean()) { + return new BooleanDataEntry(key, value.asBoolean()); + } else if (value.isDouble()) { + return new DoubleDataEntry(key, value.asDouble()); + } else if (value.isLong()) { + return new LongDataEntry(key, value.asLong()); + } else { + return new StringDataEntry(key, value.asText()); + } + } else { + throw new RuntimeException(CAN_T_PARSE_VALUE + value); + } + } +}