Commit 7c2b3a9fbf84cc58aa7546029c5c7c10a662c55a

Authored by Igor Kulikov
1 parent cd23b85b

Improve REST API error response handling. Update swagger api.

... ... @@ -339,6 +339,17 @@
339 339 <resources>
340 340 <resource>
341 341 <directory>${project.basedir}/src/main/resources</directory>
  342 + <filtering>true</filtering>
  343 + <includes>
  344 + <include>thingsboard.yml</include>
  345 + </includes>
  346 + </resource>
  347 + <resource>
  348 + <directory>${project.basedir}/src/main/resources</directory>
  349 + <filtering>false</filtering>
  350 + <excludes>
  351 + <exclude>thingsboard.yml</exclude>
  352 + </excludes>
342 353 </resource>
343 354 </resources>
344 355 <plugins>
... ...
... ... @@ -26,10 +26,12 @@ import org.springframework.core.annotation.Order;
26 26 import org.springframework.http.HttpMethod;
27 27 import org.springframework.http.HttpStatus;
28 28 import org.springframework.http.MediaType;
  29 +import org.thingsboard.server.common.data.StringUtils;
29 30 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
30 31 import org.thingsboard.server.common.data.security.Authority;
31 32 import org.thingsboard.server.exception.ThingsboardCredentialsExpiredResponse;
32 33 import org.thingsboard.server.exception.ThingsboardErrorResponse;
  34 +import org.thingsboard.server.queue.util.TbCoreComponent;
33 35 import org.thingsboard.server.service.security.auth.rest.LoginRequest;
34 36 import org.thingsboard.server.service.security.auth.rest.LoginResponse;
35 37 import springfox.documentation.builders.ApiInfoBuilder;
... ... @@ -81,6 +83,7 @@ import static springfox.documentation.builders.PathSelectors.regex;
81 83
82 84 @Slf4j
83 85 @Configuration
  86 +@TbCoreComponent
