Commit e2dd5b96aef5aca4c6a21012a5bbbda9b489169d

Authored by Yevhen Bondarenko
Committed by GitHub
1 parent 3f4714c2

added resource dao support (#4213)

* Version set to 3.3.0-SNAPSHOT

* added resource dao

* added resource support in transport lvl (get resources and "update", "delete" notifications)

* refactoring

* added resource table to hsql schema

* added check for models dir in InstallScripts

* added pageLink support to getResources
Showing 29 changed files with 801 additions and 9 deletions
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.security.access.prepost.PreAuthorize;
  20 +import org.springframework.web.bind.annotation.PathVariable;
  21 +import org.springframework.web.bind.annotation.RequestMapping;
  22 +import org.springframework.web.bind.annotation.RequestMethod;
  23 +import org.springframework.web.bind.annotation.RequestParam;
  24 +import org.springframework.web.bind.annotation.ResponseBody;
  25 +import org.springframework.web.bind.annotation.RestController;
  26 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  27 +import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.common.data.page.PageData;
  29 +import org.thingsboard.server.common.data.page.PageLink;
  30 +import org.thingsboard.server.common.data.transport.resource.Resource;
  31 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  32 +import org.thingsboard.server.dao.resource.ResourceService;
  33 +import org.thingsboard.server.queue.util.TbCoreComponent;
  34 +
  35 +@Slf4j
  36 +@RestController
  37 +@TbCoreComponent
  38 +@RequestMapping("/api")
  39 +public class ResourceController extends BaseController {
  40 +
  41 + private final ResourceService resourceService;
  42 +
  43 + public ResourceController(ResourceService resourceService) {
  44 + this.resourceService = resourceService;
  45 + }
  46 +
  47 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  48 + @RequestMapping(value = "/resource", method = RequestMethod.POST)
  49 + @ResponseBody
  50 + public Resource saveResource(Resource resource) throws ThingsboardException {
  51 + try {
  52 + resource.setTenantId(getTenantId());
  53 + Resource savedResource = checkNotNull(resourceService.saveResource(resource));
  54 + tbClusterService.onResourceChange(savedResource, null);
  55 + return savedResource;
  56 + } catch (Exception e) {
  57 + throw handleException(e);
  58 + }
  59 + }
  60 +
  61 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  62 + @RequestMapping(value = "/resource", method = RequestMethod.GET)
  63 + @ResponseBody
  64 + public PageData<Resource> getResources(@RequestParam(required = false) boolean system,
  65 + @RequestParam int pageSize,
  66 + @RequestParam int page,
  67 + @RequestParam(required = false) String sortProperty,
  68 + @RequestParam(required = false) String sortOrder) throws ThingsboardException {
  69 + try {
  70 + PageLink pageLink = createPageLink(pageSize, page, null, sortProperty, sortOrder);
  71 + return checkNotNull(resourceService.findResourcesByTenantId(system ? TenantId.SYS_TENANT_ID : getTenantId(), pageLink));
  72 + } catch (Exception e) {
  73 + throw handleException(e);
  74 + }
  75 + }
  76 +
  77 + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')")
  78 + @RequestMapping(value = "/resource/{resourceType}/{resourceId}", method = RequestMethod.DELETE)
  79 + @ResponseBody
  80 + public void deleteResource(@PathVariable("resourceType") ResourceType resourceType,
  81 + @PathVariable("resourceId") String resourceId) throws ThingsboardException {
  82 + try {
  83 + Resource resource = checkNotNull(resourceService.getResource(getTenantId(), resourceType, resourceId));
  84 + resourceService.deleteResource(getTenantId(), resourceType, resourceId);
  85 + tbClusterService.onResourceDeleted(resource, null);
  86 + } catch (Exception e) {
  87 + throw handleException(e);
  88 + }
  89 + }
  90 +}
@@ -194,6 +194,12 @@ public class ThingsboardInstallService { @@ -194,6 +194,12 @@ public class ThingsboardInstallService {
194 log.info("Updating system data..."); 194 log.info("Updating system data...");
195 systemDataLoaderService.updateSystemWidgets(); 195 systemDataLoaderService.updateSystemWidgets();
196 break; 196 break;
  197 + case "3.2.2":
  198 + log.info("Upgrading ThingsBoard from version 3.2.2 to 3.3.0 ...");
  199 + databaseEntitiesUpgradeService.upgradeDatabase("3.2.2");
  200 +
  201 + log.info("Updating system data...");
  202 + break;
197 default: 203 default:
198 throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion); 204 throw new RuntimeException("Unable to upgrade ThingsBoard, unsupported fromVersion: " + upgradeFromVersion);
199 205
@@ -226,6 +232,7 @@ public class ThingsboardInstallService { @@ -226,6 +232,7 @@ public class ThingsboardInstallService {
226 systemDataLoaderService.createAdminSettings(); 232 systemDataLoaderService.createAdminSettings();
227 systemDataLoaderService.loadSystemWidgets(); 233 systemDataLoaderService.loadSystemWidgets();
228 systemDataLoaderService.createOAuth2Templates(); 234 systemDataLoaderService.createOAuth2Templates();
  235 + systemDataLoaderService.loadSystemLwm2mResources();
229 // systemDataLoaderService.loadSystemPlugins(); 236 // systemDataLoaderService.loadSystemPlugins();
230 // systemDataLoaderService.loadSystemRules(); 237 // systemDataLoaderService.loadSystemRules();
231 238
@@ -445,6 +445,11 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { @@ -445,6 +445,11 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService {
445 installScripts.loadSystemWidgets(); 445 installScripts.loadSystemWidgets();
446 } 446 }
447 447
  448 + @Override
  449 + public void loadSystemLwm2mResources() throws Exception {
  450 + installScripts.loadSystemLwm2mResources();
  451 + }
  452 +
448 private User createUser(Authority authority, 453 private User createUser(Authority authority,
449 TenantId tenantId, 454 TenantId tenantId,
450 CustomerId customerId, 455 CustomerId customerId,
@@ -24,15 +24,17 @@ import org.springframework.util.StringUtils; @@ -24,15 +24,17 @@ import org.springframework.util.StringUtils;
24 import org.thingsboard.server.common.data.Dashboard; 24 import org.thingsboard.server.common.data.Dashboard;
25 import org.thingsboard.server.common.data.id.CustomerId; 25 import org.thingsboard.server.common.data.id.CustomerId;
26 import org.thingsboard.server.common.data.id.EntityId; 26 import org.thingsboard.server.common.data.id.EntityId;
27 -import org.thingsboard.server.common.data.id.RuleChainId;  
28 import org.thingsboard.server.common.data.id.TenantId; 27 import org.thingsboard.server.common.data.id.TenantId;
29 import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate; 28 import org.thingsboard.server.common.data.oauth2.OAuth2ClientRegistrationTemplate;
30 import org.thingsboard.server.common.data.rule.RuleChain; 29 import org.thingsboard.server.common.data.rule.RuleChain;
31 import org.thingsboard.server.common.data.rule.RuleChainMetaData; 30 import org.thingsboard.server.common.data.rule.RuleChainMetaData;
  31 +import org.thingsboard.server.common.data.transport.resource.Resource;
  32 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
32 import org.thingsboard.server.common.data.widget.WidgetType; 33 import org.thingsboard.server.common.data.widget.WidgetType;
33 import org.thingsboard.server.common.data.widget.WidgetsBundle; 34 import org.thingsboard.server.common.data.widget.WidgetsBundle;
34 import org.thingsboard.server.dao.dashboard.DashboardService; 35 import org.thingsboard.server.dao.dashboard.DashboardService;
35 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; 36 import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService;
  37 +import org.thingsboard.server.dao.resource.ResourceService;
36 import org.thingsboard.server.dao.rule.RuleChainService; 38 import org.thingsboard.server.dao.rule.RuleChainService;
37 import org.thingsboard.server.dao.widget.WidgetTypeService; 39 import org.thingsboard.server.dao.widget.WidgetTypeService;
38 import org.thingsboard.server.dao.widget.WidgetsBundleService; 40 import org.thingsboard.server.dao.widget.WidgetsBundleService;
@@ -42,6 +44,7 @@ import java.nio.file.DirectoryStream; @@ -42,6 +44,7 @@ import java.nio.file.DirectoryStream;
42 import java.nio.file.Files; 44 import java.nio.file.Files;
43 import java.nio.file.Path; 45 import java.nio.file.Path;
44 import java.nio.file.Paths; 46 import java.nio.file.Paths;
  47 +import java.util.Base64;
45 import java.util.Optional; 48 import java.util.Optional;
46 49
47 import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper; 50 import static org.thingsboard.server.service.install.DatabaseHelper.objectMapper;
@@ -66,8 +69,11 @@ public class InstallScripts { @@ -66,8 +69,11 @@ public class InstallScripts {
66 public static final String WIDGET_BUNDLES_DIR = "widget_bundles"; 69 public static final String WIDGET_BUNDLES_DIR = "widget_bundles";
67 public static final String OAUTH2_CONFIG_TEMPLATES_DIR = "oauth2_config_templates"; 70 public static final String OAUTH2_CONFIG_TEMPLATES_DIR = "oauth2_config_templates";
68 public static final String DASHBOARDS_DIR = "dashboards"; 71 public static final String DASHBOARDS_DIR = "dashboards";
  72 + public static final String MODELS_DIR = "models";
  73 + public static final String CREDENTIALS_DIR = "credentials";
69 74
70 public static final String JSON_EXT = ".json"; 75 public static final String JSON_EXT = ".json";
  76 + public static final String XML_EXT = ".xml";
71 77
72 @Value("${install.data_dir:}") 78 @Value("${install.data_dir:}")
73 private String dataDir; 79 private String dataDir;
@@ -87,6 +93,9 @@ public class InstallScripts { @@ -87,6 +93,9 @@ public class InstallScripts {
87 @Autowired 93 @Autowired
88 private OAuth2ConfigTemplateService oAuth2TemplateService; 94 private OAuth2ConfigTemplateService oAuth2TemplateService;
89 95
  96 + @Autowired
  97 + private ResourceService resourceService;
  98 +
90 public Path getTenantRuleChainsDir() { 99 public Path getTenantRuleChainsDir() {
91 return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR); 100 return Paths.get(getDataDir(), JSON_DIR, TENANT_DIR, RULE_CHAINS_DIR);
92 } 101 }
@@ -186,6 +195,42 @@ public class InstallScripts { @@ -186,6 +195,42 @@ public class InstallScripts {
186 } 195 }
187 } 196 }
188 197
  198 + public void loadSystemLwm2mResources() throws Exception {
  199 + Path modelsDir = Paths.get(getDataDir(), MODELS_DIR);
  200 + if (Files.isDirectory(modelsDir)) {
  201 + try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(modelsDir, path -> path.toString().endsWith(XML_EXT))) {
  202 + dirStream.forEach(
  203 + path -> {
  204 + try {
  205 + Resource resource = new Resource();
  206 + resource.setTenantId(TenantId.SYS_TENANT_ID);
  207 + resource.setResourceType(ResourceType.LWM2M_MODEL);
  208 + resource.setResourceId(path.getFileName().toString());
  209 + resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(path)));
  210 + resourceService.saveResource(resource);
  211 + } catch (Exception e) {
  212 + log.error("Unable to load lwm2m model [{}]", path.toString());
  213 + throw new RuntimeException("Unable to load lwm2m model", e);
  214 + }
  215 + }
  216 + );
  217 + }
  218 + }
  219 +
  220 + Path jksPath = Paths.get(getDataDir(), CREDENTIALS_DIR, "serverKeyStore.jks");
  221 + try {
  222 + Resource resource = new Resource();
  223 + resource.setTenantId(TenantId.SYS_TENANT_ID);
  224 + resource.setResourceType(ResourceType.JKS);
  225 + resource.setResourceId(jksPath.getFileName().toString());
  226 + resource.setValue(Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath)));
  227 + resourceService.saveResource(resource);
  228 + } catch (Exception e) {
  229 + log.error("Unable to load lwm2m serverKeyStore [{}]", jksPath.toString());
  230 + throw new RuntimeException("Unable to load l2m2m serverKeyStore", e);
  231 + }
  232 + }
  233 +
189 public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception { 234 public void loadDashboards(TenantId tenantId, CustomerId customerId) throws Exception {
190 Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR); 235 Path dashboardsDir = Paths.get(getDataDir(), JSON_DIR, DEMO_DIR, DASHBOARDS_DIR);
191 try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) { 236 try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(dashboardsDir, path -> path.toString().endsWith(JSON_EXT))) {
@@ -208,7 +253,6 @@ public class InstallScripts { @@ -208,7 +253,6 @@ public class InstallScripts {
208 } 253 }
209 } 254 }
210 255
211 -  
212 public void loadDemoRuleChains(TenantId tenantId) throws Exception { 256 public void loadDemoRuleChains(TenantId tenantId) throws Exception {
213 try { 257 try {
214 createDefaultRuleChains(tenantId); 258 createDefaultRuleChains(tenantId);
@@ -434,6 +434,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService @@ -434,6 +434,25 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
434 log.info("Schema updated."); 434 log.info("Schema updated.");
435 } 435 }
436 break; 436 break;
  437 + case "3.2.2":
  438 + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
  439 + log.info("Updating schema ...");
  440 + try {
  441 + conn.createStatement().execute("CREATE TABLE IF NOT EXISTS resource (" +
  442 + " tenant_id uuid NOT NULL," +
  443 + " resource_type varchar(32) NOT NULL," +
  444 + " resource_id varchar(255) NOT NULL," +
  445 + " resource_value varchar," +
  446 + " CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)" +
  447 + " );");
  448 +
  449 + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003000;");
  450 + } catch (Exception e) {
  451 + log.error("Failed updating schema!!!", e);
  452 + }
  453 + log.info("Schema updated.");
  454 + }
  455 + break;
437 default: 456 default:
438 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion); 457 throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
439 } 458 }
@@ -33,4 +33,6 @@ public interface SystemDataLoaderService { @@ -33,4 +33,6 @@ public interface SystemDataLoaderService {
33 33
34 void deleteSystemWidgetBundle(String bundleAlias) throws Exception; 34 void deleteSystemWidgetBundle(String bundleAlias) throws Exception;
35 35
  36 + void loadSystemLwm2mResources() throws Exception;
  37 +
36 } 38 }
@@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.page.PageLink; @@ -33,6 +33,7 @@ import org.thingsboard.server.common.data.page.PageLink;
33 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap; 33 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigBootstrap;
34 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer; 34 import org.thingsboard.server.common.transport.lwm2m.LwM2MTransportConfigServer;
35 import org.thingsboard.server.dao.service.Validator; 35 import org.thingsboard.server.dao.service.Validator;
  36 +import org.thingsboard.server.queue.util.TbLwM2mTransportComponent;