84 87 public class SwaggerConfiguration {
85 88
86 89 @Value("${swagger.api_path_regex}")
... ... @@ -105,6 +108,8 @@ public class SwaggerConfiguration {
105 108 private String licenseUrl;
106 109 @Value("${swagger.version}")
107 110 private String version;
  111 + @Value("${app.version:unknown}")
  112 + private String appVersion;
108 113
109 114 @Bean
110 115 public Docket thingsboardApi() {
... ... @@ -231,13 +236,17 @@ public class SwaggerConfiguration {
231 236 }
232 237
233 238 private ApiInfo apiInfo() {
  239 + String apiVersion = version;
  240 + if (StringUtils.isEmpty(apiVersion)) {
  241 + apiVersion = appVersion;
  242 + }
234 243 return new ApiInfoBuilder()
235 244 .title(title)
236 245 .description(description)
237 246 .contact(new Contact(contactName, contactUrl, contactEmail))
238 247 .license(licenseTitle)
239 248 .licenseUrl(licenseUrl)
240   - .version(version)
  249 + .version(apiVersion)
241 250 .build();
242 251 }
243 252
... ...
... ... @@ -73,7 +73,7 @@ public class AdminController extends BaseController {
73 73 @PathVariable("key") String key) throws ThingsboardException {
74 74 try {
75 75 accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
76   - AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key));
  76 + AdminSettings adminSettings = checkNotNull(adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, key), "No Administration settings found for key: " + key);
77 77 if (adminSettings.getKey().equals("mail")) {
78 78 ((ObjectNode) adminSettings.getJsonValue()).remove("password");
79 79 }
... ...
... ... @@ -319,17 +319,25 @@ public abstract class BaseController {
319 319 }
320 320
321 321 <T> T checkNotNull(T reference) throws ThingsboardException {
  322 + return checkNotNull(reference, "Requested item wasn't found!");
  323 + }
  324 +
  325 + <T> T checkNotNull(T reference, String notFoundMessage) throws ThingsboardException {
322 326 if (reference == null) {
323   - throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
  327 + throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND);
324 328 }
325 329 return reference;
326 330 }
327 331
328 332 <T> T checkNotNull(Optional<T> reference) throws ThingsboardException {
  333 + return checkNotNull(reference, "Requested item wasn't found!");
  334 + }
  335 +
  336 + <T> T checkNotNull(Optional<T> reference, String notFoundMessage) throws ThingsboardException {
329 337 if (reference.isPresent()) {
330 338 return reference.get();
331 339 } else {
332   - throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
  340 + throw new ThingsboardException(notFoundMessage, ThingsboardErrorCode.ITEM_NOT_FOUND);
333 341 }
334 342 }
335 343
... ... @@ -389,7 +397,7 @@ public abstract class BaseController {
389 397 try {
390 398 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
391 399 Tenant tenant = tenantService.findTenantById(tenantId);
392   - checkNotNull(tenant);
  400 + checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found");
393 401 accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant);
394 402 return tenant;
395 403 } catch (Exception e) {
... ... @@ -401,7 +409,7 @@ public abstract class BaseController {
401 409 try {
402 410 validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
403 411 TenantInfo tenant = tenantService.findTenantInfoById(tenantId);
404   - checkNotNull(tenant);
  412 + checkNotNull(tenant, "Tenant with id [" + tenantId + "] is not found");
405 413 accessControlService.checkPermission(getCurrentUser(), Resource.TENANT, operation, tenantId, tenant);
406 414 return tenant;
407 415 } catch (Exception e) {
... ... @@ -413,7 +421,7 @@ public abstract class BaseController {
413 421 try {
414 422 validateId(tenantProfileId, "Incorrect tenantProfileId " + tenantProfileId);
415 423 TenantProfile tenantProfile = tenantProfileService.findTenantProfileById(getTenantId(), tenantProfileId);
416   - checkNotNull(tenantProfile);
  424 + checkNotNull(tenantProfile, "Tenant profile with id [" + tenantProfileId + "] is not found");
417 425 accessControlService.checkPermission(getCurrentUser(), Resource.TENANT_PROFILE, operation);
418 426 return tenantProfile;
419 427 } catch (Exception e) {
... ... @@ -429,7 +437,7 @@ public abstract class BaseController {
429 437 try {
430 438 validateId(customerId, "Incorrect customerId " + customerId);
431 439 Customer customer = customerService.findCustomerById(getTenantId(), customerId);
432   - checkNotNull(customer);
  440 + checkNotNull(customer, "Customer with id [" + customerId + "] is not found");
433 441 accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customerId, customer);
434 442 return customer;
435 443 } catch (Exception e) {
... ... @@ -441,7 +449,7 @@ public abstract class BaseController {
441 449 try {
442 450 validateId(userId, "Incorrect userId " + userId);
443 451 User user = userService.findUserById(getCurrentUser().getTenantId(), userId);
444   - checkNotNull(user);
  452 + checkNotNull(user, "User with id [" + userId + "] is not found");
445 453 accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, userId, user);
446 454 return user;
447 455 } catch (Exception e) {
... ... @@ -460,7 +468,9 @@ public abstract class BaseController {
460 468
461 469 protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException {
462 470 try {
463   - checkNotNull(entityId);
  471 + if (entityId == null) {
  472 + throw new ThingsboardException("Parameter entityId can't be empty!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  473 + }
464 474 validateId(entityId.getId(), "Incorrect entityId " + entityId);
465 475 switch (entityId.getEntityType()) {
466 476 case ALARM:
... ... @@ -526,7 +536,7 @@ public abstract class BaseController {
526 536 try {
527 537 validateId(deviceId, "Incorrect deviceId " + deviceId);
528 538 Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId);
529   - checkNotNull(device);
  539 + checkNotNull(device, "Device with id [" + deviceId + "] is not found");
530 540 accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device);
531 541 return device;
532 542 } catch (Exception e) {
... ... @@ -538,7 +548,7 @@ public abstract class BaseController {
538 548 try {
539 549 validateId(deviceId, "Incorrect deviceId " + deviceId);
540 550 DeviceInfo device = deviceService.findDeviceInfoById(getCurrentUser().getTenantId(), deviceId);
541   - checkNotNull(device);
  551 + checkNotNull(device, "Device with id [" + deviceId + "] is not found");
542 552 accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device);
543 553 return device;
544 554 } catch (Exception e) {
... ... @@ -550,7 +560,7 @@ public abstract class BaseController {
550 560 try {
551 561 validateId(deviceProfileId, "Incorrect deviceProfileId " + deviceProfileId);
552 562 DeviceProfile deviceProfile = deviceProfileService.findDeviceProfileById(getCurrentUser().getTenantId(), deviceProfileId);
553   - checkNotNull(deviceProfile);
  563 + checkNotNull(deviceProfile, "Device profile with id [" + deviceProfileId + "] is not found");
554 564 accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE_PROFILE, operation, deviceProfileId, deviceProfile);
555 565 return deviceProfile;
556 566 } catch (Exception e) {
... ... @@ -562,7 +572,7 @@ public abstract class BaseController {
562 572 try {
563 573 validateId(entityViewId, "Incorrect entityViewId " + entityViewId);
564 574 EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId);
565   - checkNotNull(entityView);
  575 + checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found");
566 576 accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView);
567 577 return entityView;
568 578 } catch (Exception e) {
... ... @@ -574,7 +584,7 @@ public abstract class BaseController {
574 584 try {
575 585 validateId(entityViewId, "Incorrect entityViewId " + entityViewId);
576 586 EntityViewInfo entityView = entityViewService.findEntityViewInfoById(getCurrentUser().getTenantId(), entityViewId);
577   - checkNotNull(entityView);
  587 + checkNotNull(entityView, "Entity view with id [" + entityViewId + "] is not found");
578 588 accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView);
579 589 return entityView;
580 590 } catch (Exception e) {
... ... @@ -586,7 +596,7 @@ public abstract class BaseController {
586 596 try {
587 597 validateId(assetId, "Incorrect assetId " + assetId);
588 598 Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId);
589   - checkNotNull(asset);
  599 + checkNotNull(asset, "Asset with id [" + assetId + "] is not found");
590 600 accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset);
591 601 return asset;
592 602 } catch (Exception e) {
... ... @@ -598,7 +608,7 @@ public abstract class BaseController {
598 608 try {
599 609 validateId(assetId, "Incorrect assetId " + assetId);
600 610 AssetInfo asset = assetService.findAssetInfoById(getCurrentUser().getTenantId(), assetId);
601   - checkNotNull(asset);
  611 + checkNotNull(asset, "Asset with id [" + assetId + "] is not found");
602 612 accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset);
603 613 return asset;
604 614 } catch (Exception e) {
... ... @@ -610,7 +620,7 @@ public abstract class BaseController {
610 620 try {
611 621 validateId(alarmId, "Incorrect alarmId " + alarmId);
612 622 Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
613   - checkNotNull(alarm);
  623 + checkNotNull(alarm, "Alarm with id [" + alarmId + "] is not found");
614 624 accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarm);
615 625 return alarm;
616 626 } catch (Exception e) {
... ... @@ -622,7 +632,7 @@ public abstract class BaseController {
622 632 try {
623 633 validateId(alarmId, "Incorrect alarmId " + alarmId);
624 634 AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
625   - checkNotNull(alarmInfo);
  635 + checkNotNull(alarmInfo, "Alarm with id [" + alarmId + "] is not found");
626 636 accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarmInfo);
627 637 return alarmInfo;
628 638 } catch (Exception e) {
... ... @@ -634,7 +644,7 @@ public abstract class BaseController {
634 644 try {
635 645 validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
636 646 WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId);
637   - checkNotNull(widgetsBundle);
  647 + checkNotNull(widgetsBundle, "Widgets bundle with id [" + widgetsBundleId + "] is not found");
638 648 accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle);
639 649 return widgetsBundle;
640 650 } catch (Exception e) {
... ... @@ -646,7 +656,7 @@ public abstract class BaseController {
646 656 try {
647 657 validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId);
648 658 WidgetTypeDetails widgetTypeDetails = widgetTypeService.findWidgetTypeDetailsById(getCurrentUser().getTenantId(), widgetTypeId);
649   - checkNotNull(widgetTypeDetails);
  659 + checkNotNull(widgetTypeDetails, "Widget type with id [" + widgetTypeId + "] is not found");
650 660 accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, widgetTypeId, widgetTypeDetails);
651 661 return widgetTypeDetails;
652 662 } catch (Exception e) {
... ... @@ -658,7 +668,7 @@ public abstract class BaseController {
658 668 try {
659 669 validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
660 670 Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId);
661   - checkNotNull(dashboard);
  671 + checkNotNull(dashboard, "Dashboard with id [" + dashboardId + "] is not found");
662 672 accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboard);
663 673 return dashboard;
664 674 } catch (Exception e) {
... ... @@ -670,7 +680,7 @@ public abstract class BaseController {
670 680 try {
671 681 validateId(edgeId, "Incorrect edgeId " + edgeId);
672 682 Edge edge = edgeService.findEdgeById(getTenantId(), edgeId);
673   - checkNotNull(edge);
  683 + checkNotNull(edge, "Edge with id [" + edgeId + "] is not found");
674 684 accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge);
675 685 return edge;
676 686 } catch (Exception e) {
... ... @@ -682,7 +692,7 @@ public abstract class BaseController {
682 692 try {
683 693 validateId(edgeId, "Incorrect edgeId " + edgeId);
684 694 EdgeInfo edge = edgeService.findEdgeInfoById(getCurrentUser().getTenantId(), edgeId);
685   - checkNotNull(edge);
  695 + checkNotNull(edge, "Edge with id [" + edgeId + "] is not found");
686 696 accessControlService.checkPermission(getCurrentUser(), Resource.EDGE, operation, edgeId, edge);
687 697 return edge;
688 698 } catch (Exception e) {
... ... @@ -694,7 +704,7 @@ public abstract class BaseController {
694 704 try {
695 705 validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
696 706 DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(getCurrentUser().getTenantId(), dashboardId);
697   - checkNotNull(dashboardInfo);
  707 + checkNotNull(dashboardInfo, "Dashboard with id [" + dashboardId + "] is not found");
698 708 accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboardInfo);
699 709 return dashboardInfo;
700 710 } catch (Exception e) {
... ... @@ -732,7 +742,7 @@ public abstract class BaseController {
732 742 protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation) throws ThingsboardException {
733 743 validateId(ruleChainId, "Incorrect ruleChainId " + ruleChainId);
734 744 RuleChain ruleChain = ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId);
735   - checkNotNull(ruleChain);
  745 + checkNotNull(ruleChain, "Rule chain with id [" + ruleChainId + "] is not found");
736 746 accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, ruleChainId, ruleChain);
737 747 return ruleChain;
738 748 }
... ... @@ -740,7 +750,7 @@ public abstract class BaseController {
740 750 protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException {
741 751 validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId);
742 752 RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId);
743   - checkNotNull(ruleNode);
  753 + checkNotNull(ruleNode, "Rule node with id [" + ruleNodeId + "] is not found");
744 754 checkRuleChain(ruleNode.getRuleChainId(), operation);
745 755 return ruleNode;
746 756 }
... ... @@ -749,7 +759,7 @@ public abstract class BaseController {
749 759 try {
750 760 validateId(resourceId, "Incorrect resourceId " + resourceId);
751 761 TbResource resource = resourceService.findResourceById(getCurrentUser().getTenantId(), resourceId);
752   - checkNotNull(resource);
  762 + checkNotNull(resource, "Resource with id [" + resourceId + "] is not found");
753 763 accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resource);
754 764 return resource;
755 765 } catch (Exception e) {
... ... @@ -761,7 +771,7 @@ public abstract class BaseController {
761 771 try {
762 772 validateId(resourceId, "Incorrect resourceId " + resourceId);
763 773 TbResourceInfo resourceInfo = resourceService.findResourceInfoById(getCurrentUser().getTenantId(), resourceId);
764   - checkNotNull(resourceInfo);
  774 + checkNotNull(resourceInfo, "Resource with id [" + resourceId + "] is not found");
765 775 accessControlService.checkPermission(getCurrentUser(), Resource.TB_RESOURCE, operation, resourceId, resourceInfo);
766 776 return resourceInfo;
767 777 } catch (Exception e) {
... ... @@ -773,7 +783,7 @@ public abstract class BaseController {
773 783 try {
774 784 validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId);
775 785 OtaPackage otaPackage = otaPackageService.findOtaPackageById(getCurrentUser().getTenantId(), otaPackageId);
776   - checkNotNull(otaPackage);
  786 + checkNotNull(otaPackage, "OTA package with id [" + otaPackageId + "] is not found");
777 787 accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackage);
778 788 return otaPackage;
779 789 } catch (Exception e) {
... ... @@ -785,7 +795,7 @@ public abstract class BaseController {
785 795 try {
786 796 validateId(otaPackageId, "Incorrect otaPackageId " + otaPackageId);
787 797 OtaPackageInfo otaPackageIn = otaPackageService.findOtaPackageInfoById(getCurrentUser().getTenantId(), otaPackageId);
788   - checkNotNull(otaPackageIn);
  798 + checkNotNull(otaPackageIn, "OTA package with id [" + otaPackageId + "] is not found");
789 799 accessControlService.checkPermission(getCurrentUser(), Resource.OTA_PACKAGE, operation, otaPackageId, otaPackageIn);
790 800 return otaPackageIn;
791 801 } catch (Exception e) {
... ... @@ -797,7 +807,7 @@ public abstract class BaseController {
797 807 try {
798 808 validateId(rpcId, "Incorrect rpcId " + rpcId);
799 809 Rpc rpc = rpcService.findById(getCurrentUser().getTenantId(), rpcId);
800   - checkNotNull(rpc);
  810 + checkNotNull(rpc, "RPC with id [" + rpcId + "] is not found");
801 811 accessControlService.checkPermission(getCurrentUser(), Resource.RPC, operation, rpcId, rpc);
802 812 return rpc;
803 813 } catch (Exception e) {
... ...
... ... @@ -240,7 +240,7 @@ public class CustomerController extends BaseController {
240 240 @RequestParam String customerTitle) throws ThingsboardException {
241 241 try {
242 242 TenantId tenantId = getCurrentUser().getTenantId();
243   - return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle));
  243 + return checkNotNull(customerService.findCustomerByTenantIdAndTitle(tenantId, customerTitle), "Customer with title [" + customerTitle + "] is not found");
244 244 } catch (Exception e) {
245 245 throw handleException(e);
246 246 }
... ...
... ... @@ -19,6 +19,9 @@ import com.fasterxml.jackson.databind.JsonNode;
19 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 20 import io.swagger.annotations.ApiOperation;
21 21 import io.swagger.annotations.ApiParam;
  22 +import io.swagger.annotations.ApiResponse;
  23 +import io.swagger.annotations.Example;
  24 +import io.swagger.annotations.ExampleProperty;
22 25 import org.springframework.beans.factory.annotation.Value;
23 26 import org.springframework.http.HttpStatus;
24 27 import org.springframework.http.MediaType;
... ... @@ -106,6 +109,7 @@ public class DashboardController extends BaseController {
106 109 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
107 110 @RequestMapping(value = "/dashboard/serverTime", method = RequestMethod.GET)
108 111 @ResponseBody
  112 + @ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "1636023857137", mediaType = "application/json")))
109 113 public long getServerTime() throws ThingsboardException {
110 114 return System.currentTimeMillis();
111 115 }
... ... @@ -118,6 +122,7 @@ public class DashboardController extends BaseController {
118 122 @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
119 123 @RequestMapping(value = "/dashboard/maxDatapointsLimit", method = RequestMethod.GET)
120 124 @ResponseBody
  125 + @ApiResponse(code = 200, message = "OK", examples = @Example(value = @ExampleProperty(value = "5000", mediaType = "application/json")))
121 126 public long getMaxDatapointsLimit() throws ThingsboardException {
122 127 return maxDatapointsLimit;
123 128 }
... ...
... ... @@ -17,9 +17,13 @@ package org.thingsboard.server.exception;
17 17
18 18 import com.fasterxml.jackson.databind.ObjectMapper;
19 19 import lombok.extern.slf4j.Slf4j;
  20 +import org.jetbrains.annotations.NotNull;
20 21 import org.springframework.beans.factory.annotation.Autowired;
  22 +import org.springframework.http.HttpHeaders;
21 23 import org.springframework.http.HttpStatus;
22 24 import org.springframework.http.MediaType;
  25 +import org.springframework.http.ResponseEntity;
  26 +import org.springframework.lang.Nullable;
23 27 import org.springframework.security.access.AccessDeniedException;
24 28 import org.springframework.security.authentication.BadCredentialsException;
25 29 import org.springframework.security.authentication.DisabledException;
... ... @@ -30,7 +34,9 @@ import org.springframework.security.web.access.AccessDeniedHandler;
30 34 import org.springframework.web.bind.annotation.ExceptionHandler;
31 35 import org.springframework.web.bind.annotation.RestControllerAdvice;
32 36 import org.springframework.web.client.HttpClientErrorException;
  37 +import org.springframework.web.context.request.WebRequest;
33 38 import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
  39 +import org.springframework.web.util.WebUtils;
34 40 import org.thingsboard.server.common.data.exception.ThingsboardErrorCode;
35 41 import org.thingsboard.server.common.data.exception.ThingsboardException;
36 42 import org.thingsboard.server.common.msg.tools.TbRateLimitsException;
... ... @@ -42,11 +48,49 @@ import javax.servlet.ServletException;
42 48 import javax.servlet.http.HttpServletRequest;
43 49 import javax.servlet.http.HttpServletResponse;
44 50 import java.io.IOException;
  51 +import java.util.HashMap;
  52 +import java.util.Map;
45 53
46 54 @Slf4j
47 55 @RestControllerAdvice
48 56 public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHandler implements AccessDeniedHandler {
49 57
  58 + private static final Map<HttpStatus, ThingsboardErrorCode> statusToErrorCodeMap = new HashMap<>();
  59 + static {
  60 + statusToErrorCodeMap.put(HttpStatus.BAD_REQUEST, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  61 + statusToErrorCodeMap.put(HttpStatus.UNAUTHORIZED, ThingsboardErrorCode.AUTHENTICATION);
  62 + statusToErrorCodeMap.put(HttpStatus.FORBIDDEN, ThingsboardErrorCode.PERMISSION_DENIED);
  63 + statusToErrorCodeMap.put(HttpStatus.NOT_FOUND, ThingsboardErrorCode.ITEM_NOT_FOUND);
  64 + statusToErrorCodeMap.put(HttpStatus.METHOD_NOT_ALLOWED, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  65 + statusToErrorCodeMap.put(HttpStatus.NOT_ACCEPTABLE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  66 + statusToErrorCodeMap.put(HttpStatus.UNSUPPORTED_MEDIA_TYPE, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
  67 + statusToErrorCodeMap.put(HttpStatus.TOO_MANY_REQUESTS, ThingsboardErrorCode.TOO_MANY_REQUESTS);
  68 + statusToErrorCodeMap.put(HttpStatus.INTERNAL_SERVER_ERROR, ThingsboardErrorCode.GENERAL);
  69 + statusToErrorCodeMap.put(HttpStatus.SERVICE_UNAVAILABLE, ThingsboardErrorCode.GENERAL);
  70 + }
  71 + private static final Map<ThingsboardErrorCode, HttpStatus> errorCodeToStatusMap = new HashMap<>();
  72 + static {
  73 + errorCodeToStatusMap.put(ThingsboardErrorCode.GENERAL, HttpStatus.INTERNAL_SERVER_ERROR);
  74 + errorCodeToStatusMap.put(ThingsboardErrorCode.AUTHENTICATION, HttpStatus.UNAUTHORIZED);
  75 + errorCodeToStatusMap.put(ThingsboardErrorCode.JWT_TOKEN_EXPIRED, HttpStatus.UNAUTHORIZED);
  76 + errorCodeToStatusMap.put(ThingsboardErrorCode.CREDENTIALS_EXPIRED, HttpStatus.UNAUTHORIZED);
  77 + errorCodeToStatusMap.put(ThingsboardErrorCode.PERMISSION_DENIED, HttpStatus.FORBIDDEN);
  78 + errorCodeToStatusMap.put(ThingsboardErrorCode.INVALID_ARGUMENTS, HttpStatus.BAD_REQUEST);
  79 + errorCodeToStatusMap.put(ThingsboardErrorCode.BAD_REQUEST_PARAMS, HttpStatus.BAD_REQUEST);
  80 + errorCodeToStatusMap.put(ThingsboardErrorCode.ITEM_NOT_FOUND, HttpStatus.NOT_FOUND);
  81 + errorCodeToStatusMap.put(ThingsboardErrorCode.TOO_MANY_REQUESTS, HttpStatus.TOO_MANY_REQUESTS);
  82 + errorCodeToStatusMap.put(ThingsboardErrorCode.TOO_MANY_UPDATES, HttpStatus.TOO_MANY_REQUESTS);
  83 + errorCodeToStatusMap.put(ThingsboardErrorCode.SUBSCRIPTION_VIOLATION, HttpStatus.FORBIDDEN);
  84 + }
  85 +
  86 + private static ThingsboardErrorCode statusToErrorCode(HttpStatus status) {
  87 + return statusToErrorCodeMap.getOrDefault(status, ThingsboardErrorCode.GENERAL);
  88 + }
  89 +
  90 + private static HttpStatus errorCodeToStatus(ThingsboardErrorCode errorCode) {
  91 + return errorCodeToStatusMap.getOrDefault(errorCode, HttpStatus.INTERNAL_SERVER_ERROR);
  92 + }
  93 +
50 94 @Autowired
51 95 private ObjectMapper mapper;
52 96
... ... @@ -95,36 +139,22 @@ public class ThingsboardErrorResponseHandler extends ResponseEntityExceptionHand
95 139 }
96 140 }
97 141
  142 + @NotNull
  143 + @Override
  144 + protected ResponseEntity<Object> handleExceptionInternal(
  145 + @NotNull Exception ex, @Nullable Object body,
  146 + @NotNull HttpHeaders headers, @NotNull HttpStatus status,
  147 + @NotNull WebRequest request) {
  148 + if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
  149 + request.setAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE, ex, WebRequest.SCOPE_REQUEST);
  150 + }
  151 + ThingsboardErrorCode errorCode = statusToErrorCode(status);
  152 + return new ResponseEntity<>(ThingsboardErrorResponse.of(ex.getMessage(), errorCode, status), headers, status);
  153 + }
98 154
99 155 private void handleThingsboardException(ThingsboardException thingsboardException, HttpServletResponse response) throws IOException {
100   -
101 156 ThingsboardErrorCode errorCode = thingsboardException.getErrorCode();
102   - HttpStatus status;
103   -
104   - switch (errorCode) {
105   - case AUTHENTICATION:
106   - status = HttpStatus.UNAUTHORIZED;
107   - break;
108   - case PERMISSION_DENIED:
109   - status = HttpStatus.FORBIDDEN;
110   - break;
111   - case INVALID_ARGUMENTS:
112   - status = HttpStatus.BAD_REQUEST;
113   - break;
114   - case ITEM_NOT_FOUND:
115   - status = HttpStatus.NOT_FOUND;
116   - break;
117   - case BAD_REQUEST_PARAMS:
118   - status = HttpStatus.BAD_REQUEST;
119   - break;
120   - case GENERAL:
121   - status = HttpStatus.INTERNAL_SERVER_ERROR;
122   - break;
123   - default:
124   - status = HttpStatus.INTERNAL_SERVER_ERROR;
125   - break;
126   - }
127   -
  157 + HttpStatus status = errorCodeToStatus(errorCode);
128 158 response.setStatus(status.value());
129 159 mapper.writeValue(response.getWriter(), ThingsboardErrorResponse.of(thingsboardException.getMessage(), errorCode, status));
130 160 }
... ...
... ... @@ -89,6 +89,11 @@ server:
89 89 # Default value of the server side RPC timeout.
90 90 default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}"
91 91
  92 +# Application info
  93 +app:
  94 + # Application version
  95 + version: "@project.version@"
  96 +
92 97 # Zookeeper connection parameters. Used for service discovery.
93 98 zk:
94 99 # Enable/disable zookeeper discovery service.
... ... @@ -859,7 +864,7 @@ swagger:
859 864 license:
860 865 title: "${SWAGGER_LICENSE_TITLE:Apache License Version 2.0}"
861 866 url: "${SWAGGER_LICENSE_URL:https://github.com/thingsboard/thingsboard/blob/master/LICENSE}"
862   - version: "${SWAGGER_VERSION:2.0}"
  867 + version: "${SWAGGER_VERSION:}"
863 868
864 869 queue:
865 870 type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ)
... ...
... ... @@ -58,7 +58,7 @@ public class AdminSettings extends BaseData<AdminSettingsId> {
58 58 return super.getCreatedTime();
59 59 }
60 60
61   - @ApiModelProperty(position = 3, value = "The Administration Settings key, (e.g. 'general' or 'mail')")
  61 + @ApiModelProperty(position = 3, value = "The Administration Settings key, (e.g. 'general' or 'mail')", example = "mail")
62 62 public String getKey() {
63 63 return key;
64 64 }
... ...
... ... @@ -83,7 +83,7 @@
83 83 <rabbitmq.version>4.8.0</rabbitmq.version>
84 84 <surfire.version>2.19.1</surfire.version>
85 85 <jar-plugin.version>3.0.2</jar-plugin.version>
86   - <springfox-swagger.version>3.0.3</springfox-swagger.version>
  86 + <springfox-swagger.version>3.0.4</springfox-swagger.version>
87 87 <swagger-annotations.version>1.6.3</swagger-annotations.version>
88 88 <spatial4j.version>0.7</spatial4j.version>
89 89 <jts.version>1.15.0</jts.version>
... ...