36 import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode; 37 import org.thingsboard.server.transport.lwm2m.secure.LwM2MSecurityMode;
37 38
38 import java.math.BigInteger; 39 import java.math.BigInteger;
@@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.id.EntityId;
34 import org.thingsboard.server.common.data.id.RuleChainId; 34 import org.thingsboard.server.common.data.id.RuleChainId;
35 import org.thingsboard.server.common.data.id.TenantId; 35 import org.thingsboard.server.common.data.id.TenantId;
36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 36 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  37 +import org.thingsboard.server.common.data.transport.resource.Resource;
37 import org.thingsboard.server.common.msg.TbMsg; 38 import org.thingsboard.server.common.msg.TbMsg;
38 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; 39 import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg;
39 import org.thingsboard.server.common.msg.queue.ServiceType; 40 import org.thingsboard.server.common.msg.queue.ServiceType;
@@ -247,6 +248,34 @@ public class DefaultTbClusterService implements TbClusterService { @@ -247,6 +248,34 @@ public class DefaultTbClusterService implements TbClusterService {
247 onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback); 248 onEntityDelete(entity.getTenantId(), entity.getId(), entity.getName(), callback);
248 } 249 }
249 250
  251 + @Override
  252 + public void onResourceChange(Resource resource, TbQueueCallback callback) {
  253 + TenantId tenantId = resource.getTenantId();
  254 + log.trace("[{}][{}][{}] Processing change resource", tenantId, resource.getResourceType(), resource.getResourceId());
  255 + TransportProtos.ResourceUpdateMsg resourceUpdateMsg = TransportProtos.ResourceUpdateMsg.newBuilder()
  256 + .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
  257 + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
  258 + .setResourceType(resource.getResourceType().name())
  259 + .setResourceId(resource.getResourceId())
  260 + .build();
  261 + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceUpdateMsg(resourceUpdateMsg).build();
  262 + broadcast(transportMsg, callback);
  263 + }
  264 +
  265 + @Override
  266 + public void onResourceDeleted(Resource resource, TbQueueCallback callback) {
  267 + TenantId tenantId = resource.getTenantId();
  268 + log.trace("[{}][{}][{}] Processing delete resource", tenantId, resource.getResourceType(), resource.getResourceId());
  269 + TransportProtos.ResourceDeleteMsg resourceUpdateMsg = TransportProtos.ResourceDeleteMsg.newBuilder()
  270 + .setTenantIdMSB(tenantId.getId().getMostSignificantBits())
  271 + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits())
  272 + .setResourceType(resource.getResourceType().name())
  273 + .setResourceId(resource.getResourceId())
  274 + .build();
  275 + ToTransportMsg transportMsg = ToTransportMsg.newBuilder().setResourceDeleteMsg(resourceUpdateMsg).build();
  276 + broadcast(transportMsg, callback);
  277 + }
  278 +
250 public <T> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) { 279 public <T> void onEntityChange(TenantId tenantId, EntityId entityid, T entity, TbQueueCallback callback) {
251 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName(); 280 String entityName = (entity instanceof HasName) ? ((HasName) entity).getName() : entity.getClass().getName();
252 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName); 281 log.trace("[{}][{}][{}] Processing [{}] change event", tenantId, entityid.getEntityType(), entityid.getId(), entityName);
@@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.TenantProfile; @@ -24,6 +24,7 @@ import org.thingsboard.server.common.data.TenantProfile;
24 import org.thingsboard.server.common.data.id.EntityId; 24 import org.thingsboard.server.common.data.id.EntityId;
25 import org.thingsboard.server.common.data.id.TenantId; 25 import org.thingsboard.server.common.data.id.TenantId;
26 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; 26 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
  27 +import org.thingsboard.server.common.data.transport.resource.Resource;
27 import org.thingsboard.server.common.msg.TbMsg; 28 import org.thingsboard.server.common.msg.TbMsg;
28 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; 29 import org.thingsboard.server.common.msg.queue.TopicPartitionInfo;
29 import org.thingsboard.server.gen.transport.TransportProtos; 30 import org.thingsboard.server.gen.transport.TransportProtos;
@@ -71,4 +72,8 @@ public interface TbClusterService { @@ -71,4 +72,8 @@ public interface TbClusterService {
71 void onDeviceChange(Device device, TbQueueCallback callback); 72 void onDeviceChange(Device device, TbQueueCallback callback);
72 73
73 void onDeviceDeleted(Device device, TbQueueCallback callback); 74 void onDeviceDeleted(Device device, TbQueueCallback callback);
  75 +
  76 + void onResourceChange(Resource resource, TbQueueCallback callback);
  77 +
  78 + void onResourceDeleted(Resource resource, TbQueueCallback callback);
74 } 79 }
@@ -25,6 +25,7 @@ import com.google.protobuf.ByteString; @@ -25,6 +25,7 @@ import com.google.protobuf.ByteString;
25 import lombok.extern.slf4j.Slf4j; 25 import lombok.extern.slf4j.Slf4j;
26 import org.springframework.stereotype.Service; 26 import org.springframework.stereotype.Service;
27 import org.springframework.util.StringUtils; 27 import org.springframework.util.StringUtils;
  28 +import org.thingsboard.common.util.JacksonUtil;
28 import org.thingsboard.server.common.data.ApiUsageState; 29 import org.thingsboard.server.common.data.ApiUsageState;
29 import org.thingsboard.server.common.data.DataConstants; 30 import org.thingsboard.server.common.data.DataConstants;
30 import org.thingsboard.server.common.data.Device; 31 import org.thingsboard.server.common.data.Device;
@@ -38,9 +39,12 @@ import org.thingsboard.server.common.data.id.CustomerId; @@ -38,9 +39,12 @@ import org.thingsboard.server.common.data.id.CustomerId;
38 import org.thingsboard.server.common.data.id.DeviceId; 39 import org.thingsboard.server.common.data.id.DeviceId;
39 import org.thingsboard.server.common.data.id.DeviceProfileId; 40 import org.thingsboard.server.common.data.id.DeviceProfileId;
40 import org.thingsboard.server.common.data.id.TenantId; 41 import org.thingsboard.server.common.data.id.TenantId;
  42 +import org.thingsboard.server.common.data.page.PageLink;
41 import org.thingsboard.server.common.data.relation.EntityRelation; 43 import org.thingsboard.server.common.data.relation.EntityRelation;
42 import org.thingsboard.server.common.data.security.DeviceCredentials; 44 import org.thingsboard.server.common.data.security.DeviceCredentials;
43 import org.thingsboard.server.common.data.security.DeviceCredentialsType; 45 import org.thingsboard.server.common.data.security.DeviceCredentialsType;
  46 +import org.thingsboard.server.common.data.transport.resource.Resource;
  47 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
44 import org.thingsboard.server.common.msg.EncryptionUtil; 48 import org.thingsboard.server.common.msg.EncryptionUtil;
45 import org.thingsboard.server.common.msg.TbMsg; 49 import org.thingsboard.server.common.msg.TbMsg;
46 import org.thingsboard.server.common.msg.TbMsgDataType; 50 import org.thingsboard.server.common.msg.TbMsgDataType;
@@ -53,14 +57,15 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException; @@ -53,14 +57,15 @@ import org.thingsboard.server.dao.device.provision.ProvisionFailedException;
53 import org.thingsboard.server.dao.device.provision.ProvisionRequest; 57 import org.thingsboard.server.dao.device.provision.ProvisionRequest;
54 import org.thingsboard.server.dao.device.provision.ProvisionResponse; 58 import org.thingsboard.server.dao.device.provision.ProvisionResponse;
55 import org.thingsboard.server.dao.relation.RelationService; 59 import org.thingsboard.server.dao.relation.RelationService;
  60 +import org.thingsboard.server.dao.resource.ResourceService;
56 import org.thingsboard.server.dao.tenant.TbTenantProfileCache; 61 import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
57 -import org.thingsboard.common.util.JacksonUtil;  
58 import org.thingsboard.server.gen.transport.TransportProtos; 62 import org.thingsboard.server.gen.transport.TransportProtos;
59 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto; 63 import org.thingsboard.server.gen.transport.TransportProtos.DeviceInfoProto;
60 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; 64 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
61 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; 65 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
62 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 66 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
63 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg; 67 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayResponseMsg;
  68 +import org.thingsboard.server.gen.transport.TransportProtos.GetResourcesRequestMsg;
64 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg; 69 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionDeviceRequestMsg;
65 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus; 70 import org.thingsboard.server.gen.transport.TransportProtos.ProvisionResponseStatus;
66 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; 71 import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg;
@@ -77,11 +82,14 @@ import org.thingsboard.server.service.profile.TbDeviceProfileCache; @@ -77,11 +82,14 @@ import org.thingsboard.server.service.profile.TbDeviceProfileCache;
77 import org.thingsboard.server.service.queue.TbClusterService; 82 import org.thingsboard.server.service.queue.TbClusterService;
78 import org.thingsboard.server.service.state.DeviceStateService; 83 import org.thingsboard.server.service.state.DeviceStateService;
79 84
  85 +import java.util.Collections;
  86 +import java.util.List;
80 import java.util.UUID; 87 import java.util.UUID;
81 import java.util.concurrent.ConcurrentHashMap; 88 import java.util.concurrent.ConcurrentHashMap;
82 import java.util.concurrent.ConcurrentMap; 89 import java.util.concurrent.ConcurrentMap;
83 import java.util.concurrent.locks.Lock; 90 import java.util.concurrent.locks.Lock;
84 import java.util.concurrent.locks.ReentrantLock; 91 import java.util.concurrent.locks.ReentrantLock;
  92 +import java.util.stream.Collectors;
85 93
86 /** 94 /**
87 * Created by ashvayka on 05.10.18. 95 * Created by ashvayka on 05.10.18.
@@ -104,6 +112,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -104,6 +112,7 @@ public class DefaultTransportApiService implements TransportApiService {
104 private final TbClusterService tbClusterService; 112 private final TbClusterService tbClusterService;
105 private final DataDecodingEncodingService dataDecodingEncodingService; 113 private final DataDecodingEncodingService dataDecodingEncodingService;
106 private final DeviceProvisionService deviceProvisionService; 114 private final DeviceProvisionService deviceProvisionService;
  115 + private final ResourceService resourceService;
107 116
108 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>(); 117 private final ConcurrentMap<String, ReentrantLock> deviceCreationLocks = new ConcurrentHashMap<>();
109 118
@@ -112,7 +121,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -112,7 +121,7 @@ public class DefaultTransportApiService implements TransportApiService {
112 RelationService relationService, DeviceCredentialsService deviceCredentialsService, 121 RelationService relationService, DeviceCredentialsService deviceCredentialsService,
113 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService, 122 DeviceStateService deviceStateService, DbCallbackExecutorService dbCallbackExecutorService,
114 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService, 123 TbClusterService tbClusterService, DataDecodingEncodingService dataDecodingEncodingService,
115 - DeviceProvisionService deviceProvisionService) { 124 + DeviceProvisionService deviceProvisionService, ResourceService resourceService) {
116 this.deviceProfileCache = deviceProfileCache; 125 this.deviceProfileCache = deviceProfileCache;
117 this.tenantProfileCache = tenantProfileCache; 126 this.tenantProfileCache = tenantProfileCache;
118 this.apiUsageStateService = apiUsageStateService; 127 this.apiUsageStateService = apiUsageStateService;
@@ -124,6 +133,7 @@ public class DefaultTransportApiService implements TransportApiService { @@ -124,6 +133,7 @@ public class DefaultTransportApiService implements TransportApiService {
124 this.tbClusterService = tbClusterService; 133 this.tbClusterService = tbClusterService;
125 this.dataDecodingEncodingService = dataDecodingEncodingService; 134 this.dataDecodingEncodingService = dataDecodingEncodingService;
126 this.deviceProvisionService = deviceProvisionService; 135 this.deviceProvisionService = deviceProvisionService;
  136 + this.resourceService = resourceService;
127 } 137 }
128 138
129 @Override 139 @Override
@@ -157,6 +167,9 @@ public class DefaultTransportApiService implements TransportApiService { @@ -157,6 +167,9 @@ public class DefaultTransportApiService implements TransportApiService {
157 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) { 167 } else if (transportApiRequestMsg.hasProvisionDeviceRequestMsg()) {
158 return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()), 168 return Futures.transform(handle(transportApiRequestMsg.getProvisionDeviceRequestMsg()),
159 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 169 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
  170 + } else if (transportApiRequestMsg.hasResourcesRequestMsg()) {
  171 + return Futures.transform(handle(transportApiRequestMsg.getResourcesRequestMsg()),
  172 + value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
160 } 173 }
161 return Futures.transform(getEmptyTransportApiResponseFuture(), 174 return Futures.transform(getEmptyTransportApiResponseFuture(),
162 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor()); 175 value -> new TbProtoQueueMsg<>(tbProtoQueueMsg.getKey(), value, tbProtoQueueMsg.getHeaders()), MoreExecutors.directExecutor());
@@ -315,9 +328,9 @@ public class DefaultTransportApiService implements TransportApiService { @@ -315,9 +328,9 @@ public class DefaultTransportApiService implements TransportApiService {
315 return TransportApiResponseMsg.newBuilder().setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder().setStatus(status).build()).build(); 328 return TransportApiResponseMsg.newBuilder().setProvisionDeviceResponseMsg(TransportProtos.ProvisionDeviceResponseMsg.newBuilder().setStatus(status).build()).build();
316 } 329 }
317 TransportProtos.ProvisionDeviceResponseMsg.Builder provisionResponse = TransportProtos.ProvisionDeviceResponseMsg.newBuilder() 330 TransportProtos.ProvisionDeviceResponseMsg.Builder provisionResponse = TransportProtos.ProvisionDeviceResponseMsg.newBuilder()
318 - .setCredentialsType(TransportProtos.CredentialsType.valueOf(deviceCredentials.getCredentialsType().name()))  
319 - .setStatus(status);  
320 - switch (deviceCredentials.getCredentialsType()){ 331 + .setCredentialsType(TransportProtos.CredentialsType.valueOf(deviceCredentials.getCredentialsType().name()))
  332 + .setStatus(status);
  333 + switch (deviceCredentials.getCredentialsType()) {
321 case ACCESS_TOKEN: 334 case ACCESS_TOKEN:
322 provisionResponse.setCredentialsValue(deviceCredentials.getCredentialsId()); 335 provisionResponse.setCredentialsValue(deviceCredentials.getCredentialsId());
323 break; 336 break;
@@ -353,6 +366,40 @@ public class DefaultTransportApiService implements TransportApiService { @@ -353,6 +366,40 @@ public class DefaultTransportApiService implements TransportApiService {
353 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build()); 366 return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setEntityProfileResponseMsg(builder).build());
354 } 367 }
355 368
  369 + private ListenableFuture<TransportApiResponseMsg> handle(GetResourcesRequestMsg requestMsg) {
  370 + TenantId tenantId = new TenantId(new UUID(requestMsg.getTenantIdMSB(), requestMsg.getTenantIdLSB()));
  371 + TransportProtos.GetResourcesResponseMsg.Builder builder = TransportProtos.GetResourcesResponseMsg.newBuilder();
  372 + String resourceType = requestMsg.getResourceType();
  373 + String resourceId = requestMsg.getResourceId();
  374 +
  375 + List<TransportProtos.ResourceMsg> resources;
  376 +
  377 + if (resourceType != null && resourceId != null) {
  378 + resources = Collections.singletonList(toProto(
  379 + resourceService.getResource(tenantId, ResourceType.valueOf(resourceType), resourceId)));
  380 + } else {
  381 + //TODO: add page link params to request proto if need or remove this
  382 + resources = resourceService.findResourcesByTenantId(tenantId, new PageLink(100))
  383 + .getData()
  384 + .stream()
  385 + .map(this::toProto)
  386 + .collect(Collectors.toList());
  387 + }
  388 +
  389 + builder.addAllResources(resources);
  390 + return Futures.immediateFuture(TransportApiResponseMsg.newBuilder().setResourcesResponseMsg(builder).build());
  391 + }
  392 +
  393 + private TransportProtos.ResourceMsg toProto(Resource resource) {
  394 + return TransportProtos.ResourceMsg.newBuilder()
  395 + .setTenantIdMSB(resource.getTenantId().getId().getMostSignificantBits())
  396 + .setTenantIdLSB(resource.getTenantId().getId().getLeastSignificantBits())
  397 + .setResourceType(resource.getResourceType().name())
  398 + .setResourceId(resource.getResourceId())
  399 + .setValue(resource.getValue())
  400 + .build();
  401 + }
  402 +
356 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) { 403 private ListenableFuture<TransportApiResponseMsg> getDeviceInfo(DeviceId deviceId, DeviceCredentials credentials) {
357 return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> { 404 return Futures.transform(deviceService.findDeviceByIdAsync(TenantId.SYS_TENANT_ID, deviceId), device -> {
358 if (device == null) { 405 if (device == null) {
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.resource;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +import org.thingsboard.server.common.data.page.PageData;
  20 +import org.thingsboard.server.common.data.page.PageLink;
  21 +import org.thingsboard.server.common.data.transport.resource.Resource;
  22 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  23 +
  24 +
  25 +public interface ResourceService {
  26 + Resource saveResource(Resource resource);
  27 +
  28 + Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  29 +
  30 + PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink);
  31 +
  32 + void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  33 +
  34 + void deleteResourcesByTenantId(TenantId tenantId);
  35 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.transport.resource;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.HasTenantId;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +
  22 +@Data
  23 +public class Resource implements HasTenantId {
  24 + private TenantId tenantId;
  25 + private ResourceType resourceType;
  26 + private String resourceId;
  27 + private String value;
  28 +
  29 + @Override
  30 + public String toString() {
  31 + return "Resource{" +
  32 + "tenantId=" + tenantId +
  33 + ", resourceType=" + resourceType +
  34 + ", resourceId='" + resourceId + '\'' +
  35 + '}';
  36 + }
  37 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.transport.resource;
  17 +
  18 +public enum ResourceType {
  19 + LWM2M_MODEL, JKS, PKCS_12
  20 +}
@@ -21,6 +21,6 @@ import java.lang.annotation.Retention; @@ -21,6 +21,6 @@ import java.lang.annotation.Retention;
21 import java.lang.annotation.RetentionPolicy; 21 import java.lang.annotation.RetentionPolicy;
22 22
23 @Retention(RetentionPolicy.RUNTIME) 23 @Retention(RetentionPolicy.RUNTIME)
24 -@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true' ) || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')") 24 +@ConditionalOnExpression("('${service.type:null}'=='tb-transport' && '${transport.lwm2m.enabled:false}'=='true') || ('${service.type:null}'=='monolith' && '${transport.lwm2m.enabled}'=='true')")
25 public @interface TbLwM2mTransportComponent { 25 public @interface TbLwM2mTransportComponent {
26 } 26 }
@@ -201,6 +201,25 @@ message LwM2MResponseMsg { @@ -201,6 +201,25 @@ message LwM2MResponseMsg {
201 LwM2MRegistrationResponseMsg registrationMsg = 1; 201 LwM2MRegistrationResponseMsg registrationMsg = 1;
202 } 202 }
203 203
  204 +message ResourceMsg {
  205 + int64 tenantIdMSB = 1;
  206 + int64 tenantIdLSB = 2;
  207 + string resourceType = 3;
  208 + string resourceId = 4;
  209 + string value = 5;
  210 +}
  211 +
  212 +message GetResourcesRequestMsg {
  213 + int64 tenantIdMSB = 1;
  214 + int64 tenantIdLSB = 2;
  215 + string resourceType = 3;
  216 + string resourceId = 4;
  217 +}
  218 +
  219 +message GetResourcesResponseMsg {
  220 + repeated ResourceMsg resources = 1;
  221 +}
  222 +
204 message ValidateDeviceLwM2MCredentialsRequestMsg { 223 message ValidateDeviceLwM2MCredentialsRequestMsg {
205 string credentialsId = 1; 224 string credentialsId = 1;
206 } 225 }
@@ -242,6 +261,20 @@ message EntityDeleteMsg { @@ -242,6 +261,20 @@ message EntityDeleteMsg {
242 int64 entityIdLSB = 3; 261 int64 entityIdLSB = 3;
243 } 262 }
244 263
  264 +message ResourceUpdateMsg {
  265 + int64 tenantIdMSB = 1;
  266 + int64 tenantIdLSB = 2;
  267 + string resourceType = 3;
  268 + string resourceId = 4;
  269 +}
  270 +
  271 +message ResourceDeleteMsg {
  272 + int64 tenantIdMSB = 1;
  273 + int64 tenantIdLSB = 2;
  274 + string resourceType = 3;
  275 + string resourceId = 4;
  276 +}
  277 +
245 message SessionCloseNotificationProto { 278 message SessionCloseNotificationProto {
246 string message = 1; 279 string message = 1;
247 } 280 }
@@ -525,6 +558,7 @@ message TransportApiRequestMsg { @@ -525,6 +558,7 @@ message TransportApiRequestMsg {
525 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6; 558 ValidateBasicMqttCredRequestMsg validateBasicMqttCredRequestMsg = 6;
526 ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7; 559 ProvisionDeviceRequestMsg provisionDeviceRequestMsg = 7;
527 ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8; 560 ValidateDeviceLwM2MCredentialsRequestMsg validateDeviceLwM2MCredentialsRequestMsg = 8;
  561 + GetResourcesRequestMsg resourcesRequestMsg = 9;
528 } 562 }
529 563
530 /* Response from ThingsBoard Core Service to Transport Service */ 564 /* Response from ThingsBoard Core Service to Transport Service */
@@ -534,6 +568,7 @@ message TransportApiResponseMsg { @@ -534,6 +568,7 @@ message TransportApiResponseMsg {
534 GetEntityProfileResponseMsg entityProfileResponseMsg = 3; 568 GetEntityProfileResponseMsg entityProfileResponseMsg = 3;
535 ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4; 569 ProvisionDeviceResponseMsg provisionDeviceResponseMsg = 4;
536 LwM2MResponseMsg lwM2MResponseMsg = 6; 570 LwM2MResponseMsg lwM2MResponseMsg = 6;
  571 + GetResourcesResponseMsg resourcesResponseMsg = 7;
537 } 572 }
538 573
539 /* Messages that are handled by ThingsBoard Core Service */ 574 /* Messages that are handled by ThingsBoard Core Service */
@@ -578,6 +613,8 @@ message ToTransportMsg { @@ -578,6 +613,8 @@ message ToTransportMsg {
578 EntityDeleteMsg entityDeleteMsg = 9; 613 EntityDeleteMsg entityDeleteMsg = 9;
579 ProvisionDeviceResponseMsg provisionResponse = 10; 614 ProvisionDeviceResponseMsg provisionResponse = 10;
580 ToTransportUpdateCredentialsProto toTransportUpdateCredentialsNotification = 11; 615 ToTransportUpdateCredentialsProto toTransportUpdateCredentialsNotification = 11;
  616 + ResourceUpdateMsg resourceUpdateMsg = 12;
  617 + ResourceDeleteMsg resourceDeleteMsg = 13;
581 } 618 }
582 619
583 message UsageStatsKVProto{ 620 message UsageStatsKVProto{
@@ -25,6 +25,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestM @@ -25,6 +25,8 @@ import org.thingsboard.server.gen.transport.TransportProtos.GetAttributeRequestM
25 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg; 25 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileRequestMsg;
26 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg; 26 import org.thingsboard.server.gen.transport.TransportProtos.GetEntityProfileResponseMsg;
27 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg; 27 import org.thingsboard.server.gen.transport.TransportProtos.GetOrCreateDeviceFromGatewayRequestMsg;
  28 +import org.thingsboard.server.gen.transport.TransportProtos.GetResourcesRequestMsg;
  29 +import org.thingsboard.server.gen.transport.TransportProtos.GetResourcesResponseMsg;
28 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg; 30 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MRequestMsg;
29 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg; 31 import org.thingsboard.server.gen.transport.TransportProtos.LwM2MResponseMsg;
30 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg; 32 import org.thingsboard.server.gen.transport.TransportProtos.PostAttributeMsg;
@@ -51,6 +53,8 @@ public interface TransportService { @@ -51,6 +53,8 @@ public interface TransportService {
51 53
52 GetEntityProfileResponseMsg getEntityProfile(GetEntityProfileRequestMsg msg); 54 GetEntityProfileResponseMsg getEntityProfile(GetEntityProfileRequestMsg msg);
53 55
  56 + GetResourcesResponseMsg getResources(GetResourcesRequestMsg msg);
  57 +
54 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg, 58 void process(DeviceTransportType transportType, ValidateDeviceTokenRequestMsg msg,
55 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback); 59 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback);
56 60
@@ -255,6 +255,18 @@ public class DefaultTransportService implements TransportService { @@ -255,6 +255,18 @@ public class DefaultTransportService implements TransportService {
255 } 255 }
256 256
257 @Override 257 @Override
  258 + public TransportProtos.GetResourcesResponseMsg getResources(TransportProtos.GetResourcesRequestMsg msg) {
  259 + TbProtoQueueMsg<TransportProtos.TransportApiRequestMsg> protoMsg =
  260 + new TbProtoQueueMsg<>(UUID.randomUUID(), TransportProtos.TransportApiRequestMsg.newBuilder().setResourcesRequestMsg(msg).build());
  261 + try {
  262 + TbProtoQueueMsg<TransportApiResponseMsg> response = transportApiRequestTemplate.send(protoMsg).get();
  263 + return response.getValue().getResourcesResponseMsg();
  264 + } catch (InterruptedException | ExecutionException e) {
  265 + throw new RuntimeException(e);
  266 + }
  267 + }
  268 +
  269 + @Override
258 public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg, 270 public void process(DeviceTransportType transportType, TransportProtos.ValidateDeviceTokenRequestMsg msg,
259 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) { 271 TransportServiceCallback<ValidateDeviceCredentialsResponse> callback) {
260 log.trace("Processing msg: {}", msg); 272 log.trace("Processing msg: {}", msg);
@@ -688,6 +700,10 @@ public class DefaultTransportService implements TransportService { @@ -688,6 +700,10 @@ public class DefaultTransportService implements TransportService {
688 } else if (EntityType.DEVICE.equals(entityType)) { 700 } else if (EntityType.DEVICE.equals(entityType)) {
689 rateLimitService.remove(new DeviceId(entityUuid)); 701 rateLimitService.remove(new DeviceId(entityUuid));
690 } 702 }
  703 + } else if (toSessionMsg.hasResourceUpdateMsg()) {
  704 + //TODO: update resource cache
  705 + } else if (toSessionMsg.hasResourceDeleteMsg()) {
  706 + //TODO: remove resource from cache
691 } else { 707 } else {
692 //TODO: should we notify the device actor about missed session? 708 //TODO: should we notify the device actor about missed session?
693 log.debug("[{}] Missing session.", sessionId); 709 log.debug("[{}] Missing session.", sessionId);
@@ -695,6 +711,7 @@ public class DefaultTransportService implements TransportService { @@ -695,6 +711,7 @@ public class DefaultTransportService implements TransportService {
695 } 711 }
696 } 712 }
697 713
  714 +
698 public void onProfileUpdate(DeviceProfile deviceProfile) { 715 public void onProfileUpdate(DeviceProfile deviceProfile) {
699 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits(); 716 long deviceProfileIdMSB = deviceProfile.getId().getId().getMostSignificantBits();
700 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits(); 717 long deviceProfileIdLSB = deviceProfile.getId().getId().getLeastSignificantBits();
@@ -454,6 +454,15 @@ public class ModelConstants { @@ -454,6 +454,15 @@ public class ModelConstants {
454 public static final String API_USAGE_STATE_SMS_EXEC_COLUMN = "sms_exec"; 454 public static final String API_USAGE_STATE_SMS_EXEC_COLUMN = "sms_exec";
455 455
456 /** 456 /**
  457 + * Resource constants.
  458 + */
  459 + public static final String RESOURCE_TABLE_NAME = "resource";
  460 + public static final String RESOURCE_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
  461 + public static final String RESOURCE_TYPE_COLUMN = "resource_type";
  462 + public static final String RESOURCE_ID_COLUMN = "resource_id";
  463 + public static final String RESOURCE_VALUE_COLUMN = "resource_value";
  464 +
  465 + /**
457 * Cassandra attributes and timeseries constants. 466 * Cassandra attributes and timeseries constants.
458 */ 467 */
459 public static final String ATTRIBUTES_KV_CF = "attributes_kv_cf"; 468 public static final String ATTRIBUTES_KV_CF = "attributes_kv_cf";
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model.sql;
  17 +
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Data;
  20 +import lombok.NoArgsConstructor;
  21 +import org.thingsboard.server.common.data.relation.EntityRelation;
  22 +import org.thingsboard.server.common.data.transport.resource.Resource;
  23 +
  24 +import javax.persistence.Transient;
  25 +import java.io.Serializable;
  26 +import java.util.UUID;
  27 +
  28 +@NoArgsConstructor
  29 +@AllArgsConstructor
  30 +@Data
  31 +public class ResourceCompositeKey implements Serializable {
  32 +
  33 + @Transient
  34 + private static final long serialVersionUID = -3789469030818742769L;
  35 +
  36 + private UUID tenantId;
  37 + private String resourceType;
  38 + private String resourceId;
  39 +
  40 + public ResourceCompositeKey(Resource resource) {
  41 + this.tenantId = resource.getTenantId().getId();
  42 + this.resourceType = resource.getResourceType().name();
  43 + this.resourceId = resource.getResourceId();
  44 + }
  45 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.model.sql;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.data.transport.resource.Resource;
  21 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  22 +import org.thingsboard.server.dao.model.ToData;
  23 +
  24 +import javax.persistence.Column;
  25 +import javax.persistence.Entity;
  26 +import javax.persistence.Id;
  27 +import javax.persistence.IdClass;
  28 +import javax.persistence.Table;
  29 +import java.util.UUID;
  30 +
  31 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_ID_COLUMN;
  32 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TABLE_NAME;
  33 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TENANT_ID_COLUMN;
  34 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_TYPE_COLUMN;
  35 +import static org.thingsboard.server.dao.model.ModelConstants.RESOURCE_VALUE_COLUMN;
  36 +
  37 +@Data
  38 +@Entity
  39 +@Table(name = RESOURCE_TABLE_NAME)
  40 +@IdClass(ResourceCompositeKey.class)
  41 +public class ResourceEntity implements ToData<Resource> {
  42 +
  43 + @Id
  44 + @Column(name = RESOURCE_TENANT_ID_COLUMN, columnDefinition = "uuid")
  45 + private UUID tenantId;
  46 +
  47 + @Id
  48 + @Column(name = RESOURCE_TYPE_COLUMN)
  49 + private String resourceType;
  50 +
  51 + @Id
  52 + @Column(name = RESOURCE_ID_COLUMN)
  53 + private String resourceId;
  54 +
  55 + @Column(name = RESOURCE_VALUE_COLUMN)
  56 + private String value;
  57 +
  58 + public ResourceEntity() {
  59 + }
  60 +
  61 + public ResourceEntity(Resource resource) {
  62 + this.tenantId = resource.getTenantId().getId();
  63 + this.resourceType = resource.getResourceType().name();
  64 + this.resourceId = resource.getResourceId();
  65 + this.value = resource.getValue();
  66 + }
  67 +
  68 + @Override
  69 + public Resource toData() {
  70 + Resource resource = new Resource();
  71 + resource.setTenantId(new TenantId(tenantId));
  72 + resource.setResourceType(ResourceType.valueOf(resourceType));
  73 + resource.setResourceId(resourceId);
  74 + resource.setValue(value);
  75 + return resource;
  76 + }
  77 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.resource;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Service;
  20 +import org.thingsboard.server.common.data.id.TenantId;
  21 +import org.thingsboard.server.common.data.page.PageData;
  22 +import org.thingsboard.server.common.data.page.PageLink;
  23 +import org.thingsboard.server.common.data.transport.resource.Resource;
  24 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  25 +import org.thingsboard.server.dao.exception.DataValidationException;
  26 +
  27 +import static org.thingsboard.server.dao.device.DeviceServiceImpl.INCORRECT_TENANT_ID;
  28 +import static org.thingsboard.server.dao.service.Validator.validateId;
  29 +
  30 +@Service
  31 +@Slf4j
  32 +public class BaseResourceService implements ResourceService {
  33 +
  34 + private final ResourceDao resourceDao;
  35 +
  36 + public BaseResourceService(ResourceDao resourceDao) {
  37 + this.resourceDao = resourceDao;
  38 + }
  39 +
  40 + @Override
  41 + public Resource saveResource(Resource resource) {
  42 + log.trace("Executing saveResource [{}]", resource);
  43 + validate(resource);
  44 + return resourceDao.saveResource(resource);
  45 + }
  46 +
  47 + @Override
  48 + public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
  49 + log.trace("Executing getResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
  50 + validate(tenantId, resourceType, resourceId);
  51 + return resourceDao.getResource(tenantId, resourceType, resourceId);
  52 + }
  53 +
  54 + @Override
  55 + public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
  56 + log.trace("Executing deleteResource [{}] [{}] [{}]", tenantId, resourceType, resourceId);
  57 + validate(tenantId, resourceType, resourceId);
  58 + resourceDao.deleteResource(tenantId, resourceType, resourceId);
  59 + }
  60 +
  61 + @Override
  62 + public PageData<Resource> findResourcesByTenantId(TenantId tenantId, PageLink pageLink) {
  63 + log.trace("Executing findByTenantId [{}]", tenantId);
  64 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  65 + return resourceDao.findAllByTenantId(tenantId, pageLink);
  66 + }
  67 +
  68 + @Override
  69 + public void deleteResourcesByTenantId(TenantId tenantId) {
  70 + log.trace("Executing deleteDevicesByTenantId, tenantId [{}]", tenantId);
  71 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  72 + resourceDao.removeAllByTenantId(tenantId);
  73 + }
  74 +
  75 + protected void validate(Resource resource) {
  76 + if (resource == null) {
  77 + throw new DataValidationException("Resource should be specified!");
  78 + }
  79 +
  80 + if (resource.getValue() == null) {
  81 + throw new DataValidationException("Resource value should be specified!");
  82 + }
  83 + validate(resource.getTenantId(), resource.getResourceType(), resource.getResourceId());
  84 + }
  85 +
  86 + protected void validate(TenantId tenantId, ResourceType resourceType, String resourceId) {
  87 + if (resourceType == null) {
  88 + throw new DataValidationException("Resource type should be specified!");
  89 + }
  90 + if (resourceId == null) {
  91 + throw new DataValidationException("Resource id should be specified!");
  92 + }
  93 + validateId(tenantId, "Incorrect tenantId ");
  94 + }
  95 +
  96 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.resource;
  17 +
  18 +import org.thingsboard.server.common.data.id.TenantId;
  19 +import org.thingsboard.server.common.data.page.PageData;
  20 +import org.thingsboard.server.common.data.page.PageLink;
  21 +import org.thingsboard.server.common.data.transport.resource.Resource;
  22 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  23 +
  24 +public interface ResourceDao {
  25 +
  26 + Resource saveResource(Resource resource);
  27 +
  28 + Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  29 +
  30 + void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId);
  31 +
  32 + PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink);
  33 +
  34 + void removeAllByTenantId(TenantId tenantId);
  35 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.resource;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.stereotype.Component;
  20 +import org.springframework.transaction.annotation.Transactional;
  21 +import org.thingsboard.server.common.data.id.TenantId;
  22 +import org.thingsboard.server.common.data.page.PageData;
  23 +import org.thingsboard.server.common.data.page.PageLink;
  24 +import org.thingsboard.server.common.data.transport.resource.Resource;
  25 +import org.thingsboard.server.common.data.transport.resource.ResourceType;
  26 +import org.thingsboard.server.dao.DaoUtil;
  27 +import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
  28 +import org.thingsboard.server.dao.model.sql.ResourceEntity;
  29 +import org.thingsboard.server.dao.resource.ResourceDao;
  30 +
  31 +@Slf4j
  32 +@Component
  33 +public class ResourceDaoImpl implements ResourceDao {
  34 +
  35 + private final ResourceRepository resourceRepository;
  36 +
  37 + public ResourceDaoImpl(ResourceRepository resourceRepository) {
  38 + this.resourceRepository = resourceRepository;
  39 + }
  40 +
  41 + @Override
  42 + @Transactional
  43 + public Resource saveResource(Resource resource) {
  44 + return DaoUtil.getData(resourceRepository.save(new ResourceEntity(resource)));
  45 + }
  46 +
  47 + @Override
  48 + public Resource getResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
  49 + ResourceCompositeKey key = new ResourceCompositeKey();
  50 + key.setTenantId(tenantId.getId());
  51 + key.setResourceType(resourceType.name());
  52 + key.setResourceId(resourceId);
  53 +
  54 + return DaoUtil.getData(resourceRepository.findById(key));
  55 + }
  56 +
  57 + @Override
  58 + @Transactional
  59 + public void deleteResource(TenantId tenantId, ResourceType resourceType, String resourceId) {
  60 + ResourceCompositeKey key = new ResourceCompositeKey();
  61 + key.setTenantId(tenantId.getId());
  62 + key.setResourceType(resourceType.name());
  63 + key.setResourceId(resourceId);
  64 +
  65 + resourceRepository.deleteById(key);
  66 + }
  67 +
  68 + @Override
  69 + public PageData<Resource> findAllByTenantId(TenantId tenantId, PageLink pageLink) {
  70 + return DaoUtil.toPageData(resourceRepository.findAllByTenantId(tenantId.getId(), DaoUtil.toPageable(pageLink)));
  71 + }
  72 +
  73 + @Override
  74 + public void removeAllByTenantId(TenantId tenantId) {
  75 + resourceRepository.removeAllByTenantId(tenantId.getId());
  76 + }
  77 +}
  1 +/**
  2 + * Copyright © 2016-2021 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.resource;
  17 +
  18 +import org.springframework.data.domain.Page;
  19 +import org.springframework.data.domain.Pageable;
  20 +import org.springframework.data.repository.CrudRepository;
  21 +import org.thingsboard.server.dao.model.sql.ResourceCompositeKey;
  22 +import org.thingsboard.server.dao.model.sql.ResourceEntity;
  23 +
  24 +import java.util.UUID;
  25 +
  26 +public interface ResourceRepository extends CrudRepository<ResourceEntity, ResourceCompositeKey> {
  27 +
  28 + Page<ResourceEntity> findAllByTenantId(UUID tenantId, Pageable pageable);
  29 +
  30 + void removeAllByTenantId(UUID tenantId);
  31 +}
@@ -35,6 +35,7 @@ import org.thingsboard.server.dao.device.DeviceService; @@ -35,6 +35,7 @@ import org.thingsboard.server.dao.device.DeviceService;
35 import org.thingsboard.server.dao.entity.AbstractEntityService; 35 import org.thingsboard.server.dao.entity.AbstractEntityService;
36 import org.thingsboard.server.dao.entityview.EntityViewService; 36 import org.thingsboard.server.dao.entityview.EntityViewService;
37 import org.thingsboard.server.dao.exception.DataValidationException; 37 import org.thingsboard.server.dao.exception.DataValidationException;
  38 +import org.thingsboard.server.dao.resource.ResourceService;
38 import org.thingsboard.server.dao.rule.RuleChainService; 39 import org.thingsboard.server.dao.rule.RuleChainService;
39 import org.thingsboard.server.dao.service.DataValidator; 40 import org.thingsboard.server.dao.service.DataValidator;
40 import org.thingsboard.server.dao.service.PaginatedRemover; 41 import org.thingsboard.server.dao.service.PaginatedRemover;
@@ -88,6 +89,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -88,6 +89,9 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
88 @Autowired 89 @Autowired
89 private RuleChainService ruleChainService; 90 private RuleChainService ruleChainService;
90 91
  92 + @Autowired
  93 + private ResourceService resourceService;
  94 +
91 @Override 95 @Override
92 public Tenant findTenantById(TenantId tenantId) { 96 public Tenant findTenantById(TenantId tenantId) {
93 log.trace("Executing findTenantById [{}]", tenantId); 97 log.trace("Executing findTenantById [{}]", tenantId);
@@ -140,6 +144,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe @@ -140,6 +144,7 @@ public class TenantServiceImpl extends AbstractEntityService implements TenantSe
140 userService.deleteTenantAdmins(tenantId); 144 userService.deleteTenantAdmins(tenantId);
141 ruleChainService.deleteRuleChainsByTenantId(tenantId); 145 ruleChainService.deleteRuleChainsByTenantId(tenantId);
142 apiUsageStateService.deleteApiUsageStateByTenantId(tenantId); 146 apiUsageStateService.deleteApiUsageStateByTenantId(tenantId);
  147 + resourceService.deleteResourcesByTenantId(tenantId);
143 tenantDao.removeById(tenantId, tenantId.getId()); 148 tenantDao.removeById(tenantId, tenantId.getId());
144 deleteEntityRelations(tenantId, tenantId); 149 deleteEntityRelations(tenantId, tenantId);
145 } 150 }
@@ -420,3 +420,11 @@ CREATE TABLE IF NOT EXISTS api_usage_state ( @@ -420,3 +420,11 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
420 sms_exec varchar(32), 420 sms_exec varchar(32),
421 CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id) 421 CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)
422 ); 422 );
  423 +
  424 +CREATE TABLE IF NOT EXISTS resource (
  425 + tenant_id uuid NOT NULL,
  426 + resource_type varchar(32) NOT NULL,
  427 + resource_id varchar(255) NOT NULL,
  428 + resource_value varchar,
  429 + CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
  430 +);
@@ -447,6 +447,14 @@ CREATE TABLE IF NOT EXISTS api_usage_state ( @@ -447,6 +447,14 @@ CREATE TABLE IF NOT EXISTS api_usage_state (
447 CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id) 447 CONSTRAINT api_usage_state_unq_key UNIQUE (tenant_id, entity_id)
448 ); 448 );
449 449
  450 +CREATE TABLE IF NOT EXISTS resource (
  451 + tenant_id uuid NOT NULL,
  452 + resource_type varchar(32) NOT NULL,
  453 + resource_id varchar(255) NOT NULL,
  454 + resource_value varchar,
  455 + CONSTRAINT resource_unq_key UNIQUE (tenant_id, resource_type, resource_id)
  456 +);
  457 +
450 CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint) 458 CREATE OR REPLACE PROCEDURE cleanup_events_by_ttl(IN ttl bigint, IN debug_ttl bigint, INOUT deleted bigint)
451 LANGUAGE plpgsql AS 459 LANGUAGE plpgsql AS
452 $$ 460 $$
@@ -28,4 +28,5 @@ DROP TABLE IF EXISTS oauth2_client_registration; @@ -28,4 +28,5 @@ DROP TABLE IF EXISTS oauth2_client_registration;
28 DROP TABLE IF EXISTS oauth2_client_registration_info; 28 DROP TABLE IF EXISTS oauth2_client_registration_info;
29 DROP TABLE IF EXISTS oauth2_client_registration_template; 29 DROP TABLE IF EXISTS oauth2_client_registration_template;
30 DROP TABLE IF EXISTS api_usage_state; 30 DROP TABLE IF EXISTS api_usage_state;
  31 +DROP TABLE IF EXISTS resource;
31 DROP FUNCTION IF EXISTS to_uuid; 32 DROP FUNCTION IF EXISTS to_uuid;
@@ -28,4 +28,5 @@ DROP TABLE IF EXISTS tb_schema_settings; @@ -28,4 +28,5 @@ DROP TABLE IF EXISTS tb_schema_settings;
28 DROP TABLE IF EXISTS oauth2_client_registration; 28 DROP TABLE IF EXISTS oauth2_client_registration;
29 DROP TABLE IF EXISTS oauth2_client_registration_info; 29 DROP TABLE IF EXISTS oauth2_client_registration_info;
30 DROP TABLE IF EXISTS oauth2_client_registration_template; 30 DROP TABLE IF EXISTS oauth2_client_registration_template;
31 -DROP TABLE IF EXISTS api_usage_state;  
  31 +DROP TABLE IF EXISTS api_usage_state;
  32 +DROP TABLE IF EXISTS resource;